Merge branch 'DRTVWR-516-maint' of https://bitbucket.org/lindenlab/viewer

master
Ansariel 2021-05-25 11:03:48 +02:00
commit 9e415cdbb2
35 changed files with 553 additions and 615 deletions

0
BuildParams Executable file → Normal file
View File

View File

@ -129,11 +129,6 @@ pre_build()
then # show that we're doing this, just not the contents
echo source "$bugsplat_sh"
source "$bugsplat_sh"
# important: we test this and use its value in [grand-]child processes
if [ -n "${BUGSPLAT_DB:-}" ]
then echo export BUGSPLAT_DB
export BUGSPLAT_DB
fi
fi
set -x
@ -426,6 +421,15 @@ then
fi
fi
# Some of the uploads takes a long time to finish in the codeticket backend,
# causing the next codeticket upload attempt to fail.
# Inserting this after each potentially large upload may prevent those errors.
# JJ is making changes to Codeticket that we hope will eliminate this failure, then this can be removed
wait_for_codeticket()
{
sleep $(( 60 * 6 ))
}
# check status and upload results to S3
if $succeeded
then
@ -442,6 +446,7 @@ then
# Upload base package.
python_cmd "$helpers/codeticket.py" addoutput Installer "$package" \
|| fatal "Upload of installer failed"
wait_for_codeticket
# Upload additional packages.
for package_id in $additional_packages
@ -451,6 +456,7 @@ then
then
python_cmd "$helpers/codeticket.py" addoutput "Installer $package_id" "$package" \
|| fatal "Upload of installer $package_id failed"
wait_for_codeticket
else
record_failure "Failed to find additional package for '$package_id'."
fi
@ -464,6 +470,7 @@ then
# Upload crash reporter file
python_cmd "$helpers/codeticket.py" addoutput "Symbolfile" "$VIEWER_SYMBOL_FILE" \
|| fatal "Upload of symbolfile failed"
wait_for_codeticket
fi
# Upload the llphysicsextensions_tpv package, if one was produced
@ -471,6 +478,9 @@ then
if [ -r "$build_dir/llphysicsextensions_package" ]
then
llphysicsextensions_package=$(cat $build_dir/llphysicsextensions_package)
# This next upload is a frequent failure; see if giving the last one some time helps
# JJ is making changes to Codeticket that we hope will eliminate this failure soon
sleep 300
python_cmd "$helpers/codeticket.py" addoutput "Physics Extensions Package" "$llphysicsextensions_package" --private \
|| fatal "Upload of physics extensions package failed"
fi
@ -483,6 +493,7 @@ then
begin_section "Upload Extension $extension"
. $extension
[ $? -eq 0 ] || fatal "Upload of extension $extension failed"
wait_for_codeticket
end_section "Upload Extension $extension"
done
fi
@ -492,7 +503,6 @@ then
record_event "skipping upload of installer"
fi
else
record_event "skipping upload of installer due to failed build"
fi

View File

@ -13,6 +13,7 @@ project(${ROOT_PROJECT_NAME})
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
include(Variables)
include(bugsplat)
include(BuildVersion)
set(LEGACY_STDIO_LIBS)
@ -108,7 +109,10 @@ endif (WINDOWS AND EXISTS ${LIBS_CLOSED_DIR}copy_win_scripts)
add_custom_target(viewer)
if (NOT USE_BUGSPLAT)
add_subdirectory(${LIBS_OPEN_PREFIX}llcrashlogger)
endif (NOT USE_BUGSPLAT)
add_subdirectory(${LIBS_OPEN_PREFIX}llplugin)
add_subdirectory(${LIBS_OPEN_PREFIX}llui)
add_subdirectory(${LIBS_OPEN_PREFIX}viewer_components)
@ -124,31 +128,18 @@ add_subdirectory(${LIBS_OPEN_PREFIX}media_plugins)
endif (ENABLE_MEDIA_PLUGINS)
if (LINUX)
add_subdirectory(${VIEWER_PREFIX}linux_crash_logger)
if (INSTALL_PROPRIETARY)
include(LLAppearanceUtility)
add_subdirectory(${LLAPPEARANCEUTILITY_SRC_DIR} ${LLAPPEARANCEUTILITY_BIN_DIR})
endif (INSTALL_PROPRIETARY)
#<FS:TS> Huh? Where'd that target come from?
#add_dependencies(viewer linux-crash-logger-strip-target)
add_dependencies(viewer linux-crash-logger)
elseif (DARWIN)
add_subdirectory(${VIEWER_PREFIX}mac_crash_logger)
add_dependencies(viewer mac-crash-logger)
elseif (WINDOWS)
add_subdirectory(${VIEWER_PREFIX}win_crash_logger)
# cmake EXISTS requires an absolute path, see indra/cmake/Variables.cmake
if (EXISTS ${VIEWER_DIR}win_setup)
add_subdirectory(${VIEWER_DIR}win_setup)
endif (EXISTS ${VIEWER_DIR}win_setup)
# add_dependencies(viewer windows-setup windows-crash-logger)
add_dependencies(viewer windows-crash-logger)
endif (LINUX)
add_subdirectory(${VIEWER_PREFIX}newview)
add_dependencies(viewer firestorm-bin)
add_subdirectory(${VIEWER_PREFIX}doxygen EXCLUDE_FROM_ALL)
if (WINDOWS)
# cmake EXISTS requires an absolute path, see indra/cmake/Variables.cmake
if (EXISTS ${VIEWER_DIR}win_setup)
add_subdirectory(${VIEWER_DIR}win_setup)
endif (EXISTS ${VIEWER_DIR}win_setup)
endif (WINDOWS)
# sets the 'startup project' for debugging from visual studio.
set_property(
@ -156,6 +147,33 @@ set_property(
PROPERTY VS_STARTUP_PROJECT firestorm-bin
)
if (USE_BUGSPLAT)
if (BUGSPLAT_DB)
message(STATUS "Building with BugSplat; database '${BUGSPLAT_DB}'")
else (BUGSPLAT_DB)
message(WARNING "Building with BugSplat, but no database name set (BUGSPLAT_DB)")
endif (BUGSPLAT_DB)
else (USE_BUGSPLAT)
message(STATUS "Not building with BugSplat")
if (LINUX)
add_subdirectory(${VIEWER_PREFIX}linux_crash_logger)
#<FS:TS> Huh? Where'd that target come from?
#add_dependencies(viewer linux-crash-logger-strip-target)
elseif (DARWIN)
add_subdirectory(${VIEWER_PREFIX}mac_crash_logger)
add_dependencies(viewer mac-crash-logger)
elseif (WINDOWS)
add_subdirectory(${VIEWER_PREFIX}win_crash_logger)
# add_dependencies(viewer windows-setup windows-crash-logger)
add_dependencies(viewer windows-crash-logger)
endif (LINUX)
endif (USE_BUGSPLAT)
add_subdirectory(${VIEWER_PREFIX}newview)
add_dependencies(viewer firestorm-bin)
add_subdirectory(${VIEWER_PREFIX}doxygen EXCLUDE_FROM_ALL)
if (LL_TESTS)
# Define after the custom targets are created so
# individual apps can add themselves as dependencies

View File

@ -72,7 +72,7 @@ if(WINDOWS)
# Filenames are different for 32/64 bit BugSplat file and we don't
# have any control over them so need to branch.
if (BUGSPLAT_DB)
if (USE_BUGSPLAT)
if(ADDRESS_SIZE EQUAL 32)
set(release_files ${release_files} BugSplat.dll)
set(release_files ${release_files} BugSplatRc.dll)
@ -82,7 +82,7 @@ if(WINDOWS)
set(release_files ${release_files} BugSplatRc64.dll)
set(release_files ${release_files} BsSndRpt64.exe)
endif(ADDRESS_SIZE EQUAL 32)
endif (BUGSPLAT_DB)
endif (USE_BUGSPLAT)
set(release_files ${release_files} growl++.dll growl.dll )
if (FMODSTUDIO)

View File

@ -6,6 +6,7 @@ include(LLTestCommand)
#include(GoogleMock)
# </FS:ND>
include(bugsplat)
include(Tut)
#*****************************************************************************
@ -92,6 +93,12 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources)
IF(LL_TEST_VERBOSE)
MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_SOURCE_FILES ${${name}_test_SOURCE_FILES}")
ENDIF(LL_TEST_VERBOSE)
if (USE_BUGSPLAT)
SET_PROPERTY(SOURCE ${${name}_test_SOURCE_FILES}
APPEND PROPERTY COMPILE_DEFINITIONS "${BUGSPLAT_DEFINE}")
endif (USE_BUGSPLAT)
# Headers
GET_OPT_SOURCE_FILE_PROPERTY(${name}_test_additional_HEADER_FILES ${source} LL_TEST_ADDITIONAL_HEADER_FILES)
SET(${name}_test_HEADER_FILES ${name}.h ${${name}_test_additional_HEADER_FILES})
@ -229,6 +236,11 @@ FUNCTION(LL_ADD_INTEGRATION_TEST
SET_TARGET_PROPERTIES(INTEGRATION_TEST_${testname} PROPERTIES COMPILE_FLAGS -I"${TUT_INCLUDE_DIR}")
endif(USESYSTEMLIBS)
if (USE_BUGSPLAT)
SET_PROPERTY(SOURCE ${source_files}
APPEND PROPERTY COMPILE_DEFINITIONS "${BUGSPLAT_DEFINE}")
endif (USE_BUGSPLAT)
# The following was copied to llcorehttp/CMakeLists.txt's texture_load target.
# Any changes made here should be replicated there.
if (WINDOWS)

View File

@ -34,7 +34,6 @@ set(LL_TESTS OFF CACHE BOOL "Build and run unit and integration tests (disable f
set(INCREMENTAL_LINK OFF CACHE BOOL "Use incremental linking on win32 builds (enable for faster links on some machines)")
set(ENABLE_MEDIA_PLUGINS ON CACHE BOOL "Turn off building media plugins if they are imported by third-party library mechanism")
set(VIEWER_SYMBOL_FILE "" CACHE STRING "Name of tarball into which to place symbol files")
set(BUGSPLAT_DB "" CACHE STRING "BugSplat database name, if BugSplat crash reporting is desired")
if(LIBS_CLOSED_DIR)
file(TO_CMAKE_PATH "${LIBS_CLOSED_DIR}" LIBS_CLOSED_DIR)

View File

@ -1,27 +1,33 @@
# BugSplat is engaged by setting BUGSPLAT_DB to the target BugSplat database
# name.
if (BUGSPLAT_DB)
if (USESYSTEMLIBS)
message(STATUS "Looking for system BugSplat")
set(BUGSPLAT_FIND_QUIETLY ON)
set(BUGSPLAT_FIND_REQUIRED ON)
include(FindBUGSPLAT)
else (USESYSTEMLIBS)
message(STATUS "Engaging autobuild BugSplat")
include(Prebuilt)
use_prebuilt_binary(bugsplat)
if (WINDOWS)
set(BUGSPLAT_LIBRARIES
${ARCH_PREBUILT_DIRS_RELEASE}/bugsplat.lib
)
elseif (DARWIN)
find_library(BUGSPLAT_LIBRARIES BugsplatMac
PATHS "${ARCH_PREBUILT_DIRS_RELEASE}")
message(FATAL_ERROR "Bugsplat for OSX not fully implemented, please adapt llappdelegate-objc.mm to honor options of sending user name and settings.xml.")
else (WINDOWS)
message(FATAL_ERROR "Bugsplat for Linux not implemented.")
if (INSTALL_PROPRIETARY)
set(USE_BUGSPLAT ON CACHE BOOL "Use the BugSplat crash reporting system")
else (INSTALL_PROPRIETARY)
set(USE_BUGSPLAT OFF CACHE BOOL "Use the BugSplat crash reporting system")
endif (INSTALL_PROPRIETARY)
if (USE_BUGSPLAT)
if (NOT USESYSTEMLIBS)
include(Prebuilt)
use_prebuilt_binary(bugsplat)
if (WINDOWS)
set(BUGSPLAT_LIBRARIES
${ARCH_PREBUILT_DIRS_RELEASE}/bugsplat.lib
)
elseif (DARWIN)
find_library(BUGSPLAT_LIBRARIES BugsplatMac REQUIRED
NO_DEFAULT_PATH PATHS "${ARCH_PREBUILT_DIRS_RELEASE}")
message(FATAL_ERROR "Bugsplat for OSX not fully implemented, please adapt llappdelegate-objc.mm to honor options of sending user name and settings.xml.")
else (WINDOWS)
message(FATAL_ERROR "BugSplat is not supported; add -DUSE_BUGSPLAT=OFF")
endif (WINDOWS)
else (NOT USESYSTEMLIBS)
set(BUGSPLAT_FIND_QUIETLY ON)
set(BUGSPLAT_FIND_REQUIRED ON)
include(FindBUGSPLAT)
endif (NOT USESYSTEMLIBS)
set(BUGSPLAT_DB "" CACHE STRING "BugSplat crash database name")
endif (WINDOWS)
set(BUGSPLAT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/bugsplat)
endif (USESYSTEMLIBS)
endif (BUGSPLAT_DB)
set(BUGSPLAT_DEFINE "LL_BUGSPLAT")
endif (USE_BUGSPLAT)

View File

@ -0,0 +1,3 @@
This component is no longer used in Linden Lab builds.
Change requests to support continued use by open source
builds are welcome.

View File

@ -4,6 +4,7 @@ project(llcommon)
include(00-Common)
include(LLCommon)
include(bugsplat)
include(Linking)
include(Boost)
include(LLSharedLibs)
@ -291,10 +292,10 @@ list(APPEND llcommon_HEADER_FILES "tea.h" )
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})

