Blob


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 */
22 #include <u.h>
23 #include <signal.h>
24 #define NOPLAN9DEFINES
25 #include <libc.h>
27 extern char *_p9sigstr(int, char*);
28 extern int _p9strsig(char*);
30 typedef struct Sig Sig;
31 struct Sig
32 {
33 int sig; /* signal number */
34 int flags;
35 };
37 enum
38 {
39 Restart = 1<<0,
40 Ignore = 1<<1,
41 NoNotify = 1<<2,
42 };
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 };
78 static Sig*
79 findsig(int s)
80 {
81 int i;
83 for(i=0; i<nelem(sigs); i++)
84 if(sigs[i].sig == s)
85 return &sigs[i];
86 return nil;
87 }
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 };
101 static Jmp onejmp;
103 static Jmp*
104 getonejmp(void)
106 return &onejmp;
109 Jmp *(*_notejmpbuf)(void) = getonejmp;
110 static void noteinit(void);
112 /*
113 * Actual signal handler.
114 */
116 static void (*notifyf)(void*, char*); /* Plan 9 handler */
118 static void
119 signotify(int sig)
121 char tmp[64];
122 Jmp *j;
123 Sig *s;
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;
145 static void
146 signonotify(int sig)
148 USED(sig);
151 int
152 noted(int v)
154 p9longjmp((*_notejmpbuf)()->b, v==NCONT ? 2 : 1);
155 abort();
156 return 0;
159 int
160 notify(void (*f)(void*, char*))
162 static int init;
164 notifyf = f;
165 if(!init){
166 init = 1;
167 noteinit();
169 return 0;
172 /*
173 * Nonsense about enabling and disabling signals.
174 */
175 typedef void Sighandler(int);
176 static Sighandler*
177 handler(int s)
179 struct sigaction sa;
181 sigaction(s, nil, &sa);
182 return sa.sa_handler;
185 static int
186 notesetenable(int sig, int enabled)
188 sigset_t mask, omask;
190 if(sig == 0)
191 return -1;
193 sigemptyset(&mask);
194 sigaddset(&mask, sig);
195 sigprocmask(enabled ? SIG_UNBLOCK : SIG_BLOCK, &mask, &omask);
196 return !sigismember(&omask, sig);
199 int
200 noteenable(char *msg)
202 return notesetenable(_p9strsig(msg), 1);
205 int
206 notedisable(char *msg)
208 return notesetenable(_p9strsig(msg), 0);
211 static int
212 notifyseton(int s, int on)
214 Sig *sig;
215 struct sigaction sa, osa;
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;
225 /*
226 * We can't allow signals within signals because there's
227 * only one jump buffer.
228 */
229 sigfillset(&sa.sa_mask);
231 /*
232 * Install handler.
233 */
234 sigaction(sig->sig, &sa, &osa);
235 return osa.sa_handler == signotify;
238 int
239 notifyon(char *msg)
241 return notifyseton(_p9strsig(msg), 1);
244 int
245 notifyoff(char *msg)
247 return notifyseton(_p9strsig(msg), 0);
250 /*
251 * Initialization follows sigs table.
252 */
253 static void
254 noteinit(void)
256 int i;
257 Sig *sig;
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));