273 lines · 4.6 KB · C
RawDownload
/* * 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 <u.h>#include <signal.h>#define NOPLAN9DEFINES#include <libc.h> 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; i<nelem(sigs); i++)		if(sigs[i].sig == s)			return &sigs[i];	return nil;} /* * The thread library initializes _notejmpbuf to its own * routine which provides a per-pthread jump buffer. * If we're not using the thread library, we assume we are * single-threaded. */typedef struct Jmp Jmp;struct Jmp{	p9jmp_buf b;}; static Jmp onejmp; static Jmp*getonejmp(void){	return &onejmp;} Jmp *(*_notejmpbuf)(void) = getonejmp;static void noteinit(void); /* * Actual signal handler.  */ static void (*notifyf)(void*, char*);	/* Plan 9 handler */ static voidsignotify(int sig){	char tmp[64];	Jmp *j;	Sig *s; 	j = (*_notejmpbuf)();	switch(p9setjmp(j->b)){	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 voidsignonotify(int sig){	USED(sig);} intnoted(int v){	p9longjmp((*_notejmpbuf)()->b, v==NCONT ? 2 : 1);	abort();	return 0;} intnotify(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 intnotesetenable(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);	} intnoteenable(char *msg){	return notesetenable(_p9strsig(msg), 1);} intnotedisable(char *msg){	return notesetenable(_p9strsig(msg), 0);} static intnotifyseton(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;} intnotifyon(char *msg){	return notifyseton(_p9strsig(msg), 1);} intnotifyoff(char *msg){	return notifyseton(_p9strsig(msg), 0);} /* * Initialization follows sigs table. */static voidnoteinit(void){	int i;	Sig *sig; 	for(i=0; i<nelem(sigs); i++){		sig = &sigs[i];		/*		 * If someone has already installed a handler,		 * It's probably some ld preload nonsense,		 * like pct (a SIGVTALRM-based profiler).		 * Or maybe someone has already called notifyon/notifyoff.		 * Leave it alone.		 */		if(handler(sig->sig) != SIG_DFL)			continue;		notifyseton(sig->sig, !(sig->flags&NoNotify));	}}