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 };
43 static Sig sigs[] = {
44 SIGHUP, 0,
45 SIGINT, 0,
46 SIGQUIT, 0,
47 SIGILL, 0,
48 SIGTRAP, 0,
49 /* SIGABRT, 0, */
50 #ifdef SIGEMT
51 SIGEMT, 0,
52 #endif
53 SIGFPE, 0,
54 SIGBUS, 0,
55 /* SIGSEGV, 0, */
56 SIGCHLD, Restart|Ignore,
57 SIGSYS, 0,
58 SIGPIPE, Ignore,
59 SIGALRM, 0,
60 SIGTERM, 0,
61 SIGTSTP, Restart|Ignore,
62 /* SIGTTIN, Restart|Ignore, */
63 /* SIGTTOU, Restart|Ignore, */
64 SIGXCPU, 0,
65 SIGXFSZ, 0,
66 SIGVTALRM, 0,
67 SIGUSR1, 0,
68 SIGUSR2, 0,
69 #ifdef SIGWINCH
70 SIGWINCH, Restart|Ignore,
71 #endif
72 #ifdef SIGINFO
73 SIGINFO, Restart|Ignore,
74 #endif
75 };
77 static Sig*
78 findsig(int s)
79 {
80 int i;
82 for(i=0; i<nelem(sigs); i++)
83 if(sigs[i].sig == s)
84 return &sigs[i];
85 return nil;
86 }
88 /*
89 * The thread library initializes _notejmpbuf to its own
90 * routine which provides a per-pthread jump buffer.
91 * If we're not using the thread library, we assume we are
92 * single-threaded.
93 */
94 typedef struct Jmp Jmp;
95 struct Jmp
96 {
97 p9jmp_buf b;
98 };
100 static Jmp onejmp;
102 static Jmp*
103 getonejmp(void)
105 return &onejmp;
108 Jmp *(*_notejmpbuf)(void) = getonejmp;
109 static void noteinit(void);
111 /*
112 * Actual signal handler.
113 */
115 static void (*notifyf)(void*, char*); /* Plan 9 handler */
117 static void
118 signotify(int sig)
120 char tmp[64];
121 Jmp *j;
122 Sig *s;
124 j = (*_notejmpbuf)();
125 switch(p9setjmp(j->b)){
126 case 0:
127 if(notifyf)
128 (*notifyf)(nil, _p9sigstr(sig, tmp));
129 /* fall through */
130 case 1: /* noted(NDFLT) */
131 if(0)print("DEFAULT %d\n", sig);
132 s = findsig(sig);
133 if(s && (s->flags&Ignore))
134 return;
135 signal(sig, SIG_DFL);
136 raise(sig);
137 _exit(1);
138 case 2: /* noted(NCONT) */
139 if(0)print("HANDLED %d\n", sig);
140 return;
144 static void
145 signonotify(int sig)
147 USED(sig);
150 int
151 noted(int v)
153 p9longjmp((*_notejmpbuf)()->b, v==NCONT ? 2 : 1);
154 abort();
155 return 0;
158 int
159 notify(void (*f)(void*, char*))
161 static int init;
163 notifyf = f;
164 if(!init){
165 init = 1;
166 noteinit();
168 return 0;
171 /*
172 * Nonsense about enabling and disabling signals.
173 */
174 typedef void Sighandler(int);
175 static Sighandler*
176 handler(int s)
178 struct sigaction sa;
180 sigaction(s, nil, &sa);
181 return sa.sa_handler;
184 static int
185 notesetenable(int sig, int enabled)
187 sigset_t mask, omask;
189 if(sig == 0)
190 return -1;
192 sigemptyset(&mask);
193 sigaddset(&mask, sig);
194 sigprocmask(enabled ? SIG_UNBLOCK : SIG_BLOCK, &mask, &omask);
195 return !sigismember(&omask, sig);
198 int
199 noteenable(char *msg)
201 return notesetenable(_p9strsig(msg), 1);
204 int
205 notedisable(char *msg)
207 return notesetenable(_p9strsig(msg), 0);
210 static int
211 notifyseton(int s, int on)
213 Sig *sig;
214 struct sigaction sa, osa;
216 sig = findsig(s);
217 if(sig == nil)
218 return -1;
219 memset(&sa, 0, sizeof sa);
220 sa.sa_handler = on ? signotify : signonotify;
221 if(sig->flags&Restart)
222 sa.sa_flags |= SA_RESTART;
224 /*
225 * We can't allow signals within signals because there's
226 * only one jump buffer.
227 */
228 sigfillset(&sa.sa_mask);
230 /*
231 * Install handler.
232 */
233 sigaction(sig->sig, &sa, &osa);
234 return osa.sa_handler == signotify;
237 int
238 notifyon(char *msg)
240 return notifyseton(_p9strsig(msg), 1);
243 int
244 notifyoff(char *msg)
246 return notifyseton(_p9strsig(msg), 0);
249 /*
250 * Initialization follows sigs table.
251 */
252 static void
253 noteinit(void)
255 int i;
256 Sig *sig;
258 for(i=0; i<nelem(sigs); i++){
259 sig = &sigs[i];
260 /*
261 * If someone has already installed a handler,
262 * It's probably some ld preload nonsense,
263 * like pct (a SIGVTALRM-based profiler).
264 * Or maybe someone has already called notifyon/notifyoff.
265 * Leave it alone.
266 */
267 if(handler(sig->sig) != SIG_DFL)
268 continue;
269 notifyseton(sig->sig, 1);