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 BOOL ConsoleCtrlHandler(DWORD fdwCtrlType);
00051 #else
00052 # include <signal.h>
00053 # include <unistd.h>
00054 void setup_signals();
00055 void default_unix_signal_handler(int signum, siginfo_t *info, void *);
00056 # if LL_DARWIN
00057
00058 S32 LL_SMACKDOWN_SIGNAL = SIGUSR1;
00059 S32 LL_HEARTBEAT_SIGNAL = SIGUSR2;
00060 # else
00061
00062
00063
00064
00065
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
00072 LLApp* LLApp::sApplication = NULL;
00073
00074
00075
00076 BOOL LLApp::sLogInSignal = FALSE;
00077
00078
00079 LLApp::EAppStatus LLApp::sStatus = LLApp::APP_STATUS_STOPPED;
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
00093 setStatus(APP_STATUS_RUNNING);
00094
00095 LLCommon::initClass();
00096
00097 #if !LL_WINDOWS
00098
00099 sSigChildCount = new LLAtomicU32(0);
00100 #endif
00101
00102
00103 setupErrorHandling();
00104
00105
00106
00107
00108 mOptions = LLSD::emptyArray();
00109 LLSD sd;
00110 for(int i = 0; i < PRIORITY_COUNT; ++i)
00111 {
00112 mOptions.append(sd);
00113 }
00114
00115
00116
00117
00118
00119
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
00132 ms_sleep(20);
00133 if (mThreadErrorp)
00134 {
00135 delete mThreadErrorp;
00136 mThreadErrorp = NULL;
00137 }
00138
00139 LLCommon::cleanupClass();
00140 }
00141
00142
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
00181
00182
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
00235
00236
00237 #if LL_WINDOWS
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249 SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ConsoleCtrlHandler, TRUE);
00250
00251 #else
00252
00253
00254
00255
00256
00257
00258
00259 setup_signals();
00260
00261 #endif
00262
00263
00264
00265
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
00286 void LLApp::runSyncErrorHandler()
00287 {
00288 if (LLApp::sSyncErrorHandler)
00289 {
00290 LLApp::sSyncErrorHandler();
00291 }
00292 }
00293
00294
00295 void LLApp::runErrorHandler()
00296 {
00297 if (LLApp::sErrorHandler)
00298 {
00299 LLApp::sErrorHandler();
00300 }
00301
00302
00303 LLApp::setStopped();
00304 }
00305
00306
00307
00308 void LLApp::setStatus(EAppStatus status)
00309 {
00310 sStatus = status;
00311 }
00312
00313
00314
00315 void LLApp::setError()
00316 {
00317 if (!isError())
00318 {
00319
00320 runSyncErrorHandler();
00321
00322 setStatus(APP_STATUS_ERROR);
00323 }
00324 }
00325
00326
00327
00328 void LLApp::setQuitting()
00329 {
00330 if (!isExiting())
00331 {
00332
00333 llinfos << "Setting app state to QUITTING" << llendl;
00334 setStatus(APP_STATUS_QUITTING);
00335 }
00336 }
00337
00338
00339
00340 void LLApp::setStopped()
00341 {
00342 setStatus(APP_STATUS_STOPPED);
00343 }
00344
00345
00346
00347 bool LLApp::isStopped()
00348 {
00349 return (APP_STATUS_STOPPED == sStatus);
00350 }
00351
00352
00353
00354 bool LLApp::isRunning()
00355 {
00356 return (APP_STATUS_RUNNING == sStatus);
00357 }
00358
00359
00360
00361 bool LLApp::isError()
00362 {
00363 return (APP_STATUS_ERROR == sStatus);
00364 }
00365
00366
00367
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
00380 U32 LLApp::getSigChildCount()
00381 {
00382 if (sSigChildCount)
00383 {
00384 return U32(*sSigChildCount);
00385 }
00386 return 0;
00387 }
00388
00389
00390 void LLApp::incSigChildCount()
00391 {
00392 if (sSigChildCount)
00393 {
00394 (*sSigChildCount)++;
00395 }
00396 }
00397
00398 #endif
00399
00400
00401
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
00415
00416
00417
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
00428 LLApp::setError();
00429
00430
00431
00432 while (!LLApp::isStopped())
00433 {
00434 ms_sleep(10);
00435 }
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448 retval = EXCEPTION_EXECUTE_HANDLER;
00449 return retval;
00450 }
00451
00452
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:
00461 case CTRL_C_EVENT:
00462
00463 if (LLApp::isQuitting() || LLApp::isError())
00464 {
00465
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
00505 ms_sleep(10);
00506
00507
00508
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
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
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
00543 sigaction(SIGCHLD, &act, NULL);
00544 sigaction(SIGUSR2, &act, NULL);
00545
00546
00547 sigaction(SIGHUP, &act, NULL);
00548 sigaction(SIGTERM, &act, NULL);
00549 sigaction(SIGINT, &act, NULL);
00550
00551
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
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
00577 sigaction(SIGCHLD, &act, NULL);
00578
00579
00580 sigaction(SIGHUP, &act, NULL);
00581 sigaction(SIGTERM, &act, NULL);
00582 sigaction(SIGINT, &act, NULL);
00583
00584
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
00594
00595
00596
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
00613
00614
00615
00616
00617
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
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
00643
00644 if (LLApp::isQuitting() || LLApp::isError())
00645 {
00646
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
00669 if (LLApp::sLogInSignal)
00670 {
00671 llwarns << "Signal handler - Handling smackdown signal!" << llendl;
00672 }
00673 else
00674 {
00675
00676 LLError::setDefaultLevel(LLError::LEVEL_NONE);
00677 }
00678
00679
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
00690
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
00706 LLApp::setError();
00707
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