summaryrefslogtreecommitdiff
path: root/indra/llcrashlogger
diff options
context:
space:
mode:
authorMerov Linden <merov@lindenlab.com>2014-04-07 16:19:07 -0700
committerMerov Linden <merov@lindenlab.com>2014-04-07 16:19:07 -0700
commitc79abac5ad5d41f86655883fd9f3ec6a108967a7 (patch)
tree40805ae02a9ee73eb0e9832a01e1dbc0bac914d5 /indra/llcrashlogger
parent77e10d38e56d389e759d1d9c24d03b6fe71f83e0 (diff)
parent7e966f28da79d2d24f93a2615c8807421300700c (diff)
Pull merge from lindenlab/viewer-release
Diffstat (limited to 'indra/llcrashlogger')
-rwxr-xr-xindra/llcrashlogger/CMakeLists.txt2
-rw-r--r--indra/llcrashlogger/llcrashlock.cpp209
-rw-r--r--indra/llcrashlogger/llcrashlock.h73
-rwxr-xr-xindra/llcrashlogger/llcrashlogger.cpp300
-rwxr-xr-xindra/llcrashlogger/llcrashlogger.h8
5 files changed, 517 insertions, 75 deletions
diff --git a/indra/llcrashlogger/CMakeLists.txt b/indra/llcrashlogger/CMakeLists.txt
index 12986de8b2..ba4e34d92b 100755
--- a/indra/llcrashlogger/CMakeLists.txt
+++ b/indra/llcrashlogger/CMakeLists.txt
@@ -23,12 +23,14 @@ include_directories(SYSTEM
set(llcrashlogger_SOURCE_FILES
llcrashlogger.cpp
+ llcrashlock.cpp
)
set(llcrashlogger_HEADER_FILES
CMakeLists.txt
llcrashlogger.h
+ llcrashlock.h
)
set_source_files_properties(${llcrashlogger_HEADER_FILES}
diff --git a/indra/llcrashlogger/llcrashlock.cpp b/indra/llcrashlogger/llcrashlock.cpp
new file mode 100644
index 0000000000..c3d2f944fc
--- /dev/null
+++ b/indra/llcrashlogger/llcrashlock.cpp
@@ -0,0 +1,209 @@
+/**
+ * @file llformat.cpp
+ * @date January 2007
+ * @brief string formatting utility
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llcrashlock.h"
+#include "lldir.h"
+#include "llsd.h"
+#include "llsdserialize.h"
+#include "llnametable.h"
+#include "llframetimer.h"
+#include <boost/filesystem.hpp>
+#include <string>
+#include <iostream>
+#include <stdio.h>
+
+
+#if LL_WINDOWS //For windows platform.
+#include <windows.h>
+#include <TlHelp32.h>
+
+namespace {
+ inline DWORD getpid() {
+ return GetCurrentProcessId();
+ }
+}
+
+bool LLCrashLock::isProcessAlive(U32 pid, const std::string& pname)
+{
+ std::wstring wpname;
+ wpname = std::wstring(pname.begin(), pname.end());
+
+ HANDLE snapshot;
+ PROCESSENTRY32 pe32;
+
+ bool matched = false;
+
+ snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (snapshot == INVALID_HANDLE_VALUE)
+ {
+ return false;
+ }
+ else
+ {
+ pe32.dwSize = sizeof(PROCESSENTRY32);
+ if (Process32First(snapshot, &pe32))
+ {
+ do {
+ std::wstring wexecname = pe32.szExeFile;
+ std::string execname = std::string(wexecname.begin(), wexecname.end());
+ if (!wpname.compare(pe32.szExeFile))
+ {
+ if (pid == (U32)pe32.th32ProcessID)
+ {
+ matched = true;
+ break;
+ }
+ }
+ } while (Process32Next(snapshot, &pe32));
+ }
+ }
+
+ CloseHandle(snapshot);
+ return matched;
+}
+
+#else //Everyone Else
+bool LLCrashLock::isProcessAlive(U32 pid, const std::string& pname)
+{
+ //Will boost.process ever become a reality?
+ std::stringstream cmd;
+
+ cmd << "pgrep '" << pname << "' | grep '^" << pid << "$'";
+ return (!system(cmd.str().c_str()));
+}
+#endif //Everyone else.
+
+
+LLCrashLock::LLCrashLock() : mCleanUp(true), mWaitingPID(0)
+{
+}
+
+void LLCrashLock::setCleanUp(bool cleanup)
+{
+ mCleanUp = cleanup; //Allow cleanup to be disabled for debugging.
+}
+
+LLSD LLCrashLock::getLockFile(std::string filename)
+{
+ LLSD lock_sd = LLSD::emptyMap();
+
+ llifstream ifile(filename);
+
+ if (ifile.is_open())
+ {
+ LLSDSerialize::fromXML(lock_sd, ifile);
+ ifile.close();
+ }
+
+ return lock_sd;
+}
+
+bool LLCrashLock::putLockFile(std::string filename, const LLSD& data)
+{
+ bool result = true;
+ llofstream ofile(filename);
+
+ if (!LLSDSerialize::toXML(data,ofile))
+ {
+ result=false;
+ }
+ ofile.close();
+ return result;
+}
+
+bool LLCrashLock::requestMaster( F32 timeout )
+{
+ if (mMaster.empty())
+ {
+ mMaster = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
+ "crash_master.lock");
+ }
+
+ LLSD lock_sd=getLockFile(mMaster);
+
+ if (lock_sd.has("pid"))
+ {
+ mWaitingPID = lock_sd["pid"].asInteger();
+ if ( isProcessAlive(mWaitingPID, gDirUtilp->getExecutableFilename()) )
+ {
+ mTimer.resetWithExpiry(timeout);
+ return false;
+ }
+ }
+
+ U32 pid = getpid();
+ lock_sd["pid"] = (LLSD::Integer)pid;
+ return putLockFile(mMaster,lock_sd);
+}
+
+bool LLCrashLock::checkMaster()
+{
+ if (mWaitingPID)
+ {
+ return (!isProcessAlive(mWaitingPID, gDirUtilp->getExecutableFilename()));
+ }
+ return false;
+}
+
+bool LLCrashLock::isWaiting()
+{
+ return !mTimer.hasExpired();
+}
+
+void LLCrashLock::releaseMaster()
+{
+ //Yeeeeeeehaw
+ unlink(mMaster.c_str());
+}
+
+LLSD LLCrashLock::getProcessList()
+{
+ if (mDumpTable.empty())
+ {
+ mDumpTable= gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
+ "crash_table.lock");
+ }
+ return getLockFile(mDumpTable);
+}
+
+//static
+bool LLCrashLock::fileExists(std::string filename)
+{
+ return boost::filesystem::exists(filename.c_str());
+}
+
+void LLCrashLock::cleanupProcess(std::string proc_dir)
+{
+ boost::filesystem::remove_all(proc_dir);
+}
+
+bool LLCrashLock::putProcessList(const LLSD& proc_sd)
+{
+ return putLockFile(mDumpTable,proc_sd);
+}
diff --git a/indra/llcrashlogger/llcrashlock.h b/indra/llcrashlogger/llcrashlock.h
new file mode 100644
index 0000000000..cde183272f
--- /dev/null
+++ b/indra/llcrashlogger/llcrashlock.h
@@ -0,0 +1,73 @@
+/**
+ * @file llpidlock.h
+ * @brief Maintainence of disk locking files for crash reporting
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_CRASHLOCK_H
+#define LL_CRASHLOCK_H
+
+#include "llframetimer.h"
+
+class LLSD;
+
+#if !LL_WINDOWS //For non-windows platforms.
+#include <signal.h>
+#endif
+
+//Crash reporter will now be kicked off by the viewer but otherwise
+//run independent of the viewer.
+
+class LLCrashLock
+{
+public:
+ LLCrashLock();
+ bool requestMaster( F32 timeout=300.0); //Wait until timeout for master lock.
+ bool checkMaster(); //True if available. False if not.
+ void releaseMaster( ); //Release master lockfile.
+ bool isLockPresent(std::string filename); //Check if lockfile exists.
+ bool isProcessAlive(U32 pid, const std::string& pname); //Check if pid is alive.
+ bool isWaiting(); //Waiting for master lock to be released.
+ LLSD getProcessList(); //Get next process pid/dir pairs
+ void cleanupProcess(std::string proc_dir); //Remove from list, clean up working dir.
+ bool putProcessList(const LLSD& processlist); //Write pid/dir pairs back to disk.
+ static bool fileExists(std::string filename);
+
+
+ //getters
+ S32 getPID();
+
+ //setters
+ void setCleanUp(bool cleanup=true);
+ void setSaveName(std::string savename);
+private:
+ LLSD getLockFile(std::string filename);
+ bool putLockFile(std::string filename, const LLSD& data);
+ bool mCleanUp;
+ std::string mMaster;
+ std::string mDumpTable;
+ U32 mWaitingPID; //The process we're waiting on if any.
+ LLFrameTimer mTimer;
+};
+
+#endif // LL_CRASHLOCK_H
diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp
index aa66ceb4ec..38858a1a91 100755
--- a/indra/llcrashlogger/llcrashlogger.cpp
+++ b/indra/llcrashlogger/llcrashlogger.cpp
@@ -23,12 +23,14 @@
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
+
#include <cstdio>
#include <cstdlib>
#include <sstream>
#include <map>
#include "llcrashlogger.h"
+#include "llcrashlock.h"
#include "linden_common.h"
#include "llstring.h"
#include "indra_constants.h" // CRASH_BEHAVIOR_...
@@ -43,7 +45,7 @@
#include "llhttpclient.h"
#include "llsdserialize.h"
#include "llproxy.h"
-
+
LLPumpIO* gServicePump = NULL;
BOOL gBreak = false;
BOOL gSent = false;
@@ -61,7 +63,7 @@ public:
}
virtual void result(const LLSD& content)
- {
+ {
gBreak = true;
gSent = true;
}
@@ -74,14 +76,11 @@ LLCrashLogger::LLCrashLogger() :
mSentCrashLogs(false),
mCrashHost("")
{
- // Set up generic error handling
- setupErrorHandling();
}
LLCrashLogger::~LLCrashLogger()
{
- delete gServicePump;
- gServicePump = NULL;
+
}
// TRIM_SIZE must remain larger than LINE_SEARCH_SIZE.
@@ -138,19 +137,67 @@ std::string getStartupStateFromLog(std::string& sllog)
return startup_state;
}
-void LLCrashLogger::gatherFiles()
+bool LLCrashLogger::readDebugFromXML(LLSD& dest, const std::string& filename )
{
- updateApplication("Gathering logs...");
-
- // Figure out the filename of the debug log
- std::string db_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log");
- std::ifstream debug_log_file(db_file_name.c_str());
-
+ std::string db_file_name = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,filename);
+ std::ifstream debug_log_file(db_file_name.c_str());
+
// Look for it in the debug_info.log file
if (debug_log_file.is_open())
{
- LLSDSerialize::fromXML(mDebugLog, debug_log_file);
+ LLSDSerialize::fromXML(dest, debug_log_file);
+ debug_log_file.close();
+ return true;
+ }
+ return false;
+}
+
+void LLCrashLogger::mergeLogs( LLSD src_sd )
+{
+ LLSD::map_iterator iter = src_sd.beginMap();
+ LLSD::map_iterator end = src_sd.endMap();
+ for( ; iter != end; ++iter)
+ {
+ mDebugLog[iter->first] = iter->second;
+ }
+}
+
+bool LLCrashLogger::readMinidump(std::string minidump_path)
+{
+ size_t length=0;
+ std::ifstream minidump_stream(minidump_path.c_str(), std::ios_base::in | std::ios_base::binary);
+ if(minidump_stream.is_open())
+ {
+ minidump_stream.seekg(0, std::ios::end);
+ length = (size_t)minidump_stream.tellg();
+ minidump_stream.seekg(0, std::ios::beg);
+
+ LLSD::Binary data;
+ data.resize(length);
+
+ minidump_stream.read(reinterpret_cast<char *>(&(data[0])),length);
+ minidump_stream.close();
+
+ mCrashInfo["Minidump"] = data;
+ }
+ return (length>0?true:false);
+}
+
+void LLCrashLogger::gatherFiles()
+{
+ updateApplication("Gathering logs...");
+
+ LLSD static_sd;
+ LLSD dynamic_sd;
+
+ bool has_logs = readDebugFromXML( static_sd, "static_debug_info.log" );
+ has_logs |= readDebugFromXML( dynamic_sd, "dynamic_debug_info.log" );
+
+ if ( has_logs )
+ {
+ mDebugLog = static_sd;
+ mergeLogs(dynamic_sd);
mCrashInPreviousExec = mDebugLog["CrashNotHandled"].asBoolean();
mFileMap["SecondLifeLog"] = mDebugLog["SLLog"].asString();
@@ -171,20 +218,15 @@ void LLCrashLogger::gatherFiles()
{
// Figure out the filename of the second life log
LLCurl::setCAFile(gDirUtilp->getCAFile());
- mFileMap["SecondLifeLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log");
- mFileMap["SettingsXml"] = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.xml");
+
+ mFileMap["SecondLifeLog"] = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"SecondLife.log");
+ mFileMap["SettingsXml"] = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.xml");
}
- if(mCrashInPreviousExec)
- {
- // Restarting after freeze.
- // Replace the log file ext with .old, since the
- // instance that launched this process has overwritten
- // SecondLife.log
- std::string log_filename = mFileMap["SecondLifeLog"];
- log_filename.replace(log_filename.size() - 4, 4, ".old");
- mFileMap["SecondLifeLog"] = log_filename;
- }
+ if (!gDirUtilp->fileExists(mFileMap["SecondLifeLog"]) ) //We would prefer to get this from the per-run but here's our fallback.
+ {
+ mFileMap["SecondLifeLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.old");
+ }
gatherPlatformSpecificFiles();
@@ -215,7 +257,7 @@ void LLCrashLogger::gatherFiles()
mAltCrashHost = "https://login.agni.lindenlab.com:12043/crash/report";
mCrashInfo["DebugLog"] = mDebugLog;
- mFileMap["StatsLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stats.log");
+ mFileMap["StatsLog"] = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"stats.log");
updateApplication("Encoding files...");
@@ -224,7 +266,7 @@ void LLCrashLogger::gatherFiles()
std::ifstream f((*itr).second.c_str());
if(!f.is_open())
{
- std::cout << "Can't find file " << (*itr).second << std::endl;
+ LL_INFOS("CRASHREPORT") << "Can't find file " << (*itr).second << LL_ENDL;
continue;
}
std::stringstream s;
@@ -243,32 +285,55 @@ void LLCrashLogger::gatherFiles()
mCrashInfo[(*itr).first] = LLStringFn::strip_invalid_xml(rawstr_to_utf8(crash_info));
}
+ std::string minidump_path;
// Add minidump as binary.
- std::string minidump_path = mDebugLog["MinidumpPath"];
- if(minidump_path != "")
+ bool has_minidump = mDebugLog.has("MinidumpPath");
+
+ if (has_minidump)
{
- std::ifstream minidump_stream(minidump_path.c_str(), std::ios_base::in | std::ios_base::binary);
- if(minidump_stream.is_open())
- {
- minidump_stream.seekg(0, std::ios::end);
- size_t length = (size_t)minidump_stream.tellg();
- minidump_stream.seekg(0, std::ios::beg);
-
- LLSD::Binary data;
- data.resize(length);
-
- minidump_stream.read(reinterpret_cast<char *>(&(data[0])),length);
- minidump_stream.close();
-
- mCrashInfo["Minidump"] = data;
- }
+ minidump_path = mDebugLog["MinidumpPath"].asString();
}
- mCrashInfo["DebugLog"].erase("MinidumpPath");
+
+ if (has_minidump)
+ {
+ has_minidump = readMinidump(minidump_path);
+ }
+
+ if (!has_minidump) //Viewer was probably so hosed it couldn't write remaining data. Try brute force.
+ {
+ //Look for a filename at least 30 characters long in the dump dir which contains the characters MDMP as the first 4 characters in the file.
+ typedef std::vector<std::string> vec;
+ std::string pathname = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"");
+ vec file_vec = gDirUtilp->getFilesInDir(pathname);
+ for(vec::const_iterator iter=file_vec.begin(); iter!=file_vec.end(); ++iter)
+ {
+ if ( ( iter->length() > 30 ) && (iter->rfind(".dmp") == (iter->length()-4) ) )
+ {
+ std::string fullname = pathname + *iter;
+ std::ifstream fdat( fullname.c_str(), std::ifstream::binary);
+ if (fdat)
+ {
+ char buf[5];
+ fdat.read(buf,4);
+ fdat.close();
+ if (!strncmp(buf,"MDMP",4))
+ {
+ minidump_path = *iter;
+ has_minidump = readMinidump(fullname);
+ mDebugLog["MinidumpPath"] = fullname;
+ if (has_minidump)
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
}
LLSD LLCrashLogger::constructPostData()
{
- LLSD ret;
return mCrashInfo;
}
@@ -338,39 +403,106 @@ bool LLCrashLogger::runCrashLogPost(std::string host, LLSD data, std::string msg
return gSent;
}
-bool LLCrashLogger::sendCrashLogs()
+bool LLCrashLogger::sendCrashLog(std::string dump_dir)
{
+ gDirUtilp->setDumpDir( dump_dir );
+
+ std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
+ "SecondLifeCrashReport");
+ std::string report_file = dump_path + ".log";
+
gatherFiles();
-
+
LLSD post_data;
post_data = constructPostData();
-
+
updateApplication("Sending reports...");
- std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
- "SecondLifeCrashReport");
- std::string report_file = dump_path + ".log";
-
std::ofstream out_file(report_file.c_str());
LLSDSerialize::toPrettyXML(post_data, out_file);
out_file.close();
-
+
bool sent = false;
-
+
//*TODO: Translate
if(mCrashHost != "")
{
sent = runCrashLogPost(mCrashHost, post_data, std::string("Sending to server"), 3, 5);
}
-
+
if(!sent)
{
sent = runCrashLogPost(mAltCrashHost, post_data, std::string("Sending to alternate server"), 3, 5);
}
-
+
mSentCrashLogs = sent;
+
+ return sent;
+}
- return true;
+bool LLCrashLogger::sendCrashLogs()
+{
+
+ //pertinent code from below moved into a subroutine.
+ LLSD locks = mKeyMaster.getProcessList();
+ LLSD newlocks = LLSD::emptyArray();
+
+ LLSD opts = getOptionData(PRIORITY_COMMAND_LINE);
+ LLSD rec;
+
+ if ( opts.has("pid") && opts.has("dumpdir") && opts.has("procname") )
+ {
+ rec["pid"]=opts["pid"];
+ rec["dumpdir"]=opts["dumpdir"];
+ rec["procname"]=opts["procname"];
+ }
+
+ if (locks.isArray())
+ {
+ for (LLSD::array_iterator lock=locks.beginArray();
+ lock !=locks.endArray();
+ ++lock)
+ {
+ if ( (*lock).has("pid") && (*lock).has("dumpdir") && (*lock).has("procname") )
+ {
+ if ( mKeyMaster.isProcessAlive( (*lock)["pid"].asInteger(), (*lock)["procname"].asString() ) )
+ {
+ newlocks.append(*lock);
+ }
+ else
+ {
+ //TODO: This is a hack but I didn't want to include boost in another file or retest everything related to lldir
+ if (LLCrashLock::fileExists((*lock)["dumpdir"].asString()))
+ {
+ //the viewer cleans up the log directory on clean shutdown
+ //but is ignorant of the locking table.
+ if (!sendCrashLog((*lock)["dumpdir"].asString()))
+ {
+ newlocks.append(*lock); //Failed to send log so don't delete it.
+ }
+ else
+ {
+ //mCrashInfo["DebugLog"].erase("MinidumpPath");
+
+ mKeyMaster.cleanupProcess((*lock)["dumpdir"].asString());
+ }
+ }
+ }
+ }
+ else
+ {
+ llwarns << "Discarding corrupted entry from lock table." << llendl;
+ }
+ }
+ }
+
+ if (rec)
+ {
+ newlocks.append(rec);
+ }
+
+ mKeyMaster.putProcessList(newlocks);
+ return true;
}
void LLCrashLogger::updateApplication(const std::string& message)
@@ -395,44 +527,62 @@ bool LLCrashLogger::init()
// Rename current log file to ".old"
std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "crashreport.log.old");
std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "crashreport.log");
- LLFile::rename(log_file.c_str(), old_log_file.c_str());
+#if LL_WINDOWS
+ LLAPRFile::remove(old_log_file);
+#endif
+
+ LLFile::rename(log_file.c_str(), old_log_file.c_str());
+
// Set the log file to crashreport.log
- LLError::logToFile(log_file);
-
- mCrashSettings.declareS32("CrashSubmitBehavior", CRASH_BEHAVIOR_ALWAYS_SEND,
+ LLError::logToFile(log_file); //NOTE: Until this line, LL_INFOS LL_WARNS, etc are blown to the ether.
+
+ // Handle locking
+ bool locked = mKeyMaster.requestMaster(); //Request master locking file. wait time is defaulted to 300S
+
+ while (!locked && mKeyMaster.isWaiting())
+ {
+ LL_INFOS("CRASHREPORT") << "Waiting for lock." << LL_ENDL;
+#if LL_WINDOWS
+ Sleep(1000);
+#else
+ sleep(1);
+#endif
+ locked = mKeyMaster.checkMaster();
+ }
+
+ if (!locked)
+ {
+ LL_WARNS("CRASHREPORT") << "Unable to get master lock. Another crash reporter may be hung." << LL_ENDL;
+ return false;
+ }
+
+ mCrashSettings.declareS32("CrashSubmitBehavior", CRASH_BEHAVIOR_ALWAYS_SEND,
"Controls behavior when viewer crashes "
"(0 = ask before sending crash report, "
"1 = always send crash report, "
"2 = never send crash report)");
-
+
// llinfos << "Loading crash behavior setting" << llendl;
// mCrashBehavior = loadCrashBehaviorSetting();
-
+
// If user doesn't want to send, bail out
if (mCrashBehavior == CRASH_BEHAVIOR_NEVER_SEND)
{
llinfos << "Crash behavior is never_send, quitting" << llendl;
return false;
}
-
+
gServicePump = new LLPumpIO(gAPRPoolp);
gServicePump->prime(gAPRPoolp);
LLHTTPClient::setPump(*gServicePump);
-
- //If we've opened the crash logger, assume we can delete the marker file if it exists
- if( gDirUtilp )
- {
- std::string marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
- "SecondLife.exec_marker");
- LLAPRFile::remove( marker_file );
- }
-
+
return true;
}
// For cleanup code common to all platforms.
void LLCrashLogger::commonCleanup()
{
+ LLError::logToFile(""); //close crashreport.log
LLProxy::cleanupClass();
}
diff --git a/indra/llcrashlogger/llcrashlogger.h b/indra/llcrashlogger/llcrashlogger.h
index 1510d7e0b3..78acc63b6a 100755
--- a/indra/llcrashlogger/llcrashlogger.h
+++ b/indra/llcrashlogger/llcrashlogger.h
@@ -33,6 +33,7 @@
#include "llapp.h"
#include "llsd.h"
#include "llcontrol.h"
+#include "llcrashlock.h"
class LLCrashLogger : public LLApp
{
@@ -40,9 +41,13 @@ public:
LLCrashLogger();
virtual ~LLCrashLogger();
S32 loadCrashBehaviorSetting();
+ bool readDebugFromXML(LLSD& dest, const std::string& filename );
void gatherFiles();
+ void mergeLogs( LLSD src_sd );
+
virtual void gatherPlatformSpecificFiles() {}
bool saveCrashBehaviorSetting(S32 crash_behavior);
+ bool sendCrashLog(std::string dump_dir);
bool sendCrashLogs();
LLSD constructPostData();
virtual void updateApplication(const std::string& message = LLStringUtil::null);
@@ -53,6 +58,8 @@ public:
void setUserText(const std::string& text) { mCrashInfo["UserNotes"] = text; }
S32 getCrashBehavior() { return mCrashBehavior; }
bool runCrashLogPost(std::string host, LLSD data, std::string msg, int retries, int timeout);
+ bool readMinidump(std::string minidump_path);
+
protected:
S32 mCrashBehavior;
BOOL mCrashInPreviousExec;
@@ -65,6 +72,7 @@ protected:
std::string mAltCrashHost;
LLSD mDebugLog;
bool mSentCrashLogs;
+ LLCrashLock mKeyMaster;
};
#endif //LLCRASHLOGGER_H