I’ve a program, which installs a signal handler for SIGSEGV
. In signal handler ( I try to catch crash ) I restart my application.
But when my application is resurrected it doesn’t handle SIGSEGV
anymore.
Here’s an example:
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> const char * app = 0; void sig_handler(int signo) { puts("sig_handler"); const pid_t p = fork(); if (p == 0) { printf("Running app %sn", app); execl(app, 0); } exit(1); } int main(int argc, char** argv) { app = argv[0]; struct sigaction act; sigemptyset(&act.sa_mask); act.sa_handler = sig_handler; act.sa_flags = 0; const int status = sigaction(SIGSEGV, &act, 0) == 0; printf("signaction = %dn", status); sleep(5); int* a = 0; int b = *a; return 0; }
what I get in output is:
./signals signaction = 1 sig_handler Running app ./signals signaction = 1
So I can see sighandler was set in right way, but resurrected app simply crashed silently.
What am I missing?
Advertisement
Answer
What you’re missing is that, by default, when you handle a signal, any additional delivery of that signal is blocked until the handling function returns. Since you never return from your signal handler (you call execl()
instead) then your second SIGSEGV
isn’t being delivered. It’s waiting until your signal handler function returns, which it never will.
To get the results you seem to want, you have to change this default behavior. The easiest way to do that is to set the appropriate flag when you register the signal handler:
act.sa_flags = SA_NODEFER;
and you’ll get the recursive behavior you seem to be looking for. Your other option is to unblock it with sigprocmask()
before your execl()
call.
Couple of other ancillary points:
puts()
,printf()
,execl()
andexit()
are not async-safe, and shouldn’t be called from a signal handler.execle()
and_exit()
would be OK.You’re not calling
execl()
properly. The first argument should be the application name, soexecl(app, app, (char *)0);
would be correct. The cast tochar *
, which you omit, is required.