/* * Signal handling for Plan 9 programs. * We stubbornly use the strings from Plan 9 instead * of the enumerated Unix constants. * There are some weird translations. In particular, * a "kill" note is the same as SIGTERM in Unix. * There is no equivalent note to Unix's SIGKILL, since * it's not a deliverable signal anyway. * * We do not handle SIGABRT or SIGSEGV, mainly because * the thread library queues its notes for later, and we want * to dump core with the state at time of delivery. * * We have to add some extra entry points to provide the * ability to tweak which signals are deliverable and which * are acted upon. Notifydisable and notifyenable play with * the process signal mask. Notifyignore enables the signal * but will not call notifyf when it comes in. This is occasionally * useful. */ #include #include #define NOPLAN9DEFINES #include extern char *_p9sigstr(int, char*); extern int _p9strsig(char*); typedef struct Sig Sig; struct Sig { int sig; /* signal number */ int flags; }; enum { Restart = 1<<0, Ignore = 1<<1, NoNotify = 1<<2, }; static Sig sigs[] = { SIGHUP, 0, SIGINT, 0, SIGQUIT, 0, SIGILL, 0, SIGTRAP, 0, /* SIGABRT, 0, */ #ifdef SIGEMT SIGEMT, 0, #endif SIGFPE, 0, SIGBUS, 0, /* SIGSEGV, 0, */ SIGCHLD, Restart|Ignore, SIGSYS, 0, SIGPIPE, Ignore, SIGALRM, 0, SIGTERM, 0, SIGTSTP, Restart|Ignore|NoNotify, /* SIGTTIN, Restart|Ignore, */ /* SIGTTOU, Restart|Ignore, */ SIGXCPU, 0, SIGXFSZ, 0, SIGVTALRM, 0, SIGUSR1, 0, SIGUSR2, 0, #ifdef SIGWINCH SIGWINCH, Restart|Ignore|NoNotify, #endif #ifdef SIGINFO SIGINFO, Restart|Ignore|NoNotify, #endif }; static Sig* findsig(int s) { int i; for(i=0; ib)){ case 0: if(notifyf) (*notifyf)(nil, _p9sigstr(sig, tmp)); /* fall through */ case 1: /* noted(NDFLT) */ if(0)print("DEFAULT %d\n", sig); s = findsig(sig); if(s && (s->flags&Ignore)) return; signal(sig, SIG_DFL); raise(sig); _exit(1); case 2: /* noted(NCONT) */ if(0)print("HANDLED %d\n", sig); return; } } static void signonotify(int sig) { USED(sig); } int noted(int v) { p9longjmp((*_notejmpbuf)()->b, v==NCONT ? 2 : 1); abort(); return 0; } int notify(void (*f)(void*, char*)) { static int init; notifyf = f; if(!init){ init = 1; noteinit(); } return 0; } /* * Nonsense about enabling and disabling signals. */ typedef void Sighandler(int); static Sighandler* handler(int s) { struct sigaction sa; sigaction(s, nil, &sa); return sa.sa_handler; } static int notesetenable(int sig, int enabled) { sigset_t mask, omask; if(sig == 0) return -1; sigemptyset(&mask); sigaddset(&mask, sig); sigprocmask(enabled ? SIG_UNBLOCK : SIG_BLOCK, &mask, &omask); return !sigismember(&omask, sig); } int noteenable(char *msg) { return notesetenable(_p9strsig(msg), 1); } int notedisable(char *msg) { return notesetenable(_p9strsig(msg), 0); } static int notifyseton(int s, int on) { Sig *sig; struct sigaction sa, osa; sig = findsig(s); if(sig == nil) return -1; memset(&sa, 0, sizeof sa); sa.sa_handler = on ? signotify : signonotify; if(sig->flags&Restart) sa.sa_flags |= SA_RESTART; /* * We can't allow signals within signals because there's * only one jump buffer. */ sigfillset(&sa.sa_mask); /* * Install handler. */ sigaction(sig->sig, &sa, &osa); return osa.sa_handler == signotify; } int notifyon(char *msg) { return notifyseton(_p9strsig(msg), 1); } int notifyoff(char *msg) { return notifyseton(_p9strsig(msg), 0); } /* * Initialization follows sigs table. */ static void noteinit(void) { int i; Sig *sig; for(i=0; isig) != SIG_DFL) continue; notifyseton(sig->sig, !(sig->flags&NoNotify)); } }