diff options
author | Don Kjer <don@lindenlab.com> | 2007-11-09 01:56:15 +0000 |
---|---|---|
committer | Don Kjer <don@lindenlab.com> | 2007-11-09 01:56:15 +0000 |
commit | c1920e3c1c60fb792cf091750b05de618b355878 (patch) | |
tree | 204b78e0f0b87fb2875b90af0f579d53e3138cbb /indra/llcommon | |
parent | 760f2ceb1518d87e865f25ac87a540625e974517 (diff) |
EFFECTIVE MERGE: svn merge -r 70833:71458 svn+ssh://svn/svn/linden/branches/maintenance-2 into release
ACTUAL MERGE: svn merge -r 73210:73222 svn+ssh://svn/svn/linden/qa/maintenance-2-merge-73206 into release
Diffstat (limited to 'indra/llcommon')
-rw-r--r-- | indra/llcommon/llapp.cpp | 34 | ||||
-rw-r--r-- | indra/llcommon/llkeythrottle.h | 205 | ||||
-rw-r--r-- | indra/llcommon/llsd.h | 1 | ||||
-rw-r--r-- | indra/llcommon/llsdserialize.cpp | 5 |
4 files changed, 245 insertions, 0 deletions
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index b0751b80e9..2347ac9cd9 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -47,6 +47,7 @@ // #if LL_WINDOWS LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop); +BOOL ConsoleCtrlHandler(DWORD fdwCtrlType); #else #include <unistd.h> // for fork() void setup_signals(); @@ -219,6 +220,11 @@ void LLApp::setupErrorHandling() // Disable this until the viewer gets ported so server crashes can be JIT debugged. //LPTOP_LEVEL_EXCEPTION_FILTER prev_filter; //prev_filter = SetUnhandledExceptionFilter(default_windows_exception_handler); + + // This sets a callback to handle w32 signals to the console window. + // The viewer shouldn't be affected, sicne its a windowed app. + SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ConsoleCtrlHandler, TRUE); + #else // // Start up signal handling. @@ -399,6 +405,34 @@ LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *except return retval; } +// Win32 doesn't support signals. This is used instead. +BOOL ConsoleCtrlHandler(DWORD fdwCtrlType) +{ + switch (fdwCtrlType) + { + case CTRL_BREAK_EVENT: + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + case CTRL_CLOSE_EVENT: // From end task or the window close button. + case CTRL_C_EVENT: // from CTRL-C on the keyboard + // Just set our state to quitting, not error + if (LLApp::isQuitting() || LLApp::isError()) + { + // We're already trying to die, just ignore this signal + if (LLApp::sLogInSignal) + { + llinfos << "Signal handler - Already trying to quit, ignoring signal!" << llendl; + } + return TRUE; + } + LLApp::setQuitting(); + return TRUE; + + default: + return FALSE; + } +} + #else //!LL_WINDOWS void LLApp::setChildCallback(pid_t pid, LLAppChildCallback callback) { diff --git a/indra/llcommon/llkeythrottle.h b/indra/llcommon/llkeythrottle.h new file mode 100644 index 0000000000..708f23f3b1 --- /dev/null +++ b/indra/llcommon/llkeythrottle.h @@ -0,0 +1,205 @@ +/** + * @file llkeythrottle.h + * @brief LLKeyThrottle class definition + * + * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#ifndef LL_LLKEY_THROTTLE_H +#define LL_LLKEY_THROTTLE_H + +// LLKeyThrottle keeps track of the number of action occurences with a key value +// for a type over a given time period. If the rate set in the constructor is +// exceeed, the key is considered blocked. The transition from unblocked to +// blocked is noted so the responsible agent can be informed. This transition +// takes twice the look back window to clear. + +#include "linden_common.h" + +#include "llframetimer.h" +#include <map> + + +// Implementation utility class - use LLKeyThrottle, not this +template <class T> +class LLKeyThrottleImpl +{ +public: + struct Entry { + U32 count; + BOOL blocked; + + Entry() : count(0), blocked(FALSE) { } + }; + + typedef std::map<T, Entry> EntryMap; + + EntryMap * prevMap; + EntryMap * currMap; + + U32 countLimit; + // maximum number of keys allowed per interval + + U64 interval_usec; + // each map covers this time period + U64 start_usec; + // currMap started counting at this time + // prevMap covers the previous interval + + LLKeyThrottleImpl() : prevMap(0), currMap(0) { } + + static U64 getTime() + { + return LLFrameTimer::getTotalTime(); + } +}; + + +template< class T > +class LLKeyThrottle +{ +public: + LLKeyThrottle(U32 limit, F32 interval) + : m(* new LLKeyThrottleImpl<T>) + { + // limit is the maximum number of keys + // allowed per interval (in seconds) + m.countLimit = limit; + m.interval_usec = (U64)(interval * USEC_PER_SEC); + m.start_usec = LLKeyThrottleImpl<T>::getTime(); + + m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap; + m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap; + } + + ~LLKeyThrottle() + { + delete m.prevMap; + delete m.currMap; + delete &m; + } + + enum State { + THROTTLE_OK, // rate not exceeded, let pass + THROTTLE_NEWLY_BLOCKED, // rate exceed for the first time + THROTTLE_BLOCKED, // rate exceed, block key + }; + + // call each time the key wants use + State noteAction(const T& id, S32 weight = 1) + { + U64 now = LLKeyThrottleImpl<T>::getTime(); + + if (now >= (m.start_usec + m.interval_usec)) + { + if (now < (m.start_usec + 2 * m.interval_usec)) + { + // prune old data + delete m.prevMap; + m.prevMap = m.currMap; + m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap; + + m.start_usec += m.interval_usec; + } + else + { + // lots of time has passed, all data is stale + delete m.prevMap; + delete m.currMap; + m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap; + m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap; + + m.start_usec = now; + } + } + + U32 prevCount = 0; + BOOL prevBlocked = FALSE; + + typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id); + if (prev != m.prevMap->end()) + { + prevCount = prev->second.count; + prevBlocked = prev->second.blocked; + } + + typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id]; + + bool wereBlocked = curr.blocked || prevBlocked; + + curr.count += weight; + + // curr.count is the number of keys in + // this current 'time slice' from the beginning of it until now + // prevCount is the number of keys in the previous + // time slice scaled to be one full time slice back from the current + // (now) time. + + // compute current, windowed rate + F64 timeInCurrent = ((F64)(now - m.start_usec) / m.interval_usec); + F64 averageCount = curr.count + prevCount * (1.0 - timeInCurrent); + + curr.blocked |= averageCount > m.countLimit; + + bool nowBlocked = curr.blocked || prevBlocked; + + if (!nowBlocked) + { + return THROTTLE_OK; + } + else if (!wereBlocked) + { + return THROTTLE_NEWLY_BLOCKED; + } + else + { + return THROTTLE_BLOCKED; + } + } + + // call to force throttle conditions for id + void throttleAction(const T& id) + { + noteAction(id); + typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id]; + if (curr.count < m.countLimit) + { + curr.count = m.countLimit; + } + curr.blocked = TRUE; + } + + // returns TRUE if key is blocked + BOOL isThrottled(const T& id) const + { + if (m.currMap->empty() + && m.prevMap->empty()) + { + // most of the time we'll fall in here + return FALSE; + } + + // NOTE, we ignore the case where id is in the map but the map is stale. + // You might think that we'd stop throttling things in such a case, + // however it may be that a god has disabled scripts in the region or + // estate --> we probably want to report the state of the id when the + // scripting engine was paused. + typename LLKeyThrottleImpl<T>::EntryMap::const_iterator entry = m.currMap->find(id); + if (entry != m.currMap->end()) + { + return entry->second.blocked; + } + entry = m.prevMap->find(id); + if (entry != m.prevMap->end()) + { + return entry->second.blocked; + } + return FALSE; + } + +protected: + LLKeyThrottleImpl<T>& m; +}; + +#endif diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h index 1fb917f0f9..65ba7ddc4f 100644 --- a/indra/llcommon/llsd.h +++ b/indra/llcommon/llsd.h @@ -376,6 +376,7 @@ struct llsd_select_string : public std::unary_function<LLSD, LLSD::String> } }; +std::ostream& operator<<(std::ostream& s, const LLSD& llsd); /** QUESTIONS & TO DOS - Would Binary be more convenient as usigned char* buffer semantics? diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index a7470bec8b..5ab94715c5 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -1641,4 +1641,9 @@ void serialize_string(const std::string& value, std::ostream& str) } } +std::ostream& operator<<(std::ostream& s, const LLSD& llsd) +{ + s << LLSDNotationStreamer(llsd); + return s; +} |