summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2019-11-18 18:43:01 -0500
committerNat Goodspeed <nat@lindenlab.com>2020-03-25 19:21:16 -0400
commitcc9bdbcf19354c323c3f090949636267f54851e0 (patch)
tree7c40c2b455cbe630bee6b4565da78e670017e794 /indra/llcommon
parent582f9e156ebaf55f076edaad52fce39b79dac388 (diff)
DRTVWR-476: Introduce LLStacktrace, a token to stream stack trace.
LLStacktrace has no behavior except when you stream an instance to a std::ostream. Then it reports the current traceback at that point to the ostream. This bit of indirection is intended to avoid the boost/stacktrace.hpp header from being included everywhere.
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/llerror.cpp245
-rw-r--r--indra/llcommon/llerror.h54
2 files changed, 158 insertions, 141 deletions
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index ea0d06b93c..1cb93d27f7 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -53,6 +53,13 @@
#include "llstl.h"
#include "lltimer.h"
+// On Mac, got:
+// #error "Boost.Stacktrace requires `_Unwind_Backtrace` function. Define
+// `_GNU_SOURCE` macro or `BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED` if
+// _Unwind_Backtrace is available without `_GNU_SOURCE`."
+#define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED
+#include <boost/stacktrace.hpp>
+
namespace {
#if LL_WINDOWS
void debugger_print(const std::string& s)
@@ -1554,124 +1561,128 @@ namespace LLError
S32 LLCallStacks::sIndex = 0 ;
//static
- void LLCallStacks::allocateStackBuffer()
- {
- if(sBuffer == NULL)
- {
- sBuffer = new char*[512] ;
- sBuffer[0] = new char[512 * 128] ;
- for(S32 i = 1 ; i < 512 ; i++)
- {
- sBuffer[i] = sBuffer[i-1] + 128 ;
- }
- sIndex = 0 ;
- }
- }
-
- void LLCallStacks::freeStackBuffer()
- {
- if(sBuffer != NULL)
- {
- delete [] sBuffer[0] ;
- delete [] sBuffer ;
- sBuffer = NULL ;
- }
- }
-
- //static
- void LLCallStacks::push(const char* function, const int line)
- {
- LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5);
- if (!lock.isLocked())
- {
- return;
- }
-
- if(sBuffer == NULL)
- {
- allocateStackBuffer();
- }
-
- if(sIndex > 511)
- {
- clear() ;
- }
-
- strcpy(sBuffer[sIndex], function) ;
- sprintf(sBuffer[sIndex] + strlen(function), " line: %d ", line) ;
- sIndex++ ;
-
- return ;
- }
+ void LLCallStacks::allocateStackBuffer()
+ {
+ if(sBuffer == NULL)
+ {
+ sBuffer = new char*[512] ;
+ sBuffer[0] = new char[512 * 128] ;
+ for(S32 i = 1 ; i < 512 ; i++)
+ {
+ sBuffer[i] = sBuffer[i-1] + 128 ;
+ }
+ sIndex = 0 ;
+ }
+ }
- //static
- std::ostringstream* LLCallStacks::insert(const char* function, const int line)
- {
- std::ostringstream* _out = LLError::Log::out();
- *_out << function << " line " << line << " " ;
-
- return _out ;
- }
-
- //static
- void LLCallStacks::end(std::ostringstream* _out)
- {
- LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5);
- if (!lock.isLocked())
- {
- return;
- }
-
- if(sBuffer == NULL)
- {
- allocateStackBuffer();
- }
-
- if(sIndex > 511)
- {
- clear() ;
- }
-
- LLError::Log::flush(_out, sBuffer[sIndex++]) ;
- }
-
- //static
- void LLCallStacks::print()
- {
- LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5);
- if (!lock.isLocked())
- {
- return;
- }
-
- if(sIndex > 0)
- {
- LL_INFOS() << " ************* PRINT OUT LL CALL STACKS ************* " << LL_ENDL;
- while(sIndex > 0)
- {
- sIndex-- ;
- LL_INFOS() << sBuffer[sIndex] << LL_ENDL;
- }
- LL_INFOS() << " *************** END OF LL CALL STACKS *************** " << LL_ENDL;
- }
-
- if(sBuffer != NULL)
- {
- freeStackBuffer();
- }
- }
-
- //static
- void LLCallStacks::clear()
- {
- sIndex = 0 ;
- }
-
- //static
- void LLCallStacks::cleanup()
- {
- freeStackBuffer();
- }
+ void LLCallStacks::freeStackBuffer()
+ {
+ if(sBuffer != NULL)
+ {
+ delete [] sBuffer[0] ;
+ delete [] sBuffer ;
+ sBuffer = NULL ;
+ }
+ }
+
+ //static
+ void LLCallStacks::push(const char* function, const int line)
+ {
+ LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5);
+ if (!lock.isLocked())
+ {
+ return;
+ }
+
+ if(sBuffer == NULL)
+ {
+ allocateStackBuffer();
+ }
+
+ if(sIndex > 511)
+ {
+ clear() ;
+ }
+
+ strcpy(sBuffer[sIndex], function) ;
+ sprintf(sBuffer[sIndex] + strlen(function), " line: %d ", line) ;
+ sIndex++ ;
+
+ return ;
+ }
+
+ //static
+ std::ostringstream* LLCallStacks::insert(const char* function, const int line)
+ {
+ std::ostringstream* _out = LLError::Log::out();
+ *_out << function << " line " << line << " " ;
+ return _out ;
+ }
+
+ //static
+ void LLCallStacks::end(std::ostringstream* _out)
+ {
+ LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5);
+ if (!lock.isLocked())
+ {
+ return;
+ }
+
+ if(sBuffer == NULL)
+ {
+ allocateStackBuffer();
+ }
+
+ if(sIndex > 511)
+ {
+ clear() ;
+ }
+
+ LLError::Log::flush(_out, sBuffer[sIndex++]) ;
+ }
+
+ //static
+ void LLCallStacks::print()
+ {
+ LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5);
+ if (!lock.isLocked())
+ {
+ return;
+ }
+
+ if(sIndex > 0)
+ {
+ LL_INFOS() << " ************* PRINT OUT LL CALL STACKS ************* " << LL_ENDL;
+ while(sIndex > 0)
+ {
+ sIndex-- ;
+ LL_INFOS() << sBuffer[sIndex] << LL_ENDL;
+ }
+ LL_INFOS() << " *************** END OF LL CALL STACKS *************** " << LL_ENDL;
+ }
+
+ if(sBuffer != NULL)
+ {
+ freeStackBuffer();
+ }
+ }
+
+ //static
+ void LLCallStacks::clear()
+ {
+ sIndex = 0 ;
+ }
+
+ //static
+ void LLCallStacks::cleanup()
+ {
+ freeStackBuffer();
+ }
+
+ std::ostream& operator<<(std::ostream& out, const LLStacktrace&)
+ {
+ return out << boost::stacktrace::stacktrace();
+ }
}
bool debugLoggingEnabled(const std::string& tag)
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index 9613911531..48162eca9e 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -262,30 +262,36 @@ namespace LLError
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
- //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.
- //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
- {
- private:
- static char** sBuffer ;
- static S32 sIndex ;
-
- static void allocateStackBuffer();
- static void freeStackBuffer();
-
- public:
- static void push(const char* function, const int line) ;
- static std::ostringstream* insert(const char* function, const int line) ;
- static void print() ;
- static void clear() ;
- static void end(std::ostringstream* _out) ;
- static void cleanup();
- };
+ //LLCallStacks keeps track of call stacks and output the call stacks to log file
+ //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.
+ //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
+ {
+ private:
+ static char** sBuffer ;
+ static S32 sIndex ;
+
+ static void allocateStackBuffer();
+ static void freeStackBuffer();
+
+ public:
+ static void push(const char* function, const int line) ;
+ static std::ostringstream* insert(const char* function, const int line) ;
+ static void print() ;
+ static void clear() ;
+ static void end(std::ostringstream* _out) ;
+ static void cleanup();
+ };
+
+ // class which, when streamed, inserts the current stack trace
+ struct LLStacktrace
+ {
+ friend std::ostream& operator<<(std::ostream& out, const LLStacktrace&);
+ };
}
//this is cheaper than llcallstacks if no need to output other variables to call stacks.