github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/src/lib9/notify.c (about)

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