PageRenderTime 64ms CodeModel.GetById 2ms app.highlight 55ms RepoModel.GetById 2ms app.codeStats 0ms

/indra/llcommon/llapp.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 962 lines | 854 code | 43 blank | 65 comment | 32 complexity | 53041acb4b6cae3833b52ffc9fc8e072 MD5 | raw file
  1/** 
  2 * @file llapp.cpp
  3 * @brief Implementation of the LLApp class.
  4 *
  5 * $LicenseInfo:firstyear=2003&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include "linden_common.h"
 28
 29#include "llapp.h"
 30
 31#include <cstdlib>
 32
 33#ifdef LL_DARWIN
 34#include <sys/types.h>
 35#include <unistd.h>
 36#include <sys/sysctl.h>
 37#endif
 38
 39#include "llcommon.h"
 40#include "llapr.h"
 41#include "llerrorcontrol.h"
 42#include "llerrorthread.h"
 43#include "llframetimer.h"
 44#include "lllivefile.h"
 45#include "llmemory.h"
 46#include "llstl.h" // for DeletePointer()
 47#include "llstring.h"
 48#include "lleventtimer.h"
 49
 50#include "google_breakpad/exception_handler.h"
 51
 52//
 53// Signal handling
 54//
 55// Windows uses structured exceptions, so it's handled a bit differently.
 56//
 57#if LL_WINDOWS
 58LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop);
 59BOOL ConsoleCtrlHandler(DWORD fdwCtrlType);
 60bool windows_post_minidump_callback(const wchar_t* dump_path,
 61									const wchar_t* minidump_id,
 62									void* context,
 63									EXCEPTION_POINTERS* exinfo,
 64									MDRawAssertionInfo* assertion,
 65									bool succeeded);
 66#else
 67# include <signal.h>
 68# include <unistd.h> // for fork()
 69void setup_signals();
 70void default_unix_signal_handler(int signum, siginfo_t *info, void *);
 71
 72// Called by breakpad exception handler after the minidump has been generated.
 73bool unix_post_minidump_callback(const char *dump_dir,
 74					  const char *minidump_id,
 75					  void *context, bool succeeded);
 76# if LL_DARWIN
 77/* OSX doesn't support SIGRT* */
 78S32 LL_SMACKDOWN_SIGNAL = SIGUSR1;
 79S32 LL_HEARTBEAT_SIGNAL = SIGUSR2;
 80# else // linux or (assumed) other similar unixoid
 81/* We want reliable delivery of our signals - SIGRT* is it. */
 82/* Old LinuxThreads versions eat SIGRTMIN+0 to SIGRTMIN+2, avoid those. */
 83/* Note that SIGRTMIN/SIGRTMAX may expand to a glibc function call with a
 84   nonconstant result so these are not consts and cannot be used in constant-
 85   expressions.  SIGRTMAX may return -1 on rare broken setups. */
 86S32 LL_SMACKDOWN_SIGNAL = (SIGRTMAX >= 0) ? (SIGRTMAX-1) : SIGUSR1;
 87S32 LL_HEARTBEAT_SIGNAL = (SIGRTMAX >= 0) ? (SIGRTMAX-0) : SIGUSR2;
 88# endif // LL_DARWIN
 89#endif // LL_WINDOWS
 90
 91// the static application instance
 92LLApp* LLApp::sApplication = NULL;
 93
 94// Allows the generation of core files for post mortem under gdb
 95// and disables crashlogger
 96BOOL LLApp::sDisableCrashlogger = FALSE; 
 97
 98// Local flag for whether or not to do logging in signal handlers.
 99//static
