notify.c - 9base - revived minimalist port of Plan 9 userland to Unix
 (HTM) git clone git://git.suckless.org/9base
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       notify.c (4717B)
       ---
            1 /*
            2  * Signal handling for Plan 9 programs. 
            3  * We stubbornly use the strings from Plan 9 instead 
            4  * of the enumerated Unix constants.  
            5  * There are some weird translations.  In particular,
            6  * a "kill" note is the same as SIGTERM in Unix.
            7  * There is no equivalent note to Unix's SIGKILL, since
            8  * it's not a deliverable signal anyway.
            9  *
           10  * We do not handle SIGABRT or SIGSEGV, mainly because
           11  * the thread library queues its notes for later, and we want
           12  * to dump core with the state at time of delivery.
           13  *
           14  * We have to add some extra entry points to provide the
           15  * ability to tweak which signals are deliverable and which
           16  * are acted upon.  Notifydisable and notifyenable play with
           17  * the process signal mask.  Notifyignore enables the signal
           18  * but will not call notifyf when it comes in.  This is occasionally
           19  * useful.
           20  */
           21 
           22 #include <u.h>
           23 #include <signal.h>
           24 #define NOPLAN9DEFINES
           25 #include <libc.h>
           26 
           27 extern char *_p9sigstr(int, char*);
           28 extern int _p9strsig(char*);
           29 
           30 typedef struct Sig Sig;
           31 struct Sig
           32 {
           33         int sig;                        /* signal number */
           34         int flags;
           35 };
           36 
           37 enum
           38 {
           39         Restart = 1<<0,
           40         Ignore = 1<<1,
           41         NoNotify = 1<<2,
           42 };
           43 
           44 static Sig sigs[] = {
           45         SIGHUP,                0,
           46         SIGINT,                0,
           47         SIGQUIT,                0,
           48         SIGILL,                0,
           49         SIGTRAP,                0,
           50 /*        SIGABRT,                 0,         */
           51 #ifdef SIGEMT
           52         SIGEMT,                0,
           53 #endif
           54         SIGFPE,                0,
           55         SIGBUS,                0,
           56 /*        SIGSEGV,                 0,         */
           57         SIGCHLD,                Restart|Ignore,
           58         SIGSYS,                0,
           59         SIGPIPE,                Ignore,
           60         SIGALRM,                0,
           61         SIGTERM,                0,
           62         SIGTSTP,                Restart|Ignore|NoNotify,
           63 /*        SIGTTIN,                Restart|Ignore, */
           64 /*        SIGTTOU,                Restart|Ignore, */
           65         SIGXCPU,                0,
           66         SIGXFSZ,                0,
           67         SIGVTALRM,        0,
           68         SIGUSR1,                0,
           69         SIGUSR2,                0,
           70 #ifdef SIGWINCH
           71         SIGWINCH,        Restart|Ignore|NoNotify,
           72 #endif
           73 #ifdef SIGINFO
           74         SIGINFO,                Restart|Ignore|NoNotify,
           75 #endif
           76 };
           77 
           78 static Sig*
           79 findsig(int s)
           80 {
           81         int i;
           82 
           83         for(i=0; i<nelem(sigs); i++)
           84                 if(sigs[i].sig == s)
           85                         return &sigs[i];
           86         return nil;
           87 }
           88 
           89 /*
           90  * The thread library initializes _notejmpbuf to its own
           91  * routine which provides a per-pthread jump buffer.
           92  * If we're not using the thread library, we assume we are
           93  * single-threaded.
           94  */
           95 typedef struct Jmp Jmp;
           96 struct Jmp
           97 {
           98         p9jmp_buf b;
           99 };
          100 
          101 static Jmp onejmp;
          102 
          103 static Jmp*
          104 getonejmp(void)
          105 {
          106         return &onejmp;
          107 }
          108 
          109 Jmp *(*_notejmpbuf)(void) = getonejmp;
          110 static void noteinit(void);
          111 
          112 /*
          113  * Actual signal handler. 
          114  */
          115 
          116 static void (*notifyf)(void*, char*);        /* Plan 9 handler */
          117 
          118 static void
          119 signotify(int sig)
          120 {
          121         char tmp[64];
          122         Jmp *j;
          123         Sig *s;
          124 
          125         j = (*_notejmpbuf)();
          126         switch(p9setjmp(j->b)){
          127         case 0:
          128                 if(notifyf)
          129                         (*notifyf)(nil, _p9sigstr(sig, tmp));
          130                 /* fall through */
          131         case 1:        /* noted(NDFLT) */
          132                 if(0)print("DEFAULT %d\n", sig);
          133                 s = findsig(sig);
          134                 if(s && (s->flags&Ignore))
          135                         return;
          136                 signal(sig, SIG_DFL);
          137                 raise(sig);
          138                 _exit(1);
          139         case 2:        /* noted(NCONT) */
          140                 if(0)print("HANDLED %d\n", sig);
          141                 return;
          142         }
          143 }
          144 
          145 static void
          146 signonotify(int sig)
          147 {
          148         USED(sig);
          149 }
          150 
          151 int
          152 noted(int v)
          153 {
          154         p9longjmp((*_notejmpbuf)()->b, v==NCONT ? 2 : 1);
          155         abort();
          156         return 0;
          157 }
          158 
          159 int
          160 notify(void (*f)(void*, char*))
          161 {
          162         static int init;
          163 
          164         notifyf = f;
          165         if(!init){
          166                 init = 1;
          167                 noteinit();
          168         }
          169         return 0;
          170 }
          171 
          172 /*
          173  * Nonsense about enabling and disabling signals.
          174  */
          175 typedef void Sighandler(int);
          176 static Sighandler*
          177 handler(int s)
          178 {
          179         struct sigaction sa;
          180 
          181         sigaction(s, nil, &sa);
          182         return sa.sa_handler;
          183 }
          184 
          185 static int
          186 notesetenable(int sig, int enabled)
          187 {
          188         sigset_t mask, omask;
          189 
          190         if(sig == 0)
          191                 return -1;
          192 
          193         sigemptyset(&mask);
          194         sigaddset(&mask, sig);
          195         sigprocmask(enabled ? SIG_UNBLOCK : SIG_BLOCK, &mask, &omask);
          196         return !sigismember(&omask, sig);        
          197 }
          198 
          199 int
          200 noteenable(char *msg)
          201 {
          202         return notesetenable(_p9strsig(msg), 1);
          203 }
          204 
          205 int
          206 notedisable(char *msg)
          207 {
          208         return notesetenable(_p9strsig(msg), 0);
          209 }
          210 
          211 static int
          212 notifyseton(int s, int on)
          213 {
          214         Sig *sig;
          215         struct sigaction sa, osa;
          216 
          217         sig = findsig(s);
          218         if(sig == nil)
          219                 return -1;
          220         memset(&sa, 0, sizeof sa);
          221         sa.sa_handler = on ? signotify : signonotify;
          222         if(sig->flags&Restart)
          223                 sa.sa_flags |= SA_RESTART;
          224 
          225         /*
          226          * We can't allow signals within signals because there's
          227          * only one jump buffer.
          228          */
          229         sigfillset(&sa.sa_mask);
          230 
          231         /*
          232          * Install handler.
          233          */
          234         sigaction(sig->sig, &sa, &osa);
          235         return osa.sa_handler == signotify;
          236 }
          237 
          238 int
          239 notifyon(char *msg)
          240 {
          241         return notifyseton(_p9strsig(msg), 1);
          242 }
          243 
          244 int
          245 notifyoff(char *msg)
          246 {
          247         return notifyseton(_p9strsig(msg), 0);
          248 }
          249 
          250 /*
          251  * Initialization follows sigs table.
          252  */
          253 static void
          254 noteinit(void)
          255 {
          256         int i;
          257         Sig *sig;
          258 
          259         for(i=0; i<nelem(sigs); i++){
          260                 sig = &sigs[i];
          261                 /*
          262                  * If someone has already installed a handler,
          263                  * It's probably some ld preload nonsense,
          264                  * like pct (a SIGVTALRM-based profiler).
          265                  * Or maybe someone has already called notifyon/notifyoff.
          266                  * Leave it alone.
          267                  */
          268                 if(handler(sig->sig) != SIG_DFL)
          269                         continue;
          270                 notifyseton(sig->sig, !(sig->flags&NoNotify));
          271         }
          272 }
          273