问题
Assume that a cocoa app must execute some vitally important objective-c operation before it exits (for any reason—crash or quit).
Is it possible to ensure the execution of arbitrary objective-c code in response to every crash event? (SIGINT
, SIGBUS
, SIGSEGV
, etc, ignoring the "uncatchables" (SIGSTOP
, SIGKILL
, bolt of lightning, etc.))
It would be helpful to know what your hooks are trying to do.
For example: let's say that for the app to operate, it absolutely must change the value of some mutable system-wide configuration variable X. On launch, the app takes a snapshot of X's current state and then modifies it. When the app exits successfully, it just restores X to the stashed, original value before terminating. My question is this: is it possible to ensure that X gets restored even if the app crashes?
回答1:
The short answer is no.
A longer answer is still no, but you can minimise the opportunity for not being able to reset you system-wide mutable configuration variable. In outline:
- On startup have your application spawn a faceless background process;
- The faceless background process should mutate your variable and then wait (as in
wait(2)
& friends) till its parent expires; - On expiry of its parent it resets the variable and then expires itself.
Your faceless background app should be short and simple, and therefore hopefully robust. It's far from foolproof, or safe against a user with infanticide on their minds, but it narrows the opportunities for thwarting the reset of your variable.
回答2:
No, there is no way to guarantee that any given piece of code will be executed at application termination exactly because the user might terminate the application in a fashion that cannot be caught by the application (like, for example, pulling the plug on a desktop machine).
Your code absolutely must be hardened against unexpected termination.
How much you need to harden it depends on your app. In document based apps (prior to the modern auto-saving-frequently model), losing data after last save was expected (and annoying).
For your app, you need to balance the cost of persistency with the value of the data persisted.
I'm only interested in the termination signals that can be caught.
There is a difference between "can be caught" and "can do anything useful". Lots of signals can be caught, as you've noted.
However, you really can't do anything in a signal handler. Technically, you can't even allocate memory.
As well, a signal or exception is generally generated because the application has entered into an undefined, catastrophically corrupted, state. Thus, you can't count on any internal state within the application being usable.
I've seen numerous cases where an app will attempt to save off user state when a crash occurs, only to quite merrily write corrupted state that ends up causing the user to lose significantly more data.
It would be helpful to know what your hooks are trying to do.
See the sigaction man page for more information.
Specifically, the list of functions that are safe to call includes _exit(), access(), alarm(), cfgetispeed(), cfgetospeed(), cfsetispeed(), cfsetospeed(), chdir(), chmod(), chown(), close(), creat(), dup(), dup2(), execle(), execve(), fcntl(), fork(), fpathconf(), fstat(), fsync(), getegid(), geteuid(), getgid(), getgroups(), getpgrp(), getpid(), getppid(), getuid(), kill(), link(), lseek(), mkdir(), mkfifo(), open(), pathconf(), pause(), pipe(), raise(), read(), rename(), rmdir(), setgid(), setpgid(), setsid(), setuid(), sigaction(), sigaddset(), sigdelset(), sigemptyset(), sigfillset(), sigismember(), signal(), sigpending(), sigprocmask(), sigsuspend(), sleep(), stat(), sysconf(), tcdrain(), tcflow(), tcflush(), tcgetattr(), tcgetpgrp(), tcsendbreak(), tcsetattr(), tcsetpgrp(), time(), times(), umask(), uname(), unlink(), utime(), wait(), waitpid(), write(), aio_error(), sigpause(), aio_return(), aio_suspend(), sem_post(), sigset(), strcpy(), strcat(), strncpy(), strncat(), strlcpy(), and strlcat().
All functions not in the above lists are considered to be unsafe with respect to signals. That is to say, the behaviour of such functions when called from a signal handler is undefined. In general though, signal handlers should do little more than set a flag; most other actions are not safe.
Translation: You really can't do much of anything useful in a signal handler.
Mpte a;sp tjat sogma; ,au ne de;overed pm amu tjread amd ,ogjt ne de;overed nu interrupting a currently executing function.
What I meant to type: keep in mind that signal handlers may be delivered on a random thread and might interrupt a currently executing function, too. I.e. the state of your app is likely somewhat indeterminate.
回答3:
If you want to catch signal, you can use signal handler.
signal(SIGBUS, signalHandler);
signal(SIGSEGV, signalHandler);
void signalHandler(int signal)
{
NSMutableString *crashReport = [[NSMutableString alloc] init];
void* callstack[128];
int i, frames = backtrace(callstack, 128);
char** strs = backtrace_symbols(callstack, frames);
for (i = 0; i < frames; ++i) {
//printf("%s\n", strs[i]);
[crashReport appendFormat:@"%s\n",strs[i]];
}
free(strs);
// write crashReport to file
[crashReport release];
exit(1);
}
but if crash is in NSMutableString alloc or release or in free() function, this code will not work.(As explained by bbum:
there is no way to guarantee that any given piece of code will be executed at application termination)
来源:https://stackoverflow.com/questions/12663842/ensure-objective-c-code-execution-before-cocoa-application-exits