Use ev_signal to avoid async-unsafe functions (Thanks Markus)

Functions such as fprintf() might be unsafe to use in a signal handler,
see http://stackoverflow.com/questions/3941271/#answer-3941563

By using ev_signal, libev will use a tiny signal handler which just
passes on the information and then calls (outside of the signal handler)
our callback function which can use fprintf() and other unsafe
functions.

fixes #803
This commit is contained in:
Michael Stapelberg 2012-09-21 16:35:25 +02:00
parent d638e3029a
commit 514265b529
1 changed files with 20 additions and 17 deletions

View File

@ -232,13 +232,15 @@ static void i3_exit(void) {
* Unlinks the SHM log and re-raises the signal. * Unlinks the SHM log and re-raises the signal.
* *
*/ */
static void handle_signal(int sig, siginfo_t *info, void *data) { static void handle_signal(struct ev_loop *loop, ev_signal *w, int revents) {
int sig = w->signum;
fprintf(stderr, "Received signal %d, terminating\n", sig); fprintf(stderr, "Received signal %d, terminating\n", sig);
if (*shmlogname != '\0') { if (*shmlogname != '\0') {
fprintf(stderr, "Closing SHM log \"%s\"\n", shmlogname); fprintf(stderr, "Closing SHM log \"%s\"\n", shmlogname);
shm_unlink(shmlogname); shm_unlink(shmlogname);
} }
fflush(stderr); fflush(stderr);
ev_signal_stop(loop, w);
raise(sig); raise(sig);
} }
@ -780,31 +782,32 @@ int main(int argc, char *argv[]) {
} }
xcb_ungrab_server(conn); xcb_ungrab_server(conn);
struct sigaction action;
action.sa_sigaction = handle_signal; #define HANDLE_SIGNAL_EV(signum) \
action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO; do { \
sigemptyset(&action.sa_mask); struct ev_signal *signal_watcher = scalloc(sizeof(struct ev_signal)); \
ev_signal_init(signal_watcher, handle_signal, signum); \
ev_signal_start(main_loop, signal_watcher); \
} while (0)
if (!disable_signalhandler) if (!disable_signalhandler)
setup_signal_handler(); setup_signal_handler();
else { else {
/* Catch all signals with default action "Core", see signal(7) */ /* Catch all signals with default action "Core", see signal(7) */
if (sigaction(SIGQUIT, &action, NULL) == -1 || HANDLE_SIGNAL_EV(SIGQUIT);
sigaction(SIGILL, &action, NULL) == -1 || HANDLE_SIGNAL_EV(SIGILL);
sigaction(SIGABRT, &action, NULL) == -1 || HANDLE_SIGNAL_EV(SIGABRT);
sigaction(SIGFPE, &action, NULL) == -1 || HANDLE_SIGNAL_EV(SIGFPE);
sigaction(SIGSEGV, &action, NULL) == -1) HANDLE_SIGNAL_EV(SIGSEGV);
ELOG("Could not setup signal handler");
} }
/* Catch all signals with default action "Term", see signal(7) */ /* Catch all signals with default action "Term", see signal(7) */
if (sigaction(SIGHUP, &action, NULL) == -1 || HANDLE_SIGNAL_EV(SIGHUP);
sigaction(SIGINT, &action, NULL) == -1 || HANDLE_SIGNAL_EV(SIGINT);
sigaction(SIGALRM, &action, NULL) == -1 || HANDLE_SIGNAL_EV(SIGALRM);
sigaction(SIGUSR1, &action, NULL) == -1 || HANDLE_SIGNAL_EV(SIGTERM);
sigaction(SIGUSR2, &action, NULL) == -1) HANDLE_SIGNAL_EV(SIGUSR1);
ELOG("Could not setup signal handler"); HANDLE_SIGNAL_EV(SIGUSR2);
/* Ignore SIGPIPE to survive errors when an IPC client disconnects /* Ignore SIGPIPE to survive errors when an IPC client disconnects
* while we are sending him a message */ * while we are sending him a message */