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
00045
00046
00047
00048 #if LL_WINDOWS
00049 LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop);
00050 #else
00051 #include <unistd.h>
00052 void setup_signals();
00053 void default_unix_signal_handler(int signum, siginfo_t *info, void *);
00054 const S32 LL_SMACKDOWN_SIGNAL = SIGUSR1;
00055 #endif
00056
00057
00058 LLApp* LLApp::sApplication = NULL;
00059
00060
00061
00062 BOOL LLApp::sLogInSignal = FALSE;
00063
00064
00065 LLApp::EAppStatus LLApp::sStatus = LLApp::APP_STATUS_STOPPED;
00066 LLAppErrorHandler LLApp::sErrorHandler = NULL;
00067 BOOL LLApp::sErrorThreadRunning = FALSE;
00068 #if !LL_WINDOWS
00069 LLApp::child_map LLApp::sChildMap;
00070 LLAtomicU32* LLApp::sSigChildCount = NULL;
00071 LLAppChildCallback LLApp::sDefaultChildCallback = NULL;
00072 #endif
00073
00074
00075 LLApp::LLApp() : mThreadErrorp(NULL)
00076 {
00077
00078 setStatus(APP_STATUS_RUNNING);
00079
00080 LLCommon::initClass();
00081
00082 #if !LL_WINDOWS
00083
00084 sSigChildCount = new LLAtomicU32(0);
00085 #endif
00086
00087
00088 setupErrorHandling();
00089
00090
00091
00092
00093 mOptions = LLSD::emptyArray();
00094 LLSD sd;
00095 for(int i = 0; i < PRIORITY_COUNT; ++i)
00096 {
00097 mOptions.append(sd);
00098 }
00099
00100
00101
00102
00103
00104
00105 sApplication = this;
00106 }
00107
00108
00109 LLApp::~LLApp()
00110 {
00111 #if !LL_WINDOWS
00112 delete sSigChildCount;
00113 sSigChildCount = NULL;
00114 #endif
00115 setStopped();
00116
00117 ms_sleep(20);
00118 if (mThreadErrorp)
00119 {
00120 delete mThreadErrorp;
00121 mThreadErrorp = NULL;
00122 }
00123
00124 LLCommon::cleanupClass();
00125 }
00126
00127
00128 LLApp* LLApp::instance()
00129 {
00130 return sApplication;
00131 }
00132
00133
00134 LLSD LLApp::getOption(const std::string& name) const
00135 {
00136 LLSD rv;
00137 LLSD::array_const_iterator iter = mOptions.beginArray();
00138 LLSD::array_const_iterator end = mOptions.endArray();
00139 for(; iter != end; ++iter)
00140 {
00141 rv = (*iter)[name];
00142 if(rv.isDefined()) break;
00143 }
00144 return rv;
00145 }
00146
00147 bool LLApp::parseCommandOptions(int argc, char** argv)
00148 {
00149 LLSD commands;
00150 std::string name;
00151 std::string value;
00152 for(int ii = 1; ii < argc; ++ii)
00153 {
00154 if(argv[ii][0] != '-')
00155 {
00156 llinfos << "Did not find option identifier while parsing token: "
00157 << argv[ii] << llendl;
00158 return false;
00159 }
00160 int offset = 1;
00161 if(argv[ii][1] == '-') ++offset;
00162 name.assign(&argv[ii][offset]);
00163 if(((ii+1) >= argc) || (argv[ii+1][0] == '-'))
00164 {
00165
00166
00167
00168 commands[name] = true;
00169 continue;
00170 }
00171 ++ii;
00172 value.assign(argv[ii]);
00173 commands[name] = value;
00174 }
00175 setOptionData(PRIORITY_COMMAND_LINE, commands);
00176 return true;
00177 }
00178
00179 bool LLApp::setOptionData(OptionPriority level, LLSD data)
00180 {
00181 if((level < 0)
00182 || (level >= PRIORITY_COUNT)
00183 || (data.type() != LLSD::TypeMap))
00184 {
00185 return false;
00186 }
00187 mOptions[level] = data;
00188 return true;
00189 }
00190
00191 LLSD LLApp::getOptionData(OptionPriority level)
00192 {
00193 if((level < 0) || (level >= PRIORITY_COUNT))
00194 {
00195 return LLSD();
00196 }
00197 return mOptions[level];
00198 }
00199
00200 void LLApp::stepFrame()
00201 {
00202 LLFrameTimer::updateFrameTime();
00203 LLEventTimer::updateClass();
00204 mRunner.run();
00205 }
00206
00207
00208 void LLApp::setupErrorHandling()
00209 {
00210
00211
00212
00213 #if LL_WINDOWS
00214
00215
00216
00217
00218
00219
00220
00221
00222 #else
00223
00224
00225
00226
00227
00228
00229
00230 setup_signals();
00231
00232 #endif
00233
00234
00235
00236
00237
00238 llinfos << "LLApp::setupErrorHandling - Starting error thread" << llendl;
00239 mThreadErrorp = new LLErrorThread();
00240 mThreadErrorp->setUserData((void *) this);
00241 mThreadErrorp->start();
00242 }
00243
00244
00245 void LLApp::setErrorHandler(LLAppErrorHandler handler)
00246 {
00247 LLApp::sErrorHandler = handler;
00248 }
00249
00250
00251 void LLApp::runErrorHandler()
00252 {
00253 if (LLApp::sErrorHandler)
00254 {
00255 LLApp::sErrorHandler();
00256 }
00257
00258
00259 LLApp::setStopped();
00260 }
00261
00262
00263
00264 void LLApp::setStatus(EAppStatus status)
00265 {
00266 sStatus = status;
00267 }
00268
00269
00270
00271 void LLApp::setError()
00272 {
00273 setStatus(APP_STATUS_ERROR);
00274 }
00275
00276
00277
00278 void LLApp::setQuitting()
00279 {
00280 if (!isExiting())
00281 {
00282
00283 llinfos << "Setting app state to QUITTING" << llendl;
00284 setStatus(APP_STATUS_QUITTING);
00285 }
00286 }
00287
00288
00289
00290 void LLApp::setStopped()
00291 {
00292 setStatus(APP_STATUS_STOPPED);
00293 }
00294
00295
00296
00297 bool LLApp::isStopped()
00298 {
00299 return (APP_STATUS_STOPPED == sStatus);
00300 }
00301
00302
00303
00304 bool LLApp::isRunning()
00305 {
00306 return (APP_STATUS_RUNNING == sStatus);
00307 }
00308
00309
00310
00311 bool LLApp::isError()
00312 {
00313 return (APP_STATUS_ERROR == sStatus);
00314 }
00315
00316
00317
00318 bool LLApp::isQuitting()
00319 {
00320 return (APP_STATUS_QUITTING == sStatus);
00321 }
00322
00323 bool LLApp::isExiting()
00324 {
00325 return isQuitting() || isError();
00326 }
00327
00328 #if !LL_WINDOWS
00329
00330 U32 LLApp::getSigChildCount()
00331 {
00332 if (sSigChildCount)
00333 {
00334 return U32(*sSigChildCount);
00335 }
00336 return 0;
00337 }
00338
00339
00340 void LLApp::incSigChildCount()
00341 {
00342 if (sSigChildCount)
00343 {
00344 (*sSigChildCount)++;
00345 }
00346 }
00347
00348 #endif
00349
00350
00351
00352 int LLApp::getPid()
00353 {
00354 #if LL_WINDOWS
00355 return 0;
00356 #else
00357 return getpid();
00358 #endif
00359 }
00360
00361 #if LL_WINDOWS
00362 LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop)
00363 {
00364
00365
00366
00367
00368 LONG retval;
00369
00370 if (LLApp::isError())
00371 {
00372 llwarns << "Got another fatal signal while in the error handler, die now!" << llendl;
00373 retval = EXCEPTION_EXECUTE_HANDLER;
00374 return retval;
00375 }
00376
00377
00378 LLApp::setError();
00379
00380
00381
00382 while (!LLApp::isStopped())
00383 {
00384 ms_sleep(10);
00385 }
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398 retval = EXCEPTION_EXECUTE_HANDLER;
00399 return retval;
00400 }
00401
00402 #else
00403 void LLApp::setChildCallback(pid_t pid, LLAppChildCallback callback)
00404 {
00405 LLChildInfo child_info;
00406 child_info.mCallback = callback;
00407 LLApp::sChildMap[pid] = child_info;
00408 }
00409
00410 void LLApp::setDefaultChildCallback(LLAppChildCallback callback)
00411 {
00412 LLApp::sDefaultChildCallback = callback;
00413 }
00414
00415 pid_t LLApp::fork()
00416 {
00417 pid_t pid = ::fork();
00418 if( pid < 0 )
00419 {
00420 int system_error = errno;
00421 llwarns << "Unable to fork! Operating system error code: "
00422 << system_error << llendl;
00423 }
00424 else if (pid == 0)
00425 {
00426
00427 ms_sleep(10);
00428
00429
00430
00431 setupErrorHandling();
00432 }
00433 else
00434 {
00435 llinfos << "Forked child process " << pid << llendl;
00436 }
00437 return pid;
00438 }
00439
00440 void setup_signals()
00441 {
00442
00443
00444
00445 struct sigaction act;
00446 act.sa_sigaction = default_unix_signal_handler;
00447 sigemptyset( &act.sa_mask );
00448 act.sa_flags = SA_SIGINFO;
00449
00450
00451 sigaction(SIGABRT, &act, NULL);
00452 sigaction(SIGALRM, &act, NULL);
00453 sigaction(SIGBUS, &act, NULL);
00454 sigaction(SIGFPE, &act, NULL);
00455 sigaction(SIGHUP, &act, NULL);
00456 sigaction(SIGILL, &act, NULL);
00457 sigaction(SIGPIPE, &act, NULL);
00458 sigaction(SIGSEGV, &act, NULL);
00459 sigaction(SIGSYS, &act, NULL);
00460
00461
00462 sigaction(SIGCHLD, &act, NULL);
00463 sigaction(SIGUSR2, &act, NULL);
00464
00465
00466 sigaction(SIGHUP, &act, NULL);
00467 sigaction(SIGTERM, &act, NULL);
00468 sigaction(SIGINT, &act, NULL);
00469
00470
00471 sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL);
00472 sigaction(SIGQUIT, &act, NULL);
00473 }
00474
00475 void clear_signals()
00476 {
00477 struct sigaction act;
00478 act.sa_handler = SIG_DFL;
00479 sigemptyset( &act.sa_mask );
00480 act.sa_flags = SA_SIGINFO;
00481
00482
00483 sigaction(SIGABRT, &act, NULL);
00484 sigaction(SIGALRM, &act, NULL);
00485 sigaction(SIGBUS, &act, NULL);
00486 sigaction(SIGFPE, &act, NULL);
00487 sigaction(SIGHUP, &act, NULL);
00488 sigaction(SIGILL, &act, NULL);
00489 sigaction(SIGPIPE, &act, NULL);
00490 sigaction(SIGSEGV, &act, NULL);
00491 sigaction(SIGSYS, &act, NULL);
00492
00493
00494 sigaction(SIGCHLD, &act, NULL);
00495
00496
00497 sigaction(SIGHUP, &act, NULL);
00498 sigaction(SIGTERM, &act, NULL);
00499 sigaction(SIGINT, &act, NULL);
00500
00501
00502 sigaction(SIGUSR2, &act, NULL);
00503 sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL);
00504 sigaction(SIGQUIT, &act, NULL);
00505 }
00506
00507
00508
00509 void default_unix_signal_handler(int signum, siginfo_t *info, void *)
00510 {
00511
00512
00513
00514
00515
00516 if (LLApp::sLogInSignal)
00517 {
00518 llinfos << "Signal handler - Got signal " << signum << " - " << apr_signal_description_get(signum) << llendl;
00519 }
00520
00521
00522 switch (signum)
00523 {
00524 case SIGALRM:
00525 case SIGPIPE:
00526 case SIGUSR2:
00527
00528 if (LLApp::sLogInSignal)
00529 {
00530 llinfos << "Signal handler - Ignoring this signal" << llendl;
00531 }
00532 return;
00533 case SIGCHLD:
00534 if (LLApp::sLogInSignal)
00535 {
00536 llinfos << "Signal handler - Got SIGCHLD from " << info->si_pid << llendl;
00537 }
00538
00539
00540
00541
00542
00543
00544
00545 if (LLApp::sChildMap.count(info->si_pid))
00546 {
00547 LLApp::sChildMap[info->si_pid].mGotSigChild = TRUE;
00548 }
00549
00550 LLApp::incSigChildCount();
00551
00552 return;
00553 case SIGABRT:
00554
00555 if (LLApp::sLogInSignal)
00556 {
00557 llwarns << "Signal handler - Got SIGABRT, terminating" << llendl;
00558 }
00559 clear_signals();
00560 raise(signum);
00561 return;
00562 case LL_SMACKDOWN_SIGNAL:
00563 if (LLApp::sLogInSignal)
00564 {
00565 llwarns << "Signal handler - Handling smackdown signal!" << llendl;
00566 }
00567 else
00568 {
00569
00570 LLError::setDefaultLevel(LLError::LEVEL_NONE);
00571 }
00572
00573
00574 signum = SIGABRT;
00575 case SIGBUS:
00576 case SIGSEGV:
00577 case SIGQUIT:
00578 if (LLApp::sLogInSignal)
00579 {
00580 llwarns << "Signal handler - Handling fatal signal!" << llendl;
00581 }
00582 if (LLApp::isError())
00583 {
00584
00585
00586 clear_signals();
00587
00588 if (LLApp::sLogInSignal)
00589 {
00590 llwarns << "Signal handler - Got another fatal signal while in the error handler, die now!" << llendl;
00591 }
00592 raise(signum);
00593 return;
00594 }
00595
00596 if (LLApp::sLogInSignal)
00597 {
00598 llwarns << "Signal handler - Flagging error status and waiting for shutdown" << llendl;
00599 }
00600
00601 LLApp::setError();
00602
00603 while (LLApp::sErrorThreadRunning && !LLApp::isStopped())
00604 {
00605 ms_sleep(10);
00606 }
00607
00608 if (LLApp::sLogInSignal)
00609 {
00610 llwarns << "Signal handler - App is stopped, reraising signal" << llendl;
00611 }
00612 clear_signals();
00613 raise(signum);
00614 return;
00615 case SIGINT:
00616 case SIGHUP:
00617 case SIGTERM:
00618 if (LLApp::sLogInSignal)
00619 {
00620 llwarns << "Signal handler - Got SIGINT, HUP, or TERM, exiting gracefully" << llendl;
00621 }
00622
00623
00624 if (LLApp::isQuitting() || LLApp::isError())
00625 {
00626
00627 if (LLApp::sLogInSignal)
00628 {
00629 llinfos << "Signal handler - Already trying to quit, ignoring signal!" << llendl;
00630 }
00631 return;
00632 }
00633 LLApp::setQuitting();
00634 return;
00635 default:
00636 if (LLApp::sLogInSignal)
00637 {
00638 llwarns << "Signal handler - Unhandled signal, ignoring!" << llendl;
00639 }
00640 }
00641 }
00642
00643 #endif // !WINDOWS