The Go Programming Language

Text file src/lib9/notify.c

     1	/*
     2	Plan 9 from User Space src/lib9/notify.c
     3	http://code.swtch.com/plan9port/src/tip/src/lib9/notify.c
     4	
     5	Copyright 2001-2007 Russ Cox.  All Rights Reserved.
     6	
     7	Permission is hereby granted, free of charge, to any person obtaining a copy
     8	of this software and associated documentation files (the "Software"), to deal
     9	in the Software without restriction, including without limitation the rights
    10	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    11	copies of the Software, and to permit persons to whom the Software is
    12	furnished to do so, subject to the following conditions:
    13	
    14	The above copyright notice and this permission notice shall be included in
    15	all copies or substantial portions of the Software.
    16	
    17	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    18	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    19	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    20	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    21	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    22	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    23	THE SOFTWARE.
    24	*/
    25	
    26	/*
    27	 * Signal handling for Plan 9 programs.
    28	 * We stubbornly use the strings from Plan 9 instead
    29	 * of the enumerated Unix constants.
    30	 * There are some weird translations.  In particular,
    31	 * a "kill" note is the same as SIGTERM in Unix.
    32	 * There is no equivalent note to Unix's SIGKILL, since
    33	 * it's not a deliverable signal anyway.
    34	 *
    35	 * We do not handle SIGABRT or SIGSEGV, mainly because
    36	 * the thread library queues its notes for later, and we want
    37	 * to dump core with the state at time of delivery.
    38	 *
    39	 * We have to add some extra entry points to provide the
    40	 * ability to tweak which signals are deliverable and which
    41	 * are acted upon.  Notifydisable and notifyenable play with
    42	 * the process signal mask.  Notifyignore enables the signal
    43	 * but will not call notifyf when it comes in.  This is occasionally
    44	 * useful.
    45	 */
    46	
    47	#include <u.h>
    48	#include <signal.h>
    49	#define NOPLAN9DEFINES
    50	#include <libc.h>
    51	
    52	extern char *_p9sigstr(int, char*);
    53	extern int _p9strsig(char*);
    54	
    55	typedef struct Sig Sig;
    56	struct Sig
    57	{
    58		int sig;			/* signal number */
    59		int flags;
    60	};
    61	
    62	enum
    63	{
    64		Restart = 1<<0,
    65		Ignore = 1<<1
    66	};
    67	
    68	static Sig sigs[] = {
    69		SIGHUP,		0,
    70		SIGINT,		0,
    71		SIGQUIT,		0,
    72		SIGILL,		0,
    73		SIGTRAP,		0,
    74	/*	SIGABRT, 		0, 	*/
    75	#ifdef SIGEMT
    76		SIGEMT,		0,
    77	#endif
    78		SIGFPE,		0,
    79		SIGBUS,		0,
    80	/*	SIGSEGV, 		0, 	*/
    81		SIGCHLD,		Restart|Ignore,
    82		SIGSYS,		0,
    83		SIGPIPE,		Ignore,
    84		SIGALRM,		0,
    85		SIGTERM,		0,
    86		SIGTSTP,		Restart|Ignore,
    87	/*	SIGTTIN,		Restart|Ignore, */
    88	/*	SIGTTOU,		Restart|Ignore, */
    89		SIGXCPU,		0,
    90		SIGXFSZ,		0,
    91		SIGVTALRM,	0,
    92		SIGUSR1,		0,
    93		SIGUSR2,		0,
    94	#ifdef SIGWINCH
    95		SIGWINCH,	Restart|Ignore,
    96	#endif
    97	#ifdef SIGINFO
    98		SIGINFO,		Restart|Ignore,
    99	#endif
   100	};
   101	
   102	static Sig*
   103	findsig(int s)
   104	{
   105		int i;
   106	
   107		for(i=0; i<nelem(sigs); i++)
   108			if(sigs[i].sig == s)
   109				return &sigs[i];
   110		return nil;
   111	}
   112	
   113	/*
   114	 * The thread library initializes _notejmpbuf to its own
   115	 * routine which provides a per-pthread jump buffer.
   116	 * If we're not using the thread library, we assume we are
   117	 * single-threaded.
   118	 */
   119	typedef struct Jmp Jmp;
   120	struct Jmp
   121	{
   122		p9jmp_buf b;
   123	};
   124	
   125	static Jmp onejmp;
   126	
   127	static Jmp*
   128	getonejmp(void)
   129	{
   130		return &onejmp;
   131	}
   132	
   133	Jmp *(*_notejmpbuf)(void) = getonejmp;
   134	static void noteinit(void);
   135	
   136	/*
   137	 * Actual signal handler.
   138	 */
   139	
   140	static void (*notifyf)(void*, char*);	/* Plan 9 handler */
   141	
   142	static void
   143	signotify(int sig)
   144	{
   145		char tmp[64];
   146		Jmp *j;
   147		Sig *s;
   148	
   149		j = (*_notejmpbuf)();
   150		switch(p9setjmp(j->b)){
   151		case 0:
   152			if(notifyf)
   153				(*notifyf)(nil, _p9sigstr(sig, tmp));
   154			/* fall through */
   155		case 1:	/* noted(NDFLT) */
   156			if(0)print("DEFAULT %d\n", sig);
   157			s = findsig(sig);
   158			if(s && (s->flags&Ignore))
   159				return;
   160			signal(sig, SIG_DFL);
   161			raise(sig);
   162			_exit(1);
   163		case 2:	/* noted(NCONT) */
   164			if(0)print("HANDLED %d\n", sig);
   165			return;
   166		}
   167	}
   168	
   169	static void
   170	signonotify(int sig)
   171	{
   172		USED(sig);
   173	}
   174	
   175	int
   176	noted(int v)
   177	{
   178		p9longjmp((*_notejmpbuf)()->b, v==NCONT ? 2 : 1);
   179		abort();
   180		return 0;
   181	}
   182	
   183	int
   184	notify(void (*f)(void*, char*))
   185	{
   186		static int init;
   187	
   188		notifyf = f;
   189		if(!init){
   190			init = 1;
   191			noteinit();
   192		}
   193		return 0;
   194	}
   195	
   196	/*
   197	 * Nonsense about enabling and disabling signals.
   198	 */
   199	typedef void Sighandler(int);
   200	static Sighandler*
   201	handler(int s)
   202	{
   203		struct sigaction sa;
   204	
   205		sigaction(s, nil, &sa);
   206		return sa.sa_handler;
   207	}
   208	
   209	static int
   210	notesetenable(int sig, int enabled)
   211	{
   212		sigset_t mask, omask;
   213	
   214		if(sig == 0)
   215			return -1;
   216	
   217		sigemptyset(&mask);
   218		sigaddset(&mask, sig);
   219		sigprocmask(enabled ? SIG_UNBLOCK : SIG_BLOCK, &mask, &omask);
   220		return !sigismember(&omask, sig);
   221	}
   222	
   223	int
   224	noteenable(char *msg)
   225	{
   226		return notesetenable(_p9strsig(msg), 1);
   227	}
   228	
   229	int
   230	notedisable(char *msg)
   231	{
   232		return notesetenable(_p9strsig(msg), 0);
   233	}
   234	
   235	static int
   236	notifyseton(int s, int on)
   237	{
   238		Sig *sig;
   239		struct sigaction sa, osa;
   240	
   241		sig = findsig(s);
   242		if(sig == nil)
   243			return -1;
   244		memset(&sa, 0, sizeof sa);
   245		sa.sa_handler = on ? signotify : signonotify;
   246		if(sig->flags&Restart)
   247			sa.sa_flags |= SA_RESTART;
   248	
   249		/*
   250		 * We can't allow signals within signals because there's
   251		 * only one jump buffer.
   252		 */
   253		sigfillset(&sa.sa_mask);
   254	
   255		/*
   256		 * Install handler.
   257		 */
   258		sigaction(sig->sig, &sa, &osa);
   259		return osa.sa_handler == signotify;
   260	}
   261	
   262	int
   263	notifyon(char *msg)
   264	{
   265		return notifyseton(_p9strsig(msg), 1);
   266	}
   267	
   268	int
   269	notifyoff(char *msg)
   270	{
   271		return notifyseton(_p9strsig(msg), 0);
   272	}
   273	
   274	/*
   275	 * Initialization follows sigs table.
   276	 */
   277	static void
   278	noteinit(void)
   279	{
   280		int i;
   281		Sig *sig;
   282	
   283		for(i=0; i<nelem(sigs); i++){
   284			sig = &sigs[i];
   285			/*
   286			 * If someone has already installed a handler,
   287			 * It's probably some ld preload nonsense,
   288			 * like pct (a SIGVTALRM-based profiler).
   289			 * Or maybe someone has already called notifyon/notifyoff.
   290			 * Leave it alone.
   291			 */
   292			if(handler(sig->sig) != SIG_DFL)
   293				continue;
   294			notifyseton(sig->sig, 1);
   295		}
   296	}
   297	

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.