summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
authorDon Kjer <don@lindenlab.com>2007-11-09 01:56:15 +0000
committerDon Kjer <don@lindenlab.com>2007-11-09 01:56:15 +0000
commitc1920e3c1c60fb792cf091750b05de618b355878 (patch)
tree204b78e0f0b87fb2875b90af0f579d53e3138cbb /indra/llcommon
parent760f2ceb1518d87e865f25ac87a540625e974517 (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.cpp34
-rw-r--r--indra/llcommon/llkeythrottle.h205
-rw-r--r--indra/llcommon/llsd.h1
-rw-r--r--indra/llcommon/llsdserialize.cpp5
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;
+}