View File

@ -531,7 +531,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()
@ -811,7 +816,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);
@ -848,7 +855,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);
@ -901,6 +910,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)
{

View File

@ -488,8 +488,6 @@ namespace
protected:
Globals();
public:
std::ostringstream messageStream;
bool messageStreamInUse;
std::string mFatalMessage;
void addCallSite(LLError::CallSite&);
@ -499,12 +497,7 @@ namespace
CallSiteVector callSites;
};
Globals::Globals()
: messageStream(),
messageStreamInUse(false),
callSites()
{
}
Globals::Globals() {}
Globals* Globals::getInstance()
{
@ -595,7 +588,7 @@ namespace LLError
mFileLevelMap(),
mTagLevelMap(),
mUniqueLogMessages(),
mCrashFunction(NULL),
mCrashFunction([](const std::string&){}),
mTimeFunction(NULL),
mRecorders(),
mShouldLogCallCounter(0)
@ -780,7 +773,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
@ -1419,57 +1411,7 @@ namespace LLError
}
std::ostringstream* Log::out()
{
LLMutexTrylock lock(getMutex<LOG_MUTEX>(),5);
if (lock.isLocked())
{
Globals* g = Globals::getInstance();
if (!g->messageStreamInUse)
{
g->messageStreamInUse = true;
return &g->messageStream;
}
}
return new std::ostringstream;
}
void Log::flush(std::ostringstream* out, char* message)
{
LLMutexTrylock lock(getMutex<LOG_MUTEX>(),5);
if (!lock.isLocked())
{
return;
}
if(strlen(out->str().c_str()) < 128)
{
strcpy(message, out->str().c_str());
}
else
{
strncpy(message, out->str().c_str(), 127);
message[127] = '\0' ;
}
Globals* g = Globals::getInstance();
if (out == &g->messageStream)
{
g->messageStream.clear();
g->messageStream.str("");
g->messageStreamInUse = false;
}
else
{
delete out;
}
return ;
}
void Log::flush(std::ostringstream* out, const CallSite& site)
void Log::flush(const std::ostringstream& out, const CallSite& site)
{
LLMutexTrylock lock(getMutex<LOG_MUTEX>(),5);
if (!lock.isLocked())
@ -1480,21 +1422,11 @@ namespace LLError
Globals* g = Globals::getInstance();
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
std::string message = out->str();
if (out == &g->messageStream)
{
g->messageStream.clear();
g->messageStream.str("");
g->messageStreamInUse = false;
}
else
{
delete out;
}
std::string message = out.str();
if (site.mPrintOnce)
{
std::ostringstream message_stream;
std::ostringstream message_stream;
std::map<std::string, unsigned int>::iterator messageIter = s->mUniqueLogMessages.find(message);
if (messageIter != s->mUniqueLogMessages.end())
@ -1515,8 +1447,8 @@ namespace LLError
message_stream << "ONCE: ";
s->mUniqueLogMessages[message] = 1;
}
message_stream << message;
message = message_stream.str();
message_stream << message;
message = message_stream.str();
}
writeToRecorders(site, message);
@ -1524,10 +1456,7 @@ namespace LLError
if (site.mLevel == LEVEL_ERROR)
{
g->mFatalMessage = message;
if (s->mCrashFunction)
{
s->mCrashFunction(message);
}
s->mCrashFunction(message);
}
}
}
@ -1591,29 +1520,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);
@ -1630,33 +1536,7 @@ namespace LLError
namespace LLError
{
char** LLCallStacks::sBuffer = NULL ;
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 ;
}
}
LLCallStacks::StringVector LLCallStacks::sBuffer ;
//static
void LLCallStacks::push(const char* function, const int line)
@ -1667,33 +1547,24 @@ namespace LLError
return;
}
if(sBuffer == NULL)
{
allocateStackBuffer();
}
if(sIndex > 511)
if(sBuffer.size() > 511)
{
clear() ;
}
strcpy(sBuffer[sIndex], function) ;
sprintf(sBuffer[sIndex] + strlen(function), " line: %d ", line) ;
sIndex++ ;
return ;
std::ostringstream out;
insert(out, function, line);
sBuffer.push_back(out.str());
}
//static
std::ostringstream* LLCallStacks::insert(const char* function, const int line)
void LLCallStacks::insert(std::ostream& out, const char* function, const int line)
{
std::ostringstream* _out = LLError::Log::out();
*_out << function << " line " << line << " " ;
return _out ;
out << function << " line " << line << " " ;
}
//static
void LLCallStacks::end(std::ostringstream* _out)
void LLCallStacks::end(const std::ostringstream& out)
{
LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5);
if (!lock.isLocked())
@ -1701,17 +1572,12 @@ namespace LLError
return;
}
if(sBuffer == NULL)
{
allocateStackBuffer();
}
if(sIndex > 511)
if(sBuffer.size() > 511)
{
clear() ;
}
LLError::Log::flush(_out, sBuffer[sIndex++]) ;
sBuffer.push_back(out.str());
}
//static
@ -1723,33 +1589,30 @@ namespace LLError
return;
}
if(sIndex > 0)
if(! sBuffer.empty())
{
LL_INFOS() << " ************* PRINT OUT LL CALL STACKS ************* " << LL_ENDL;
while(sIndex > 0)
for (StringVector::const_reverse_iterator ri(sBuffer.rbegin()), re(sBuffer.rend());
ri != re; ++ri)
{
sIndex-- ;
LL_INFOS() << sBuffer[sIndex] << LL_ENDL;
LL_INFOS() << (*ri) << LL_ENDL;
}
LL_INFOS() << " *************** END OF LL CALL STACKS *************** " << LL_ENDL;
}
if(sBuffer != NULL)
{
freeStackBuffer();
}
cleanup();
}
//static
void LLCallStacks::clear()
{
sIndex = 0 ;
sBuffer.clear();
}
//static
void LLCallStacks::cleanup()
{
freeStackBuffer();
clear();
}
std::ostream& operator<<(std::ostream& out, const LLStacktrace&)

View File

