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