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 restart; /* do we restart the system call after this signal is handled? */
35 int enabled; /* is this signal enabled (not masked)? */
36 int notified; /* do we call the notify function for this signal? */
37 };
39 /* initial settings; for current status, ask the kernel */
40 static Sig sigs[] = {
41 SIGHUP, 0, 1, 1,
42 SIGINT, 0, 1, 1,
43 SIGQUIT, 0, 1, 1,
44 SIGILL, 0, 1, 1,
45 SIGTRAP, 0, 1, 1,
46 /* SIGABRT, 0, 1, 1, */
47 #ifdef SIGEMT
48 SIGEMT, 0, 1, 1,
49 #endif
50 SIGFPE, 0, 1, 1,
51 SIGBUS, 0, 1, 1,
52 /* SIGSEGV, 0, 1, 1, */
53 SIGCHLD, 1, 0, 1,
54 SIGSYS, 0, 1, 1,
55 SIGPIPE, 0, 0, 1,
56 SIGALRM, 0, 1, 1,
57 SIGTERM, 0, 1, 1,
58 SIGTSTP, 1, 0, 1,
59 SIGTTIN, 1, 0, 1,
60 SIGTTOU, 1, 0, 1,
61 SIGXCPU, 0, 1, 1,
62 SIGXFSZ, 0, 1, 1,
63 SIGVTALRM, 0, 1, 1,
64 SIGUSR1, 0, 1, 1,
65 SIGUSR2, 0, 1, 1,
66 SIGWINCH, 1, 0, 1,
67 #ifdef SIGINFO
68 SIGINFO, 1, 1, 1,
69 #endif
70 };
72 static Sig*
73 findsig(int s)
74 {
75 int i;
77 for(i=0; i<nelem(sigs); i++)
78 if(sigs[i].sig == s)
79 return &sigs[i];
80 return nil;
81 }
83 /*
84 * The thread library initializes _notejmpbuf to its own
85 * routine which provides a per-pthread jump buffer.
86 * If we're not using the thread library, we assume we are
87 * single-threaded.
88 */
89 typedef struct Jmp Jmp;
90 struct Jmp
91 {
92 p9jmp_buf b;
93 };
95 static Jmp onejmp;
97 static Jmp*
98 getonejmp(void)
99 {
100 return &onejmp;
103 Jmp *(*_notejmpbuf)(void) = getonejmp;
104 static void noteinit(void);
106 /*
107 * Actual signal handler.
108 */
110 static void (*notifyf)(void*, char*); /* Plan 9 handler */
112 static void
113 signotify(int sig)
115 char tmp[64];
116 Jmp *j;
118 j = (*_notejmpbuf)();
119 switch(p9setjmp(j->b)){
120 case 0:
121 if(notifyf)
122 (*notifyf)(nil, _p9sigstr(sig, tmp));
123 /* fall through */
124 case 1: /* noted(NDFLT) */
125 if(0)print("DEFAULT %d\n", sig);
126 signal(sig, SIG_DFL);
127 raise(sig);
128 _exit(1);
129 case 2: /* noted(NCONT) */
130 if(0)print("HANDLED %d\n", sig);
131 return;
135 static void
136 signonotify(int sig)
138 USED(sig);
141 int
142 noted(int v)
144 p9longjmp((*_notejmpbuf)()->b, v==NCONT ? 2 : 1);
145 abort();
146 return 0;
149 int
150 notify(void (*f)(void*, char*))
152 static int init;
154 notifyf = f;
155 if(!init){
156 init = 1;
157 noteinit();
159 return 0;
162 /*
163 * Nonsense about enabling and disabling signals.
164 */
165 typedef void Sighandler(int);
166 static Sighandler*
167 handler(int s)
169 struct sigaction sa;
171 sigaction(s, nil, &sa);
172 return sa.sa_handler;
175 static void
176 notesetenable(int sig, int enabled)
178 sigset_t mask;
180 if(sig == 0)
181 return;
183 sigemptyset(&mask);
184 sigaddset(&mask, sig);
185 sigprocmask(enabled ? SIG_UNBLOCK : SIG_BLOCK, &mask, nil);
188 void
189 noteenable(char *msg)
191 notesetenable(_p9strsig(msg), 1);
194 void
195 notedisable(char *msg)
197 notesetenable(_p9strsig(msg), 0);
200 static void
201 notifyseton(int s, int on)
203 Sig *sig;
204 struct sigaction sa;
206 sig = findsig(s);
207 if(sig == nil)
208 return;
209 memset(&sa, 0, sizeof sa);
210 sa.sa_handler = on ? signotify : signonotify;
211 if(sig->restart)
212 sa.sa_flags |= SA_RESTART;
214 /*
215 * We can't allow signals within signals because there's
216 * only one jump buffer.
217 */
218 sigfillset(&sa.sa_mask);
220 /*
221 * Install handler.
222 */
223 sigaction(sig->sig, &sa, nil);
226 void
227 notifyon(char *msg)
229 notifyseton(_p9strsig(msg), 1);
232 void
233 notifyoff(char *msg)
235 notifyseton(_p9strsig(msg), 0);
238 /*
239 * Initialization follows sigs table.
240 */
241 static void
242 noteinit(void)
244 int i;
245 Sig *sig;
247 for(i=0; i<nelem(sigs); i++){
248 sig = &sigs[i];
249 /*
250 * If someone has already installed a handler,
251 * It's probably some ld preload nonsense,
252 * like pct (a SIGVTALRM-based profiler).
253 * Or maybe someone has already called notifyon/notifyoff.
254 * Leave it alone.
255 */
256 if(handler(sig->sig) != SIG_DFL)
257 continue;
258 /*
259 * Should we only disable and not enable signals?
260 * (I.e. if parent has disabled for us, should we still enable?)
261 * Right now we always initialize to the state we want.
262 */
263 notesetenable(sig->sig, sig->enabled);
264 notifyseton(sig->sig, sig->notified);