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