@ -29,7 +29,9 @@
#define LL_LLERROR_H
#include <sstream>
#include <string>
#include <typeinfo>
#include <vector>
#include "stdtypes.h"
@ -204,9 +206,7 @@ namespace LLError
{
public:
static bool shouldLog(CallSite&);
static std::ostringstream* out();
static void flush(std::ostringstream* out, char* message);
static void flush(std::ostringstream*, const CallSite&);
static void flush(const std::ostringstream&, const CallSite&);
static std::string demangle(const char* mangled);
/// classname<TYPE>()
template <typename T>
@ -287,18 +287,15 @@ namespace LLError
class LL_COMMON_API LLCallStacks
{
private:
static char** sBuffer ;
static S32 sIndex ;
static void allocateStackBuffer();
static void freeStackBuffer();
typedef std::vector<std::string> StringVector;
static StringVector sBuffer ;
public:
static void push(const char* function, const int line) ;
static std::ostringstream* insert(const char* function, const int line) ;
static void insert(std::ostream& out, const char* function, const int line) ;
static void print() ;
static void clear() ;
static void end(std::ostringstream* _out) ;
static void end(const std::ostringstream& out) ;
static void cleanup();
};
@ -312,10 +309,11 @@ namespace LLError
//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(__FUNCTION__, __LINE__) ; \
(*_out)
#define llcallstacks \
{ \
std::ostringstream _out; \
LLError::LLCallStacks::insert(_out, __FUNCTION__, __LINE__) ; \
_out
#define llcallstacksendl \
LLError::End(); \
@ -361,11 +359,11 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
static LLError::CallSite _site(lllog_site_args_(level, once, tags)); \
lllog_test_()
#define lllog_test_() \
if (LL_UNLIKELY(_site.shouldLog())) \
{ \
std::ostringstream* _out = LLError::Log::out(); \
(*_out)
#define lllog_test_() \
if (LL_UNLIKELY(_site.shouldLog())) \
{ \
std::ostringstream _out; \
_out
#define lllog_site_args_(level, once, tags) \
level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), \
@ -384,15 +382,27 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
// 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'
#define LL_ENDL \
LLError::End(); \
LLError::Log::flush(_out, _site); \
} \
} while(0)
// Use this only in LL_ERRS or in a place that LL_ERRS may not be used
#define LLERROR_CRASH \
{ \
int* make_me_crash = NULL;\
*make_me_crash = 0; \
exit(*make_me_crash); \
}
#define LL_ENDL \
LLError::End(); \
LLError::Log::flush(_out, _site); \
if (_site.mLevel == LLError::LEVEL_ERROR) \
{ \
LLERROR_CRASH \
} \
} \
} while(0)
// NEW Macros for debugging, allow the passing of a string tag

View File

@ -94,14 +94,16 @@ namespace LLError
*/
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
// The fatal function will be called after 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.
// that message from causing the fatal function to be invoked.
// The passed FatalFunction will be the LAST log function called
// before LL_ERRS crashes its caller. A FatalFunction can throw an
// exception, or call exit(), to bypass the crash. It MUST disrupt the
// flow of control because no caller expects LL_ERRS to return.
LL_COMMON_API FatalFunction getFatalFunction();
// Retrieve the previously-set FatalFunction
@ -147,14 +149,14 @@ namespace LLError
virtual void recordMessage(LLError::ELevel, const std::string& message) = 0;
// use the level for better display, not for filtering
virtual bool enabled() { return true; }
virtual bool enabled() { return true; }
bool wantsTime();
bool wantsTags();
bool wantsLevel();
bool wantsLocation();
bool wantsFunctionName();
bool wantsMultiline();
bool wantsMultiline();
void showTime(bool show);
void showTags(bool show);
@ -165,15 +167,35 @@ namespace LLError
protected:
bool mWantsTime;
bool mWantsTags;
bool mWantsLevel;
bool mWantsLocation;
bool mWantsFunctionName;
bool mWantsMultiline;
bool mWantsTags;
bool mWantsLevel;
bool mWantsLocation;
bool mWantsFunctionName;
bool mWantsMultiline;
};
typedef boost::shared_ptr<Recorder> RecorderPtr;
/**
* Instantiate GenericRecorder with a callable(level, message) to get
* control on every log message without having to code an explicit
* Recorder subclass.
*/
template <typename CALLABLE>
class GenericRecorder: public Recorder
{
public:
GenericRecorder(const CALLABLE& callable):
mCallable(callable)
{}
void recordMessage(LLError::ELevel level, const std::string& message) override
{
mCallable(level, message);
}
private:
CALLABLE mCallable;
};
/**
* @NOTE: addRecorder() and removeRecorder() uses the boost::shared_ptr to allow for shared ownership
* while still ensuring that the allocated memory is eventually freed
@ -181,6 +203,19 @@ namespace LLError
LL_COMMON_API void addRecorder(RecorderPtr);
LL_COMMON_API void removeRecorder(RecorderPtr);
// each error message is passed to each recorder via recordMessage()
/**
* Call addGenericRecorder() with a callable(level, message) to get
* control on every log message without having to code an explicit
* Recorder subclass. Save the returned RecorderPtr if you later want to
* call removeRecorder().
*/
template <typename CALLABLE>
RecorderPtr addGenericRecorder(const CALLABLE& callable)
{
RecorderPtr ptr{ new GenericRecorder<CALLABLE>(callable) };
addRecorder(ptr);
return ptr;
}
LL_COMMON_API void logToFile(const std::string& filename);
LL_COMMON_API void logToStderr();

View File

@ -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
@ -146,7 +145,9 @@ public:
.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));
mRecorder = LLError::addGenericRecorder(
[this](LLError::ELevel level, const std::string& message)
{ onError(level, message); });
// Send child a preliminary event reporting our own reply-pump name --
// which would otherwise be pretty tricky to guess!
@ -162,8 +163,7 @@ public:
virtual ~LLLeapImpl()
{
LL_DEBUGS("LLLeap") << "destroying LLLeap(\"" << mDesc << "\")" << LL_ENDL;
// Restore original FatalFunction
LLError::setFatalFunction(mPrevFatalFunction);
LLError::removeRecorder(mRecorder);
}
// Listener for failed launch attempt
@ -377,28 +377,28 @@ public:
return false;
}
void fatalFunction(const std::string& error)
void onError(LLError::ELevel level, 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)
if (level == LLError::LEVEL_ERROR)
{
mainloop.post(nop);
}
// Notify plugin
LLSD event;
event["type"] = "error";
event["error"] = error;
mReplyPump.post(event);
// forward the call to the previous FatalFunction
mPrevFatalFunction(error);
// 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);
}
}
}
private:
@ -421,7 +421,7 @@ private:
mStdinConnection, mStdoutConnection, mStdoutDataConnection, mStderrConnection;
boost::scoped_ptr<LLEventPump::Blocker> mBlocker;
LLProcess::ReadPipe::size_type mExpect;
LLError::FatalFunction mPrevFatalFunction;
LLError::RecorderPtr mRecorder;
boost::scoped_ptr<LLLeapListener> mListener;
};

View File

@ -38,11 +38,6 @@
#include <sstream>
#include <stdexcept>
namespace {
void log(LLError::ELevel level,
const char* p1, const char* p2, const char* p3, const char* p4);
} // anonymous namespace
// Our master list of all LLSingletons is itself an LLSingleton. We used to
// store it in a function-local static, but that could get destroyed before
// the last of the LLSingletons -- and ~LLSingletonBase() definitely wants to
@ -218,8 +213,8 @@ void LLSingletonBase::pop_initializing()
if (list.empty())
{
logerrs("Underflow in stack of currently-initializing LLSingletons at ",
classname(this).c_str(), "::getInstance()");
logerrs({"Underflow in stack of currently-initializing LLSingletons at ",
classname(this), "::getInstance()"});
}
// Now we know list.back() exists: capture it
@ -240,9 +235,9 @@ void LLSingletonBase::pop_initializing()
// Now validate the newly-popped LLSingleton.
if (back != this)
{
logerrs("Push/pop mismatch in stack of currently-initializing LLSingletons: ",
classname(this).c_str(), "::getInstance() trying to pop ",
classname(back).c_str());
logerrs({"Push/pop mismatch in stack of currently-initializing LLSingletons: ",
classname(this), "::getInstance() trying to pop ",
classname(back)});
}
// log AFTER popping so logging singletons don't cry circularity
@ -331,15 +326,15 @@ void LLSingletonBase::capture_dependency()
//
// Example: LLNotifications singleton initializes default channels.
// Channels register themselves with singleton once done.
logdebugs("LLSingleton circularity: ", out.str().c_str(),
classname(this).c_str(), "");
logdebugs({"LLSingleton circularity: ", out.str(),
classname(this)});
}
else
{
// Actual circularity with other singleton (or single singleton is used extensively).
// Dependency can be unclear.
logwarns("LLSingleton circularity: ", out.str().c_str(),
classname(this).c_str(), "");
logwarns({"LLSingleton circularity: ", out.str(),
classname(this)});
}
}
else
@ -352,8 +347,8 @@ void LLSingletonBase::capture_dependency()
if (current->mDepends.insert(this).second)
{
// only log the FIRST time we hit this dependency!
logdebugs(classname(current).c_str(),
" depends on ", classname(this).c_str());
logdebugs({classname(current),
" depends on ", classname(this)});
}
}
}
@ -401,7 +396,7 @@ LLSingletonBase::vec_t LLSingletonBase::dep_sort()
void LLSingletonBase::cleanup_()
{
logdebugs("calling ", classname(this).c_str(), "::cleanupSingleton()");
logdebugs({"calling ", classname(this), "::cleanupSingleton()"});
try
{
cleanupSingleton();
@ -427,23 +422,23 @@ void LLSingletonBase::deleteAll()
if (! sp->mDeleteSingleton)
{
// This Should Not Happen... but carry on.
logwarns(name.c_str(), "::mDeleteSingleton not initialized!");
logwarns({name, "::mDeleteSingleton not initialized!"});
}
else
{
// properly initialized: call it.
logdebugs("calling ", name.c_str(), "::deleteSingleton()");
logdebugs({"calling ", name, "::deleteSingleton()"});
// From this point on, DO NOT DEREFERENCE sp!
sp->mDeleteSingleton();
}
}
catch (const std::exception& e)
{
logwarns("Exception in ", name.c_str(), "::deleteSingleton(): ", e.what());
logwarns({"Exception in ", name, "::deleteSingleton(): ", e.what()});
}
catch (...)
{
logwarns("Unknown exception in ", name.c_str(), "::deleteSingleton()");
logwarns({"Unknown exception in ", name, "::deleteSingleton()"});
}
}
}
@ -451,49 +446,40 @@ void LLSingletonBase::deleteAll()
/*---------------------------- Logging helpers -----------------------------*/
namespace {
void log(LLError::ELevel level,
const char* p1, const char* p2, const char* p3, const char* p4)
std::ostream& operator<<(std::ostream& out, const LLSingletonBase::string_params& args)
{
LL_VLOGS(level, "LLSingleton") << p1 << p2 << p3 << p4 << LL_ENDL;
// However many args there are in args, stream each of them to 'out'.
for (auto arg : args)
{
out << arg;
}
return out;
}
} // anonymous namespace
//static
void LLSingletonBase::logwarns(const char* p1, const char* p2, const char* p3, const char* p4)
void LLSingletonBase::logwarns(const string_params& args)
{
log(LLError::LEVEL_WARN, p1, p2, p3, p4);
LL_WARNS("LLSingleton") << args << LL_ENDL;
}
//static
void LLSingletonBase::loginfos(const char* p1, const char* p2, const char* p3, const char* p4)
void LLSingletonBase::loginfos(const string_params& args)
{
log(LLError::LEVEL_INFO, p1, p2, p3, p4);
LL_INFOS("LLSingleton") << args << LL_ENDL;
}
//static
void LLSingletonBase::logdebugs(const char* p1, const char* p2, const char* p3, const char* p4)
void LLSingletonBase::logdebugs(const string_params& args)
{
log(LLError::LEVEL_DEBUG, p1, p2, p3, p4);
LL_DEBUGS("LLSingleton") << args << LL_ENDL;
}
//static
void LLSingletonBase::logerrs(const char* p1, const char* p2, const char* p3, const char* p4)
void LLSingletonBase::logerrs(const string_params& args)
{
log(LLError::LEVEL_ERROR, p1, p2, p3, p4);
// The other important side effect of LL_ERRS() is
// 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());
}
LL_ERRS("LLSingleton") << args << LL_ENDL;
}
std::string LLSingletonBase::demangle(const char* mangled)

