#include #include #include #include #include typedef void (*pqsigfunc) (int signo); sigjmp_buf *PG_exception_stack; static void printmask(const char *labl) { sigset_t sigs; int i; printf("masked signals at %s: ", labl); if (sigprocmask(SIG_SETMASK, NULL, &sigs) == 0) { for (i = 1; i <= 32; i++) { // if (sigs.sigset[0] & sigmask(i)) if (sigs & sigmask(i)) printf("%d, ", i); } } else printf("failed!"); printf("\n"); fflush(stdout); } static void sigint_handler(int signo) { printmask("sigint_handler"); siglongjmp(*PG_exception_stack, 1); abort(); } static pqsigfunc pqsignal(int signo, pqsigfunc func) { struct sigaction act, oact; act.sa_handler = func; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (signo != SIGALRM) act.sa_flags |= SA_RESTART; #ifdef SA_NOCLDSTOP if (signo == SIGCHLD) act.sa_flags |= SA_NOCLDSTOP; #endif if (sigaction(signo, &act, &oact) < 0) return SIG_ERR; return oact.sa_handler; } void intermediate_func(int level) { do { sigjmp_buf *save_exception_stack = PG_exception_stack; sigjmp_buf local_sigjmp_buf; if (sigsetjmp(local_sigjmp_buf, 0) == 0) { PG_exception_stack = &local_sigjmp_buf; if (level > 0) intermediate_func(level - 1); else { kill(getpid(), SIGINT); sleep(1); abort(); } } else { PG_exception_stack = save_exception_stack; printmask("inner longjmp catcher"); siglongjmp(*PG_exception_stack, 1); abort(); } PG_exception_stack = save_exception_stack; } while (0); } int main(int argc, char **argv) { sigjmp_buf outer_sigjmp_buf; printmask("startup"); pqsignal(SIGINT, sigint_handler); if (sigsetjmp(outer_sigjmp_buf, 1) != 0) { printmask("outer longjmp catcher"); return 0; } PG_exception_stack = &outer_sigjmp_buf; intermediate_func(2); printmask("unexpected exit"); return 0; }