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