View File

@ -27,9 +27,10 @@
#include <boost/noncopyable.hpp>
#include <boost/unordered_set.hpp>
#include <initializer_list>
#include <list>
#include <vector>
#include <typeinfo>
#include <vector>
#include "mutex.h"
#include "lockstatic.h"
#include "llthread.h" // on_main_thread()
@ -111,14 +112,13 @@ protected:
void capture_dependency();
// delegate logging calls to llsingleton.cpp
static void logerrs(const char* p1, const char* p2="",
const char* p3="", const char* p4="");
static void logwarns(const char* p1, const char* p2="",
const char* p3="", const char* p4="");
static void loginfos(const char* p1, const char* p2="",
const char* p3="", const char* p4="");
static void logdebugs(const char* p1, const char* p2="",
const char* p3="", const char* p4="");
public:
typedef std::initializer_list<const std::string> string_params;
protected:
static void logerrs (const string_params&);
static void logwarns (const string_params&);
static void loginfos (const string_params&);
static void logdebugs(const string_params&);
static std::string demangle(const char* mangled);
// these classname() declarations restate template functions declared in
// llerror.h because we avoid #including that here
@ -368,8 +368,8 @@ private:
// init stack to its previous size BEFORE logging so log-machinery
// LLSingletons don't record a dependency on DERIVED_TYPE!
LLSingleton_manage_master<DERIVED_TYPE>().reset_initializing(prev_size);
logwarns("Error constructing ", classname<DERIVED_TYPE>().c_str(),
": ", err.what());
logwarns({"Error constructing ", classname<DERIVED_TYPE>(),
": ", err.what()});
// There isn't a separate EInitState value meaning "we attempted
// to construct this LLSingleton subclass but could not," so use
// DELETED. That seems slightly more appropriate than UNINITIALIZED.
@ -397,8 +397,8 @@ private:
// BEFORE logging, so log-machinery LLSingletons don't record a
// dependency on DERIVED_TYPE!
pop_initializing(lk->mInstance);
logwarns("Error in ", classname<DERIVED_TYPE>().c_str(),
"::initSingleton(): ", err.what());
logwarns({"Error in ", classname<DERIVED_TYPE>(),
"::initSingleton(): ", err.what()});
// Get rid of the instance entirely. This call depends on our
// recursive_mutex. We could have a deleteSingleton(LockStatic&)
// overload and pass lk, but we don't strictly need it.
@ -547,9 +547,9 @@ public:
case CONSTRUCTING:
// here if DERIVED_TYPE's constructor (directly or indirectly)
// calls DERIVED_TYPE::getInstance()
logerrs("Tried to access singleton ",
classname<DERIVED_TYPE>().c_str(),
" from singleton constructor!");
logerrs({"Tried to access singleton ",
classname<DERIVED_TYPE>(),
" from singleton constructor!"});
return nullptr;
case INITIALIZING:
@ -564,9 +564,9 @@ public:
case DELETED:
// called after deleteSingleton()
logwarns("Trying to access deleted singleton ",
classname<DERIVED_TYPE>().c_str(),
" -- creating new instance");
logwarns({"Trying to access deleted singleton ",
classname<DERIVED_TYPE>(),
" -- creating new instance"});
// fall through
case UNINITIALIZED:
case QUEUED:
@ -593,8 +593,8 @@ public:
} // unlock 'lk'
// Per the comment block above, dispatch to the main thread.
loginfos(classname<DERIVED_TYPE>().c_str(),
"::getInstance() dispatching to main thread");
loginfos({classname<DERIVED_TYPE>(),
"::getInstance() dispatching to main thread"});
auto instance = LLMainThreadTask::dispatch(
[](){
// VERY IMPORTANT to call getInstance() on the main thread,
@ -604,16 +604,16 @@ public:
// the main thread processes them, only the FIRST such request
// actually constructs the instance -- every subsequent one
// simply returns the existing instance.
loginfos(classname<DERIVED_TYPE>().c_str(),
"::getInstance() on main thread");
loginfos({classname<DERIVED_TYPE>(),
"::getInstance() on main thread"});
return getInstance();
});
// record the dependency chain tracked on THIS thread, not the main
// thread (consider a getInstance() overload with a tag param that
// suppresses dep tracking when dispatched to the main thread)
capture_dependency(instance);
loginfos(classname<DERIVED_TYPE>().c_str(),
"::getInstance() returning on requesting thread");
loginfos({classname<DERIVED_TYPE>(),
"::getInstance() returning on requesting thread"});
return instance;
}
@ -682,16 +682,16 @@ private:
// For organizational purposes this function shouldn't be called twice
if (lk->mInitState != super::UNINITIALIZED)
{
super::logerrs("Tried to initialize singleton ",
super::template classname<DERIVED_TYPE>().c_str(),
" twice!");
super::logerrs({"Tried to initialize singleton ",
super::template classname<DERIVED_TYPE>(),
" twice!"});
return nullptr;
}
else if (on_main_thread())
{
// on the main thread, simply construct instance while holding lock
super::logdebugs(super::template classname<DERIVED_TYPE>().c_str(),
"::initParamSingleton()");
super::logdebugs({super::template classname<DERIVED_TYPE>(),
"::initParamSingleton()"});
super::constructSingleton(lk, std::forward<Args>(args)...);
return lk->mInstance;
}
@ -703,8 +703,8 @@ private:
lk->mInitState = super::QUEUED;
// very important to unlock here so main thread can actually process
lk.unlock();
super::loginfos(super::template classname<DERIVED_TYPE>().c_str(),
"::initParamSingleton() dispatching to main thread");
super::loginfos({super::template classname<DERIVED_TYPE>(),
"::initParamSingleton() dispatching to main thread"});
// Normally it would be the height of folly to reference-bind
// 'args' into a lambda to be executed on some other thread! By
// the time that thread executed the lambda, the references would
@ -715,12 +715,12 @@ private:
// references.
auto instance = LLMainThreadTask::dispatch(
[&](){
super::loginfos(super::template classname<DERIVED_TYPE>().c_str(),
"::initParamSingleton() on main thread");
super::loginfos({super::template classname<DERIVED_TYPE>(),
"::initParamSingleton() on main thread"});
return initParamSingleton_(std::forward<Args>(args)...);
});
super::loginfos(super::template classname<DERIVED_TYPE>().c_str(),
"::initParamSingleton() returning on requesting thread");
super::loginfos({super::template classname<DERIVED_TYPE>(),
"::initParamSingleton() returning on requesting thread"});
return instance;
}
}
@ -748,14 +748,14 @@ public:
{
case super::UNINITIALIZED:
case super::QUEUED:
super::logerrs("Uninitialized param singleton ",
super::template classname<DERIVED_TYPE>().c_str());
super::logerrs({"Uninitialized param singleton ",
super::template classname<DERIVED_TYPE>()});
break;
case super::CONSTRUCTING:
super::logerrs("Tried to access param singleton ",
super::template classname<DERIVED_TYPE>().c_str(),
" from singleton constructor!");
super::logerrs({"Tried to access param singleton ",
super::template classname<DERIVED_TYPE>(),
" from singleton constructor!"});
break;
case super::INITIALIZING:
@ -767,8 +767,8 @@ public:
return lk->mInstance;
case super::DELETED:
super::logerrs("Trying to access deleted param singleton ",
super::template classname<DERIVED_TYPE>().c_str());
super::logerrs({"Trying to access deleted param singleton ",
super::template classname<DERIVED_TYPE>()});
break;
}

View File

