Fixes for crash reporter startup race condition, crash reporter CPU use, Secondlife.log filehandle, XP Crash.

meow-7.2.2
Aura Linden 2014-03-07 14:58:22 -08:00
parent 8fd270af1c
commit d2bb4dae98
11 changed files with 166 additions and 109 deletions

View File

@ -342,12 +342,13 @@ void LLApp::setupErrorHandling()
std::wstring wpipe_name;
wpipe_name = mCrashReportPipeStr + wstringize(getPid());
::Sleep(3000); //HACK hopefully a static wait won't blow up in my face before google fixes their implementation.
const std::wstring wdump_path(wstringize(mDumpPath));
//HACK this for loop is ueless. Breakpad dumbly returns success when the OOP handler isn't initialized.
for (int retries=0;retries<5;++retries)
int retries = 30;
for (; retries > 0; --retries)
{
if (mExceptionHandler != 0) delete mExceptionHandler;
mExceptionHandler = new google_breakpad::ExceptionHandler(
wdump_path,
NULL, //No filter
@ -357,25 +358,20 @@ void LLApp::setupErrorHandling()
MiniDumpNormal, //Generate a 'normal' minidump.
wpipe_name.c_str(),
NULL); //No custom client info.
if (mExceptionHandler)
if (mExceptionHandler->IsOutOfProcess())
{
LL_INFOS("CRASHREPORT") << "Successfully attached to Out of Process exception handler." << LL_ENDL;
break;
}
else
{
LL_WARNS("CRASHREPORT") << "Unable to attach to Out of Process exception handler. " << retries << " retries remaining." << LL_ENDL;
::Sleep(100); //Wait a tick and try again.
}
}
if (!mExceptionHandler)
{
llwarns << "Failed to initialize OOP exception handler. Defaulting to In Process handling" << llendl;
mExceptionHandler = new google_breakpad::ExceptionHandler(
wstringize(mDumpPath),
0, //dump filename
windows_post_minidump_callback,
0,
google_breakpad::ExceptionHandler::HANDLER_ALL);
}
if (retries == 0) LL_WARNS("CRASHREPORT") << "Unable to attach to Out of Process exception handler." << LL_ENDL;
if (mExceptionHandler)
{
mExceptionHandler->set_handle_debug_exceptions(true);
@ -991,6 +987,7 @@ bool windows_post_minidump_callback(const wchar_t* dump_path,
S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH;
size_t bytesUsed;
LL_INFOS("MINIDUMPCALLBACK") << "Dump file was generated." << LL_ENDL;
bytesUsed = wcstombs(path, dump_path, static_cast<size_t>(remaining));
remaining -= bytesUsed;
path += bytesUsed;

View File

@ -265,6 +265,37 @@ int LLFile::rename(const std::string& filename, const std::string& newname)
return warnif(STRINGIZE("rename to '" << newname << "' from"), filename, rc);
}
bool LLFile::copy(const std::string from, const std::string to)
{
bool copied = false;
LLFILE* in = LLFile::fopen(from, "rb"); /* Flawfinder: ignore */
if (in)
{
LLFILE* out = LLFile::fopen(to, "wb"); /* Flawfinder: ignore */
if (out)
{
char buf[16384]; /* Flawfinder: ignore */
size_t readbytes;
bool write_ok = true;
while(write_ok && (readbytes = fread(buf, 1, 16384, in))) /* Flawfinder: ignore */
{
if (fwrite(buf, 1, readbytes, out) != readbytes)
{
LL_WARNS("LLFile") << "Short write" << LL_ENDL;
write_ok = false;
}
}
if ( write_ok )
{
copied = true;
}
fclose(out);
}
fclose(in);
}
return copied;
}
int LLFile::stat(const std::string& filename, llstat* filestatus)
{
#if LL_WINDOWS

View File

@ -75,6 +75,8 @@ public:
static int rmdir(const std::string& filename);
static int remove(const std::string& filename);
static int rename(const std::string& filename,const std::string& newname);
static bool copy(const std::string from, const std::string to);
static int stat(const std::string& filename,llstat* file_status);
static bool isdir(const std::string& filename);
static bool isfile(const std::string& filename);

View File

@ -218,21 +218,10 @@ 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["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;
}
gatherPlatformSpecificFiles();
//Use the debug log to reconstruct the URL to send the crash report to
@ -271,7 +260,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;
@ -488,6 +477,12 @@ bool LLCrashLogger::sendCrashLogs()
else
{
//mCrashInfo["DebugLog"].erase("MinidumpPath");
//To preserve logfile on clean shutdown move to regular log dir.
std::string curr_log = (*lock)["dumpdir"].asString() + "SecondLife.log";
std::string last_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log");
LLFile::remove(last_log);
LLFile::rename(curr_log, last_log); //Before we blow away the directory, perserve log of previous run.
mKeyMaster.cleanupProcess((*lock)["dumpdir"].asString());
}
@ -529,26 +524,7 @@ bool LLCrashLogger::init()
// Default to the product name "Second Life" (this is overridden by the -name argument)
mProductName = "Second Life";
// Handle locking
bool locked = mKeyMaster.requestMaster(); //Request maser locking file. wait time is defaulted to 300S
while (!locked && mKeyMaster.isWaiting())
{
#if LL_WINDOWS
Sleep(1000);
#else
sleep(1);
#endif
locked = mKeyMaster.checkMaster();
}
if (!locked)
{
llwarns << "Unable to get master lock. Another crash reporter may be hung." << llendl;
return false;
}
// Rename current log file to ".old"
// 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");
@ -559,7 +535,27 @@ bool LLCrashLogger::init()
LLFile::rename(log_file.c_str(), old_log_file.c_str());
// Set the log file to crashreport.log
LLError::logToFile(log_file);
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 "
@ -587,5 +583,6 @@ bool LLCrashLogger::init()
// For cleanup code common to all platforms.
void LLCrashLogger::commonCleanup()
{
LLError::logToFile(""); //close crashreport.log
LLProxy::cleanupClass();
}

View File

@ -187,8 +187,30 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask)
U32 LLDir::deleteDirAndContents(const std::string& dir_name)
{
//Removes the directory and its contents. Returns number of files removed.
return boost::filesystem::remove_all(dir_name);
//Removes the directory and its contents. Returns number of files deleted.
U32 num_deleted = 0;
try
{
boost::filesystem::path dir_path(dir_name);
if (boost::filesystem::exists (dir_path))
{
if (!boost::filesystem::is_empty (dir_path))
{ // Directory has content
num_deleted = boost::filesystem::remove_all (dir_path);
}
else
{ // Directory is empty
boost::filesystem::remove (dir_path);
}
}
}
catch (boost::filesystem::filesystem_error &er)
{
llwarns << "Failed to delete " << dir_name << " with error " << er.code().message() << llendl;
}
return num_deleted;
}
const std::string LLDir::findFile(const std::string &filename,

View File

@ -1940,7 +1940,6 @@ bool LLAppViewer::cleanup()
gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""), "*.*");
}
removeDumpDir();
writeDebugInfo();
LLLocationHistory::getInstance()->save();
@ -2102,6 +2101,14 @@ bool LLAppViewer::cleanup()
llinfos << "Goodbye!" << llendflush;
//To preserve logfile on clean shutdown move to regular log dir.
std::string curr_log = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"SecondLife.log");
std::string last_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log");
LLError::logToFile(""); //Close Secondlife.log
LLFile::remove(last_log);
LLFile::copy(curr_log, last_log);
removeDumpDir();
// return 0;
return true;
}
@ -2191,7 +2198,7 @@ void LLAppViewer::initLoggingAndGetLastDuration()
// Get name of the log file
std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
"SecondLife.log");
/*
/*
* Before touching any log files, compute the duration of the last run
* by comparing the ctime of the previous start marker file with the ctime
* of the last log file.
@ -2237,6 +2244,8 @@ void LLAppViewer::initLoggingAndGetLastDuration()
// Rename current log file to ".old"
LLFile::rename(log_file, old_log_file);
log_file = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,
"SecondLife.log");
// Set the log file to SecondLife.log
LLError::logToFile(log_file);
if (!duration_log_msg.empty())
@ -3505,7 +3514,7 @@ void LLAppViewer::handleViewerCrash()
LL_WARNS("MarkerFile") << "No gDirUtilp with which to create error marker file name" << LL_ENDL;
}
#ifdef LL_WINDOWS //SPATTERS Wild guess that filename for Breakpad is not being returned due to sleep cycle in Crash Reporter.
#ifdef LL_WINDOWS
Sleep(2000);
#endif
@ -3514,12 +3523,9 @@ void LLAppViewer::handleViewerCrash()
if(minidump_file && minidump_file[0] != 0)
{
gDebugInfo["Dynamic"]["MinidumpPath"] = minidump_file;
//SPATTERS another possibility is that when using OOP it must be initiated by a wrapping program so that when the
//viewer crashes, we are from a sibling thread than as a child. Might be able to request minidump at this point
//as a work-around.
}
#ifdef LL_WINDOWS
else //SPATTERS there is no else here in the older code
else
{
getFileList();
}

View File

@ -276,7 +276,7 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash);
#if LL_SEND_CRASH_REPORTS
::SetUnhandledExceptionFilter(catchallCrashHandler);
// ::SetUnhandledExceptionFilter(catchallCrashHandler);
#endif
// Set a debug info flag to indicate if multiple instances are running.
@ -698,8 +698,35 @@ void LLAppViewerWin32::initCrashReporting(bool reportFreeze)
{
logdir = logdir.substr(0,end+1);
}
std::string arg_str = "\"" + exe_path + "\" -dumpdir \"" + logdir + "\" -procname \"" + appname + "\" -pid " + stringize(LLApp::getPid());
_spawnl(_P_NOWAIT, exe_path.c_str(), arg_str.c_str(), NULL);
//std::string arg_str = "\"" + exe_path + "\" -dumpdir \"" + logdir + "\" -procname \"" + appname + "\" -pid " + stringize(LLApp::getPid());
//_spawnl(_P_NOWAIT, exe_path.c_str(), arg_str.c_str(), NULL);
std::string arg_str = "\"" + exe_path + "\" -dumpdir \"" + logdir + "\" -procname \"" + appname + "\" -pid " + stringize(LLApp::getPid());
STARTUPINFO startInfo={sizeof(startInfo)};
PROCESS_INFORMATION processInfo;
std::wstring exe_wstr;
exe_wstr=wstringize(exe_path);
std::wstring arg_wstr;
arg_wstr=wstringize(arg_str);
LL_INFOS("CrashReport") << "Creating crash reporter process " << exe_path << " with params: " << arg_str << LL_ENDL;
if(CreateProcess(exe_wstr.c_str(),
&arg_wstr[0], // Application arguments
0,
0,
FALSE,
CREATE_DEFAULT_ERROR_MODE,
0,
0, // Working directory
&startInfo,
&processInfo) == FALSE)
// Could not start application -> call 'GetLastError()'
{
LL_WARNS("CrashReport Launch") << "CreateProcess failed " << GetLastError() << LL_ENDL;
return;
}
}
//virtual

View File

@ -307,12 +307,12 @@ void LLFloaterSpellCheckerImport::onBtnOK()
else
{
std::string settings_dic = LLSpellChecker::getDictionaryUserPath() + mDictionaryBasename + ".dic";
if ( copyFile( dict_dic, settings_dic ) )
if ( LLFile::copy( dict_dic, settings_dic ) )
{
if (gDirUtilp->fileExists(dict_aff))
{
std::string settings_aff = LLSpellChecker::getDictionaryUserPath() + mDictionaryBasename + ".aff";
if (copyFile( dict_aff, settings_aff ))
if ( LLFile::copy( dict_aff, settings_aff ))
{
imported = true;
}
@ -385,37 +385,6 @@ void LLFloaterSpellCheckerImport::onBtnOK()
closeFloater(false);
}
bool LLFloaterSpellCheckerImport::copyFile(const std::string from, const std::string to)
{
bool copied = false;
LLFILE* in = LLFile::fopen(from, "rb"); /* Flawfinder: ignore */
if (in)
{
LLFILE* out = LLFile::fopen(to, "wb"); /* Flawfinder: ignore */
if (out)
{
char buf[16384]; /* Flawfinder: ignore */
size_t readbytes;
bool write_ok = true;
while(write_ok && (readbytes = fread(buf, 1, 16384, in))) /* Flawfinder: ignore */
{
if (fwrite(buf, 1, readbytes, out) != readbytes)
{
LL_WARNS("SpellCheck") << "Short write" << LL_ENDL;
write_ok = false;
}
}
if ( write_ok )
{
copied = true;
}
fclose(out);
}
}
fclose(in);
return copied;
}
std::string LLFloaterSpellCheckerImport::parseXcuFile(const std::string& file_path) const
{
LLXMLNodePtr xml_root;

View File

@ -58,7 +58,6 @@ protected:
void onBtnBrowse();
void onBtnCancel();
void onBtnOK();
bool copyFile(const std::string from, const std::string to);
std::string parseXcuFile(const std::string& file_path) const;
std::string mDictionaryDir;

View File

@ -260,8 +260,7 @@ LLCrashLoggerWindows::~LLCrashLoggerWindows(void)
bool LLCrashLoggerWindows::getMessageWithTimeout(MSG *msg, UINT to)
{
bool res;
const int timerID=37;
SetTimer(NULL, timerID, to, NULL);
UINT_PTR timerID = SetTimer(NULL, NULL, to, NULL);
res = GetMessage(msg, NULL, 0, 0);
KillTimer(NULL, timerID);
if (!res)
@ -273,7 +272,10 @@ bool LLCrashLoggerWindows::getMessageWithTimeout(MSG *msg, UINT to)
int LLCrashLoggerWindows::processingLoop() {
const int millisecs=1000;
static int first_connect = 1;
int retries = 0;
const int max_retries = 60;
LL_DEBUGS("CRASHREPORT") << "Entering processing loop for OOP server" << LL_ENDL;
LLSD options = getOptionData( LLApp::PRIORITY_COMMAND_LINE );
@ -290,11 +292,17 @@ int LLCrashLoggerWindows::processingLoop() {
DispatchMessage(&msg);
}
if (first_connect )
if ( retries < max_retries ) //Wait up to 1 minute for the viewer to say hello.
{
if ( mClientsConnected > 0)
if (mClientsConnected == 0)
{
first_connect = 0;
LL_DEBUGS("CRASHREPORT") << "Waiting for client to connect." << LL_ENDL;
++retries;
}
else
{
LL_INFOS("CRASHREPORT") << "Client has connected!" << LL_ENDL;
retries = max_retries;
}
}
else
@ -311,9 +319,7 @@ int LLCrashLoggerWindows::processingLoop() {
}
llinfos << "session ending.." << llendl;
llinfos << "clients connected :" << mClientsConnected << llendl;
return 0;
}
@ -321,16 +327,15 @@ int LLCrashLoggerWindows::processingLoop() {
void LLCrashLoggerWindows::OnClientConnected(void* context,
const google_breakpad::ClientInfo* client_info)
{
llinfos << "client start. pid = " << client_info->pid() << llendl;
sInstance->mClientsConnected++;
LL_INFOS("CRASHREPORT") << "Client connected. pid = " << client_info->pid() << " total clients " << sInstance->mClientsConnected << LL_ENDL;
}
void LLCrashLoggerWindows::OnClientExited(void* context,
const google_breakpad::ClientInfo* client_info)
{
llinfos << "client end. pid = " << client_info->pid() << llendl;
sInstance->mClientsConnected--;
LL_INFOS("CRASHREPORT") << "Client disconnected. pid = " << client_info->pid() << " total clients " << sInstance->mClientsConnected << LL_ENDL;
}
@ -402,19 +407,21 @@ bool LLCrashLoggerWindows::initCrashServer()
return false;
}
LL_INFOS("CRASHREPORT") << "Initialized OOP server with pipe named " << stringize(wpipe_name) << LL_ENDL;
return true;
}
bool LLCrashLoggerWindows::init(void)
{
initCrashServer();
bool ok = LLCrashLogger::init();
if(!ok) return false;
initCrashServer();
/*
mbstowcs( gProductName, mProductName.c_str(), LL_ARRAY_SIZE(gProductName) );
gProductName[ LL_ARRY_SIZE(gProductName) - 1 ] = 0;
swprintf(gProductName, L"Second Life");
swprintf(gProductName, L"Second Life");
*/
llinfos << "Loading dialogs" << llendl;

View File

@ -34,7 +34,7 @@ int APIENTRY WinMain(HINSTANCE hInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
llinfos << "Starting crash reporter." << llendl;
llinfos << "Starting crash reporter with args" << &lpCmdLine << llendl;
LLCrashLoggerWindows app;
app.setHandle(hInstance);
app.parseCommandOptions(__argc, __argv);