summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/CMakeLists.txt9
-rw-r--r--indra/llcommon/indra_constants.cpp1
-rw-r--r--indra/llcommon/indra_constants.h1
-rw-r--r--indra/llcommon/llapp.cpp10
-rw-r--r--indra/llcommon/llassettype.cpp19
-rw-r--r--indra/llcommon/llassettype.h19
-rw-r--r--indra/llcommon/llerror.cpp128
-rw-r--r--indra/llcommon/llerror.h32
-rw-r--r--indra/llcommon/llerrorcontrol.h47
-rw-r--r--indra/llcommon/llleap.cpp31
-rw-r--r--indra/llcommon/llmemory.cpp6
-rw-r--r--indra/llcommon/llprocessor.cpp9
-rw-r--r--indra/llcommon/llsd.cpp26
-rw-r--r--indra/llcommon/llsd.h5
-rw-r--r--indra/llcommon/llsdserialize.cpp12
-rw-r--r--indra/llcommon/llsdserialize.h2
-rw-r--r--indra/llcommon/llsdutil.cpp275
-rw-r--r--indra/llcommon/llsdutil.h96
-rw-r--r--indra/llcommon/llsingleton.cpp10
-rw-r--r--indra/llcommon/llsingleton.h15
-rw-r--r--indra/llcommon/llunittype.h37
-rw-r--r--indra/llcommon/lluuid.h20
-rw-r--r--indra/llcommon/tests/llerror_test.cpp25
-rw-r--r--indra/llcommon/tests/wrapllerrs.h28
24 files changed, 650 insertions, 213 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index af41b9e460..e3afa5eca4 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -5,6 +5,7 @@ project(llcommon)
include(00-Common)
include(LLCommon)
+include(bugsplat)
include(Linking)
include(Boost)
include(LLSharedLibs)
@@ -257,10 +258,10 @@ set(llcommon_HEADER_FILES
set_source_files_properties(${llcommon_HEADER_FILES}
PROPERTIES HEADER_FILE_ONLY TRUE)
-if (BUGSPLAT_DB)
- set_source_files_properties(llapp.cpp
- PROPERTIES COMPILE_DEFINITIONS "LL_BUGSPLAT")
-endif (BUGSPLAT_DB)
+if (USE_BUGSPLAT)
+ set_source_files_properties(${llcommon_SOURCE_FILES}
+ PROPERTIES COMPILE_DEFINITIONS "${BUGSPLAT_DEFINE}")
+endif (USE_BUGSPLAT)
list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES})
diff --git a/indra/llcommon/indra_constants.cpp b/indra/llcommon/indra_constants.cpp
index e13176e8fa..1b48e4daf3 100644
--- a/indra/llcommon/indra_constants.cpp
+++ b/indra/llcommon/indra_constants.cpp
@@ -64,7 +64,6 @@ const LLUUID IMG_ALPHA_GRAD ("e97cf410-8e61-7005-ec06-629eba4cd1fb"); // VIEW
const LLUUID IMG_ALPHA_GRAD_2D ("38b86f85-2575-52a9-a531-23108d8da837"); // VIEWER
const LLUUID IMG_TRANSPARENT ("8dcd4a48-2d37-4909-9f78-f7a9eb4ef903"); // VIEWER
-const LLUUID IMG_BLOOM1 ("3c59f7fe-9dc8-47f9-8aaf-a9dd1fbc3bef"); // VIEWER
const LLUUID TERRAIN_DIRT_DETAIL ("0bc58228-74a0-7e83-89bc-5c23464bcec5"); // VIEWER
const LLUUID TERRAIN_GRASS_DETAIL ("63338ede-0037-c4fd-855b-015d77112fc8"); // VIEWER
const LLUUID TERRAIN_MOUNTAIN_DETAIL ("303cd381-8560-7579-23f1-f0a880799740"); // VIEWER
diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h
index 0fbf4b966b..e7b0e0ef8e 100644
--- a/indra/llcommon/indra_constants.h
+++ b/indra/llcommon/indra_constants.h
@@ -200,7 +200,6 @@ LL_COMMON_API extern const LLUUID IMG_ALPHA_GRAD;
LL_COMMON_API extern const LLUUID IMG_ALPHA_GRAD_2D;
LL_COMMON_API extern const LLUUID IMG_TRANSPARENT;
-LL_COMMON_API extern const LLUUID IMG_BLOOM1;
LL_COMMON_API extern const LLUUID TERRAIN_DIRT_DETAIL;
LL_COMMON_API extern const LLUUID TERRAIN_GRASS_DETAIL;
LL_COMMON_API extern const LLUUID TERRAIN_MOUNTAIN_DETAIL;
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index 421af3006e..27960371f1 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -526,7 +526,12 @@ void LLApp::setupErrorHandling(bool second_instance)
#endif // LL_LINUX
#endif // ! LL_WINDOWS
+
+#ifdef LL_BUGSPLAT
+ // do not start our own error thread
+#else // ! LL_BUGSPLAT
startErrorThread();
+#endif
}
void LLApp::startErrorThread()
@@ -774,7 +779,9 @@ void setup_signals()
act.sa_flags = SA_SIGINFO;
// Synchronous signals
+# ifndef LL_BUGSPLAT
sigaction(SIGABRT, &act, NULL);
+# endif
sigaction(SIGALRM, &act, NULL);
sigaction(SIGBUS, &act, NULL);
sigaction(SIGFPE, &act, NULL);
@@ -811,7 +818,9 @@ void clear_signals()
act.sa_flags = SA_SIGINFO;
// Synchronous signals
+# ifndef LL_BUGSPLAT
sigaction(SIGABRT, &act, NULL);
+# endif
sigaction(SIGALRM, &act, NULL);
sigaction(SIGBUS, &act, NULL);
sigaction(SIGFPE, &act, NULL);
@@ -864,6 +873,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
return;
case SIGABRT:
+ // Note that this handler is not set for SIGABRT when using Bugsplat
// Abort just results in termination of the app, no funky error handling.
if (LLApp::sLogInSignal)
{
diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp
index 7e5a157cdf..e6cc06e8d0 100644
--- a/indra/llcommon/llassettype.cpp
+++ b/indra/llcommon/llassettype.cpp
@@ -95,11 +95,14 @@ LLAssetDictionary::LLAssetDictionary()
addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", false, false, false));
addEntry(LLAssetType::AT_WIDGET, new AssetEntry("WIDGET", "widget", "widget", false, false, false));
addEntry(LLAssetType::AT_PERSON, new AssetEntry("PERSON", "person", "person", false, false, false));
+ addEntry(LLAssetType::AT_SETTINGS, new AssetEntry("SETTINGS", "settings", "settings blob", true, true, true));
addEntry(LLAssetType::AT_UNKNOWN, new AssetEntry("UNKNOWN", "invalid", NULL, false, false, false));
- addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, FALSE, FALSE, FALSE));
+ addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, FALSE, FALSE, FALSE));
};
+const std::string LLAssetType::BADLOOKUP("llassettype_bad_lookup");
+
// static
LLAssetType::EType LLAssetType::getType(const std::string& desc_name)
{
@@ -118,7 +121,7 @@ const std::string &LLAssetType::getDesc(LLAssetType::EType asset_type)
}
else
{
- return badLookup();
+ return BADLOOKUP;
}
}
@@ -133,7 +136,7 @@ const char *LLAssetType::lookup(LLAssetType::EType asset_type)
}
else
{
- return badLookup().c_str();
+ return BADLOOKUP.c_str();
}
}
@@ -171,7 +174,7 @@ const char *LLAssetType::lookupHumanReadable(LLAssetType::EType asset_type)
}
else
{
- return badLookup().c_str();
+ return BADLOOKUP.c_str();
}
}
@@ -222,14 +225,6 @@ bool LLAssetType::lookupIsLinkType(EType asset_type)
}
// static
-const std::string &LLAssetType::badLookup()
-{
- static const std::string sBadLookup = "llassettype_bad_lookup";
- return sBadLookup;
-
-}
-
-// static
bool LLAssetType::lookupIsAssetFetchByIDAllowed(EType asset_type)
{
const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h
index 79ab3d7efe..652c548d59 100644
--- a/indra/llcommon/llassettype.h
+++ b/indra/llcommon/llassettype.h
@@ -116,10 +116,19 @@ public:
AT_PERSON = 45,
// A user uuid which is not an inventory asset type, used in viewer only for adding a person to a chat via drag and drop.
- AT_MESH = 49,
- // Mesh data in our proprietary SLM format
-
- AT_COUNT = 50,
+ AT_MESH = 49,
+ // Mesh data in our proprietary SLM format
+
+ AT_RESERVED_1 = 50,
+ AT_RESERVED_2 = 51,
+ AT_RESERVED_3 = 52,
+ AT_RESERVED_4 = 53,
+ AT_RESERVED_5 = 54,
+ AT_RESERVED_6 = 55,
+
+ AT_SETTINGS = 56, // Collection of settings
+
+ AT_COUNT = 57,
// +*********************************************************+
// | TO ADD AN ELEMENT TO THIS ENUM: |
@@ -153,7 +162,7 @@ public:
static bool lookupIsAssetFetchByIDAllowed(EType asset_type); // the asset allows direct download
static bool lookupIsAssetIDKnowable(EType asset_type); // asset data can be known by the viewer
- static const std::string& badLookup(); // error string when a lookup fails
+ static const std::string BADLOOKUP;
protected:
LLAssetType() {}
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 335a0995fe..d98229fb0a 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -25,6 +25,7 @@
* $/LicenseInfo$
*/
+#define _LLERROR_CPP_
#include "linden_common.h"
#include "llerror.h"
@@ -181,32 +182,35 @@ namespace {
return LLError::getEnabledLogTypesMask() & 0x04;
}
+ LL_FORCE_INLINE std::string createANSI(const std::string& color)
+ {
+ std::string ansi_code;
+ ansi_code += '\033';
+ ansi_code += "[";
+ ansi_code += color;
+ ansi_code += "m";
+ return ansi_code;
+ }
+
virtual void recordMessage(LLError::ELevel level,
const std::string& message) override
- {
- if (ANSI_PROBE == mUseANSI)
- mUseANSI = (checkANSI() ? ANSI_YES : ANSI_NO);
+ {
+ static std::string s_ansi_error = createANSI("31"); // red
+ static std::string s_ansi_warn = createANSI("34"); // blue
+ static std::string s_ansi_debug = createANSI("35"); // magenta
+
+ mUseANSI = (ANSI_PROBE == mUseANSI) ? (checkANSI() ? ANSI_YES : ANSI_NO) : mUseANSI;
if (ANSI_YES == mUseANSI)
{
- // Default all message levels to bold so we can distinguish our own messages from those dumped by subprocesses and libraries.
- colorANSI("1"); // bold
- switch (level) {
- case LLError::LEVEL_ERROR:
- colorANSI("31"); // red
- break;
- case LLError::LEVEL_WARN:
- colorANSI("34"); // blue
- break;
- case LLError::LEVEL_DEBUG:
- colorANSI("35"); // magenta
- break;
- default:
- break;
- }
+ writeANSI((level == LLError::LEVEL_ERROR) ? s_ansi_error :
+ (level == LLError::LEVEL_WARN) ? s_ansi_warn :
+ s_ansi_debug, message);
}
- fprintf(stderr, "%s\n", message.c_str());
- if (ANSI_YES == mUseANSI) colorANSI("0"); // reset
+ else
+ {
+ fprintf(stderr, "%s\n", message.c_str());
+ }
}
private:
@@ -217,11 +221,14 @@ namespace {
ANSI_NO
} mUseANSI;
- void colorANSI(const std::string color)
+ LL_FORCE_INLINE void writeANSI(const std::string& ansi_code, const std::string& message)
{
- // ANSI color code escape sequence
- fprintf(stderr, "\033[%sm", color.c_str() );
- };
+ static std::string s_ansi_bold = createANSI("1"); // bold
+ static std::string s_ansi_reset = createANSI("0"); // reset
+ // ANSI color code escape sequence, message, and reset in one fprintf call
+ // Default all message levels to bold so we can distinguish our own messages from those dumped by subprocesses and libraries.
+ fprintf(stderr, "%s%s%s\n%s", s_ansi_bold.c_str(), ansi_code.c_str(), message.c_str(), s_ansi_reset.c_str() );
+ }
bool checkANSI(void)
{
@@ -232,8 +239,8 @@ namespace {
return (0 != isatty(2)) &&
(NULL == getenv("LL_NO_ANSI_COLOR"));
#endif // LL_LINUX
- return false;
- };
+ return FALSE; // works in a cygwin shell... ;)
+ }
};
class RecordToFixedBuffer : public LLError::Recorder
@@ -482,7 +489,7 @@ namespace LLError
LevelMap mTagLevelMap;
std::map<std::string, unsigned int> mUniqueLogMessages;
- LLError::FatalFunction mCrashFunction;
+ LLError::FatalHook mFatalHook;
LLError::TimeFunction mTimeFunction;
Recorders mRecorders;
@@ -522,7 +529,7 @@ namespace LLError
mFileLevelMap(),
mTagLevelMap(),
mUniqueLogMessages(),
- mCrashFunction(NULL),
+ mFatalHook(NULL),
mTimeFunction(NULL),
mRecorders(),
mFileRecorder(),
@@ -683,7 +690,6 @@ namespace
LLError::setDefaultLevel(LLError::LEVEL_INFO);
LLError::setAlwaysFlush(true);
LLError::setEnabledLogTypesMask(0xFFFFFFFF);
- LLError::setFatalFunction(LLError::crashAndLoop);
LLError::setTimeFunction(LLError::utcTime);
// log_to_stderr is only false in the unit and integration tests to keep builds quieter
@@ -719,16 +725,20 @@ namespace LLError
commonInit(user_dir, app_dir, log_to_stderr);
}
- void setFatalFunction(const FatalFunction& f)
+ void setFatalHook(const FatalHook& fatal_hook)
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
- s->mCrashFunction = f;
- }
-
- FatalFunction getFatalFunction()
+ LL_DEBUGS("FatalHook") << "set fatal hook to " << (fatal_hook ? "non-null" : "null")
+ << " was " << (s->mFatalHook ? "non-null" : "null")
+ << LL_ENDL;
+ s->mFatalHook = fatal_hook;
+ }
+
+ FatalHook getFatalHook()
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
- return s->mCrashFunction;
+ LL_DEBUGS("FatalHook") << "read fatal hook was " << (s->mFatalHook ? "non-null" : "null") << LL_ENDL;
+ return s->mFatalHook;
}
std::string getFatalMessage()
@@ -1306,12 +1316,12 @@ namespace LLError
return ;
}
- void Log::flush(std::ostringstream* out, const CallSite& site)
+ ErrFatalHookResult Log::flush(std::ostringstream* out, const CallSite& site)
{
LLMutexTrylock lock(&gLogMutex,5);
if (!lock.isLocked())
{
- return;
+ return ERR_DO_NOT_CRASH; // because this wasn't logged, it cannot be fatal
}
// If we hit a logging request very late during shutdown processing,
@@ -1319,7 +1329,7 @@ namespace LLError
// DO NOT resurrect them.
if (Settings::wasDeleted() || Globals::wasDeleted())
{
- return;
+ return ERR_DO_NOT_CRASH; // because this wasn't logged, it cannot be fatal
}
Globals* g = Globals::getInstance();
@@ -1353,7 +1363,7 @@ namespace LLError
}
else
{
- return;
+ return ERR_DO_NOT_CRASH; // because this wasn't logged, it cannot be fatal
}
}
else
@@ -1369,12 +1379,19 @@ namespace LLError
if (site.mLevel == LEVEL_ERROR)
{
- g->mFatalMessage = message;
- if (s->mCrashFunction)
- {
- s->mCrashFunction(message);
- }
+ if (s->mFatalHook)
+ {
+ return s->mFatalHook(message);
+ }
+ else
+ {
+ return ERR_CRASH; // calling macro should crash
+ }
}
+ else
+ {
+ return ERR_DO_NOT_CRASH; // not ERROR, so do not crash
+ }
}
}
@@ -1437,29 +1454,6 @@ namespace LLError
return s->mShouldLogCallCounter;
}
-#if LL_WINDOWS
- // VC80 was optimizing the error away.
- #pragma optimize("", off)
-#endif
- void crashAndLoop(const std::string& message)
- {
- // Now, we go kaboom!
- int* make_me_crash = NULL;
-
- *make_me_crash = 0;
-
- while(true)
- {
- // Loop forever, in case the crash didn't work?
- }
-
- // this is an attempt to let Coverity and other semantic scanners know that this function won't be returning ever.
- exit(EXIT_FAILURE);
- }
-#if LL_WINDOWS
- #pragma optimize("", on)
-#endif
-
std::string utcTime()
{
time_t now = time(NULL);
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index 0a78229555..6bdb2e852f 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -194,13 +194,19 @@ namespace LLError
struct CallSite;
+ enum ErrFatalHookResult { ERR_DO_NOT_CRASH, ERR_CRASH };
+
class LL_COMMON_API Log
{
public:
static bool shouldLog(CallSite&);
static std::ostringstream* out();
+
static void flush(std::ostringstream* out, char* message);
- static void flush(std::ostringstream*, const CallSite&);
+
+ // returns false iff the calling macro should crash
+ static ErrFatalHookResult flush(std::ostringstream*, const CallSite&);
+
static std::string demangle(const char* mangled);
};
@@ -266,7 +272,7 @@ namespace LLError
//when LLAppViewer::handleViewerCrash() is triggered.
//
//Note: to be simple, efficient and necessary to keep track of correct call stacks,
- //LLCallStacks is designed not to be thread-safe.
+ //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.
class LL_COMMON_API LLCallStacks
@@ -367,10 +373,24 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
#define LL_NEWLINE '\n'
-#define LL_ENDL \
- LLError::End(); \
- LLError::Log::flush(_out, _site); \
- } \
+#ifdef _LLERROR_CPP_
+volatile int* gCauseCrash = NULL;
+#else
+volatile extern int* gCauseCrash;
+#endif // _LLERROR_CPP_
+
+// Use this only in LL_ERRS or in a place that LL_ERRS may not be used
+#define LLERROR_CRASH \
+{ \
+ *gCauseCrash = 0; \
+ exit(*gCauseCrash); \
+}
+
+#define LL_ENDL \
+ LLError::End(); \
+ if (LLError::ERR_CRASH == LLError::Log::flush(_out, _site)) \
+ LLERROR_CRASH \
+ } \
} while(0)
// NEW Macros for debugging, allow the passing of a string tag
diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h
index 276d22fc36..e7c5241cc9 100644
--- a/indra/llcommon/llerrorcontrol.h
+++ b/indra/llcommon/llerrorcontrol.h
@@ -93,40 +93,27 @@ namespace LLError
Control functions.
*/
- typedef boost::function<void(const std::string&)> FatalFunction;
- LL_COMMON_API void crashAndLoop(const std::string& message);
- // Default fatal function: access null pointer and loops forever
-
- LL_COMMON_API void setFatalFunction(const FatalFunction&);
- // The fatal function will be called when an message of LEVEL_ERROR
+ // A FatalHook is called if set using setFatalHook; its return controls
+ // whether or not the calling error logging code should crash.
+ // ERR_DO_NOT_CRASH should be used only in test code.
+ typedef boost::function<LLError::ErrFatalHookResult(const std::string&)> FatalHook;
+
+ /// Supplement and control the default behavior of crashing on LL_ERRS
+ /// This may be used to suppress crashes only in test code;
+ /// otherwise, the FatalHook should always either return
+ /// the result from the previous hook (see getFatalHook below),
+ /// or return LLError::ERR_CRASH
+ LL_COMMON_API void setFatalHook(const FatalHook& fatal_hook);
+ // The fatal_hook function will be called when an message of LEVEL_ERROR
// is logged. Note: supressing a LEVEL_ERROR message from being logged
- // (by, for example, setting a class level to LEVEL_NONE), will keep
- // the that message from causing the fatal funciton to be invoked.
+ // (by, for example, setting a class level to LEVEL_NONE), will also
+ // prevent the fatal_hook being called and the resulting deliberate crash
- LL_COMMON_API FatalFunction getFatalFunction();
- // Retrieve the previously-set FatalFunction
+ /// Retrieve the previously-set FatalHook
+ LL_COMMON_API FatalHook getFatalHook();
LL_COMMON_API std::string getFatalMessage();
- // Retrieve the message last passed to FatalFunction, if any
-
- /// temporarily override the FatalFunction for the duration of a
- /// particular scope, e.g. for unit tests
- class LL_COMMON_API OverrideFatalFunction
- {
- public:
- OverrideFatalFunction(const FatalFunction& func):
- mPrev(getFatalFunction())
- {
- setFatalFunction(func);
- }
- ~OverrideFatalFunction()
- {
- setFatalFunction(mPrev);
- }
-
- private:
- FatalFunction mPrev;
- };
+ // Retrieve the message last passed to LL_ERRS, if any
typedef std::string (*TimeFunction)();
LL_COMMON_API std::string utcTime();
diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp
index cf8f8cc6a5..8293c35516 100644
--- a/indra/llcommon/llleap.cpp
+++ b/indra/llcommon/llleap.cpp
@@ -59,7 +59,6 @@ public:
// pump name -- so it should NOT need tweaking for uniqueness.
mReplyPump(LLUUID::generateNewID().asString()),
mExpect(0),
- mPrevFatalFunction(LLError::getFatalFunction()),
// Instantiate a distinct LLLeapListener for this plugin. (Every
// plugin will want its own collection of managed listeners, etc.)
// Pass it a callback to our connect() method, so it can send events
@@ -145,9 +144,6 @@ public:
mStderrConnection = childerr.getPump()
.listen("LLLeap", boost::bind(&LLLeapImpl::rstderr, this, _1));
- // For our lifespan, intercept any LL_ERRS so we can notify plugin
- LLError::setFatalFunction(boost::bind(&LLLeapImpl::fatalFunction, this, _1));
-
// Send child a preliminary event reporting our own reply-pump name --
// which would otherwise be pretty tricky to guess!
wstdin(mReplyPump.getName(),
@@ -162,8 +158,6 @@ public:
virtual ~LLLeapImpl()
{
LL_DEBUGS("LLLeap") << "destroying LLLeap(\"" << mDesc << "\")" << LL_ENDL;
- // Restore original FatalFunction
- LLError::setFatalFunction(mPrevFatalFunction);
}
// Listener for failed launch attempt
@@ -377,30 +371,6 @@ public:
return false;
}
- void fatalFunction(const std::string& error)
- {
- // Notify plugin
- LLSD event;
- event["type"] = "error";
- event["error"] = error;
- mReplyPump.post(event);
-
- // All the above really accomplished was to buffer the serialized
- // event in our WritePipe. Have to pump mainloop a couple times to
- // really write it out there... but time out in case we can't write.
- LLProcess::WritePipe& childin(mChild->getWritePipe(LLProcess::STDIN));
- LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
- LLSD nop;
- F64 until = (LLTimer::getElapsedSeconds() + 2).value();
- while (childin.size() && LLTimer::getElapsedSeconds() < until)
- {
- mainloop.post(nop);
- }
-
- // forward the call to the previous FatalFunction
- mPrevFatalFunction(error);
- }
-
private:
/// We always want to listen on mReplyPump with wstdin(); under some
/// circumstances we'll also echo other LLEventPumps to the plugin.
@@ -421,7 +391,6 @@ private:
mStdinConnection, mStdoutConnection, mStdoutDataConnection, mStderrConnection;
boost::scoped_ptr<LLEventPump::Blocker> mBlocker;
LLProcess::ReadPipe::size_type mExpect;
- LLError::FatalFunction mPrevFatalFunction;
boost::scoped_ptr<LLLeapListener> mListener;
};
diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp
index b3debf3550..1884d6f04f 100644
--- a/indra/llcommon/llmemory.cpp
+++ b/indra/llcommon/llmemory.cpp
@@ -77,7 +77,7 @@ void ll_assert_aligned_func(uintptr_t ptr,U32 alignment)
//static
void LLMemory::initMaxHeapSizeGB(F32Gigabytes max_heap_size, BOOL prevent_heap_failure)
{
- sMaxHeapSizeInKB = max_heap_size;
+ sMaxHeapSizeInKB = U32Kilobytes::convert(max_heap_size);
sEnableMemoryFailurePrevention = prevent_heap_failure ;
}
@@ -93,9 +93,9 @@ void LLMemory::updateMemoryInfo()
return ;
}
- sAllocatedMemInKB = U64Bytes(counters.WorkingSetSize) ;
+ sAllocatedMemInKB = U32Kilobytes::convert(U64Bytes(counters.WorkingSetSize));
sample(sAllocatedMem, sAllocatedMemInKB);
- sAllocatedPageSizeInKB = U64Bytes(counters.PagefileUsage) ;
+ sAllocatedPageSizeInKB = U32Kilobytes::convert(U64Bytes(counters.PagefileUsage));
sample(sVirtualMem, sAllocatedPageSizeInKB);
U32Kilobytes avail_phys, avail_virtual;
diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp
index a618a1cc70..5d16a4b74d 100644
--- a/indra/llcommon/llprocessor.cpp
+++ b/indra/llcommon/llprocessor.cpp
@@ -195,6 +195,8 @@ namespace
std::string amd_CPUFamilyName(int composed_family)
{
+ // https://en.wikipedia.org/wiki/List_of_AMD_CPU_microarchitectures
+ // https://developer.amd.com/resources/developer-guides-manuals/
switch(composed_family)
{
case 4: return "AMD 80486/5x86";
@@ -202,6 +204,13 @@ namespace
case 6: return "AMD K7";
case 0xF: return "AMD K8";
case 0x10: return "AMD K8L";
+ case 0x12: return "AMD K10";
+ case 0x14: return "AMD Bobcat";
+ case 0x15: return "AMD Bulldozer";
+ case 0x16: return "AMD Jaguar";
+ case 0x17: return "AMD Zen/Zen+/Zen2";
+ case 0x18: return "AMD Hygon Dhyana";
+ case 0x19: return "AMD Zen 3";
}
return STRINGIZE("AMD <unknown 0x" << std::hex << composed_family << ">");
}
diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp
index 57aa7d9c07..57b746889d 100644
--- a/indra/llcommon/llsd.cpp
+++ b/indra/llcommon/llsd.cpp
@@ -132,6 +132,7 @@ public:
virtual bool has(const String&) const { return false; }
virtual LLSD get(const String&) const { return LLSD(); }
+ virtual LLSD getKeys() const { return LLSD::emptyArray(); }
virtual void erase(const String&) { }
virtual const LLSD& ref(const String&) const{ return undef(); }
@@ -380,7 +381,8 @@ namespace
using LLSD::Impl::erase; // Unhiding erase(LLSD::Integer)
using LLSD::Impl::ref; // Unhiding ref(LLSD::Integer)
virtual LLSD get(const LLSD::String&) const;
- void insert(const LLSD::String& k, const LLSD& v);
+ virtual LLSD getKeys() const;
+ void insert(const LLSD::String& k, const LLSD& v);
virtual void erase(const LLSD::String&);
LLSD& ref(const LLSD::String&);
virtual const LLSD& ref(const LLSD::String&) const;
@@ -421,7 +423,19 @@ namespace
DataMap::const_iterator i = mData.find(k);
return (i != mData.end()) ? i->second : LLSD();
}
-
+
+ LLSD ImplMap::getKeys() const
+ {
+ LLSD keys = LLSD::emptyArray();
+ DataMap::const_iterator iter = mData.begin();
+ while (iter != mData.end())
+ {
+ keys.append((*iter).first);
+ iter++;
+ }
+ return keys;
+ }
+
void ImplMap::insert(const LLSD::String& k, const LLSD& v)
{
mData.insert(DataMap::value_type(k, v));
@@ -502,7 +516,7 @@ namespace
virtual LLSD get(LLSD::Integer) const;
void set(LLSD::Integer, const LLSD&);
void insert(LLSD::Integer, const LLSD&);
- void append(const LLSD&);
+ LLSD& append(const LLSD&);
virtual void erase(LLSD::Integer);
LLSD& ref(LLSD::Integer);
virtual const LLSD& ref(LLSD::Integer) const;
@@ -570,9 +584,10 @@ namespace
mData.insert(mData.begin() + index, v);
}
- void ImplArray::append(const LLSD& v)
+ LLSD& ImplArray::append(const LLSD& v)
{
mData.push_back(v);
+ return mData.back();
}
void ImplArray::erase(LLSD::Integer i)
@@ -862,6 +877,7 @@ LLSD LLSD::emptyMap()
bool LLSD::has(const String& k) const { return safe(impl).has(k); }
LLSD LLSD::get(const String& k) const { return safe(impl).get(k); }
+LLSD LLSD::getKeys() const { return safe(impl).getKeys(); }
void LLSD::insert(const String& k, const LLSD& v) { makeMap(impl).insert(k, v); }
LLSD& LLSD::with(const String& k, const LLSD& v)
@@ -895,7 +911,7 @@ LLSD& LLSD::with(Integer i, const LLSD& v)
makeArray(impl).insert(i, v);
return *this;
}
-void LLSD::append(const LLSD& v) { makeArray(impl).append(v); }
+LLSD& LLSD::append(const LLSD& v) { return makeArray(impl).append(v); }
void LLSD::erase(Integer i) { makeArray(impl).erase(i); }
LLSD& LLSD::operator[](Integer i)
diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h
index 7b9b1285f5..5b6d5545af 100644
--- a/indra/llcommon/llsd.h
+++ b/indra/llcommon/llsd.h
@@ -79,7 +79,7 @@
an LLSD array).
An array is a sequence of zero or more LLSD values.
-
+
Thread Safety
In general, these LLSD classes offer *less* safety than STL container
@@ -284,6 +284,7 @@ public:
bool has(const String&) const;
LLSD get(const String&) const;
+ LLSD getKeys() const; // Return an LLSD array with keys as strings
void insert(const String&, const LLSD&);
void erase(const String&);
LLSD& with(const String&, const LLSD&);
@@ -301,7 +302,7 @@ public:
LLSD get(Integer) const;
void set(Integer, const LLSD&);
void insert(Integer, const LLSD&);
- void append(const LLSD&);
+ LLSD& append(const LLSD&);
void erase(Integer);
LLSD& with(Integer, const LLSD&);
diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index 1aaff5628f..79934642ae 100644
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -55,6 +55,7 @@ static const S32 UNZIP_LLSD_MAX_DEPTH = 96;
static const char LEGACY_NON_HEADER[] = "<llsd>";
const std::string LLSD_BINARY_HEADER("LLSD/Binary");
const std::string LLSD_XML_HEADER("LLSD/XML");
+const std::string LLSD_NOTATION_HEADER("llsd/notation");
//used to deflate a gzipped asset (currently used for navmeshes)
#define windowBits 15
@@ -81,6 +82,11 @@ void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize
f = new LLSDXMLFormatter;
break;
+ case LLSD_NOTATION:
+ str << "<? " << LLSD_NOTATION_HEADER << " ?>\n";
+ f = new LLSDNotationFormatter;
+ break;
+
default:
LL_WARNS() << "serialize request for unknown ELLSD_Serialize" << LL_ENDL;
}
@@ -168,6 +174,10 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, S32 max_bytes)
{
p = new LLSDXMLParser;
}
+ else if (header == LLSD_NOTATION_HEADER)
+ {
+ p = new LLSDNotationParser;
+ }
else
{
LL_WARNS() << "deserialize request for unknown ELLSD_Serialize" << LL_ENDL;
@@ -2241,7 +2251,7 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is,
return ZR_SIZE_ERROR;
}
#endif
- catch (std::bad_alloc)
+ catch (std::bad_alloc&)
{
free(result);
return ZR_MEM_ERROR;
diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h
index 8165410e80..fe0f4443ef 100644
--- a/indra/llcommon/llsdserialize.h
+++ b/indra/llcommon/llsdserialize.h
@@ -706,7 +706,7 @@ class LL_COMMON_API LLSDSerialize
public:
enum ELLSD_Serialize
{
- LLSD_BINARY, LLSD_XML
+ LLSD_BINARY, LLSD_XML, LLSD_NOTATION
};
/**
diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp
index 859d2eb567..1f8384f415 100644
--- a/indra/llcommon/llsdutil.cpp
+++ b/indra/llcommon/llsdutil.cpp
@@ -322,6 +322,180 @@ BOOL compare_llsd_with_template(
return TRUE;
}
+// filter_llsd_with_template() is a direct clone (copy-n-paste) of
+// compare_llsd_with_template with the following differences:
+// (1) bool vs BOOL return types
+// (2) A map with the key value "*" is a special value and maps any key in the
+// test llsd that doesn't have an explicitly matching key in the template.
+// (3) The element of an array with exactly one element is taken as a template
+// for *all* the elements of the test array. If the template array is of
+// different size, compare_llsd_with_template() semantics apply.
+bool filter_llsd_with_template(
+ const LLSD & llsd_to_test,
+ const LLSD & template_llsd,
+ LLSD & resultant_llsd)
+{
+ if (llsd_to_test.isUndefined() && template_llsd.isDefined())
+ {
+ resultant_llsd = template_llsd;
+ return true;
+ }
+ else if (llsd_to_test.type() != template_llsd.type())
+ {
+ resultant_llsd = LLSD();
+ return false;
+ }
+
+ if (llsd_to_test.isArray())
+ {
+ //they are both arrays
+ //we loop over all the items in the template
+ //verifying that the to_test has a subset (in the same order)
+ //any shortcoming in the testing_llsd are just taken
+ //to be the rest of the template
+ LLSD data;
+ LLSD::array_const_iterator test_iter;
+ LLSD::array_const_iterator template_iter;
+
+ resultant_llsd = LLSD::emptyArray();
+ test_iter = llsd_to_test.beginArray();
+
+ if (1 == template_llsd.size())
+ {
+ // If the template has a single item, treat it as
+ // the template for *all* items in the test LLSD.
+ template_iter = template_llsd.beginArray();
+
+ for (; test_iter != llsd_to_test.endArray(); ++test_iter)
+ {
+ if (! filter_llsd_with_template(*test_iter, *template_iter, data))
+ {
+ resultant_llsd = LLSD();
+ return false;
+ }
+ else
+ {
+ resultant_llsd.append(data);
+ }
+ }
+ }
+ else
+ {
+ // Traditional compare_llsd_with_template matching
+
+ for (template_iter = template_llsd.beginArray();
+ template_iter != template_llsd.endArray() &&
+ test_iter != llsd_to_test.endArray();
+ ++template_iter, ++test_iter)
+ {
+ if (! filter_llsd_with_template(*test_iter, *template_iter, data))
+ {
+ resultant_llsd = LLSD();
+ return false;
+ }
+ else
+ {
+ resultant_llsd.append(data);
+ }
+ }
+
+ //so either the test or the template ended
+ //we do another loop now to the end of the template
+ //grabbing the default values
+ for (;
+ template_iter != template_llsd.endArray();
+ ++template_iter)
+ {
+ resultant_llsd.append(*template_iter);
+ }
+ }
+ }
+ else if (llsd_to_test.isMap())
+ {
+ resultant_llsd = LLSD::emptyMap();
+
+ //now we loop over the keys of the two maps
+ //any excess is taken from the template
+ //excess is ignored in the test
+
+ // Special tag for wildcarded LLSD map key templates
+ const LLSD::String wildcard_tag("*");
+
+ const bool template_has_wildcard = template_llsd.has(wildcard_tag);
+ LLSD wildcard_value;
+ LLSD value;
+
+ const LLSD::map_const_iterator template_iter_end(template_llsd.endMap());
+ for (LLSD::map_const_iterator template_iter(template_llsd.beginMap());
+ template_iter_end != template_iter;
+ ++template_iter)
+ {
+ if (wildcard_tag == template_iter->first)
+ {
+ wildcard_value = template_iter->second;
+ }
+ else if (llsd_to_test.has(template_iter->first))
+ {
+ //the test LLSD has the same key
+ if (! filter_llsd_with_template(llsd_to_test[template_iter->first],
+ template_iter->second,
+ value))
+ {
+ resultant_llsd = LLSD();
+ return false;
+ }
+ else
+ {
+ resultant_llsd[template_iter->first] = value;
+ }
+ }
+ else if (! template_has_wildcard)
+ {
+ // test llsd doesn't have it...take the
+ // template as default value
+ resultant_llsd[template_iter->first] = template_iter->second;
+ }
+ }
+ if (template_has_wildcard)
+ {
+ LLSD sub_value;
+ LLSD::map_const_iterator test_iter;
+
+ for (test_iter = llsd_to_test.beginMap();
+ test_iter != llsd_to_test.endMap();
+ ++test_iter)
+ {
+ if (resultant_llsd.has(test_iter->first))
+ {
+ // Final value has test key, assume more specific
+ // template matched and we shouldn't modify it again.
+ continue;
+ }
+ else if (! filter_llsd_with_template(test_iter->second,
+ wildcard_value,
+ sub_value))
+ {
+ // Test value doesn't match wildcarded template
+ resultant_llsd = LLSD();
+ return false;
+ }
+ else
+ {
+ // Test value matches template, add the actuals.
+ resultant_llsd[test_iter->first] = sub_value;
+ }
+ }
+ }
+ }
+ else
+ {
+ //of same type...take the test llsd's value
+ resultant_llsd = llsd_to_test;
+ }
+
+ return true;
+}
+
/*****************************************************************************
* Helpers for llsd_matches()
*****************************************************************************/
@@ -681,3 +855,104 @@ bool llsd_equals(const LLSD& lhs, const LLSD& rhs, int bits)
return false; // pacify the compiler
}
}
+
+// Construct a deep partial clone of of an LLSD object. primitive types share
+// references, however maps, arrays and binary objects are duplicated. An optional
+// filter may be include to exclude/include keys in a map.
+LLSD llsd_clone(LLSD value, LLSD filter)
+{
+ LLSD clone;
+ bool has_filter(filter.isMap());
+
+ switch (value.type())
+ {
+ case LLSD::TypeMap:
+ clone = LLSD::emptyMap();
+ for (LLSD::map_const_iterator itm = value.beginMap(); itm != value.endMap(); ++itm)
+ {
+ if (has_filter)
+ {
+ if (filter.has((*itm).first))
+ {
+ if (!filter[(*itm).first].asBoolean())
+ continue;
+ }
+ else if (filter.has("*"))
+ {
+ if (!filter["*"].asBoolean())
+ continue;
+ }
+ else
+ {
+ continue;
+ }
+ }
+ clone[(*itm).first] = llsd_clone((*itm).second, filter);
+ }
+ break;
+ case LLSD::TypeArray:
+ clone = LLSD::emptyArray();
+ for (LLSD::array_const_iterator ita = value.beginArray(); ita != value.endArray(); ++ita)
+ {
+ clone.append(llsd_clone(*ita, filter));
+ }
+ break;
+
+ case LLSD::TypeBinary:
+ {
+ LLSD::Binary bin(value.asBinary().begin(), value.asBinary().end());
+ clone = LLSD::Binary(bin);
+ break;
+ }
+ default:
+ clone = value;
+ }
+
+ return clone;
+}
+
+LLSD llsd_shallow(LLSD value, LLSD filter)
+{
+ LLSD shallow;
+ bool has_filter(filter.isMap());
+
+ if (value.isMap())
+ {
+ shallow = LLSD::emptyMap();
+ for (LLSD::map_const_iterator itm = value.beginMap(); itm != value.endMap(); ++itm)
+ {
+ if (has_filter)
+ {
+ if (filter.has((*itm).first))
+ {
+ if (!filter[(*itm).first].asBoolean())
+ continue;
+ }
+ else if (filter.has("*"))
+ {
+ if (!filter["*"].asBoolean())
+ continue;
+ }
+ else
+ {
+ continue;
+ }
+ }
+ shallow[(*itm).first] = (*itm).second;
+ }
+ }
+ else if (value.isArray())
+ {
+ shallow = LLSD::emptyArray();
+ for (LLSD::array_const_iterator ita = value.beginArray(); ita != value.endArray(); ++ita)
+ {
+ shallow.append(*ita);
+ }
+ }
+ else
+ {
+ return value;
+ }
+
+ return shallow;
+}
diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h
index 01ab6bcb8d..863be04c8a 100644
--- a/indra/llcommon/llsdutil.h
+++ b/indra/llcommon/llsdutil.h
@@ -30,6 +30,7 @@
#define LL_LLSDUTIL_H
#include "llsd.h"
+#include <boost/functional/hash.hpp>
// U32
LL_COMMON_API LLSD ll_sd_from_U32(const U32);
@@ -70,6 +71,19 @@ LL_COMMON_API BOOL compare_llsd_with_template(
const LLSD& template_llsd,
LLSD& resultant_llsd);
+// filter_llsd_with_template() is a direct clone (copy-n-paste) of
+// compare_llsd_with_template with the following differences:
+// (1) bool vs BOOL return types
+// (2) A map with the key value "*" is a special value and maps any key in the
+// test llsd that doesn't have an explicitly matching key in the template.
+// (3) The element of an array with exactly one element is taken as a template
+// for *all* the elements of the test array. If the template array is of
+// different size, compare_llsd_with_template() semantics apply.
+bool filter_llsd_with_template(
+ const LLSD & llsd_to_test,
+ const LLSD & template_llsd,
+ LLSD & resultant_llsd);
+
/**
* Recursively determine whether a given LLSD data block "matches" another
* LLSD prototype. The returned string is empty() on success, non-empty() on
@@ -421,4 +435,86 @@ private:
} // namespace llsd
+
+// Creates a deep clone of an LLSD object. Maps, Arrays and binary objects
+// are duplicated, atomic primitives (Boolean, Integer, Real, etc) simply
+// use a shared reference.
+// Optionally a filter may be specified to control what is duplicated. The
+// map takes the form "keyname/boolean".
+// If the value is true the value will be duplicated otherwise it will be skipped
+// when encountered in a map. A key name of "*" can be specified as a wild card
+// and will specify the default behavior. If no wild card is given and the clone
+// encounters a name not in the filter, that value will be skipped.
+LLSD llsd_clone(LLSD value, LLSD filter = LLSD());
+
+// Creates a shallow copy of a map or array. If passed any other type of LLSD
+// object it simply returns that value. See llsd_clone for a description of
+// the filter parameter.
+LLSD llsd_shallow(LLSD value, LLSD filter = LLSD());
+
+
+// Specialization for generating a hash value from an LLSD block.
+template <>
+struct boost::hash<LLSD>
+{
+ typedef LLSD argument_type;
+ typedef std::size_t result_type;
+ result_type operator()(argument_type const& s) const
+ {
+ result_type seed(0);
+
+ LLSD::Type stype = s.type();
+ boost::hash_combine(seed, (S32)stype);
+
+ switch (stype)
+ {
+ case LLSD::TypeBoolean:
+ boost::hash_combine(seed, s.asBoolean());
+ break;
+ case LLSD::TypeInteger:
+ boost::hash_combine(seed, s.asInteger());
+ break;
+ case LLSD::TypeReal:
+ boost::hash_combine(seed, s.asReal());
+ break;
+ case LLSD::TypeURI:
+ case LLSD::TypeString:
+ boost::hash_combine(seed, s.asString());
+ break;
+ case LLSD::TypeUUID:
+ boost::hash_combine(seed, s.asUUID());
+ break;
+ case LLSD::TypeDate:
+ boost::hash_combine(seed, s.asDate().secondsSinceEpoch());
+ break;
+ case LLSD::TypeBinary:
+ {
+ const LLSD::Binary &b(s.asBinary());
+ boost::hash_range(seed, b.begin(), b.end());
+ break;
+ }
+ case LLSD::TypeMap:
+ {
+ for (LLSD::map_const_iterator itm = s.beginMap(); itm != s.endMap(); ++itm)
+ {
+ boost::hash_combine(seed, (*itm).first);
+ boost::hash_combine(seed, (*itm).second);
+ }
+ break;
+ }
+ case LLSD::TypeArray:
+ for (LLSD::array_const_iterator ita = s.beginArray(); ita != s.endArray(); ++ita)
+ {
+ boost::hash_combine(seed, (*ita));
+ }
+ break;
+ case LLSD::TypeUndefined:
+ default:
+ break;
+ }
+
+ return seed;
+ }
+};
+
#endif // LL_LLSDUTIL_H
diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp
index c45c144570..6f254ef670 100644
--- a/indra/llcommon/llsingleton.cpp
+++ b/indra/llcommon/llsingleton.cpp
@@ -461,15 +461,7 @@ void LLSingletonBase::logerrs(const char* p1, const char* p2, const char* p3, co
// https://www.youtube.com/watch?v=OMG7paGJqhQ (emphasis on OMG)
std::ostringstream out;
out << p1 << p2 << p3 << p4;
- auto crash = LLError::getFatalFunction();
- if (crash)
- {
- crash(out.str());
- }
- else
- {
- LLError::crashAndLoop(out.str());
- }
+ LLERROR_CRASH;
}
std::string LLSingletonBase::demangle(const char* mangled)
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 0da6d548ab..7def9b019c 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -764,6 +764,17 @@ private: \
DERIVED_CLASS(__VA_ARGS__)
/**
+ * A slight variance from the above, but includes the "override" keyword
+ */
+#define LLSINGLETON_C11(DERIVED_CLASS) \
+private: \
+ /* implement LLSingleton pure virtual method whose sole purpose */ \
+ /* is to remind people to use this macro */ \
+ virtual void you_must_use_LLSINGLETON_macro() override {} \
+ friend class LLSingleton<DERIVED_CLASS>; \
+ DERIVED_CLASS()
+
+/**
* Use LLSINGLETON_EMPTY_CTOR(Foo); at the start of an LLSingleton<Foo>
* subclass body when the constructor is trivial:
*
@@ -781,4 +792,8 @@ private: \
/* LLSINGLETON() is carefully implemented to permit exactly this */ \
LLSINGLETON(DERIVED_CLASS) {}
+#define LLSINGLETON_EMPTY_CTOR_C11(DERIVED_CLASS) \
+ /* LLSINGLETON() is carefully implemented to permit exactly this */ \
+ LLSINGLETON_C11(DERIVED_CLASS) {}
+
#endif
diff --git a/indra/llcommon/llunittype.h b/indra/llcommon/llunittype.h
index ac8504ca61..81f244e422 100644
--- a/indra/llcommon/llunittype.h
+++ b/indra/llcommon/llunittype.h
@@ -132,23 +132,34 @@ struct LLUnit
return mValue;
}
- LL_FORCE_INLINE void value(storage_t value)
+ LL_FORCE_INLINE void value(const storage_t& value)
{
mValue = value;
}
template<typename NEW_UNITS>
- storage_t valueInUnits()
+ storage_t valueInUnits() const
{
return LLUnit<storage_t, NEW_UNITS>(*this).value();
}
template<typename NEW_UNITS>
- void valueInUnits(storage_t value)
+ void valueInUnits(const storage_t& value) const
{
*this = LLUnit<storage_t, NEW_UNITS>(value);
}
+ LL_FORCE_INLINE operator storage_t() const
+ {
+ return value();
+ }
+
+ /*LL_FORCE_INLINE self_t& operator= (storage_t v)
+ {
+ value(v);
+ return *this;
+ }*/
+
LL_FORCE_INLINE void operator += (self_t other)
{
mValue += convert(other).mValue;
@@ -159,60 +170,60 @@ struct LLUnit
mValue -= convert(other).mValue;
}
- LL_FORCE_INLINE void operator *= (storage_t multiplicand)
+ LL_FORCE_INLINE void operator *= (const storage_t& multiplicand)
{
mValue *= multiplicand;
}
- LL_FORCE_INLINE void operator *= (self_t multiplicand)
+ LL_FORCE_INLINE void operator *= (const self_t& multiplicand)
{
// spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "Multiplication of unit types not supported.");
}
- LL_FORCE_INLINE void operator /= (storage_t divisor)
+ LL_FORCE_INLINE void operator /= (const storage_t& divisor)
{
mValue /= divisor;
}
- void operator /= (self_t divisor)
+ void operator /= (const self_t& divisor)
{
// spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "Illegal in-place division of unit types.");
}
template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS>
- LL_FORCE_INLINE bool operator == (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const
+ LL_FORCE_INLINE bool operator == (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const
{
return mValue == convert(other).value();
}
template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS>
- LL_FORCE_INLINE bool operator != (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const
+ LL_FORCE_INLINE bool operator != (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const
{
return mValue != convert(other).value();
}
template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS>
- LL_FORCE_INLINE bool operator < (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const
+ LL_FORCE_INLINE bool operator < (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const
{
return mValue < convert(other).value();
}
template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS>
- LL_FORCE_INLINE bool operator <= (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const
+ LL_FORCE_INLINE bool operator <= (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const
{
return mValue <= convert(other).value();
}
template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS>
- LL_FORCE_INLINE bool operator > (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const
+ LL_FORCE_INLINE bool operator > (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const
{
return mValue > convert(other).value();
}
template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS>
- LL_FORCE_INLINE bool operator >= (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const
+ LL_FORCE_INLINE bool operator >= (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const
{
return mValue >= convert(other).value();
}
diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h
index dd8660a3c8..fe7482ba29 100644
--- a/indra/llcommon/lluuid.h
+++ b/indra/llcommon/lluuid.h
@@ -31,6 +31,7 @@
#include <vector>
#include "stdtypes.h"
#include "llpreprocessor.h"
+#include <boost/functional/hash.hpp>
class LLMutex;
@@ -164,6 +165,25 @@ public:
LLAssetID makeAssetID(const LLUUID& session) const;
};
+// Generate a hash of an LLUUID object using the boost hash templates.
+template <>
+struct boost::hash<LLUUID>
+{
+ typedef LLUUID argument_type;
+ typedef std::size_t result_type;
+ result_type operator()(argument_type const& s) const
+ {
+ result_type seed(0);
+
+ for (S32 i = 0; i < UUID_BYTES; ++i)
+ {
+ boost::hash_combine(seed, s.mData[i]);
+ }
+
+ return seed;
+ }
+};
+
#endif
diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp
index 8e1f4c14ac..cdc2bf8c87 100644
--- a/indra/llcommon/tests/llerror_test.cpp
+++ b/indra/llcommon/tests/llerror_test.cpp
@@ -70,7 +70,11 @@ namespace
namespace
{
static bool fatalWasCalled;
- void fatalCall(const std::string&) { fatalWasCalled = true; }
+ LLError::ErrFatalHookResult fatalHook(const std::string&)
+ {
+ fatalWasCalled = true;
+ return LLError::ERR_DO_NOT_CRASH;
+ }
}
namespace tut
@@ -120,7 +124,7 @@ namespace tut
mPriorErrorSettings = LLError::saveAndResetSettings();
LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
- LLError::setFatalFunction(fatalCall);
+ LLError::setFatalHook(fatalHook);
LLError::addRecorder(mRecorder);
}
@@ -777,30 +781,33 @@ namespace tut
// proper cached, efficient lookup of filtering
void ErrorTestObject::test<15>()
{
- LLError::setDefaultLevel(LLError::LEVEL_NONE);
+ LLError::setDefaultLevel(LLError::LEVEL_NONE);
+
+ // Note that the setFatalHook in the ErrorTestData constructor
+ // increments the shouldLogCallCount
TestAlpha::doInfo();
ensure_message_count(0);
- ensure_equals("first check", LLError::shouldLogCallCount(), 1);
+ ensure_equals("first check", LLError::shouldLogCallCount(), 2);
TestAlpha::doInfo();
ensure_message_count(0);
- ensure_equals("second check", LLError::shouldLogCallCount(), 1);
+ ensure_equals("second check", LLError::shouldLogCallCount(), 2);
LLError::setClassLevel("TestAlpha", LLError::LEVEL_DEBUG);
TestAlpha::doInfo();
ensure_message_count(1);
- ensure_equals("third check", LLError::shouldLogCallCount(), 2);
+ ensure_equals("third check", LLError::shouldLogCallCount(), 3);
TestAlpha::doInfo();
ensure_message_count(2);
- ensure_equals("fourth check", LLError::shouldLogCallCount(), 2);
+ ensure_equals("fourth check", LLError::shouldLogCallCount(), 3);
LLError::setClassLevel("TestAlpha", LLError::LEVEL_WARN);
TestAlpha::doInfo();
ensure_message_count(2);
- ensure_equals("fifth check", LLError::shouldLogCallCount(), 3);
+ ensure_equals("fifth check", LLError::shouldLogCallCount(), 4);
TestAlpha::doInfo();
ensure_message_count(2);
- ensure_equals("sixth check", LLError::shouldLogCallCount(), 3);
+ ensure_equals("sixth check", LLError::shouldLogCallCount(), 4);
}
template<> template<>
diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h
index b07d5afbd8..a6c44d5fdd 100644
--- a/indra/llcommon/tests/wrapllerrs.h
+++ b/indra/llcommon/tests/wrapllerrs.h
@@ -46,25 +46,24 @@
// statically reference the function in test.cpp... it's short, we could
// replicate, but better to reuse
-extern void wouldHaveCrashed(const std::string& message);
+extern LLError::ErrFatalHookResult wouldHaveCrashed(const std::string& message);
struct WrapLLErrs
{
- WrapLLErrs():
+ WrapLLErrs()
// Resetting Settings discards the default Recorder that writes to
// stderr. Otherwise, expected llerrs (LL_ERRS) messages clutter the
// console output of successful tests, potentially confusing things.
- mPriorErrorSettings(LLError::saveAndResetSettings()),
- // Save shutdown function called by LL_ERRS
- mPriorFatal(LLError::getFatalFunction())
+ :mPriorErrorSettings(LLError::saveAndResetSettings())
+ ,mPriorFatalHook(LLError::getFatalHook())
{
// Make LL_ERRS call our own operator() method
- LLError::setFatalFunction(boost::bind(&WrapLLErrs::operator(), this, _1));
+ LLError::setFatalHook(boost::bind(&WrapLLErrs::operator(), this, _1));
}
~WrapLLErrs()
{
- LLError::setFatalFunction(mPriorFatal);
+ LLError::setFatalHook(mPriorFatalHook);
LLError::restoreSettings(mPriorErrorSettings);
}
@@ -73,7 +72,7 @@ struct WrapLLErrs
FatalException(const std::string& what): LLException(what) {}
};
- void operator()(const std::string& message)
+ LLError::ErrFatalHookResult operator()(const std::string& message)
{
// Save message for later in case consumer wants to sense the result directly
error = message;
@@ -109,7 +108,7 @@ struct WrapLLErrs
std::string error;
LLError::SettingsStoragePtr mPriorErrorSettings;
- LLError::FatalFunction mPriorFatal;
+ LLError::FatalHook mPriorFatalHook;
};
/**
@@ -199,11 +198,12 @@ public:
// with that output. If it turns out that saveAndResetSettings() has
// some bad effect, give up and just let the DEBUG level log messages
// display.
- : boost::noncopyable(),
- mOldSettings(LLError::saveAndResetSettings()),
- mRecorder(new CaptureLogRecorder())
+ : boost::noncopyable()
+ , mOldSettings(LLError::saveAndResetSettings())
+ , mPriorFatalHook(LLError::getFatalHook())
+ , mRecorder(new CaptureLogRecorder())
{
- LLError::setFatalFunction(wouldHaveCrashed);
+ LLError::setFatalHook(wouldHaveCrashed);
LLError::setDefaultLevel(level);
LLError::addRecorder(mRecorder);
}
@@ -212,6 +212,7 @@ public:
{
LLError::removeRecorder(mRecorder);
LLError::restoreSettings(mOldSettings);
+ LLError::setFatalHook(mPriorFatalHook);
}
/// Don't assume the message we want is necessarily the LAST log message
@@ -229,6 +230,7 @@ public:
private:
LLError::SettingsStoragePtr mOldSettings;
+ LLError::FatalHook mPriorFatalHook;
LLError::RecorderPtr mRecorder;
};