llapp.cpp

Go to the documentation of this file.
00001 
00032 #include "linden_common.h"
00033 #include "llapp.h"
00034 
00035 #include "llcommon.h"
00036 #include "llapr.h"
00037 #include "llerrorcontrol.h"
00038 #include "llerrorthread.h"
00039 #include "llframetimer.h"
00040 #include "llmemory.h"
00041 #include "lltimer.h"
00042 
00043 //
00044 // Signal handling
00045 //
00046 // Windows uses structured exceptions, so it's handled a bit differently.
00047 //
00048 #if LL_WINDOWS
00049 LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop);
00050 BOOL ConsoleCtrlHandler(DWORD fdwCtrlType);
00051 #else
00052 # include <signal.h>
00053 # include <unistd.h> // for fork()
00054 void setup_signals();
00055 void default_unix_signal_handler(int signum, siginfo_t *info, void *);
00056 # if LL_DARWIN
00057 /* OSX doesn't support SIGRT* */
00058 S32 LL_SMACKDOWN_SIGNAL = SIGUSR1;
00059 S32 LL_HEARTBEAT_SIGNAL = SIGUSR2;
00060 # else
00061 /* We want reliable delivery of our signals - SIGRT* is it. */
00062 /* Old LinuxThreads versions eat SIGRTMIN+0 to SIGRTMIN+2, avoid those. */
00063 /* Note that SIGRTMIN/SIGRTMAX may expand to a glibc function call with a
00064    nonconstant result so these are not consts and cannot be used in constant-
00065    expressions.  SIGRTMAX may return -1 on rare broken setups. */
00066 S32 LL_SMACKDOWN_SIGNAL = (SIGRTMAX >= 0) ? (SIGRTMAX-1) : SIGUSR1;
00067 S32 LL_HEARTBEAT_SIGNAL = (SIGRTMAX >= 0) ? (SIGRTMAX-0) : SIGUSR2;
00068 # endif // LL_DARWIN
00069 #endif // LL_WINDOWS
00070 
00071 // the static application instance
00072 LLApp* LLApp::sApplication = NULL;
00073 
00074 // Local flag for whether or not to do logging in signal handlers.
00075 //static
00076 BOOL LLApp::sLogInSignal = FALSE;
00077 
00078 // static
00079 LLApp::EAppStatus LLApp::sStatus = LLApp::APP_STATUS_STOPPED; // Keeps track of application status
00080 LLAppErrorHandler LLApp::sErrorHandler = NULL;
00081 LLAppErrorHandler LLApp::sSyncErrorHandler = NULL;
00082 BOOL LLApp::sErrorThreadRunning = FALSE;
00083 #if !LL_WINDOWS
00084 LLApp::child_map LLApp::sChildMap;
00085 LLAtomicU32* LLApp::sSigChildCount = NULL;
00086 LLAppChildCallback LLApp::sDefaultChildCallback = NULL;
00087 #endif
00088 
00089 
00090 LLApp::LLApp() : mThreadErrorp(NULL)
00091 {
00092         // Set our status to running
00093         setStatus(APP_STATUS_RUNNING);
00094 
00095         LLCommon::initClass();
00096 
00097 #if !LL_WINDOWS
00098         // This must be initialized before the error handler.
00099         sSigChildCount = new LLAtomicU32(0);    
00100 #endif
00101         
00102         // Setup error handling
00103         setupErrorHandling();
00104 
00105         // initialize the options structure. We need to make this an array
00106         // because the structured data will not auto-allocate if we
00107         // reference an invalid location with the [] operator.
00108         mOptions = LLSD::emptyArray();
00109         LLSD sd;
00110         for(int i = 0; i < PRIORITY_COUNT; ++i)
00111         {
00112                 mOptions.append(sd);
00113         }
00114 
00115         // Make sure we clean up APR when we exit
00116         // Don't need to do this if we're cleaning up APR in the destructor
00117         //atexit(ll_cleanup_apr);
00118 
00119         // Set the application to this instance.
00120         sApplication = this;
00121 }
00122 
00123 
00124 LLApp::~LLApp()
00125 {
00126 #if !LL_WINDOWS
00127         delete sSigChildCount;
00128         sSigChildCount = NULL;
00129 #endif
00130         setStopped();
00131         // HACK: wait for the error thread to clean itself
00132         ms_sleep(20);
00133         if (mThreadErrorp)
00134         {
00135                 delete mThreadErrorp;
00136                 mThreadErrorp = NULL;
00137         }
00138 
00139         LLCommon::cleanupClass();
00140 }
00141 
00142 // static
00143 LLApp* LLApp::instance()
00144 {
00145         return sApplication;
00146 }
00147 
00148 
00149 LLSD LLApp::getOption(const std::string& name) const
00150 {
00151         LLSD rv;
00152         LLSD::array_const_iterator iter = mOptions.beginArray();
00153         LLSD::array_const_iterator end = mOptions.endArray();
00154         for(; iter != end; ++iter)
00155         {
00156                 rv = (*iter)[name];
00157                 if(rv.isDefined()) break;
00158         }
00159         return rv;
00160 }
00161 
00162 bool LLApp::parseCommandOptions(int argc, char** argv)
00163 {
00164         LLSD commands;
00165         std::string name;
00166         std::string value;
00167         for(int ii = 1; ii < argc; ++ii)
00168         {
00169                 if(argv[ii][0] != '-')
00170                 {
00171                         llinfos << "Did not find option identifier while parsing token: "
00172                                 << argv[ii] << llendl;
00173                         return false;
00174                 }
00175                 int offset = 1;
00176                 if(argv[ii][1] == '-') ++offset;
00177                 name.assign(&argv[ii][offset]);
00178                 if(((ii+1) >= argc) || (argv[ii+1][0] == '-'))
00179                 {
00180                         // we found another option after this one or we have
00181                         // reached the end. simply record that this option was
00182                         // found and continue.
00183                         int flag = name.compare("logfile");
00184                         if (0 == flag)
00185                         {
00186                                 commands[name] = "log";
00187                         }
00188                         else
00189                         {
00190                                 commands[name] = true;
00191                         }
00192                         
00193                         continue;
00194                 }
00195                 ++ii;
00196                 value.assign(argv[ii]);
00197                 commands[name] = value;
00198         }
00199         setOptionData(PRIORITY_COMMAND_LINE, commands);
00200         return true;
00201 }
00202 
00203 bool LLApp::setOptionData(OptionPriority level, LLSD data)
00204 {
00205         if((level < 0)
00206            || (level >= PRIORITY_COUNT)
00207            || (data.type() != LLSD::TypeMap))
00208         {
00209                 return false;
00210         }
00211         mOptions[level] = data;
00212         return true;
00213 }
00214 
00215 LLSD LLApp::getOptionData(OptionPriority level)
00216 {
00217         if((level < 0) || (level >= PRIORITY_COUNT))
00218         {
00219                 return LLSD();
00220         }
00221         return mOptions[level];
00222 }
00223 
00224 void LLApp::stepFrame()
00225 {
00226         LLFrameTimer::updateFrameTime();
00227         LLEventTimer::updateClass();
00228         mRunner.run();
00229 }
00230 
00231 
00232 void LLApp::setupErrorHandling()
00233 {
00234         // Error handling is done by starting up an error handling thread, which just sleeps and
00235         // occasionally checks to see if the app is in an error state, and sees if it needs to be run.
00236 
00237 #if LL_WINDOWS
00238         // Windows doesn't have the same signal handling mechanisms as UNIX, thus APR doesn't provide
00239         // a signal handling thread implementation.
00240         // What we do is install an unhandled exception handler, which will try to do the right thing
00241         // in the case of an error (generate a minidump)
00242 
00243         // Disable this until the viewer gets ported so server crashes can be JIT debugged.
00244         //LPTOP_LEVEL_EXCEPTION_FILTER prev_filter;
00245         //prev_filter = SetUnhandledExceptionFilter(default_windows_exception_handler);
00246 
00247         // This sets a callback to handle w32 signals to the console window.
00248         // The viewer shouldn't be affected, sicne its a windowed app.
00249         SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ConsoleCtrlHandler, TRUE);
00250 
00251 #else
00252         //
00253         // Start up signal handling.
00254         //
00255         // There are two different classes of signals.  Synchronous signals are delivered to a specific
00256         // thread, asynchronous signals can be delivered to any thread (in theory)
00257         //
00258 
00259         setup_signals();
00260 
00261 #endif
00262 
00263         //
00264         // Start the error handling thread, which is responsible for taking action
00265         // when the app goes into the APP_STATUS_ERROR state
00266         //
00267         llinfos << "LLApp::setupErrorHandling - Starting error thread" << llendl;
00268         mThreadErrorp = new LLErrorThread();
00269         mThreadErrorp->setUserData((void *) this);
00270         mThreadErrorp->start();
00271 }
00272 
00273 
00274 void LLApp::setErrorHandler(LLAppErrorHandler handler)
00275 {
00276         LLApp::sErrorHandler = handler;
00277 }
00278 
00279 
00280 void LLApp::setSyncErrorHandler(LLAppErrorHandler handler)
00281 {
00282         LLApp::sSyncErrorHandler = handler;
00283 }
00284 
00285 // static
00286 void LLApp::runSyncErrorHandler()
00287 {
00288         if (LLApp::sSyncErrorHandler)
00289         {
00290                 LLApp::sSyncErrorHandler();
00291         }
00292 }
00293 
00294 // static
00295 void LLApp::runErrorHandler()
00296 {
00297         if (LLApp::sErrorHandler)
00298         {
00299                 LLApp::sErrorHandler();
00300         }
00301 
00302         //llinfos << "App status now STOPPED" << llendl;
00303         LLApp::setStopped();
00304 }
00305 
00306 
00307 // static
00308 void LLApp::setStatus(EAppStatus status)
00309 {
00310         sStatus = status;
00311 }
00312 
00313 
00314 // static
00315 void LLApp::setError()
00316 {
00317         if (!isError())
00318         {
00319                 // perform any needed synchronous error-handling
00320                 runSyncErrorHandler();
00321                 // set app status to ERROR so that the LLErrorThread notices
00322                 setStatus(APP_STATUS_ERROR);
00323         }
00324 }
00325 
00326 
00327 // static
00328 void LLApp::setQuitting()
00329 {
00330         if (!isExiting())
00331         {
00332                 // If we're already exiting, we don't want to reset our state back to quitting.
00333                 llinfos << "Setting app state to QUITTING" << llendl;
00334                 setStatus(APP_STATUS_QUITTING);
00335         }
00336 }
00337 
00338 
00339 // static
00340 void LLApp::setStopped()
00341 {
00342         setStatus(APP_STATUS_STOPPED);
00343 }
00344 
00345 
00346 // static
00347 bool LLApp::isStopped()
00348 {
00349         return (APP_STATUS_STOPPED == sStatus);
00350 }
00351 
00352 
00353 // static
00354 bool LLApp::isRunning()
00355 {
00356         return (APP_STATUS_RUNNING == sStatus);
00357 }
00358 
00359 
00360 // static
00361 bool LLApp::isError()
00362 {
00363         return (APP_STATUS_ERROR == sStatus);
00364 }
00365 
00366 
00367 // static
00368 bool LLApp::isQuitting()
00369 {
00370         return (APP_STATUS_QUITTING == sStatus);
00371 }
00372 
00373 bool LLApp::isExiting()
00374 {
00375         return isQuitting() || isError();
00376 }
00377 
00378 #if !LL_WINDOWS
00379 // static
00380 U32 LLApp::getSigChildCount()
00381 {
00382         if (sSigChildCount)
00383         {
00384                 return U32(*sSigChildCount);
00385         }
00386         return 0;
00387 }
00388 
00389 // static
00390 void LLApp::incSigChildCount()
00391 {
00392         if (sSigChildCount)
00393         {
00394                 (*sSigChildCount)++;
00395         }
00396 }
00397 
00398 #endif
00399 
00400 
00401 // static
00402 int LLApp::getPid()
00403 {
00404 #if LL_WINDOWS
00405         return 0;
00406 #else
00407         return getpid();
00408 #endif
00409 }
00410 
00411 #if LL_WINDOWS
00412 LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop)
00413 {
00414         // Translate the signals/exceptions into cross-platform stuff
00415         // Windows implementation
00416 
00417         // Make sure the user sees something to indicate that the app crashed.
00418         LONG retval;
00419 
00420         if (LLApp::isError())
00421         {
00422                 llwarns << "Got another fatal signal while in the error handler, die now!" << llendl;
00423                 retval = EXCEPTION_EXECUTE_HANDLER;
00424                 return retval;
00425         }
00426 
00427         // Flag status to error, so thread_error starts its work
00428         LLApp::setError();
00429 
00430         // Block in the exception handler until the app has stopped
00431         // This is pretty sketchy, but appears to work just fine
00432         while (!LLApp::isStopped())
00433         {
00434                 ms_sleep(10);
00435         }
00436 
00437         //
00438         // Generate a minidump if we can.
00439         //
00440         // TODO: This needs to be ported over form the viewer-specific
00441         // LLWinDebug class
00442 
00443         //
00444         // At this point, we always want to exit the app.  There's no graceful
00445         // recovery for an unhandled exception.
00446         // 
00447         // Just kill the process.
00448         retval = EXCEPTION_EXECUTE_HANDLER;     
00449         return retval;
00450 }
00451 
00452 // Win32 doesn't support signals. This is used instead.
00453 BOOL ConsoleCtrlHandler(DWORD fdwCtrlType) 
00454 { 
00455         switch (fdwCtrlType) 
00456         { 
00457                 case CTRL_BREAK_EVENT: 
00458                 case CTRL_LOGOFF_EVENT: 
00459                 case CTRL_SHUTDOWN_EVENT: 
00460                 case CTRL_CLOSE_EVENT: // From end task or the window close button.
00461                 case CTRL_C_EVENT:  // from CTRL-C on the keyboard
00462                         // Just set our state to quitting, not error
00463                         if (LLApp::isQuitting() || LLApp::isError())
00464                         {
00465                                 // We're already trying to die, just ignore this signal
00466                                 if (LLApp::sLogInSignal)
00467                                 {
00468                                         llinfos << "Signal handler - Already trying to quit, ignoring signal!" << llendl;
00469                                 }
00470                                 return TRUE;
00471                         }
00472                         LLApp::setQuitting();
00473                         return TRUE; 
00474         
00475                 default: 
00476                         return FALSE; 
00477         } 
00478 } 
00479 
00480 #else 
00481 void LLApp::setChildCallback(pid_t pid, LLAppChildCallback callback)
00482 {
00483         LLChildInfo child_info;
00484         child_info.mCallback = callback;
00485         LLApp::sChildMap[pid] = child_info;
00486 }
00487 
00488 void LLApp::setDefaultChildCallback(LLAppChildCallback callback)
00489 {
00490         LLApp::sDefaultChildCallback = callback;
00491 }
00492 
00493 pid_t LLApp::fork()
00494 {
00495         pid_t pid = ::fork();
00496         if( pid < 0 )
00497         {
00498                 int system_error = errno;
00499                 llwarns << "Unable to fork! Operating system error code: "
00500                                 << system_error << llendl;
00501         }
00502         else if (pid == 0)
00503         {
00504                 // Sleep a bit to allow the parent to set up child callbacks.
00505                 ms_sleep(10);
00506 
00507                 // We need to disable signal handling, because we don't have a
00508                 // signal handling thread anymore.
00509                 setupErrorHandling();
00510         }
00511         else
00512         {
00513                 llinfos << "Forked child process " << pid << llendl;
00514         }
00515         return pid;
00516 }
00517 
00518 void setup_signals()
00519 {
00520         //
00521         // Set up signal handlers that may result in program termination
00522         //
00523         struct sigaction act;
00524         act.sa_sigaction = default_unix_signal_handler;
00525         sigemptyset( &act.sa_mask );
00526         act.sa_flags = SA_SIGINFO;
00527 
00528         // Synchronous signals
00529         sigaction(SIGABRT, &act, NULL);
00530         sigaction(SIGALRM, &act, NULL);
00531         sigaction(SIGBUS, &act, NULL);
00532         sigaction(SIGFPE, &act, NULL);
00533         sigaction(SIGHUP, &act, NULL); 
00534         sigaction(SIGILL, &act, NULL);
00535         sigaction(SIGPIPE, &act, NULL);
00536         sigaction(SIGSEGV, &act, NULL);
00537         sigaction(SIGSYS, &act, NULL);
00538 
00539         sigaction(LL_HEARTBEAT_SIGNAL, &act, NULL);
00540         sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL);
00541 
00542         // Asynchronous signals that are normally ignored
00543         sigaction(SIGCHLD, &act, NULL);
00544         sigaction(SIGUSR2, &act, NULL);
00545 
00546         // Asynchronous signals that result in attempted graceful exit
00547         sigaction(SIGHUP, &act, NULL);
00548         sigaction(SIGTERM, &act, NULL);
00549         sigaction(SIGINT, &act, NULL);
00550 
00551         // Asynchronous signals that result in core
00552         sigaction(SIGQUIT, &act, NULL);
00553 }
00554 
00555 void clear_signals()
00556 {
00557         struct sigaction act;
00558         act.sa_handler = SIG_DFL;
00559         sigemptyset( &act.sa_mask );
00560         act.sa_flags = SA_SIGINFO;
00561 
00562         // Synchronous signals
00563         sigaction(SIGABRT, &act, NULL);
00564         sigaction(SIGALRM, &act, NULL);
00565         sigaction(SIGBUS, &act, NULL);
00566         sigaction(SIGFPE, &act, NULL);
00567         sigaction(SIGHUP, &act, NULL); 
00568         sigaction(SIGILL, &act, NULL);
00569         sigaction(SIGPIPE, &act, NULL);
00570         sigaction(SIGSEGV, &act, NULL);
00571         sigaction(SIGSYS, &act, NULL);
00572 
00573         sigaction(LL_HEARTBEAT_SIGNAL, &act, NULL);
00574         sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL);
00575 
00576         // Asynchronous signals that are normally ignored
00577         sigaction(SIGCHLD, &act, NULL);
00578 
00579         // Asynchronous signals that result in attempted graceful exit
00580         sigaction(SIGHUP, &act, NULL);
00581         sigaction(SIGTERM, &act, NULL);
00582         sigaction(SIGINT, &act, NULL);
00583 
00584         // Asynchronous signals that result in core
00585         sigaction(SIGUSR2, &act, NULL);
00586         sigaction(SIGQUIT, &act, NULL);
00587 }
00588 
00589 
00590 
00591 void default_unix_signal_handler(int signum, siginfo_t *info, void *)
00592 {
00593         // Unix implementation of synchronous signal handler
00594         // This runs in the thread that threw the signal.
00595         // We do the somewhat sketchy operation of blocking in here until the error handler
00596         // has gracefully stopped the app.
00597 
00598         if (LLApp::sLogInSignal)
00599         {
00600                 llinfos << "Signal handler - Got signal " << signum << " - " << apr_signal_description_get(signum) << llendl;
00601         }
00602 
00603 
00604         switch (signum)
00605         {
00606         case SIGCHLD:
00607                 if (LLApp::sLogInSignal)
00608                 {
00609                         llinfos << "Signal handler - Got SIGCHLD from " << info->si_pid << llendl;
00610                 }
00611 
00612                 // Check result code for all child procs for which we've
00613                 // registered callbacks THIS WILL NOT WORK IF SIGCHLD IS SENT
00614                 // w/o killing the child (Go, launcher!)
00615                 // TODO: Now that we're using SIGACTION, we can actually
00616                 // implement the launcher behavior to determine who sent the
00617                 // SIGCHLD even if it doesn't result in child termination
00618                 if (LLApp::sChildMap.count(info->si_pid))
00619                 {
00620                         LLApp::sChildMap[info->si_pid].mGotSigChild = TRUE;
00621                 }
00622                 
00623                 LLApp::incSigChildCount();
00624 
00625                 return;
00626         case SIGABRT:
00627                 // Abort just results in termination of the app, no funky error handling.
00628                 if (LLApp::sLogInSignal)
00629                 {
00630                         llwarns << "Signal handler - Got SIGABRT, terminating" << llendl;
00631                 }
00632                 clear_signals();
00633                 raise(signum);
00634                 return;
00635         case SIGINT:
00636         case SIGHUP:
00637         case SIGTERM:
00638                 if (LLApp::sLogInSignal)
00639                 {
00640                         llwarns << "Signal handler - Got SIGINT, HUP, or TERM, exiting gracefully" << llendl;
00641                 }
00642                 // Graceful exit
00643                 // Just set our state to quitting, not error
00644                 if (LLApp::isQuitting() || LLApp::isError())
00645                 {
00646                         // We're already trying to die, just ignore this signal
00647                         if (LLApp::sLogInSignal)
00648                         {
00649                                 llinfos << "Signal handler - Already trying to quit, ignoring signal!" << llendl;
00650                         }
00651                         return;
00652                 }
00653                 LLApp::setQuitting();
00654                 return;
00655         case SIGALRM:
00656         case SIGPIPE:
00657         case SIGUSR2:
00658         default:
00659                 if (signum == LL_SMACKDOWN_SIGNAL ||
00660                     signum == SIGBUS ||
00661                     signum == SIGILL ||
00662                     signum == SIGFPE ||
00663                     signum == SIGSEGV ||
00664                     signum == SIGQUIT)
00665                 { 
00666                         if (signum == LL_SMACKDOWN_SIGNAL)
00667                         {
00668                                 // Smackdown treated just like any other app termination, for now
00669                                 if (LLApp::sLogInSignal)
00670                                 {
00671                                         llwarns << "Signal handler - Handling smackdown signal!" << llendl;
00672                                 }
00673                                 else
00674                                 {
00675                                         // Don't log anything, even errors - this is because this signal could happen anywhere.
00676                                         LLError::setDefaultLevel(LLError::LEVEL_NONE);
00677                                 }
00678                                 
00679                                 // Change the signal that we reraise to SIGABRT, so we generate a core dump.
00680                                 signum = SIGABRT;
00681                         }
00682                         
00683                         if (LLApp::sLogInSignal)
00684                         {
00685                                 llwarns << "Signal handler - Handling fatal signal!" << llendl;
00686                         }
00687                         if (LLApp::isError())
00688                         {
00689                                 // Received second fatal signal while handling first, just die right now
00690                                 // Set the signal handlers back to default before handling the signal - this makes the next signal wipe out the app.
00691                                 clear_signals();
00692                                 
00693                                 if (LLApp::sLogInSignal)
00694                                 {
00695                                         llwarns << "Signal handler - Got another fatal signal while in the error handler, die now!" << llendl;
00696                                 }
00697                                 raise(signum);
00698                                 return;
00699                         }
00700                         
00701                         if (LLApp::sLogInSignal)
00702                         {
00703                                 llwarns << "Signal handler - Flagging error status and waiting for shutdown" << llendl;
00704                         }
00705                         // Flag status to ERROR, so thread_error does its work.
00706                         LLApp::setError();
00707                         // Block in the signal handler until somebody says that we're done.
00708                         while (LLApp::sErrorThreadRunning && !LLApp::isStopped())
00709                         {
00710                                 ms_sleep(10);
00711                         }
00712                         
00713                         if (LLApp::sLogInSignal)
00714                         {
00715                                 llwarns << "Signal handler - App is stopped, reraising signal" << llendl;
00716                         }
00717                         clear_signals();
00718                         raise(signum);
00719                         return;
00720                 } else {
00721                         if (LLApp::sLogInSignal)
00722                         {
00723                                 llinfos << "Signal handler - Unhandled signal " << signum << ", ignoring!" << llendl;
00724                         }
00725                 }
00726         }
00727 }
00728 
00729 #endif // !WINDOWS

Generated on Fri May 16 08:32:01 2008 for SecondLife by  doxygen 1.5.5