tnotify.c - plan9port - [fork] Plan 9 from user space | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
tnotify.c (4710B) | |
--- | |
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/notifyof… | |
266 * Leave it alone. | |
267 */ | |
268 if(handler(sig->sig) != SIG_DFL) | |
269 continue; | |
270 notifyseton(sig->sig, !(sig->flags&NoNotify)); | |
271 } | |
272 } |