100BOOL LLApp::sLogInSignal = FALSE;
101
102// static
103LLApp::EAppStatus LLApp::sStatus = LLApp::APP_STATUS_STOPPED; // Keeps track of application status
104LLAppErrorHandler LLApp::sErrorHandler = NULL;
105BOOL LLApp::sErrorThreadRunning = FALSE;
106#if !LL_WINDOWS
107LLApp::child_map LLApp::sChildMap;
108LLAtomicU32* LLApp::sSigChildCount = NULL;
109LLAppChildCallback LLApp::sDefaultChildCallback = NULL;
110#endif
111
112
113LLApp::LLApp() : mThreadErrorp(NULL)
114{
115	commonCtor();
116}
117
118void LLApp::commonCtor()
119{
120	// Set our status to running
121	setStatus(APP_STATUS_RUNNING);
122
123	LLCommon::initClass();
124
125#if !LL_WINDOWS
126	// This must be initialized before the error handler.
127	sSigChildCount = new LLAtomicU32(0);
128#endif
129
130	// initialize the options structure. We need to make this an array
131	// because the structured data will not auto-allocate if we
132	// reference an invalid location with the [] operator.
133	mOptions = LLSD::emptyArray();
134	LLSD sd;
135	for(int i = 0; i < PRIORITY_COUNT; ++i)
136	{
137		mOptions.append(sd);
138	}
139
140	// Make sure we clean up APR when we exit
141	// Don't need to do this if we're cleaning up APR in the destructor
142	//atexit(ll_cleanup_apr);
143
144	// Set the application to this instance.
145	sApplication = this;
146	
147	mExceptionHandler = 0;
148	
149	// initialize the buffer to write the minidump filename to
150	// (this is used to avoid allocating memory in the crash handler)
151	memset(minidump_path, 0, MAX_MINDUMP_PATH_LENGTH);
152}
153
154LLApp::LLApp(LLErrorThread *error_thread) :
155	mThreadErrorp(error_thread)
156{
157	commonCtor();
158}
159
160
161LLApp::~LLApp()
162{
163#if !LL_WINDOWS
164	delete sSigChildCount;
165	sSigChildCount = NULL;
166#endif
167
168	// reclaim live file memory
169	std::for_each(mLiveFiles.begin(), mLiveFiles.end(), DeletePointer());
170	mLiveFiles.clear();
171
172	setStopped();
173	// HACK: wait for the error thread to clean itself
174	ms_sleep(20);
175	if (mThreadErrorp)
176	{
177		delete mThreadErrorp;
178		mThreadErrorp = NULL;
179	}
180	
181	if(mExceptionHandler != 0) delete mExceptionHandler;
182
183	LLCommon::cleanupClass();
184}
185
186// static
187LLApp* LLApp::instance()
188{
189	return sApplication;
190}
191
192
193LLSD LLApp::getOption(const std::string& name) const
194{
195	LLSD rv;
196	LLSD::array_const_iterator iter = mOptions.beginArray();
197	LLSD::array_const_iterator end = mOptions.endArray();
198	for(; iter != end; ++iter)
199	{
200		rv = (*iter)[name];
201		if(rv.isDefined()) break;
202	}
203	return rv;
204}
205
206bool LLApp::parseCommandOptions(int argc, char** argv)
207{
208	LLSD commands;
209	std::string name;
210	std::string value;
211	for(int ii = 1; ii < argc; ++ii)
212	{
213		if(argv[ii][0] != '-')
214		{
215			llinfos << "Did not find option identifier while parsing token: "
216				<< argv[ii] << llendl;
217			return false;
218		}
219		int offset = 1;
220		if(argv[ii][1] == '-') ++offset;
221		name.assign(&argv[ii][offset]);
222		if(((ii+1) >= argc) || (argv[ii+1][0] == '-'))
223		{
224			// we found another option after this one or we have
225			// reached the end. simply record that this option was
226			// found and continue.
227			int flag = name.compare("logfile");
228			if (0 == flag)
229			{
230				commands[name] = "log";
231			}
232			else
233			{
234				commands[name] = true;
235			}
236			
237			continue;
238		}
239		++ii;
240		value.assign(argv[ii]);
241		commands[name] = value;
242	}
243	setOptionData(PRIORITY_COMMAND_LINE, commands);
244	return true;
245}
246
247
248void LLApp::manageLiveFile(LLLiveFile* livefile)
249{
250	if(!livefile) return;
251	livefile->checkAndReload();
252	livefile->addToEventTimer();
253	mLiveFiles.push_back(livefile);
254}
255
256bool LLApp::setOptionData(OptionPriority level, LLSD data)
257{
258	if((level < 0)
259	   || (level >= PRIORITY_COUNT)
260	   || (data.type() != LLSD::TypeMap))
261	{
262		return false;
263	}
264	mOptions[level] = data;
265	return true;
266}
267
268LLSD LLApp::getOptionData(OptionPriority level)
269{
270	if((level < 0) || (level >= PRIORITY_COUNT))
271	{
272		return LLSD();
273	}
274	return mOptions[level];
275}
276
277void LLApp::stepFrame()
278{
279	LLFrameTimer::updateFrameTime();
280	LLFrameTimer::updateFrameCount();
281	LLEventTimer::updateClass();
282	mRunner.run();
283}
284
285
286void LLApp::setupErrorHandling()
287{
288	// Error handling is done by starting up an error handling thread, which just sleeps and
289	// occasionally checks to see if the app is in an error state, and sees if it needs to be run.
290
291#if LL_WINDOWS
292	// This sets a callback to handle w32 signals to the console window.
293	// The viewer shouldn't be affected, sicne its a windowed app.
294	SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ConsoleCtrlHandler, TRUE);
295
296	// Install the Google Breakpad crash handler for Windows
297	if(mExceptionHandler == 0)
298	{
299		llwarns << "adding breakpad exception handler" << llendl;
300		mExceptionHandler = new google_breakpad::ExceptionHandler(
301			L"C:\\Temp\\", 0, windows_post_minidump_callback, 0, google_breakpad::ExceptionHandler::HANDLER_ALL);
302	}
303
304#else
305	//
306	// Start up signal handling.
307	//
308	// There are two different classes of signals.  Synchronous signals are delivered to a specific
309	// thread, asynchronous signals can be delivered to any thread (in theory)
310	//
311	setup_signals();
312	
313	// Add google breakpad exception handler configured for Darwin/Linux.
314	bool installHandler = true;
315#ifdef LL_DARWIN
316	// For the special case of Darwin, we do not want to install the handler if
317	// the process is being debugged as the app will exit with value ABRT (6) if
318	// we do.  Unfortunately, the code below which performs that test relies on
319	// the structure kinfo_proc which has been tagged by apple as an unstable
320	// API.  We disable this test for shipping versions to avoid conflicts with
321	// future releases of Darwin.  This test is really only needed for developers
322	// starting the app from a debugger anyway.
323	#ifndef LL_RELEASE_FOR_DOWNLOAD
324    int mib[4];
325	mib[0] = CTL_KERN;
326	mib[1] = KERN_PROC;
327	mib[2] = KERN_PROC_PID;
328	mib[3] = getpid();
329	
330	struct kinfo_proc info;
331	memset(&info, 0, sizeof(info));
332	
333	size_t size = sizeof(info);
334	int result = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
335	if((result == 0) || (errno == ENOMEM))
336	{
337		// P_TRACED flag is set, so this process is being debugged; do not install
338		// the handler
339		if(info.kp_proc.p_flag & P_TRACED) installHandler = false;
340	}
341	else
342	{
343		// Failed to discover if the process is being debugged; default to
344		// installing the handler.
345		installHandler = true;
346	}
347	#endif
348#endif
349	if(installHandler && (mExceptionHandler == 0))
350	{
351		std::string dumpPath = "/tmp/";
352		mExceptionHandler = new google_breakpad::ExceptionHandler(dumpPath, 0, &unix_post_minidump_callback, 0, true);
353	}
354#endif
355
356	startErrorThread();
357}
358
359void LLApp::startErrorThread()
360{
361	//
362	// Start the error handling thread, which is responsible for taking action
363	// when the app goes into the APP_STATUS_ERROR state
364	//
365	if(!mThreadErrorp)
366	{
367		llinfos << "Starting error thread" << llendl;
368		mThreadErrorp = new LLErrorThread();
369		mThreadErrorp->setUserData((void *) this);
370		mThreadErrorp->start();
371	}
372}
373
374void LLApp::setErrorHandler(LLAppErrorHandler handler)
375{
376	LLApp::sErrorHandler = handler;
377}
378
379// static
380void LLApp::runErrorHandler()
381{
382	if (LLApp::sErrorHandler)
383	{
384		LLApp::sErrorHandler();
385	}
386
387	//llinfos << "App status now STOPPED" << llendl;
388	LLApp::setStopped();
389}
390
391// static
392void LLApp::setStatus(EAppStatus status)
393{
394	sStatus = status;
395}
396
397
398// static
399void LLApp::setError()
400{
401	// set app status to ERROR so that the LLErrorThread notices
402	setStatus(APP_STATUS_ERROR);
403}
404
405void LLApp::setMiniDumpDir(const std::string &path)
406{
407	if(mExceptionHandler == 0) return;
408#ifdef LL_WINDOWS
409	wchar_t buffer[MAX_MINDUMP_PATH_LENGTH];
410	mbstowcs(buffer, path.c_str(), MAX_MINDUMP_PATH_LENGTH);
411	mExceptionHandler->set_dump_path(std::wstring(buffer));
412#else
413	mExceptionHandler->set_dump_path(path);
414#endif
415}
416
417void LLApp::writeMiniDump()
418{
419	if(mExceptionHandler == 0) return;
420	mExceptionHandler->WriteMinidump();
421}
422
423// static
424void LLApp::setQuitting()
425{
426	if (!isExiting())
427	{
428		// If we're already exiting, we don't want to reset our state back to quitting.
429		llinfos << "Setting app state to QUITTING" << llendl;
430		setStatus(APP_STATUS_QUITTING);
431	}
432}
433
434
435// static
436void LLApp::setStopped()
437{
438	setStatus(APP_STATUS_STOPPED);
439}
440
441
442// static
443bool LLApp::isStopped()
444{
445	return (APP_STATUS_STOPPED == sStatus);
446}
447
448
449// static
450bool LLApp::isRunning()
451{
452	return (APP_STATUS_RUNNING == sStatus);
453}
454
455
456// static
457bool LLApp::isError()
458{
459	return (APP_STATUS_ERROR == sStatus);
460}
461
462
463// static
464bool LLApp::isQuitting()
465{
466	return (APP_STATUS_QUITTING == sStatus);
467}
468
469// static
470bool LLApp::isExiting()
471{
472	return isQuitting() || isError();
473}
474
475void LLApp::disableCrashlogger()
476{
477	// Disable Breakpad exception handler.
478	if (mExceptionHandler != 0)
479	{
480		delete mExceptionHandler;
481		mExceptionHandler = 0;
482	}
483
484	sDisableCrashlogger = TRUE;
485}
486
487// static
488bool LLApp::isCrashloggerDisabled()
489{
490	return (sDisableCrashlogger == TRUE); 
491}
492
493#if !LL_WINDOWS
494// static
495U32 LLApp::getSigChildCount()
496{
497	if (sSigChildCount)
498	{
499		return U32(*sSigChildCount);
500	}
501	return 0;
502}
503
504// static
505void LLApp::incSigChildCount()
506{
507	if (sSigChildCount)
508	{
509		(*sSigChildCount)++;
510	}
511}
512
513#endif
514
515
516// static
517int LLApp::getPid()
518{
519#if LL_WINDOWS
520	return 0;
521#else
522	return getpid();
523#endif
524}
525
526#if LL_WINDOWS
527LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop)
528{
529	// Translate the signals/exceptions into cross-platform stuff
530	// Windows implementation
531
532	// Make sure the user sees something to indicate that the app crashed.
533	LONG retval;
534
535	if (LLApp::isError())
536	{
537		llwarns << "Got another fatal signal while in the error handler, die now!" << llendl;
538		retval = EXCEPTION_EXECUTE_HANDLER;
539		return retval;
540	}
541
542	// Flag status to error, so thread_error starts its work
543	LLApp::setError();
544
545	// Block in the exception handler until the app has stopped
546	// This is pretty sketchy, but appears to work just fine
547	while (!LLApp::isStopped())
548	{
549		ms_sleep(10);
550	}
551
552	//
553	// Generate a minidump if we can.
554	//
555	// TODO: This needs to be ported over form the viewer-specific
556	// LLWinDebug class
557
558	//
559	// At this point, we always want to exit the app.  There's no graceful
560	// recovery for an unhandled exception.
561	// 
562	// Just kill the process.
563	retval = EXCEPTION_EXECUTE_HANDLER;	
564	return retval;
565}
566
567// Win32 doesn't support signals. This is used instead.
568BOOL ConsoleCtrlHandler(DWORD fdwCtrlType) 
569{ 
570	switch (fdwCtrlType) 
571	{ 
572 		case CTRL_BREAK_EVENT: 
573		case CTRL_LOGOFF_EVENT: 
574		case CTRL_SHUTDOWN_EVENT: 
575		case CTRL_CLOSE_EVENT: // From end task or the window close button.
576		case CTRL_C_EVENT:  // from CTRL-C on the keyboard
577			// Just set our state to quitting, not error
578			if (LLApp::isQuitting() || LLApp::isError())
579			{
580				// We're already trying to die, just ignore this signal
581				if (LLApp::sLogInSignal)
582				{
583					llinfos << "Signal handler - Already trying to quit, ignoring signal!" << llendl;
584				}
585				return TRUE;
586			}
587			LLApp::setQuitting();
588			return TRUE; 
589	
590		default: 
591			return FALSE; 
592	} 
593} 
594
595#else //!LL_WINDOWS
596void LLApp::setChildCallback(pid_t pid, LLAppChildCallback callback)
597{
598	LLChildInfo child_info;
599	child_info.mCallback = callback;
600	LLApp::sChildMap[pid] = child_info;
601}
602
603void LLApp::setDefaultChildCallback(LLAppChildCallback callback)
604{
605	LLApp::sDefaultChildCallback = callback;
606}
607
608pid_t LLApp::fork()
609{
610	fflush(NULL); // flush all buffers before the child inherits them
611	pid_t pid = ::fork();
612	if( pid < 0 )
613	{
614		int system_error = errno;
615		llwarns << "Unable to fork! Operating system error code: "
616				<< system_error << llendl;
617	}
618	else if (pid == 0)
619	{
620		// Sleep a bit to allow the parent to set up child callbacks.
621		ms_sleep(10);
622
623		// We need to disable signal handling, because we don't have a
624		// signal handling thread anymore.
625		setupErrorHandling();
626	}
627	else
628	{
629		llinfos << "Forked child process " << pid << llendl;
630	}
631	return pid;
632}
633
634void setup_signals()
635{
636	//
637	// Set up signal handlers that may result in program termination
638	//
639	struct sigaction act;
640	act.sa_sigaction = default_unix_signal_handler;
641	sigemptyset( &act.sa_mask );
642	act.sa_flags = SA_SIGINFO;
643
644	// Synchronous signals
645	sigaction(SIGABRT, &act, NULL);
646	sigaction(SIGALRM, &act, NULL);
647	sigaction(SIGBUS, &act, NULL);
648	sigaction(SIGFPE, &act, NULL);
649	sigaction(SIGHUP, &act, NULL); 
650	sigaction(SIGILL, &act, NULL);
651	sigaction(SIGPIPE, &act, NULL);
652	sigaction(SIGSEGV, &act, NULL);
653	sigaction(SIGSYS, &act, NULL);
654
655	sigaction(LL_HEARTBEAT_SIGNAL, &act, NULL);
656	sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL);
657
658	// Asynchronous signals that are normally ignored
659#ifndef LL_IGNORE_SIGCHLD
660	sigaction(SIGCHLD, &act, NULL);
661#endif // LL_IGNORE_SIGCHLD
662	sigaction(SIGUSR2, &act, NULL);
663
664	// Asynchronous signals that result in attempted graceful exit
665	sigaction(SIGHUP, &act, NULL);
666	sigaction(SIGTERM, &act, NULL);
667	sigaction(SIGINT, &act, NULL);
668
669	// Asynchronous signals that result in core
670	sigaction(SIGQUIT, &act, NULL);
671	
672}
673
674void clear_signals()
675{
676	struct sigaction act;
677	act.sa_handler = SIG_DFL;
678	sigemptyset( &act.sa_mask );
679	act.sa_flags = SA_SIGINFO;
680
681	// Synchronous signals
682	sigaction(SIGABRT, &act, NULL);
683	sigaction(SIGALRM, &act, NULL);
684	sigaction(SIGBUS, &act, NULL);
685	sigaction(SIGFPE, &act, NULL);
686	sigaction(SIGHUP, &act, NULL); 
687	sigaction(SIGILL, &act, NULL);
688	sigaction(SIGPIPE, &act, NULL);
689	sigaction(SIGSEGV, &act, NULL);
690	sigaction(SIGSYS, &act, NULL);
691
692	sigaction(LL_HEARTBEAT_SIGNAL, &act, NULL);
693	sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL);
694
695	// Asynchronous signals that are normally ignored
696#ifndef LL_IGNORE_SIGCHLD
697	sigaction(SIGCHLD, &act, NULL);
698#endif // LL_IGNORE_SIGCHLD
699
700	// Asynchronous signals that result in attempted graceful exit
701	sigaction(SIGHUP, &act, NULL);
702	sigaction(SIGTERM, &act, NULL);
703	sigaction(SIGINT, &act, NULL);
704
705	// Asynchronous signals that result in core
706	sigaction(SIGUSR2, &act, NULL);
707	sigaction(SIGQUIT, &act, NULL);
708}
709
710
711
712void default_unix_signal_handler(int signum, siginfo_t *info, void *)
713{
714	// Unix implementation of synchronous signal handler
715	// This runs in the thread that threw the signal.
716	// We do the somewhat sketchy operation of blocking in here until the error handler
717	// has gracefully stopped the app.
718
719	if (LLApp::sLogInSignal)
720	{
721		llinfos << "Signal handler - Got signal " << signum << " - " << apr_signal_description_get(signum) << llendl;
722	}
723
724
725	switch (signum)
726	{
727	case SIGCHLD:
728		if (LLApp::sLogInSignal)
729		{
730			llinfos << "Signal handler - Got SIGCHLD from " << info->si_pid << llendl;
731		}
732
733		// Check result code for all child procs for which we've
734		// registered callbacks THIS WILL NOT WORK IF SIGCHLD IS SENT
735		// w/o killing the child (Go, launcher!)
736		// TODO: Now that we're using SIGACTION, we can actually
737		// implement the launcher behavior to determine who sent the
738		// SIGCHLD even if it doesn't result in child termination
739		if (LLApp::sChildMap.count(info->si_pid))
740		{
741			LLApp::sChildMap[info->si_pid].mGotSigChild = TRUE;
742		}
743		
744		LLApp::incSigChildCount();
745
746		return;
747	case SIGABRT:
748		// Abort just results in termination of the app, no funky error handling.
749		if (LLApp::sLogInSignal)
750		{
751			llwarns << "Signal handler - Got SIGABRT, terminating" << llendl;
752		}
753		clear_signals();
754		raise(signum);
755		return;
756	case SIGINT:
757	case SIGHUP:
758	case SIGTERM:
759		if (LLApp::sLogInSignal)
760		{
761			llwarns << "Signal handler - Got SIGINT, HUP, or TERM, exiting gracefully" << llendl;
762		}
763		// Graceful exit
764		// Just set our state to quitting, not error
765		if (LLApp::isQuitting() || LLApp::isError())
766		{
767			// We're already trying to die, just ignore this signal
768			if (LLApp::sLogInSignal)
769			{
770				llinfos << "Signal handler - Already trying to quit, ignoring signal!" << llendl;
771			}
772			return;
773		}
774		LLApp::setQuitting();
775		return;
776	case SIGALRM:
777	case SIGPIPE:
778	case SIGUSR2:
779	default:
780		if (signum == LL_SMACKDOWN_SIGNAL ||
781		    signum == SIGBUS ||
782		    signum == SIGILL ||
783		    signum == SIGFPE ||
784		    signum == SIGSEGV ||
785		    signum == SIGQUIT)
786		{ 
787			if (signum == LL_SMACKDOWN_SIGNAL)
788			{
789				// Smackdown treated just like any other app termination, for now
790				if (LLApp::sLogInSignal)
791				{
792					llwarns << "Signal handler - Handling smackdown signal!" << llendl;
793				}
794				else
795				{
796					// Don't log anything, even errors - this is because this signal could happen anywhere.
797					LLError::setDefaultLevel(LLError::LEVEL_NONE);
798				}
799				
800				// Change the signal that we reraise to SIGABRT, so we generate a core dump.
801				signum = SIGABRT;
802			}
803			
804			if (LLApp::sLogInSignal)
805			{
806				llwarns << "Signal handler - Handling fatal signal!" << llendl;
807			}
808			if (LLApp::isError())
809			{
810				// Received second fatal signal while handling first, just die right now
811				// Set the signal handlers back to default before handling the signal - this makes the next signal wipe out the app.
812				clear_signals();
813				
814				if (LLApp::sLogInSignal)
815				{
816					llwarns << "Signal handler - Got another fatal signal while in the error handler, die now!" << llendl;
817				}
818				raise(signum);
819				return;
820			}
821			
822			if (LLApp::sLogInSignal)
823			{
824				llwarns << "Signal handler - Flagging error status and waiting for shutdown" << llendl;
825			}
826									
827			if (LLApp::isCrashloggerDisabled())	// Don't gracefully handle any signal, crash and core for a gdb post mortem
828			{
829				clear_signals();
830				llwarns << "Fatal signal received, not handling the crash here, passing back to operating system" << llendl;
831				raise(signum);
832				return;
833			}		
834			
835			// Flag status to ERROR, so thread_error does its work.
836			LLApp::setError();
837			// Block in the signal handler until somebody says that we're done.
838			while (LLApp::sErrorThreadRunning && !LLApp::isStopped())
839			{
840				ms_sleep(10);
841			}
842			
843			if (LLApp::sLogInSignal)
844			{
845				llwarns << "Signal handler - App is stopped, reraising signal" << llendl;
846			}
847			clear_signals();
848			raise(signum);
849			return;
850		} else {
851			if (LLApp::sLogInSignal)
852			{
853				llinfos << "Signal handler - Unhandled signal " << signum << ", ignoring!" << llendl;
854			}
855		}
856	}
857}
858
859bool unix_post_minidump_callback(const char *dump_dir,
860					  const char *minidump_id,
861					  void *context, bool succeeded)
862{
863	// Copy minidump file path into fixed buffer in the app instance to avoid
864	// heap allocations in a crash handler.
865	
866	// path format: <dump_dir>/<minidump_id>.dmp
867	int dirPathLength = strlen(dump_dir);
868	int idLength = strlen(minidump_id);
869	
870	// The path must not be truncated.
871	llassert((dirPathLength + idLength + 5) <= LLApp::MAX_MINDUMP_PATH_LENGTH);
872	
873	char * path = LLApp::instance()->getMiniDumpFilename();
874	S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH;
875	strncpy(path, dump_dir, remaining);
876	remaining -= dirPathLength;
877	path += dirPathLength;
878	if (remaining > 0 && dirPathLength > 0 && path[-1] != '/')
879	{
880		*path++ = '/';
881		--remaining;
882	}
883	if (remaining > 0)
884	{
885		strncpy(path, minidump_id, remaining);
886		remaining -= idLength;
887		path += idLength;
888		strncpy(path, ".dmp", remaining);
889	}
890	
891	llinfos << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << llendl;
892	LLApp::runErrorHandler();
893	
894#ifndef LL_RELEASE_FOR_DOWNLOAD
895	clear_signals();
896	return false;
897#else
898	return true;
899#endif
900}
901#endif // !WINDOWS
902
903#ifdef LL_WINDOWS
904bool windows_post_minidump_callback(const wchar_t* dump_path,
905									const wchar_t* minidump_id,
906									void* context,
907									EXCEPTION_POINTERS* exinfo,
908									MDRawAssertionInfo* assertion,
909									bool succeeded)
910{
911	char * path = LLApp::instance()->getMiniDumpFilename();
912	S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH;
913	size_t bytesUsed;
914
915	bytesUsed = wcstombs(path, dump_path, static_cast<size_t>(remaining));
916	remaining -= bytesUsed;
917	path += bytesUsed;
918	if(remaining > 0 && bytesUsed > 0 && path[-1] != '\\')
919	{
920		*path++ = '\\';
921		--remaining;
922	}
923	if(remaining > 0)
924	{
925		bytesUsed = wcstombs(path, minidump_id, static_cast<size_t>(remaining));
926		remaining -= bytesUsed;
927		path += bytesUsed;
928	}
929	if(remaining > 0)
930	{
931		strncpy(path, ".dmp", remaining);
932	}
933
934	llinfos << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << llendl;
935    // *NOTE:Mani - this code is stolen from LLApp, where its never actually used.
936	//OSMessageBox("Attach Debugger Now", "Error", OSMB_OK);
937    // *TODO: Translate the signals/exceptions into cross-platform stuff
938	// Windows implementation
939	llinfos << "Entering Windows Exception Handler..." << llendl;
940
941	if (LLApp::isError())
942	{
943		llwarns << "Got another fatal signal while in the error handler, die now!" << llendl;
944	}
945
946	// Flag status to error, so thread_error starts its work
947	LLApp::setError();
948
949	// Block in the exception handler until the app has stopped
950	// This is pretty sketchy, but appears to work just fine
951	while (!LLApp::isStopped())
952	{
953		ms_sleep(10);
954	}
955
956#ifndef LL_RELEASE_FOR_DOWNLOAD
957	return false;
958#else
959	return true;
960#endif
961}
962#endif