@ -26,6 +26,7 @@
*/
#include <vector>
#include <stdexcept>
#include "linden_common.h"
@ -69,21 +70,41 @@ namespace
namespace
{
static bool fatalWasCalled;
void fatalCall(const std::string&) { fatalWasCalled = true; }
static bool fatalWasCalled = false;
struct FatalWasCalled: public std::runtime_error
{
FatalWasCalled(const std::string& what): std::runtime_error(what) {}
};
void fatalCall(const std::string& msg) { throw FatalWasCalled(msg); }
}
// Because we use LLError::setFatalFunction(fatalCall), any LL_ERRS call we
// issue will throw FatalWasCalled. But we want the test program to continue.
// So instead of writing:
// LL_ERRS("tag") << "some message" << LL_ENDL;
// write:
// CATCH(LL_ERRS("tag"), "some message");
#define CATCH(logcall, expr) \
try \
{ \
logcall << expr << LL_ENDL; \
} \
catch (const FatalWasCalled&) \
{ \
fatalWasCalled = true; \
}
namespace tut
{
class TestRecorder : public LLError::Recorder
{
public:
TestRecorder()
{
showTime(false);
}
{
showTime(false);
}
virtual ~TestRecorder()
{}
{}
virtual void recordMessage(LLError::ELevel level,
const std::string& message)
@ -252,7 +273,7 @@ namespace
LL_DEBUGS("WriteTag","AnotherTag") << "one" << LL_ENDL;
LL_INFOS("WriteTag") << "two" << LL_ENDL;
LL_WARNS("WriteTag") << "three" << LL_ENDL;
LL_ERRS("WriteTag") << "four" << LL_ENDL;
CATCH(LL_ERRS("WriteTag"), "four");
}
};
@ -380,7 +401,7 @@ namespace
std::string errorReturningLocation()
{
LL_ERRS() << "die" << LL_ENDL; int this_line = __LINE__;
int this_line = __LINE__; CATCH(LL_ERRS(), "die");
return locationString(this_line);
}
}
@ -701,7 +722,7 @@ public:
static void doDebug() { LL_DEBUGS() << "add dice" << LL_ENDL; }
static void doInfo() { LL_INFOS() << "any idea" << LL_ENDL; }
static void doWarn() { LL_WARNS() << "aim west" << LL_ENDL; }
static void doError() { LL_ERRS() << "ate eels" << LL_ENDL; }
static void doError() { CATCH(LL_ERRS(), "ate eels"); }
static void doAll() { doDebug(); doInfo(); doWarn(); doError(); }
};
@ -712,7 +733,7 @@ public:
static void doDebug() { LL_DEBUGS() << "bed down" << LL_ENDL; }
static void doInfo() { LL_INFOS() << "buy iron" << LL_ENDL; }
static void doWarn() { LL_WARNS() << "bad word" << LL_ENDL; }
static void doError() { LL_ERRS() << "big easy" << LL_ENDL; }
static void doError() { CATCH(LL_ERRS(), "big easy"); }
static void doAll() { doDebug(); doInfo(); doWarn(); doError(); }
};
@ -874,13 +895,10 @@ namespace tut
namespace
{
std::string writeTagWithSpaceReturningLocation()
{
LL_DEBUGS("Write Tag") << "not allowed" << LL_ENDL; int this_line = __LINE__;
std::ostringstream location;
location << LLError::abbreviateFile(__FILE__).c_str() << "(" << this_line << ")";
return location.str();
}
{
int this_line = __LINE__; CATCH(LL_DEBUGS("Write Tag"), "not allowed");
return locationString(this_line);
}
};
namespace tut
@ -894,9 +912,9 @@ namespace tut
std::string location = writeTagWithSpaceReturningLocation();
std::string expected = "Space is not allowed in a log tag at " + location;
ensure_message_field_equals(0, LEVEL_FIELD, "ERROR");
ensure_message_field_equals(0, MSG_FIELD, expected);
ensure("fatal callback called", fatalWasCalled);
ensure_message_field_equals(0, LEVEL_FIELD, "ERROR");
ensure_message_field_equals(0, MSG_FIELD, expected);
ensure("fatal callback called", fatalWasCalled);
}
}

View File

@ -44,10 +44,6 @@
#include <list>
#include <string>
// statically reference the function in test.cpp... it's short, we could
// replicate, but better to reuse
extern void wouldHaveCrashed(const std::string& message);
struct WrapLLErrs
{
WrapLLErrs():
@ -59,7 +55,8 @@ struct WrapLLErrs
mPriorFatal(LLError::getFatalFunction())
{
// Make LL_ERRS call our own operator() method
LLError::setFatalFunction(boost::bind(&WrapLLErrs::operator(), this, _1));
LLError::setFatalFunction(
[this](const std::string& message){ (*this)(message); });
}
~WrapLLErrs()
@ -199,11 +196,13 @@ 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(),
: boost::noncopyable(),
mFatalFunction(LLError::getFatalFunction()),
mOldSettings(LLError::saveAndResetSettings()),
mRecorder(new CaptureLogRecorder())
mRecorder(new CaptureLogRecorder())
{
LLError::setFatalFunction(wouldHaveCrashed);
// reinstate the FatalFunction we just reset
LLError::setFatalFunction(mFatalFunction);
LLError::setDefaultLevel(level);
LLError::addRecorder(mRecorder);
}
@ -219,17 +218,18 @@ public:
/// for the sought string.
std::string messageWith(const std::string& search, bool required=true)
{
return boost::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->messageWith(search, required);
return boost::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->messageWith(search, required);
}
std::ostream& streamto(std::ostream& out) const
{
return boost::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->streamto(out);
return boost::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->streamto(out);
}
private:
LLError::FatalFunction mFatalFunction;
LLError::SettingsStoragePtr mOldSettings;
LLError::RecorderPtr mRecorder;
LLError::RecorderPtr mRecorder;
};
#endif /* ! defined(LL_WRAPLLERRS_H) */

View File

@ -17,6 +17,7 @@ include(LLAddBuildTest)
include(LLMessage)
include(LLCommon)
include(Tut)
include(bugsplat)
include_directories (${CMAKE_CURRENT_SOURCE_DIR})

View File

@ -0,0 +1,3 @@
This component is no longer used in Linden Lab builds.
Change requests to support continued use by open source
builds are welcome.

View File

