summaryrefslogtreecommitdiff
path: root/indra/llcommon/llerror.h
diff options
context:
space:
mode:
authorAndrey Lihatskiy <alihatskiy@productengine.com>2024-04-29 07:43:28 +0300
committerAndrey Lihatskiy <alihatskiy@productengine.com>2024-04-29 07:56:09 +0300
commit1b68f71348ecf3983b76b40d7940da8377f049b7 (patch)
tree2974eddaef130a067c26033d60a59fc790365b3d /indra/llcommon/llerror.h
parentaf4ea94efc1999f3b19fd8d643d0331f0b77e265 (diff)
#824 Process source files in bulk: replace tabs with spaces, convert CRLF to LF, and trim trailing whitespaces as needed
Diffstat (limited to 'indra/llcommon/llerror.h')
-rw-r--r--indra/llcommon/llerror.h480
1 files changed, 240 insertions, 240 deletions
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index 6f6b349cf5..6176ce0d1d 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -1,4 +1,4 @@
-/**
+/**
* @file llerror.h
* @date December 2006
* @brief error message system
@@ -6,21 +6,21 @@
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -79,16 +79,16 @@ const int LL_ERR_NOERR = 0;
#define llassert_always_msg(func, msg) if (LL_UNLIKELY(!(func))) LL_ERRS() << "ASSERT (" << msg << ")" << LL_ENDL
-#define llassert_always(func) llassert_always_msg(func, #func)
+#define llassert_always(func) llassert_always_msg(func, #func)
#ifdef SHOW_ASSERT
-#define llassert(func) llassert_always_msg(func, #func)
-#define llassert_msg(func, msg) llassert_always_msg(func, msg)
-#define llverify(func) llassert_always_msg(func, #func)
+#define llassert(func) llassert_always_msg(func, #func)
+#define llassert_msg(func, msg) llassert_always_msg(func, msg)
+#define llverify(func) llassert_always_msg(func, #func)
#else
#define llassert(func)
#define llassert_msg(func, msg)
-#define llverify(func) do {if (func) {}} while(0)
+#define llverify(func) do {if (func) {}} while(0)
#endif
#ifdef LL_WINDOWS
@@ -102,59 +102,59 @@ const int LL_ERR_NOERR = 0;
/** Error Logging Facility
- Information for most users:
-
- Code can log messages with constructions like this:
-
- LL_INFOS("StringTag") << "request to fizzbip agent " << agent_id
- << " denied due to timeout" << LL_ENDL;
-
- Messages can be logged to one of four increasing levels of concern,
- using one of four "streams":
-
- LL_DEBUGS("StringTag") - debug messages that are normally suppressed
- LL_INFOS("StringTag") - informational messages that are normal shown
- LL_WARNS("StringTag") - warning messages that signal a problem
- LL_ERRS("StringTag") - error messages that are major, unrecoverable failures
-
- The later (LL_ERRS("StringTag")) automatically crashes the process after the message
- is logged.
-
- Note that these "streams" are actually #define magic. Rules for use:
- * they cannot be used as normal streams, only to start a message
- * messages written to them MUST be terminated with LL_ENDL
- * between the opening and closing, the << operator is indeed
- writing onto a std::ostream, so all conversions and stream
- formating are available
-
- These messages are automatically logged with function name, and (if enabled)
- file and line of the message. (Note: Existing messages that already include
- the function name don't get name printed twice.)
-
- If you have a class, adding LOG_CLASS line to the declaration will cause
- all messages emitted from member functions (normal and static) to be tagged
- with the proper class name as well as the function name:
-
- class LLFoo
- {
- LOG_CLASS(LLFoo);
- public:
- ...
- };
-
- void LLFoo::doSomething(int i)
- {
- if (i > 100)
- {
- LL_WARNS("FooBarTag") << "called with a big value for i: " << i << LL_ENDL;
- }
- ...
- }
-
- will result in messages like:
-
- WARN #FooBarTag# llcommon/llfoo(100) LLFoo::doSomething : called with a big value for i: 283
-
+ Information for most users:
+
+ Code can log messages with constructions like this:
+
+ LL_INFOS("StringTag") << "request to fizzbip agent " << agent_id
+ << " denied due to timeout" << LL_ENDL;
+
+ Messages can be logged to one of four increasing levels of concern,
+ using one of four "streams":
+
+ LL_DEBUGS("StringTag") - debug messages that are normally suppressed
+ LL_INFOS("StringTag") - informational messages that are normal shown
+ LL_WARNS("StringTag") - warning messages that signal a problem
+ LL_ERRS("StringTag") - error messages that are major, unrecoverable failures
+
+ The later (LL_ERRS("StringTag")) automatically crashes the process after the message
+ is logged.
+
+ Note that these "streams" are actually #define magic. Rules for use:
+ * they cannot be used as normal streams, only to start a message
+ * messages written to them MUST be terminated with LL_ENDL
+ * between the opening and closing, the << operator is indeed
+ writing onto a std::ostream, so all conversions and stream
+ formating are available
+
+ These messages are automatically logged with function name, and (if enabled)
+ file and line of the message. (Note: Existing messages that already include
+ the function name don't get name printed twice.)
+
+ If you have a class, adding LOG_CLASS line to the declaration will cause
+ all messages emitted from member functions (normal and static) to be tagged
+ with the proper class name as well as the function name:
+
+ class LLFoo
+ {
+ LOG_CLASS(LLFoo);
+ public:
+ ...
+ };
+
+ void LLFoo::doSomething(int i)
+ {
+ if (i > 100)
+ {
+ LL_WARNS("FooBarTag") << "called with a big value for i: " << i << LL_ENDL;
+ }
+ ...
+ }
+
+ will result in messages like:
+
+ WARN #FooBarTag# llcommon/llfoo(100) LLFoo::doSomething : called with a big value for i: 283
+
the syntax is:
<timestamp> SPACE <level> SPACE <tags> SPACE <location> SPACE <function> SPACE COLON SPACE <message>
@@ -164,121 +164,121 @@ const int LL_ERR_NOERR = 0;
The tags must be a single word (may not contain a space); if more than one tag is specified,
they are all surrounded by '#' ( #FooTag#BarTag# ).
- Which messages are logged and which are suppressed can be controlled at run
- time from the configuration file. The default configuration is in newview/app_settings/logcontrol.xml
+ Which messages are logged and which are suppressed can be controlled at run
+ time from the configuration file. The default configuration is in newview/app_settings/logcontrol.xml
A copy of that file named logcontrol-dev.xml can be made in the users personal settings
directory; that will override the installed default file. See the logcontrol.xml
file or http://wiki.secondlife.com/wiki/Logging_System_Overview for configuration details.
-
- Lastly, logging is now very efficient in both compiled code and execution
- when skipped. There is no need to wrap messages, even debugging ones, in
- #ifdef _DEBUG constructs. LL_DEBUGS("StringTag") messages are compiled into all builds,
- even release. Which means you can use them to help debug even when deployed
- to a real grid.
+
+ Lastly, logging is now very efficient in both compiled code and execution
+ when skipped. There is no need to wrap messages, even debugging ones, in
+ #ifdef _DEBUG constructs. LL_DEBUGS("StringTag") messages are compiled into all builds,
+ even release. Which means you can use them to help debug even when deployed
+ to a real grid.
*/
namespace LLError
{
- enum ELevel
- {
- LEVEL_ALL = 0,
- // used to indicate that all messages should be logged
-
- LEVEL_DEBUG = 0,
- LEVEL_INFO = 1,
- LEVEL_WARN = 2,
- LEVEL_ERROR = 3, // used to be called FATAL
-
- LEVEL_NONE = 4
- // not really a level
- // used to indicate that no messages should be logged
- };
- // If you change ELevel, please update llvlog() macro below.
-
- /* Macro support
- The classes CallSite and Log are used by the logging macros below.
- They are not intended for general use.
- */
-
- struct CallSite;
-
- class LL_COMMON_API Log
- {
- public:
- static bool shouldLog(CallSite&);
- static void flush(const std::ostringstream&, const CallSite&);
- static std::string demangle(const char* mangled);
- /// classname<TYPE>()
- template <typename T>
- static std::string classname() { return demangle(typeid(T).name()); }
- /// classname(some_pointer)
- template <typename T>
- static std::string classname(T* const ptr) { return ptr? demangle(typeid(*ptr).name()) : "nullptr"; }
- /// classname(some_reference)
- template <typename T>
- static std::string classname(const T& obj) { return demangle(typeid(obj).name()); }
- };
-
- struct LL_COMMON_API CallSite
- {
- // Represents a specific place in the code where a message is logged
- // This is public because it is used by the macros below. It is not
- // intended for public use.
- CallSite(ELevel level,
- const char* file,
- int line,
- const std::type_info& class_info,
- const char* function,
- bool print_once,
- const char** tags,
- size_t tag_count);
-
- ~CallSite();
+ enum ELevel
+ {
+ LEVEL_ALL = 0,
+ // used to indicate that all messages should be logged
+
+ LEVEL_DEBUG = 0,
+ LEVEL_INFO = 1,
+ LEVEL_WARN = 2,
+ LEVEL_ERROR = 3, // used to be called FATAL
+
+ LEVEL_NONE = 4
+ // not really a level
+ // used to indicate that no messages should be logged
+ };
+ // If you change ELevel, please update llvlog() macro below.
+
+ /* Macro support
+ The classes CallSite and Log are used by the logging macros below.
+ They are not intended for general use.
+ */
+
+ struct CallSite;
+
+ class LL_COMMON_API Log
+ {
+ public:
+ static bool shouldLog(CallSite&);
+ static void flush(const std::ostringstream&, const CallSite&);
+ static std::string demangle(const char* mangled);
+ /// classname<TYPE>()
+ template <typename T>
+ static std::string classname() { return demangle(typeid(T).name()); }
+ /// classname(some_pointer)
+ template <typename T>
+ static std::string classname(T* const ptr) { return ptr? demangle(typeid(*ptr).name()) : "nullptr"; }
+ /// classname(some_reference)
+ template <typename T>
+ static std::string classname(const T& obj) { return demangle(typeid(obj).name()); }
+ };
+
+ struct LL_COMMON_API CallSite
+ {
+ // Represents a specific place in the code where a message is logged
+ // This is public because it is used by the macros below. It is not
+ // intended for public use.
+ CallSite(ELevel level,
+ const char* file,
+ int line,
+ const std::type_info& class_info,
+ const char* function,
+ bool print_once,
+ const char** tags,
+ size_t tag_count);
+
+ ~CallSite();
#ifdef LL_LIBRARY_INCLUDE
- bool shouldLog();
+ bool shouldLog();
#else // LL_LIBRARY_INCLUDE
- bool shouldLog()
- {
- return mCached
- ? mShouldLog
- : Log::shouldLog(*this);
- }
- // this member function needs to be in-line for efficiency
+ bool shouldLog()
+ {
+ return mCached
+ ? mShouldLog
+ : Log::shouldLog(*this);
+ }
+ // this member function needs to be in-line for efficiency
#endif // LL_LIBRARY_INCLUDE
-
- void invalidate();
-
- // these describe the call site and never change
- const ELevel mLevel;
- const char* const mFile;
- const int mLine;
- const std::type_info& mClassInfo;
- const char* const mFunction;
- const char** mTags;
- size_t mTagCount;
- const bool mPrintOnce;
- const char* mLevelString;
- std::string mLocationString,
- mFunctionString,
- mTagString;
- bool mCached,
- mShouldLog;
-
- friend class Log;
- };
-
-
- class End { };
- inline std::ostream& operator<<(std::ostream& s, const End&)
- { return s; }
- // used to indicate the end of a message
-
- class LL_COMMON_API NoClassInfo { };
- // used to indicate no class info known for logging
+
+ void invalidate();
+
+ // these describe the call site and never change
+ const ELevel mLevel;
+ const char* const mFile;
+ const int mLine;
+ const std::type_info& mClassInfo;
+ const char* const mFunction;
+ const char** mTags;
+ size_t mTagCount;
+ const bool mPrintOnce;
+ const char* mLevelString;
+ std::string mLocationString,
+ mFunctionString,
+ mTagString;
+ bool mCached,
+ mShouldLog;
+
+ friend class Log;
+ };
+
+
+ class End { };
+ inline std::ostream& operator<<(std::ostream& s, const End&)
+ { return s; }
+ // used to indicate the end of a message
+
+ class LL_COMMON_API NoClassInfo { };
+ // used to indicate no class info known for logging
//LLCallStacks keeps track of call stacks and output the call stacks to log file
//
- //Note: to be simple, efficient and necessary to keep track of correct call stacks,
+ //Note: to be simple, efficient and necessary to keep track of correct call stacks,
//LLCallStacks is designed not to be thread-safe.
//so try not to use it in multiple parallel threads at same time.
//Used in a single thread at a time is fine.
@@ -287,8 +287,8 @@ namespace LLError
private:
typedef std::vector<std::string> StringVector;
static StringVector sBuffer ;
-
- public:
+
+ public:
static void push(const char* function, const int line) ;
static void insert(std::ostream& out, const char* function, const int line) ;
static void print() ;
@@ -326,34 +326,34 @@ namespace LLError
};
}
-//this is cheaper than llcallstacks if no need to output other variables to call stacks.
+//this is cheaper than llcallstacks if no need to output other variables to call stacks.
#define LL_PUSH_CALLSTACKS() LLError::LLCallStacks::push(__FUNCTION__, __LINE__)
#define llcallstacks \
- { \
- std::ostringstream _out; \
- LLError::LLCallStacks::insert(_out, __FUNCTION__, __LINE__) ; \
- _out
+ { \
+ std::ostringstream _out; \
+ LLError::LLCallStacks::insert(_out, __FUNCTION__, __LINE__) ; \
+ _out
#define llcallstacksendl \
- LLError::End(); \
- LLError::LLCallStacks::end(_out) ; \
- }
+ LLError::End(); \
+ LLError::LLCallStacks::end(_out) ; \
+ }
#define LL_CLEAR_CALLSTACKS() LLError::LLCallStacks::clear()
-#define LL_PRINT_CALLSTACKS() LLError::LLCallStacks::print()
+#define LL_PRINT_CALLSTACKS() LLError::LLCallStacks::print()
/*
- Class type information for logging
+ Class type information for logging
*/
-#define LOG_CLASS(s) typedef s _LL_CLASS_TO_LOG
- // Declares class to tag logged messages with.
- // See top of file for example of how to use this
-
+#define LOG_CLASS(s) typedef s _LL_CLASS_TO_LOG
+ // Declares class to tag logged messages with.
+ // See top of file for example of how to use this
+
typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
- // Outside a class declaration, or in class without LOG_CLASS(), this
- // typedef causes the messages to not be associated with any class.
+ // Outside a class declaration, or in class without LOG_CLASS(), this
+ // typedef causes the messages to not be associated with any class.
/////////////////////////////////
// Error Logging Macros
@@ -376,34 +376,34 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
#define lllog(level, once, ...) \
do { \
LL_PROFILE_ZONE_NAMED("lllog"); \
- const char* tags[] = {"", ##__VA_ARGS__}; \
- static LLError::CallSite _site(lllog_site_args_(level, once, tags)); \
- lllog_test_()
+ const char* tags[] = {"", ##__VA_ARGS__}; \
+ static LLError::CallSite _site(lllog_site_args_(level, once, tags)); \
+ lllog_test_()
#define lllog_test_() \
- if (LL_UNLIKELY(_site.shouldLog())) \
- { \
- std::ostringstream _out; \
- _out
+ if (LL_UNLIKELY(_site.shouldLog())) \
+ { \
+ std::ostringstream _out; \
+ _out
#define lllog_site_args_(level, once, tags) \
- level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), \
- __FUNCTION__, once, &tags[1], LL_ARRAY_SIZE(tags)-1
+ level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), \
+ __FUNCTION__, once, &tags[1], LL_ARRAY_SIZE(tags)-1
//Use this construct if you need to do computation in the middle of a
//message:
-//
-// LL_INFOS("AgentGesture") << "the agent " << agend_id;
-// switch (f)
-// {
-// case FOP_SHRUGS: LL_CONT << "shrugs"; break;
-// case FOP_TAPS: LL_CONT << "points at " << who; break;
-// case FOP_SAYS: LL_CONT << "says " << message; break;
-// }
-// LL_CONT << " for " << t << " seconds" << LL_ENDL;
-//
+//
+// LL_INFOS("AgentGesture") << "the agent " << agend_id;
+// switch (f)
+// {
+// case FOP_SHRUGS: LL_CONT << "shrugs"; break;
+// case FOP_TAPS: LL_CONT << "points at " << who; break;
+// case FOP_SAYS: LL_CONT << "says " << message; break;
+// }
+// LL_CONT << " for " << t << " seconds" << LL_ENDL;
+//
//Such computation is done iff the message will be logged.
-#define LL_CONT _out
+#define LL_CONT _out
#define LL_NEWLINE '\n'
@@ -426,24 +426,24 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
// NEW Macros for debugging, allow the passing of a string tag
// Pass comma separated list of tags (currently only supports up to 0, 1, or 2)
-#define LL_DEBUGS(...) lllog(LLError::LEVEL_DEBUG, false, ##__VA_ARGS__)
-#define LL_INFOS(...) lllog(LLError::LEVEL_INFO, false, ##__VA_ARGS__)
-#define LL_WARNS(...) lllog(LLError::LEVEL_WARN, false, ##__VA_ARGS__)
-#define LL_ERRS(...) lllog(LLError::LEVEL_ERROR, false, ##__VA_ARGS__)
+#define LL_DEBUGS(...) lllog(LLError::LEVEL_DEBUG, false, ##__VA_ARGS__)
+#define LL_INFOS(...) lllog(LLError::LEVEL_INFO, false, ##__VA_ARGS__)
+#define LL_WARNS(...) lllog(LLError::LEVEL_WARN, false, ##__VA_ARGS__)
+#define LL_ERRS(...) lllog(LLError::LEVEL_ERROR, false, ##__VA_ARGS__)
// alternative to llassert_always that prints explanatory message
// note ## token paste operator hack used above will only work in gcc following
// a comma and is completely unnecessary in VS since the comma is automatically
// suppressed
// https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html
// https://docs.microsoft.com/en-us/cpp/preprocessor/variadic-macros?view=vs-2015
-#define LL_WARNS_IF(exp, ...) if (exp) LL_WARNS(__VA_ARGS__) << "(" #exp ")"
-#define LL_ERRS_IF(exp, ...) if (exp) LL_ERRS(__VA_ARGS__) << "(" #exp ")"
+#define LL_WARNS_IF(exp, ...) if (exp) LL_WARNS(__VA_ARGS__) << "(" #exp ")"
+#define LL_ERRS_IF(exp, ...) if (exp) LL_ERRS(__VA_ARGS__) << "(" #exp ")"
// Only print the log message once (good for warnings or infos that would otherwise
// spam the log file over and over, such as tighter loops).
-#define LL_DEBUGS_ONCE(...) lllog(LLError::LEVEL_DEBUG, true, ##__VA_ARGS__)
-#define LL_INFOS_ONCE(...) lllog(LLError::LEVEL_INFO, true, ##__VA_ARGS__)
-#define LL_WARNS_ONCE(...) lllog(LLError::LEVEL_WARN, true, ##__VA_ARGS__)
+#define LL_DEBUGS_ONCE(...) lllog(LLError::LEVEL_DEBUG, true, ##__VA_ARGS__)
+#define LL_INFOS_ONCE(...) lllog(LLError::LEVEL_INFO, true, ##__VA_ARGS__)
+#define LL_WARNS_ONCE(...) lllog(LLError::LEVEL_WARN, true, ##__VA_ARGS__)
// Use this if you need to pass LLError::ELevel as a variable.
#define LL_VLOGS(level, ...) llvlog(level, false, ##__VA_ARGS__)
@@ -459,33 +459,33 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
// instance for the passed level value.
// Compare implementation to lllog() above.
#define llvlog(level, once, ...) \
- do { \
- const char* tags[] = {"", ##__VA_ARGS__}; \
- /* Need a static CallSite instance per expected ELevel value. */ \
- /* Since we intend to index this array with the ELevel, */ \
- /* _sites[0] should be ELevel(0), and so on -- avoid using */ \
- /* ELevel symbolic names when initializing -- except for */ \
- /* the last entry, which handles anything beyond the end. */ \
- /* (Commented ELevel value names are from 2016-09-01.) */ \
- /* Passing an ELevel past the end of this array is itself */ \
- /* a fatal error, so ensure the last is LEVEL_ERROR. */ \
- static LLError::CallSite _sites[] = \
- { \
- /* LEVEL_DEBUG */ \
- LLError::CallSite(lllog_site_args_(LLError::ELevel(0), once, tags)), \
- /* LEVEL_INFO */ \
- LLError::CallSite(lllog_site_args_(LLError::ELevel(1), once, tags)), \
- /* LEVEL_WARN */ \
- LLError::CallSite(lllog_site_args_(LLError::ELevel(2), once, tags)), \
- /* LEVEL_ERROR */ \
- LLError::CallSite(lllog_site_args_(LLError::LEVEL_ERROR, once, tags)) \
- }; \
- /* Clamp the passed 'level' to at most last entry */ \
- std::size_t which((std::size_t(level) >= LL_ARRAY_SIZE(_sites)) ? \
- (LL_ARRAY_SIZE(_sites) - 1) : std::size_t(level)); \
- /* selected CallSite *must* be named _site for LL_ENDL */ \
- LLError::CallSite& _site(_sites[which]); \
- lllog_test_()
+ do { \
+ const char* tags[] = {"", ##__VA_ARGS__}; \
+ /* Need a static CallSite instance per expected ELevel value. */ \
+ /* Since we intend to index this array with the ELevel, */ \
+ /* _sites[0] should be ELevel(0), and so on -- avoid using */ \
+ /* ELevel symbolic names when initializing -- except for */ \
+ /* the last entry, which handles anything beyond the end. */ \
+ /* (Commented ELevel value names are from 2016-09-01.) */ \
+ /* Passing an ELevel past the end of this array is itself */ \
+ /* a fatal error, so ensure the last is LEVEL_ERROR. */ \
+ static LLError::CallSite _sites[] = \
+ { \
+ /* LEVEL_DEBUG */ \
+ LLError::CallSite(lllog_site_args_(LLError::ELevel(0), once, tags)), \
+ /* LEVEL_INFO */ \
+ LLError::CallSite(lllog_site_args_(LLError::ELevel(1), once, tags)), \
+ /* LEVEL_WARN */ \
+ LLError::CallSite(lllog_site_args_(LLError::ELevel(2), once, tags)), \
+ /* LEVEL_ERROR */ \
+ LLError::CallSite(lllog_site_args_(LLError::LEVEL_ERROR, once, tags)) \
+ }; \
+ /* Clamp the passed 'level' to at most last entry */ \
+ std::size_t which((std::size_t(level) >= LL_ARRAY_SIZE(_sites)) ? \
+ (LL_ARRAY_SIZE(_sites) - 1) : std::size_t(level)); \
+ /* selected CallSite *must* be named _site for LL_ENDL */ \
+ LLError::CallSite& _site(_sites[which]); \
+ lllog_test_()
/*
// Check at run-time whether logging is enabled, without generating output.
@@ -510,7 +510,7 @@ LL_ENDL;
LL_DEBUGS("SomeTag") performs the locking and map-searching ONCE, then caches
the result in a static variable.
-*/
+*/
// used by LLERROR_CRASH
void crashdriver(void (*)(int*));