llapp.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:18k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llapp.cpp
  3.  * @brief Implementation of the LLApp class.
  4.  *
  5.  * $LicenseInfo:firstyear=2003&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2003-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "linden_common.h"
  33. #include "llapp.h"
  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 "lleventtimer.h"
  43. //
  44. // Signal handling
  45. //
  46. // Windows uses structured exceptions, so it's handled a bit differently.
  47. //
  48. #if LL_WINDOWS
  49. LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop);
  50. BOOL ConsoleCtrlHandler(DWORD fdwCtrlType);
  51. #else
  52. # include <signal.h>
  53. # include <unistd.h> // for fork()
  54. void setup_signals();
  55. void default_unix_signal_handler(int signum, siginfo_t *info, void *);
  56. # if LL_DARWIN
  57. /* OSX doesn't support SIGRT* */
  58. S32 LL_SMACKDOWN_SIGNAL = SIGUSR1;
  59. S32 LL_HEARTBEAT_SIGNAL = SIGUSR2;
  60. # else // linux or (assumed) other similar unixoid
  61. /* We want reliable delivery of our signals - SIGRT* is it. */
  62. /* Old LinuxThreads versions eat SIGRTMIN+0 to SIGRTMIN+2, avoid those. */
  63. /* Note that SIGRTMIN/SIGRTMAX may expand to a glibc function call with a
  64.    nonconstant result so these are not consts and cannot be used in constant-
  65.    expressions.  SIGRTMAX may return -1 on rare broken setups. */
  66. S32 LL_SMACKDOWN_SIGNAL = (SIGRTMAX >= 0) ? (SIGRTMAX-1) : SIGUSR1;
  67. S32 LL_HEARTBEAT_SIGNAL = (SIGRTMAX >= 0) ? (SIGRTMAX-0) : SIGUSR2;
  68. # endif // LL_DARWIN
  69. #endif // LL_WINDOWS
  70. // the static application instance
  71. LLApp* LLApp::sApplication = NULL;
  72. // Local flag for whether or not to do logging in signal handlers.
  73. //static
  74. BOOL LLApp::sLogInSignal = FALSE;
  75. // static
  76. LLApp::EAppStatus LLApp::sStatus = LLApp::APP_STATUS_STOPPED; // Keeps track of application status
  77. LLAppErrorHandler LLApp::sErrorHandler = NULL;
  78. LLAppErrorHandler LLApp::sSyncErrorHandler = NULL;
  79. BOOL LLApp::sErrorThreadRunning = FALSE;
  80. #if !LL_WINDOWS
  81. LLApp::child_map LLApp::sChildMap;
  82. LLAtomicU32* LLApp::sSigChildCount = NULL;
  83. LLAppChildCallback LLApp::sDefaultChildCallback = NULL;
  84. #endif
  85. LLApp::LLApp() : mThreadErrorp(NULL)
  86. {
  87. commonCtor();
  88. }
  89. void LLApp::commonCtor()
  90. {
  91. // Set our status to running
  92. setStatus(APP_STATUS_RUNNING);
  93. LLCommon::initClass();
  94. #if !LL_WINDOWS
  95. // This must be initialized before the error handler.
  96. sSigChildCount = new LLAtomicU32(0);
  97. #endif
  98. // initialize the options structure. We need to make this an array
  99. // because the structured data will not auto-allocate if we
  100. // reference an invalid location with the [] operator.
  101. mOptions = LLSD::emptyArray();
  102. LLSD sd;
  103. for(int i = 0; i < PRIORITY_COUNT; ++i)
  104. {
  105. mOptions.append(sd);
  106. }
  107. // Make sure we clean up APR when we exit
  108. // Don't need to do this if we're cleaning up APR in the destructor
  109. //atexit(ll_cleanup_apr);
  110. // Set the application to this instance.
  111. sApplication = this;
  112. }
  113. LLApp::LLApp(LLErrorThread *error_thread) :
  114. mThreadErrorp(error_thread)
  115. {
  116. commonCtor();
  117. }
  118. LLApp::~LLApp()
  119. {
  120. #if !LL_WINDOWS
  121. delete sSigChildCount;
  122. sSigChildCount = NULL;
  123. #endif
  124. // reclaim live file memory
  125. std::for_each(mLiveFiles.begin(), mLiveFiles.end(), DeletePointer());
  126. mLiveFiles.clear();
  127. setStopped();
  128. // HACK: wait for the error thread to clean itself
  129. ms_sleep(20);
  130. if (mThreadErrorp)
  131. {
  132. delete mThreadErrorp;
  133. mThreadErrorp = NULL;
  134. }
  135. LLCommon::cleanupClass();
  136. }
  137. // static
  138. LLApp* LLApp::instance()
  139. {
  140. return sApplication;
  141. }
  142. LLSD LLApp::getOption(const std::string& name) const
  143. {
  144. LLSD rv;
  145. LLSD::array_const_iterator iter = mOptions.beginArray();
  146. LLSD::array_const_iterator end = mOptions.endArray();
  147. for(; iter != end; ++iter)
  148. {
  149. rv = (*iter)[name];
  150. if(rv.isDefined()) break;
  151. }
  152. return rv;
  153. }
  154. bool LLApp::parseCommandOptions(int argc, char** argv)
  155. {
  156. LLSD commands;
  157. std::string name;
  158. std::string value;
  159. for(int ii = 1; ii < argc; ++ii)
  160. {
  161. if(argv[ii][0] != '-')
  162. {
  163. llinfos << "Did not find option identifier while parsing token: "
  164. << argv[ii] << llendl;
  165. return false;
  166. }
  167. int offset = 1;
  168. if(argv[ii][1] == '-') ++offset;
  169. name.assign(&argv[ii][offset]);
  170. if(((ii+1) >= argc) || (argv[ii+1][0] == '-'))
  171. {
  172. // we found another option after this one or we have
  173. // reached the end. simply record that this option was
  174. // found and continue.
  175. int flag = name.compare("logfile");
  176. if (0 == flag)
  177. {
  178. commands[name] = "log";
  179. }
  180. else
  181. {
  182. commands[name] = true;
  183. }
  184. continue;
  185. }
  186. ++ii;
  187. value.assign(argv[ii]);
  188. commands[name] = value;
  189. }
  190. setOptionData(PRIORITY_COMMAND_LINE, commands);
  191. return true;
  192. }
  193. void LLApp::manageLiveFile(LLLiveFile* livefile)
  194. {
  195. if(!livefile) return;
  196. livefile->checkAndReload();
  197. livefile->addToEventTimer();
  198. mLiveFiles.push_back(livefile);
  199. }
  200. bool LLApp::setOptionData(OptionPriority level, LLSD data)
  201. {
  202. if((level < 0)
  203.    || (level >= PRIORITY_COUNT)
  204.    || (data.type() != LLSD::TypeMap))
  205. {
  206. return false;
  207. }
  208. mOptions[level] = data;
  209. return true;
  210. }
  211. LLSD LLApp::getOptionData(OptionPriority level)
  212. {
  213. if((level < 0) || (level >= PRIORITY_COUNT))
  214. {
  215. return LLSD();
  216. }
  217. return mOptions[level];
  218. }
  219. void LLApp::stepFrame()
  220. {
  221. LLFrameTimer::updateFrameTime();
  222. LLFrameTimer::updateFrameCount();
  223. LLEventTimer::updateClass();
  224. mRunner.run();
  225. }
  226. void LLApp::setupErrorHandling()
  227. {
  228. // Error handling is done by starting up an error handling thread, which just sleeps and
  229. // occasionally checks to see if the app is in an error state, and sees if it needs to be run.
  230. #if LL_WINDOWS
  231. // Windows doesn't have the same signal handling mechanisms as UNIX, thus APR doesn't provide
  232. // a signal handling thread implementation.
  233. // What we do is install an unhandled exception handler, which will try to do the right thing
  234. // in the case of an error (generate a minidump)
  235. // Disable this until the viewer gets ported so server crashes can be JIT debugged.
  236. //LPTOP_LEVEL_EXCEPTION_FILTER prev_filter;
  237. //prev_filter = SetUnhandledExceptionFilter(default_windows_exception_handler);
  238. // This sets a callback to handle w32 signals to the console window.
  239. // The viewer shouldn't be affected, sicne its a windowed app.
  240. SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ConsoleCtrlHandler, TRUE);
  241. #else
  242. //
  243. // Start up signal handling.
  244. //
  245. // There are two different classes of signals.  Synchronous signals are delivered to a specific
  246. // thread, asynchronous signals can be delivered to any thread (in theory)
  247. //
  248. setup_signals();
  249. #endif
  250. startErrorThread();
  251. }
  252. void LLApp::startErrorThread()
  253. {
  254. //
  255. // Start the error handling thread, which is responsible for taking action
  256. // when the app goes into the APP_STATUS_ERROR state
  257. //
  258. if(!mThreadErrorp)
  259. {
  260. llinfos << "Starting error thread" << llendl;
  261. mThreadErrorp = new LLErrorThread();
  262. mThreadErrorp->setUserData((void *) this);
  263. mThreadErrorp->start();
  264. }
  265. }
  266. void LLApp::setErrorHandler(LLAppErrorHandler handler)
  267. {
  268. LLApp::sErrorHandler = handler;
  269. }
  270. void LLApp::setSyncErrorHandler(LLAppErrorHandler handler)
  271. {
  272. LLApp::sSyncErrorHandler = handler;
  273. }
  274. // static
  275. void LLApp::runSyncErrorHandler()
  276. {
  277. if (LLApp::sSyncErrorHandler)
  278. {
  279. LLApp::sSyncErrorHandler();
  280. }
  281. }
  282. // static
  283. void LLApp::runErrorHandler()
  284. {
  285. if (LLApp::sErrorHandler)
  286. {
  287. LLApp::sErrorHandler();
  288. }
  289. //llinfos << "App status now STOPPED" << llendl;
  290. LLApp::setStopped();
  291. }
  292. // static
  293. void LLApp::setStatus(EAppStatus status)
  294. {
  295. sStatus = status;
  296. }
  297. // static
  298. void LLApp::setError()
  299. {
  300. if (!isError())
  301. {
  302. // perform any needed synchronous error-handling
  303. runSyncErrorHandler();
  304. // set app status to ERROR so that the LLErrorThread notices
  305. setStatus(APP_STATUS_ERROR);
  306. }
  307. }
  308. // static
  309. void LLApp::setQuitting()
  310. {
  311. if (!isExiting())
  312. {
  313. // If we're already exiting, we don't want to reset our state back to quitting.
  314. llinfos << "Setting app state to QUITTING" << llendl;
  315. setStatus(APP_STATUS_QUITTING);
  316. }
  317. }
  318. // static
  319. void LLApp::setStopped()
  320. {
  321. setStatus(APP_STATUS_STOPPED);
  322. }
  323. // static
  324. bool LLApp::isStopped()
  325. {
  326. return (APP_STATUS_STOPPED == sStatus);
  327. }
  328. // static
  329. bool LLApp::isRunning()
  330. {
  331. return (APP_STATUS_RUNNING == sStatus);
  332. }
  333. // static
  334. bool LLApp::isError()
  335. {
  336. return (APP_STATUS_ERROR == sStatus);
  337. }
  338. // static
  339. bool LLApp::isQuitting()
  340. {
  341. return (APP_STATUS_QUITTING == sStatus);
  342. }
  343. bool LLApp::isExiting()
  344. {
  345. return isQuitting() || isError();
  346. }
  347. #if !LL_WINDOWS
  348. // static
  349. U32 LLApp::getSigChildCount()
  350. {
  351. if (sSigChildCount)
  352. {
  353. return U32(*sSigChildCount);
  354. }
  355. return 0;
  356. }
  357. // static
  358. void LLApp::incSigChildCount()
  359. {
  360. if (sSigChildCount)
  361. {
  362. (*sSigChildCount)++;
  363. }
  364. }
  365. #endif
  366. // static
  367. int LLApp::getPid()
  368. {
  369. #if LL_WINDOWS
  370. return 0;
  371. #else
  372. return getpid();
  373. #endif
  374. }
  375. #if LL_WINDOWS
  376. LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop)
  377. {
  378. // Translate the signals/exceptions into cross-platform stuff
  379. // Windows implementation
  380. // Make sure the user sees something to indicate that the app crashed.
  381. LONG retval;
  382. if (LLApp::isError())
  383. {
  384. llwarns << "Got another fatal signal while in the error handler, die now!" << llendl;
  385. retval = EXCEPTION_EXECUTE_HANDLER;
  386. return retval;
  387. }
  388. // Flag status to error, so thread_error starts its work
  389. LLApp::setError();
  390. // Block in the exception handler until the app has stopped
  391. // This is pretty sketchy, but appears to work just fine
  392. while (!LLApp::isStopped())
  393. {
  394. ms_sleep(10);
  395. }
  396. //
  397. // Generate a minidump if we can.
  398. //
  399. // TODO: This needs to be ported over form the viewer-specific
  400. // LLWinDebug class
  401. //
  402. // At this point, we always want to exit the app.  There's no graceful
  403. // recovery for an unhandled exception.
  404. // 
  405. // Just kill the process.
  406. retval = EXCEPTION_EXECUTE_HANDLER;
  407. return retval;
  408. }
  409. // Win32 doesn't support signals. This is used instead.
  410. BOOL ConsoleCtrlHandler(DWORD fdwCtrlType) 
  411. switch (fdwCtrlType) 
  412.   case CTRL_BREAK_EVENT: 
  413. case CTRL_LOGOFF_EVENT: 
  414. case CTRL_SHUTDOWN_EVENT: 
  415. case CTRL_CLOSE_EVENT: // From end task or the window close button.
  416. case CTRL_C_EVENT:  // from CTRL-C on the keyboard
  417. // Just set our state to quitting, not error
  418. if (LLApp::isQuitting() || LLApp::isError())
  419. {
  420. // We're already trying to die, just ignore this signal
  421. if (LLApp::sLogInSignal)
  422. {
  423. llinfos << "Signal handler - Already trying to quit, ignoring signal!" << llendl;
  424. }
  425. return TRUE;
  426. }
  427. LLApp::setQuitting();
  428. return TRUE; 
  429. default: 
  430. return FALSE; 
  431. #else //!LL_WINDOWS
  432. void LLApp::setChildCallback(pid_t pid, LLAppChildCallback callback)
  433. {
  434. LLChildInfo child_info;
  435. child_info.mCallback = callback;
  436. LLApp::sChildMap[pid] = child_info;
  437. }
  438. void LLApp::setDefaultChildCallback(LLAppChildCallback callback)
  439. {
  440. LLApp::sDefaultChildCallback = callback;
  441. }
  442. pid_t LLApp::fork()
  443. {
  444. fflush(NULL); // flush all buffers before the child inherits them
  445. pid_t pid = ::fork();
  446. if( pid < 0 )
  447. {
  448. int system_error = errno;
  449. llwarns << "Unable to fork! Operating system error code: "
  450. << system_error << llendl;
  451. }
  452. else if (pid == 0)
  453. {
  454. // Sleep a bit to allow the parent to set up child callbacks.
  455. ms_sleep(10);
  456. // We need to disable signal handling, because we don't have a
  457. // signal handling thread anymore.
  458. setupErrorHandling();
  459. }
  460. else
  461. {
  462. llinfos << "Forked child process " << pid << llendl;
  463. }
  464. return pid;
  465. }
  466. void setup_signals()
  467. {
  468. //
  469. // Set up signal handlers that may result in program termination
  470. //
  471. struct sigaction act;
  472. act.sa_sigaction = default_unix_signal_handler;
  473. sigemptyset( &act.sa_mask );
  474. act.sa_flags = SA_SIGINFO;
  475. // Synchronous signals
  476. sigaction(SIGABRT, &act, NULL);
  477. sigaction(SIGALRM, &act, NULL);
  478. sigaction(SIGBUS, &act, NULL);
  479. sigaction(SIGFPE, &act, NULL);
  480. sigaction(SIGHUP, &act, NULL); 
  481. sigaction(SIGILL, &act, NULL);
  482. sigaction(SIGPIPE, &act, NULL);
  483. sigaction(SIGSEGV, &act, NULL);
  484. sigaction(SIGSYS, &act, NULL);
  485. sigaction(LL_HEARTBEAT_SIGNAL, &act, NULL);
  486. sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL);
  487. // Asynchronous signals that are normally ignored
  488. #ifndef LL_IGNORE_SIGCHLD
  489. sigaction(SIGCHLD, &act, NULL);
  490. #endif // LL_IGNORE_SIGCHLD
  491. sigaction(SIGUSR2, &act, NULL);
  492. // Asynchronous signals that result in attempted graceful exit
  493. sigaction(SIGHUP, &act, NULL);
  494. sigaction(SIGTERM, &act, NULL);
  495. sigaction(SIGINT, &act, NULL);
  496. // Asynchronous signals that result in core
  497. sigaction(SIGQUIT, &act, NULL);
  498. }
  499. void clear_signals()
  500. {
  501. struct sigaction act;
  502. act.sa_handler = SIG_DFL;
  503. sigemptyset( &act.sa_mask );
  504. act.sa_flags = SA_SIGINFO;
  505. // Synchronous signals
  506. sigaction(SIGABRT, &act, NULL);
  507. sigaction(SIGALRM, &act, NULL);
  508. sigaction(SIGBUS, &act, NULL);
  509. sigaction(SIGFPE, &act, NULL);
  510. sigaction(SIGHUP, &act, NULL); 
  511. sigaction(SIGILL, &act, NULL);
  512. sigaction(SIGPIPE, &act, NULL);
  513. sigaction(SIGSEGV, &act, NULL);
  514. sigaction(SIGSYS, &act, NULL);
  515. sigaction(LL_HEARTBEAT_SIGNAL, &act, NULL);
  516. sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL);
  517. // Asynchronous signals that are normally ignored
  518. #ifndef LL_IGNORE_SIGCHLD
  519. sigaction(SIGCHLD, &act, NULL);
  520. #endif // LL_IGNORE_SIGCHLD
  521. // Asynchronous signals that result in attempted graceful exit
  522. sigaction(SIGHUP, &act, NULL);
  523. sigaction(SIGTERM, &act, NULL);
  524. sigaction(SIGINT, &act, NULL);
  525. // Asynchronous signals that result in core
  526. sigaction(SIGUSR2, &act, NULL);
  527. sigaction(SIGQUIT, &act, NULL);
  528. }
  529. void default_unix_signal_handler(int signum, siginfo_t *info, void *)
  530. {
  531. // Unix implementation of synchronous signal handler
  532. // This runs in the thread that threw the signal.
  533. // We do the somewhat sketchy operation of blocking in here until the error handler
  534. // has gracefully stopped the app.
  535. if (LLApp::sLogInSignal)
  536. {
  537. llinfos << "Signal handler - Got signal " << signum << " - " << apr_signal_description_get(signum) << llendl;
  538. }
  539. switch (signum)
  540. {
  541. case SIGCHLD:
  542. if (LLApp::sLogInSignal)
  543. {
  544. llinfos << "Signal handler - Got SIGCHLD from " << info->si_pid << llendl;
  545. }
  546. // Check result code for all child procs for which we've
  547. // registered callbacks THIS WILL NOT WORK IF SIGCHLD IS SENT
  548. // w/o killing the child (Go, launcher!)
  549. // TODO: Now that we're using SIGACTION, we can actually
  550. // implement the launcher behavior to determine who sent the
  551. // SIGCHLD even if it doesn't result in child termination
  552. if (LLApp::sChildMap.count(info->si_pid))
  553. {
  554. LLApp::sChildMap[info->si_pid].mGotSigChild = TRUE;
  555. }
  556. LLApp::incSigChildCount();
  557. return;
  558. case SIGABRT:
  559. // Abort just results in termination of the app, no funky error handling.
  560. if (LLApp::sLogInSignal)
  561. {
  562. llwarns << "Signal handler - Got SIGABRT, terminating" << llendl;
  563. }
  564. clear_signals();
  565. raise(signum);
  566. return;
  567. case SIGINT:
  568. case SIGHUP:
  569. case SIGTERM:
  570. if (LLApp::sLogInSignal)
  571. {
  572. llwarns << "Signal handler - Got SIGINT, HUP, or TERM, exiting gracefully" << llendl;
  573. }
  574. // Graceful exit
  575. // Just set our state to quitting, not error
  576. if (LLApp::isQuitting() || LLApp::isError())
  577. {
  578. // We're already trying to die, just ignore this signal
  579. if (LLApp::sLogInSignal)
  580. {
  581. llinfos << "Signal handler - Already trying to quit, ignoring signal!" << llendl;
  582. }
  583. return;
  584. }
  585. LLApp::setQuitting();
  586. return;
  587. case SIGALRM:
  588. case SIGPIPE:
  589. case SIGUSR2:
  590. default:
  591. if (signum == LL_SMACKDOWN_SIGNAL ||
  592.     signum == SIGBUS ||
  593.     signum == SIGILL ||
  594.     signum == SIGFPE ||
  595.     signum == SIGSEGV ||
  596.     signum == SIGQUIT)
  597. if (signum == LL_SMACKDOWN_SIGNAL)
  598. {
  599. // Smackdown treated just like any other app termination, for now
  600. if (LLApp::sLogInSignal)
  601. {
  602. llwarns << "Signal handler - Handling smackdown signal!" << llendl;
  603. }
  604. else
  605. {
  606. // Don't log anything, even errors - this is because this signal could happen anywhere.
  607. LLError::setDefaultLevel(LLError::LEVEL_NONE);
  608. }
  609. // Change the signal that we reraise to SIGABRT, so we generate a core dump.
  610. signum = SIGABRT;
  611. }
  612. if (LLApp::sLogInSignal)
  613. {
  614. llwarns << "Signal handler - Handling fatal signal!" << llendl;
  615. }
  616. if (LLApp::isError())
  617. {
  618. // Received second fatal signal while handling first, just die right now
  619. // Set the signal handlers back to default before handling the signal - this makes the next signal wipe out the app.
  620. clear_signals();
  621. if (LLApp::sLogInSignal)
  622. {
  623. llwarns << "Signal handler - Got another fatal signal while in the error handler, die now!" << llendl;
  624. }
  625. raise(signum);
  626. return;
  627. }
  628. if (LLApp::sLogInSignal)
  629. {
  630. llwarns << "Signal handler - Flagging error status and waiting for shutdown" << llendl;
  631. }
  632. // Flag status to ERROR, so thread_error does its work.
  633. LLApp::setError();
  634. // Block in the signal handler until somebody says that we're done.
  635. while (LLApp::sErrorThreadRunning && !LLApp::isStopped())
  636. {
  637. ms_sleep(10);
  638. }
  639. if (LLApp::sLogInSignal)
  640. {
  641. llwarns << "Signal handler - App is stopped, reraising signal" << llendl;
  642. }
  643. clear_signals();
  644. raise(signum);
  645. return;
  646. } else {
  647. if (LLApp::sLogInSignal)
  648. {
  649. llinfos << "Signal handler - Unhandled signal " << signum << ", ignoring!" << llendl;
  650. }
  651. }
  652. }
  653. }
  654. #endif // !WINDOWS