@ -11,6 +11,7 @@ include(LLKDU)
include(LLImageJ2COJ)
include(ZLIB)
include(LLAddBuildTest)
include(bugsplat)
include(Tut)
include_directories(

View File

@ -4,6 +4,7 @@ project(llmath)
include(00-Common)
include(LLCommon)
include(bugsplat)
include(Boost)
include_directories(

View File

@ -0,0 +1,3 @@
This component is no longer used in Linden Lab builds.
Change requests to support continued use by open source
builds are welcome.

View File

@ -8,9 +8,7 @@ include(00-Common)
include(Linking)
include(Boost)
if (BUGSPLAT_DB)
include(bugsplat)
endif (BUGSPLAT_DB)
include(bugsplat)
include(BuildPackagesInfo)
include(BuildVersion)
include(CMakeCopyIfDifferent)
@ -110,18 +108,18 @@ include_directories(
${CMAKE_CURRENT_BINARY_DIR}
)
if (BUGSPLAT_DB)
include_directories(
${BUGSPLAT_INCLUDE_DIR}
)
endif (BUGSPLAT_DB)
include_directories(SYSTEM
${LLCOMMON_SYSTEM_INCLUDE_DIRS}
${LLXML_SYSTEM_INCLUDE_DIRS}
${LLPHYSICSEXTENSIONS_INCLUDE_DIRS}
)
if (USE_BUGSPLAT)
include_directories(AFTER
${BUGSPLAT_INCLUDE_DIR}
)
endif (USE_BUGSPLAT)
set(viewer_SOURCE_FILES
# <Add FS includes below this line>
alfloaterregiontracker.cpp
@ -1735,11 +1733,11 @@ if (DARWIN)
${COREAUDIO_LIBRARY}
)
if (BUGSPLAT_DB)
if (USE_BUGSPLAT)
list(APPEND viewer_LIBRARIES
${BUGSPLAT_LIBRARIES}
)
endif (BUGSPLAT_DB)
endif (USE_BUGSPLAT)
# Add resource files to the project.
set(viewer_RESOURCE_FILES
@ -2187,10 +2185,10 @@ if (SDL_FOUND)
)
endif (SDL_FOUND)
if (BUGSPLAT_DB)
if (USE_BUGSPLAT)
set_property(TARGET ${VIEWER_BINARY_NAME}
PROPERTY COMPILE_DEFINITIONS "LL_BUGSPLAT")
endif (BUGSPLAT_DB)
PROPERTY COMPILE_DEFINITIONS "${BUGSPLAT_DEFINE}")
endif (USE_BUGSPLAT)
# add package files
file(GLOB EVENT_HOST_SCRIPT_GLOB_LIST
@ -2276,9 +2274,12 @@ if (WINDOWS)
media_plugin_cef
media_plugin_libvlc
#media_plugin_example # <FS:Ansariel> Don't package example plugin
windows-crash-logger
)
if (NOT USE_BUGSPLAT)
LIST(APPEND COPY_INPUT_DEPENDENCIES windows-crash-logger)
endif (NOT USE_BUGSPLAT)
# <FS:Ansariel> Only copy OpenJPEG dll if needed
if (NOT USE_KDU)
list(APPEND COPY_INPUT_DEPENDENCIES
@ -2352,10 +2353,11 @@ if (WINDOWS)
add_dependencies(${VIEWER_BINARY_NAME} copy_win_scripts)
endif (EXISTS ${CMAKE_SOURCE_DIR}/copy_win_scripts)
add_dependencies(${VIEWER_BINARY_NAME}
SLPlugin
windows-crash-logger
)
add_dependencies(${VIEWER_BINARY_NAME} SLPlugin)
if (NOT USE_BUGSPLAT)
add_dependencies(${VIEWER_BINARY_NAME} windows-crash-logger)
endif (NOT USE_BUGSPLAT)
# sets the 'working directory' for debugging from visual studio.
# Condition for version can be moved to requirements once build agents will be updated (see TOOL-3865)
@ -2518,11 +2520,11 @@ target_link_libraries(${VIEWER_BINARY_NAME}
target_link_libraries(${VIEWER_BINARY_NAME} ${DISCORD_LIBRARY} )
if (BUGSPLAT_DB)
if (USE_BUGSPLAT)
target_link_libraries(${VIEWER_BINARY_NAME}
${BUGSPLAT_LIBRARIES}
)
endif (BUGSPLAT_DB)
endif (USE_BUGSPLAT)
if (WINDOWS)
target_link_libraries(${VIEWER_BINARY_NAME}
@ -2544,7 +2546,6 @@ if (LINUX)
if (NOT ENABLE_MEDIA_PLUGINS)
set(COPY_INPUT_DEPENDENCIES
${VIEWER_BINARY_NAME}
linux-crash-logger
SLPlugin
media_plugin_cef
#media_plugin_gstreamer010
@ -2562,6 +2563,10 @@ else (NOT ENABLE_MEDIA_PLUGINS)
)
endif (NOT ENABLE_MEDIA_PLUGINS)
if (NOT USE_BUGSPLAT)
LIST(APPEND COPY_INPUT_DEPENDENCIES linux-crash-logger)
endif (NOT USE_BUGSPLAT)
add_custom_command(
OUTPUT ${product}.tar.bz2
COMMAND ${PYTHON_EXECUTABLE}
@ -2710,8 +2715,11 @@ if (DARWIN)
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
)
add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_libvlc media_plugin_cef mac-crash-logger)
add_dependencies(${VIEWER_BINARY_NAME} mac-crash-logger)
add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_libvlc media_plugin_cef)
if (NOT USE_BUGSPLAT)
add_dependencies(${VIEWER_BINARY_NAME} mac-crash-logger)
endif (NOT USE_BUGSPLAT)
if (ENABLE_SIGNING)
set(SIGNING_SETTING "--signature=${SIGNING_IDENTITY}")
@ -2755,7 +2763,7 @@ endif (INSTALL)
# Note that the conventional VIEWER_SYMBOL_FILE is set by ../../build.sh
if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIEWER_SYMBOL_FILE)
if (NOT BUGSPLAT_DB)
if (NOT USE_BUGSPLAT)
# Breakpad symbol-file generation
set(SYMBOL_SEARCH_DIRS "")
if (WINDOWS)
@ -2772,7 +2780,7 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE
list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/llplugin/slplugin/${CMAKE_CFG_INTDIR}")
list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/mac_crash_logger/${CMAKE_CFG_INTDIR}")
list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/gstreamer010/${CMAKE_CFG_INTDIR}")
## set(VIEWER_EXE_GLOBS "'${product}' SLPlugin mac-crash-logger")
## set(VIEWER_EXE_GLOBS "'${product}' SLPlugin")
set(VIEWER_EXE_GLOBS "'${product}' mac-crash-logger")
set(VIEWER_LIB_GLOB "*.dylib")
endif (DARWIN)
@ -2811,7 +2819,7 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE
add_dependencies(generate_symbols "${VIEWER_COPY_MANIFEST}")
endif (WINDOWS OR LINUX)
else (NOT BUGSPLAT_DB)
else (NOT USE_BUGSPLAT)
# BugSplat symbol-file generation
if (WINDOWS)
# Just pack up a tarball containing only the .pdb file for the
@ -2895,9 +2903,9 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE
if (LINUX)
# TBD
endif (LINUX)
endif (NOT BUGSPLAT_DB)
endif (NOT USE_BUGSPLAT)
# for both BUGSPLAT_DB and Breakpad
# for both Bugsplat and Breakpad
add_dependencies(llpackage generate_symbols)
endif ()

View File

@ -18080,8 +18080,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>VivoxVadSensitivity</key>
<map>
<key>Comment</key>
<string>
A dimensionless value between 0 and 100, indicating the 'sensitivity of the VAD'. Increasing this value corresponds to decreasing the sensitivity of the VAD and 0 is turned off altogether</string>
<string>A dimensionless value between 0 and 100, indicating the 'sensitivity of the VAD'. Increasing this value corresponds to decreasing the sensitivity of the VAD and 0 is turned off altogether</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>

View File

@ -66,6 +66,7 @@
constructViewer();
#if defined(LL_BUGSPLAT)
infos("bugsplat setup");
// Engage BugsplatStartupManager *before* calling initViewer() to handle
// any crashes during initialization.
// https://www.bugsplat.com/docs/platforms/os-x#initialization
@ -74,6 +75,7 @@
[BugsplatStartupManager sharedManager].delegate = self;
[[BugsplatStartupManager sharedManager] start];
#endif
infos("post-bugsplat setup");
frameTimer = nil;
@ -303,9 +305,13 @@ struct AttachmentInfo
// We "happen to know" that info[0].basename is "SecondLife.old" -- due to
// the fact that BugsplatMac only notices a crash during the viewer run
// following the crash. Replace .old with .log to reduce confusion.
// following the crash.
// The Bugsplat service doesn't respect the MIME type above when returning
// the log data to a browser, so take this opportunity to rename the file
// from <base>.old to <base>_log.txt
info[0].basename =
boost::filesystem::path(info[0].pathname).stem().string() + ".log";
boost::filesystem::path(info[0].pathname).stem().string() + "_log.txt";
infos("attachmentsForBugsplatStartupManager attaching log " + info[0].basename);
NSMutableArray *attachments = [[NSMutableArray alloc] init];

View File

@ -811,14 +811,14 @@ LLAppViewer::LLAppViewer()
// from the previous viewer run between this constructor call and the
// init() call, which will overwrite the static_debug_info.log file for
// THIS run. So setDebugFileNames() early.
#if LL_BUGSPLAT
# ifdef LL_BUGSPLAT
// MAINT-8917: don't create a dump directory just for the
// static_debug_info.log file
std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
#else // ! LL_BUGSPLAT
# else // ! LL_BUGSPLAT
// write Google Breakpad minidump files to a per-run dump directory to avoid multiple viewer issues.
std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "");
#endif // ! LL_BUGSPLAT
# endif // ! LL_BUGSPLAT
mDumpPath = logdir;
setMiniDumpDir(logdir);
setDebugFileNames(logdir);
@ -843,17 +843,6 @@ public:
}
};
namespace {
// With Xcode 6, _exit() is too magical to use with boost::bind(), so provide
// this little helper function.
void fast_exit(int rc)
{
_exit(rc);
}
}
bool LLAppViewer::init()
{
@ -992,9 +981,9 @@ bool LLAppViewer::init()
if (rc >= 0)
{
// QAModeTermCode set, terminate with that rc on LL_ERRS. Use
// fast_exit() rather than exit() because normal cleanup depends too
// _exit() rather than exit() because normal cleanup depends too
// much on successful startup!
LLError::setFatalFunction(boost::bind(fast_exit, rc));
LLError::setFatalFunction([rc](const std::string&){ _exit(rc); });
}
// <FS:Ansariel> Get rid of unused LLAllocator
@ -2553,28 +2542,6 @@ bool LLAppViewer::cleanup()
return true;
}
// A callback for LL_ERRS() to call during the watchdog error.
void watchdog_llerrs_callback(const std::string &error_string)
{
gLLErrorActivated = true;
gDebugInfo["FatalMessage"] = error_string;
LLAppViewer::instance()->writeDebugInfo();
#ifdef LL_WINDOWS
RaiseException(0,0,0,0);
#else
raise(SIGQUIT);
#endif
}
// A callback for the watchdog to call.
void watchdog_killer_callback()
{
LLError::setFatalFunction(watchdog_llerrs_callback);
LL_ERRS() << "Watchdog killer event" << LL_ENDL;
}
bool LLAppViewer::initThreads()
{
static const bool enable_threads = true;
@ -2613,52 +2580,51 @@ bool LLAppViewer::initThreads()
return true;
}
void errorCallback(const std::string &error_string)
void errorCallback(LLError::ELevel level, const std::string &error_string)
{
LLStringUtil::format_map_t map;
map["ERROR_DETAILS"]=error_string;
std::string error_display_string=LLTrans::getString("MBApplicationErrorDetails",map);
// <FS:Ansariel> If we crash before loading the configuration, LLTrans
// won't be able to find the localized string, so we
// fall back to the English version instead of showing
// a dialog saying "MissingString("<LocalizationStringId>".
std::string caption = LLTrans::getString("MBApplicationError");
if (level == LLError::LEVEL_ERROR)
{
LLStringUtil::format_map_t map;
map["ERROR_DETAILS"]=error_string;
std::string error_display_string=LLTrans::getString("MBApplicationErrorDetails",map);
if (error_display_string.find("MissingString(") != std::string::npos)
{
error_display_string = "We are sorry, but Firestorm has crashed and needs to be closed. If you see this issue happening repeatedly, please contact our support team and submit the following message:\n\n[ERROR_DETAILS]";
LLStringUtil::format(error_display_string, map);
}
if (caption.find("MissingString(") != std::string::npos)
{
caption = "Application Error - Don't Panic";
}
// </FS:Ansariel>
// <FS:Ansariel> If we crash before loading the configuration, LLTrans
// won't be able to find the localized string, so we
// fall back to the English version instead of showing
// a dialog saying "MissingString("<LocalizationStringId>".
std::string caption = LLTrans::getString("MBApplicationError");
if (error_display_string.find("MissingString(") != std::string::npos)
{
error_display_string = "We are sorry, but Firestorm has crashed and needs to be closed. If you see this issue happening repeatedly, please contact our support team and submit the following message:\n\n[ERROR_DETAILS]";
LLStringUtil::format(error_display_string, map);
}
if (caption.find("MissingString(") != std::string::npos)
{
caption = "Application Error - Don't Panic";
}
// </FS:Ansariel>
#if !LL_RELEASE_FOR_DOWNLOAD
// <FS:Ansariel> Changed to fix missing string error upon early crash
//if (OSBTN_CANCEL == OSMessageBox(error_display_string, LLTrans::getString("MBApplicationError"), OSMB_OKCANCEL))
if (OSBTN_CANCEL == OSMessageBox(error_display_string, caption, OSMB_OKCANCEL))
return;
// <FS:Ansariel> Changed to fix missing string error upon early crash
//if (OSBTN_CANCEL == OSMessageBox(error_display_string, LLTrans::getString("MBApplicationError"), OSMB_OKCANCEL))
if (OSBTN_CANCEL == OSMessageBox(error_display_string, caption, OSMB_OKCANCEL))
return;
#else
// <FS:Ansariel> Changed to fix missing string error upon early crash
//OSMessageBox(error_display_string, LLTrans::getString("MBApplicationError"), OSMB_OK);
OSMessageBox(error_display_string, caption, OSMB_OK);
// <FS:Ansariel> Changed to fix missing string error upon early crash
//OSMessageBox(error_display_string, LLTrans::getString("MBApplicationError"), OSMB_OK);
OSMessageBox(error_display_string, caption, OSMB_OK);
#endif // !LL_RELEASE_FOR_DOWNLOAD
//Set the ErrorActivated global so we know to create a marker file
gLLErrorActivated = true;
//Set the ErrorActivated global so we know to create a marker file
gLLErrorActivated = true;
gDebugInfo["FatalMessage"] = error_string;
// We're not already crashing -- we simply *intend* to crash. Since we
// haven't actually trashed anything yet, we can afford to write the whole
// static info file.
LLAppViewer::instance()->writeDebugInfo();
#ifndef SHADER_CRASH_NONFATAL
LLError::crashAndLoop(error_string);
#endif
gDebugInfo["FatalMessage"] = error_string;
// We're not already crashing -- we simply *intend* to crash. Since we
// haven't actually trashed anything yet, we can afford to write the whole
// static info file.
LLAppViewer::instance()->writeDebugInfo();
}
}
void LLAppViewer::initLoggingAndGetLastDuration()
@ -2669,7 +2635,7 @@ void LLAppViewer::initLoggingAndGetLastDuration()
LLError::initForApplication( gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "")
,gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")
);
LLError::setFatalFunction(errorCallback);
LLError::addGenericRecorder(&errorCallback);
//LLError::setTimeFunction(getRuntime);
// <FS:Ansariel> Remove old CEF log file (defined in dullahan.h)
@ -3581,26 +3547,28 @@ bool LLAppViewer::initWindow()
LL_INFOS("AppInit") << "gViewerwindow created." << LL_ENDL;
// Need to load feature table before cheking to start watchdog.
// <FS:Ansariel> Fix Watchdog settings/feature table mess
//bool use_watchdog = false;
//int watchdog_enabled_setting = gSavedSettings.getS32("WatchdogEnabled");
//if (watchdog_enabled_setting == -1)
//{
// use_watchdog = !LLFeatureManager::getInstance()->isFeatureAvailable("WatchdogDisabled");
//}
//else
//{
// // The user has explicitly set this setting; always use that value.
// use_watchdog = bool(watchdog_enabled_setting);
//}
//if (use_watchdog)
if (gSavedSettings.getS32("WatchdogEnabled"))
// </FS:Ansariel>
bool use_watchdog = false;
int watchdog_enabled_setting = gSavedSettings.getS32("WatchdogEnabled");
if (watchdog_enabled_setting == -1)
{
LLWatchdog::getInstance()->init(watchdog_killer_callback);
use_watchdog = !LLFeatureManager::getInstance()->isFeatureAvailable("WatchdogDisabled");
}
else
{
// The user has explicitly set this setting; always use that value.
use_watchdog = bool(watchdog_enabled_setting);
}
LL_INFOS("AppInit") << "watchdog"
<< (use_watchdog ? " " : " NOT ")
<< "enabled"
<< " (setting = " << watchdog_enabled_setting << ")"
<< LL_ENDL;
if (use_watchdog)
{
LLWatchdog::getInstance()->init();
}
LL_INFOS("AppInit") << "watchdog setting is done." << LL_ENDL;
// <FS:Ansariel> Init group notices, IMs and chiclets position before the
// screenchannel gets created
@ -4223,8 +4191,8 @@ void LLAppViewer::writeSystemInfo()
gDebugInfo["CPUInfo"]["CPUSSE"] = gSysCPU.hasSSE();
gDebugInfo["CPUInfo"]["CPUSSE2"] = gSysCPU.hasSSE2();
gDebugInfo["RAMInfo"]["Physical"] = (LLSD::Integer)(gSysMemory.getPhysicalMemoryKB().value());
gDebugInfo["RAMInfo"]["Allocated"] = (LLSD::Integer)(gMemoryAllocated.valueInUnits<LLUnits::Kilobytes>());
gDebugInfo["RAMInfo"]["Physical"] = LLSD::Integer(gSysMemory.getPhysicalMemoryKB().value());
gDebugInfo["RAMInfo"]["Allocated"] = LLSD::Integer(gMemoryAllocated.valueInUnits<LLUnits::Kilobytes>());
gDebugInfo["OSInfo"] = LLOSInfo::instance().getOSStringSimple();
// The user is not logged on yet, but record the current grid choice login url
@ -4237,12 +4205,18 @@ void LLAppViewer::writeSystemInfo()
gDebugInfo["MainloopThreadID"] = (S32)thread_id;
#endif
#ifndef LL_BUGSPLAT
// "CrashNotHandled" is set here, while things are running well,
// in case of a freeze. If there is a freeze, the crash logger will be launched
// and can read this value from the debug_info.log.
// If the crash is handled by LLAppViewer::handleViewerCrash, ie not a freeze,
// then the value of "CrashNotHandled" will be set to true.
gDebugInfo["CrashNotHandled"] = (LLSD::Boolean)true;
gDebugInfo["CrashNotHandled"] = LLSD::Boolean(true);
#else // LL_BUGSPLAT
// "CrashNotHandled" is obsolete; it used (not very successsfully)
// to try to distinguish crashes from freezes - the intent here to to avoid calling it a freeze
gDebugInfo["CrashNotHandled"] = LLSD::Boolean(false);
#endif // ! LL_BUGSPLAT
// Insert crash host url (url to post crash log to) if configured. This insures
// that the crash report will go to the proper location in the case of a
@ -4282,7 +4256,7 @@ void LLAppViewer::writeSystemInfo()
gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName();
gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath();
gDebugInfo["FirstLogin"] = (LLSD::Boolean) gAgent.isFirstLogin();
gDebugInfo["FirstLogin"] = LLSD::Boolean(gAgent.isFirstLogin());
gDebugInfo["FirstRunThisInstall"] = gSavedSettings.getBOOL("FirstRunThisInstall");
gDebugInfo["StartupState"] = LLStartUp::getStartupStateString();
@ -4412,7 +4386,7 @@ void LLAppViewer::handleViewerCrash()
// The crash is being handled here so set this value to false.
// Otherwise the crash logger will think this crash was a freeze.
gDebugInfo["Dynamic"]["CrashNotHandled"] = (LLSD::Boolean)false;
gDebugInfo["Dynamic"]["CrashNotHandled"] = LLSD::Boolean(false);
//Write out the crash status file
//Use marker file style setup, as that's the simplest, especially since
@ -4485,6 +4459,8 @@ void LLAppViewer::handleViewerCrash()
if (LLWorld::instanceExists()) LLWorld::getInstance()->getInfo(gDebugInfo["Dynamic"]);
gDebugInfo["FatalMessage"] = LLError::getFatalMessage();
// Close the debug file
pApp->writeDebugInfo(false); //false answers the isStatic question with the least overhead.
}
@ -4589,9 +4565,8 @@ void LLAppViewer::processMarkerFiles()
else if (marker_is_same_version)
{
// the file existed, is ours, and matched our version, so we can report on what it says
LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found; last exec FROZE" << LL_ENDL;
gLastExecEvent = LAST_EXEC_FROZE;
LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found; last exec crashed" << LL_ENDL;
gLastExecEvent = LAST_EXEC_OTHER_CRASH;
}
else
{
@ -6518,11 +6493,6 @@ void LLAppViewer::pauseMainloopTimeout()
void LLAppViewer::pingMainloopTimeout( char const* state, F32 secs)
// </FS:ND>
{
// if(!restoreErrorTrap())
// {
// LL_WARNS() << "!!!!!!!!!!!!! Its an error trap!!!!" << state << LL_ENDL;
// }
if(mMainloopTimeout)
{
if(secs < 0.0f)

View File

@ -68,39 +68,21 @@ namespace
int gArgC;
char** gArgV;
LLAppViewerMacOSX* gViewerAppPtr = NULL;
void (*gOldTerminateHandler)() = NULL;
std::string gHandleSLURL;
}
static void exceptionTerminateHandler()
{
// reinstall default terminate() handler in case we re-terminate.
if (gOldTerminateHandler) std::set_terminate(gOldTerminateHandler);
// treat this like a regular viewer crash, with nice stacktrace etc.
long *null_ptr;
null_ptr = 0;
*null_ptr = 0xDEADBEEF; //Force an exception that will trigger breakpad.
//LLAppViewer::handleViewerCrash();
// we've probably been killed-off before now, but...
gOldTerminateHandler(); // call old terminate() handler
}
void constructViewer()
{
// Set the working dir to <bundle>/Contents/Resources
if (chdir(gDirUtilp->getAppRODataDir().c_str()) == -1)
{
LL_WARNS() << "Could not change directory to "
LL_WARNS("InitOSX") << "Could not change directory to "
<< gDirUtilp->getAppRODataDir() << ": " << strerror(errno)
<< LL_ENDL;
}
gViewerAppPtr = new LLAppViewerMacOSX();
// install unexpected exception handler
gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler);
gViewerAppPtr->setErrorHandler(LLAppViewer::handleViewerCrash);
}
@ -109,7 +91,7 @@ bool initViewer()
bool ok = gViewerAppPtr->init();
if(!ok)
{
LL_WARNS() << "Application init failed." << LL_ENDL;
LL_WARNS("InitOSX") << "Application init failed." << LL_ENDL;
}
else if (!gHandleSLURL.empty())
{
@ -172,7 +154,7 @@ class CrashMetadataSingleton: public CrashMetadata, public LLSingleton<CrashMeta
std::string get_metadata(const LLSD& info, const LLSD::String& key) const
{
std::string data(info[key].asString());
LL_INFOS() << " " << key << "='" << data << "'" << LL_ENDL;
LL_INFOS("Bugsplat") << " " << key << "='" << data << "'" << LL_ENDL;
return data;
}
};
@ -188,22 +170,22 @@ CrashMetadataSingleton::CrashMetadataSingleton()
LLSD info;
if (! static_file.is_open())
{
LL_INFOS() << "Can't open '" << staticDebugPathname
LL_WARNS("Bugsplat") << "Can't open '" << staticDebugPathname
<< "'; no metadata about previous run" << LL_ENDL;
}
else if (! LLSDSerialize::deserialize(info, static_file, LLSDSerialize::SIZE_UNLIMITED))
{
LL_INFOS() << "Can't parse '" << staticDebugPathname
LL_WARNS("Bugsplat") << "Can't parse '" << staticDebugPathname
<< "'; no metadata about previous run" << LL_ENDL;
}
else
{
LL_INFOS() << "Metadata from '" << staticDebugPathname << "':" << LL_ENDL;
logFilePathname = get_metadata(info, "SLLog");
userSettingsPathname = get_metadata(info, "SettingsFilename");
LL_INFOS("Bugsplat") << "Previous run metadata from '" << staticDebugPathname << "':" << LL_ENDL;
logFilePathname = get_metadata(info, "SLLog");
userSettingsPathname = get_metadata(info, "SettingsFilename");
accountSettingsPathname = get_metadata(info, "PerAccountSettingsFilename");
OSInfo = get_metadata(info, "OSInfo");
agentFullname = get_metadata(info, "LoginName");
OSInfo = get_metadata(info, "OSInfo");
agentFullname = get_metadata(info, "LoginName");
// Translate underscores back to spaces
LLStringUtil::replaceChar(agentFullname, '_', ' ');
regionName = get_metadata(info, "CurrentRegion");
@ -219,7 +201,7 @@ CrashMetadata& CrashMetadata_instance()
void infos(const std::string& message)
{
LL_INFOS() << message << LL_ENDL;
LL_INFOS("InitOSX", "Bugsplat") << message << LL_ENDL;
}
int main( int argc, char **argv )
@ -242,14 +224,11 @@ bool LLAppViewerMacOSX::init()
{
bool success = LLAppViewer::init();
#if LL_SEND_CRASH_REPORTS
if (success)
{
LLAppViewer* pApp = LLAppViewer::instance();
pApp->initCrashReporting();
}
#endif
return success;
}
@ -334,11 +313,12 @@ bool LLAppViewerMacOSX::restoreErrorTrap()
unsigned int reset_count = 0;
#define SET_SIG(S) sigaction(SIGABRT, &act, &old_act); \
if(act.sa_sigaction != old_act.sa_sigaction) \
++reset_count;
#define SET_SIG(SIGNAL) sigaction(SIGNAL, &act, &old_act); \
if(act.sa_sigaction != old_act.sa_sigaction) ++reset_count;
// Synchronous signals
SET_SIG(SIGABRT)
# ifndef LL_BUGSPLAT
SET_SIG(SIGABRT) // let bugsplat catch this
# endif
SET_SIG(SIGALRM)
SET_SIG(SIGBUS)
SET_SIG(SIGFPE)
@ -369,6 +349,10 @@ bool LLAppViewerMacOSX::restoreErrorTrap()
void LLAppViewerMacOSX::initCrashReporting(bool reportFreeze)
{
#if defined LL_BUGSPLAT
LL_DEBUGS("InitOSX", "Bugsplat") << "using BugSplat crash logger" << LL_ENDL;
#elif LL_SEND_CRASH_REPORTS
LL_DEBUGS("InitOSX") << "Initializing legacy crash logger" << LL_ENDL;
std::string command_str = "mac-crash-logger.app";
std::stringstream pid_str;
@ -380,6 +364,9 @@ void LLAppViewerMacOSX::initCrashReporting(bool reportFreeze)
LL_WARNS() << "about to launch mac-crash-logger" << pid_str.str()
<< " " << logdir << " " << appname << LL_ENDL;
launchApplication(&command_str, &args);
#else
LL_DEBUGS("InitOSX") << "No crash logger enabled" << LL_ENDL;
#endif // ! LL_BUGSPLAT
}
std::string LLAppViewerMacOSX::generateSerialNumber()
@ -391,7 +378,8 @@ std::string LLAppViewerMacOSX::generateSerialNumber()
CFStringRef serialNumber = NULL;
io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault,
IOServiceMatching("IOPlatformExpertDevice"));
if (platformExpert) {
if (platformExpert)
{
serialNumber = (CFStringRef) IORegistryEntryCreateCFProperty(platformExpert,
CFSTR(kIOPlatformSerialNumberKey),
kCFAllocatorDefault, 0);

View File

@ -233,7 +233,7 @@ static void exceptionTerminateHandler()
long *null_ptr;
null_ptr = 0;
*null_ptr = 0xDEADBEEF; //Force an exception that will trigger breakpad.
//LLAppViewer::handleViewerCrash();
// we've probably been killed-off before now, but...
gOldTerminateHandler(); // call old terminate() handler
}
@ -494,10 +494,6 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash);
#if LL_SEND_CRASH_REPORTS
// ::SetUnhandledExceptionFilter(catchallCrashHandler);
#endif
// Set a debug info flag to indicate if multiple instances are running.
bool found_other_instance = !create_app_mutex();
gDebugInfo["FoundOtherInstanceAtStartup"] = LLSD::Boolean(found_other_instance);
@ -1066,8 +1062,7 @@ bool LLAppViewerWin32::beingDebugged()
bool LLAppViewerWin32::restoreErrorTrap()
{
return true;
//return LLWinDebug::checkExceptionHandler();
return true; // we don't check for handler collisions on windows, so just say they're ok
}
void LLAppViewerWin32::initCrashReporting(bool reportFreeze)

View File

@ -1920,7 +1920,8 @@ LLViewerWindow::LLViewerWindow(const Params& p)
if (!LLAppViewer::instance()->restoreErrorTrap())
{
LL_WARNS("Window") << " Someone took over my signal/exception handler (post createWindow)!" << LL_ENDL;
// this always happens, so downgrading it to INFO
LL_INFOS("Window") << " Someone took over my signal/exception handler (post createWindow; normal)" << LL_ENDL;
}
const bool do_not_enforce = false;

View File

@ -31,15 +31,6 @@
const U32 WATCHDOG_SLEEP_TIME_USEC = 1000000;
void default_killer_callback()
{
#ifdef LL_WINDOWS
RaiseException(0,0,0,0);
#else
raise(SIGQUIT);
#endif
}
// This class runs the watchdog timing thread.
class LLWatchdogTimerThread : public LLThread
{
@ -165,11 +156,10 @@ void LLWatchdogTimeout::ping(const char *state)
}
// LLWatchdog
LLWatchdog::LLWatchdog() :
mSuspectsAccessMutex(),
mTimer(NULL),
mLastClockCount(0),
mKillerCallback(&default_killer_callback)
LLWatchdog::LLWatchdog()
:mSuspectsAccessMutex()
,mTimer(NULL)
,mLastClockCount(0)
{
}
@ -191,9 +181,8 @@ void LLWatchdog::remove(LLWatchdogEntry* e)
unlockThread();
}
void LLWatchdog::init(killer_event_callback func)
void LLWatchdog::init()
{
mKillerCallback = func;
if(!mSuspectsAccessMutex && !mTimer)
{
mSuspectsAccessMutex = new LLMutex();
@ -260,8 +249,7 @@ void LLWatchdog::run()
mTimer->stop();
}
LL_INFOS() << "Watchdog detected error:" << LL_ENDL;
mKillerCallback();
LL_ERRS() << "Watchdog timer expired; assuming viewer is hung and crashing" << LL_ENDL;
}
}

View File

@ -98,9 +98,7 @@ public:
void add(LLWatchdogEntry* e);
void remove(LLWatchdogEntry* e);
typedef boost::function<void (void)> killer_event_callback;
void init(killer_event_callback func = NULL);
void init();
void run();
void cleanup();
@ -113,8 +111,6 @@ private:
LLMutex* mSuspectsAccessMutex;
LLWatchdogTimerThread* mTimer;
U64 mLastClockCount;
killer_event_callback mKillerCallback;
};
#endif // LL_LLTHREADWATCHDOG_H

View File

@ -782,10 +782,11 @@ class WindowsManifest(ViewerManifest):
self.path("libvlccore.dll")
self.path("plugins/")
# pull in the crash logger from other projects
# tag:"crash-logger" here as a cue to the exporter
self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'],
dst="win_crash_logger.exe")
if not self.args.get('bugsplat'): # don't include the win_crash_logger if we are using BugSplat
# pull in the crash logger from other projects
# tag:"crash-logger" here as a cue to the exporter
self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'],
dst="win_crash_logger.exe")
if not self.is_packaging_viewer():
self.package_file = "copied_deps"
@ -1474,10 +1475,8 @@ class DarwinManifest(ViewerManifest):
# our apps
executable_path = {}
for app_bld_dir, app in (("mac_crash_logger", "mac-crash-logger.app"),
# plugin launcher
(os.path.join("llplugin", "slplugin"), "SLPlugin.app"),
):
embedded_apps = [ (os.path.join("llplugin", "slplugin"), "SLPlugin.app") ]
for app_bld_dir, app in embedded_apps:
self.path2basename(os.path.join(os.pardir,
app_bld_dir, self.args['configuration']),
app)

View File

@ -13,6 +13,7 @@ include(LLXML)
include(Linking)
include(Tut)
include(LLAddBuildTest)
include(bugsplat)
# <FS:ND> Google Mock/Test is not used
#include(GoogleMock)
# </FS:ND>
@ -84,6 +85,10 @@ list(APPEND test_SOURCE_FILES ${test_HEADER_FILES})
add_executable(lltest ${test_SOURCE_FILES})
if (USE_BUGSPLAT)
set_target_properties(lltest PROPERTIES COMPILE_DEFINITIONS "${BUGSPLAT_DEFINE}")
endif (USE_BUGSPLAT)
target_link_libraries(lltest
${LEGACY_STDIO_LIBS}
${LLDATABASE_LIBRARIES}

View File

@ -0,0 +1,3 @@
This component is no longer used in Linden Lab builds.
Change requests to support continued use by open source
builds are welcome.