OLD | NEW |
| (Empty) |
1 /* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */ | |
2 | |
3 /* | |
4 * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu> | |
5 * All rights reserved. | |
6 * | |
7 * Redistribution and use in source and binary forms, with or without | |
8 * modification, are permitted provided that the following conditions | |
9 * are met: | |
10 * 1. Redistributions of source code must retain the above copyright | |
11 * notice, this list of conditions and the following disclaimer. | |
12 * 2. Redistributions in binary form must reproduce the above copyright | |
13 * notice, this list of conditions and the following disclaimer in the | |
14 * documentation and/or other materials provided with the distribution. | |
15 * 3. The name of the author may not be used to endorse or promote products | |
16 * derived from this software without specific prior written permission. | |
17 * | |
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
28 */ | |
29 #ifdef HAVE_CONFIG_H | |
30 #include "config.h" | |
31 #endif | |
32 | |
33 #ifdef WIN32 | |
34 #define WIN32_LEAN_AND_MEAN | |
35 #include <winsock2.h> | |
36 #include <windows.h> | |
37 #undef WIN32_LEAN_AND_MEAN | |
38 #endif | |
39 #include <sys/types.h> | |
40 #ifdef HAVE_SYS_TIME_H | |
41 #include <sys/time.h> | |
42 #endif | |
43 #include <sys/queue.h> | |
44 #ifdef HAVE_SYS_SOCKET_H | |
45 #include <sys/socket.h> | |
46 #endif | |
47 #include <signal.h> | |
48 #include <stdio.h> | |
49 #include <stdlib.h> | |
50 #include <string.h> | |
51 #ifdef HAVE_UNISTD_H | |
52 #include <unistd.h> | |
53 #endif | |
54 #include <errno.h> | |
55 #ifdef HAVE_FCNTL_H | |
56 #include <fcntl.h> | |
57 #endif | |
58 #include <assert.h> | |
59 | |
60 #include "event.h" | |
61 #include "event-internal.h" | |
62 #include "evsignal.h" | |
63 #include "evutil.h" | |
64 #include "log.h" | |
65 | |
66 struct event_base *evsignal_base = NULL; | |
67 | |
68 static void evsignal_handler(int sig); | |
69 | |
70 #ifdef WIN32 | |
71 #define error_is_eagain(err) \ | |
72 ((err) == EAGAIN || (err) == WSAEWOULDBLOCK) | |
73 #else | |
74 #define error_is_eagain(err) ((err) == EAGAIN) | |
75 #endif | |
76 | |
77 /* Callback for when the signal handler write a byte to our signaling socket */ | |
78 static void | |
79 evsignal_cb(int fd, short what, void *arg) | |
80 { | |
81 static char signals[1]; | |
82 #ifdef WIN32 | |
83 SSIZE_T n; | |
84 #else | |
85 ssize_t n; | |
86 #endif | |
87 | |
88 n = recv(fd, signals, sizeof(signals), 0); | |
89 if (n == -1) { | |
90 int err = EVUTIL_SOCKET_ERROR(); | |
91 if (! error_is_eagain(err)) | |
92 event_err(1, "%s: read", __func__); | |
93 } | |
94 } | |
95 | |
96 #ifdef HAVE_SETFD | |
97 #define FD_CLOSEONEXEC(x) do { \ | |
98 if (fcntl(x, F_SETFD, 1) == -1) \ | |
99 event_warn("fcntl(%d, F_SETFD)", x); \ | |
100 } while (0) | |
101 #else | |
102 #define FD_CLOSEONEXEC(x) | |
103 #endif | |
104 | |
105 int | |
106 evsignal_init(struct event_base *base) | |
107 { | |
108 int i; | |
109 | |
110 /* | |
111 * Our signal handler is going to write to one end of the socket | |
112 * pair to wake up our event loop. The event loop then scans for | |
113 * signals that got delivered. | |
114 */ | |
115 if (evutil_socketpair( | |
116 AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1) { | |
117 #ifdef WIN32 | |
118 /* Make this nonfatal on win32, where sometimes people | |
119 have localhost firewalled. */ | |
120 event_warn("%s: socketpair", __func__); | |
121 #else | |
122 event_err(1, "%s: socketpair", __func__); | |
123 #endif | |
124 return -1; | |
125 } | |
126 | |
127 FD_CLOSEONEXEC(base->sig.ev_signal_pair[0]); | |
128 FD_CLOSEONEXEC(base->sig.ev_signal_pair[1]); | |
129 base->sig.sh_old = NULL; | |
130 base->sig.sh_old_max = 0; | |
131 base->sig.evsignal_caught = 0; | |
132 memset(&base->sig.evsigcaught, 0, sizeof(sig_atomic_t)*NSIG); | |
133 /* initialize the queues for all events */ | |
134 for (i = 0; i < NSIG; ++i) | |
135 TAILQ_INIT(&base->sig.evsigevents[i]); | |
136 | |
137 evutil_make_socket_nonblocking(base->sig.ev_signal_pair[0]); | |
138 evutil_make_socket_nonblocking(base->sig.ev_signal_pair[1]); | |
139 | |
140 event_set(&base->sig.ev_signal, base->sig.ev_signal_pair[1], | |
141 EV_READ | EV_PERSIST, evsignal_cb, &base->sig.ev_signal); | |
142 base->sig.ev_signal.ev_base = base; | |
143 base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL; | |
144 | |
145 return 0; | |
146 } | |
147 | |
148 /* Helper: set the signal handler for evsignal to handler in base, so that | |
149 * we can restore the original handler when we clear the current one. */ | |
150 int | |
151 _evsignal_set_handler(struct event_base *base, | |
152 int evsignal, void (*handler)(int)) | |
153 { | |
154 #ifdef HAVE_SIGACTION | |
155 struct sigaction sa; | |
156 #else | |
157 ev_sighandler_t sh; | |
158 #endif | |
159 struct evsignal_info *sig = &base->sig; | |
160 void *p; | |
161 | |
162 /* | |
163 * resize saved signal handler array up to the highest signal number. | |
164 * a dynamic array is used to keep footprint on the low side. | |
165 */ | |
166 if (evsignal >= sig->sh_old_max) { | |
167 int new_max = evsignal + 1; | |
168 event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing", | |
169 __func__, evsignal, sig->sh_old_max)); | |
170 p = realloc(sig->sh_old, new_max * sizeof(*sig->sh_old)); | |
171 if (p == NULL) { | |
172 event_warn("realloc"); | |
173 return (-1); | |
174 } | |
175 | |
176 memset((char *)p + sig->sh_old_max * sizeof(*sig->sh_old), | |
177 0, (new_max - sig->sh_old_max) * sizeof(*sig->sh_old)); | |
178 | |
179 sig->sh_old_max = new_max; | |
180 sig->sh_old = p; | |
181 } | |
182 | |
183 /* allocate space for previous handler out of dynamic array */ | |
184 sig->sh_old[evsignal] = malloc(sizeof *sig->sh_old[evsignal]); | |
185 if (sig->sh_old[evsignal] == NULL) { | |
186 event_warn("malloc"); | |
187 return (-1); | |
188 } | |
189 | |
190 /* save previous handler and setup new handler */ | |
191 #ifdef HAVE_SIGACTION | |
192 memset(&sa, 0, sizeof(sa)); | |
193 sa.sa_handler = handler; | |
194 sa.sa_flags |= SA_RESTART; | |
195 sigfillset(&sa.sa_mask); | |
196 | |
197 if (sigaction(evsignal, &sa, sig->sh_old[evsignal]) == -1) { | |
198 event_warn("sigaction"); | |
199 free(sig->sh_old[evsignal]); | |
200 sig->sh_old[evsignal] = NULL; | |
201 return (-1); | |
202 } | |
203 #else | |
204 if ((sh = signal(evsignal, handler)) == SIG_ERR) { | |
205 event_warn("signal"); | |
206 free(sig->sh_old[evsignal]); | |
207 sig->sh_old[evsignal] = NULL; | |
208 return (-1); | |
209 } | |
210 *sig->sh_old[evsignal] = sh; | |
211 #endif | |
212 | |
213 return (0); | |
214 } | |
215 | |
216 int | |
217 evsignal_add(struct event *ev) | |
218 { | |
219 int evsignal; | |
220 struct event_base *base = ev->ev_base; | |
221 struct evsignal_info *sig = &ev->ev_base->sig; | |
222 | |
223 if (ev->ev_events & (EV_READ|EV_WRITE)) | |
224 event_errx(1, "%s: EV_SIGNAL incompatible use", __func__); | |
225 evsignal = EVENT_SIGNAL(ev); | |
226 assert(evsignal >= 0 && evsignal < NSIG); | |
227 if (TAILQ_EMPTY(&sig->evsigevents[evsignal])) { | |
228 event_debug(("%s: %p: changing signal handler", __func__, ev)); | |
229 if (_evsignal_set_handler( | |
230 base, evsignal, evsignal_handler) == -1) | |
231 return (-1); | |
232 | |
233 /* catch signals if they happen quickly */ | |
234 evsignal_base = base; | |
235 | |
236 if (!sig->ev_signal_added) { | |
237 if (event_add(&sig->ev_signal, NULL)) | |
238 return (-1); | |
239 sig->ev_signal_added = 1; | |
240 } | |
241 } | |
242 | |
243 /* multiple events may listen to the same signal */ | |
244 TAILQ_INSERT_TAIL(&sig->evsigevents[evsignal], ev, ev_signal_next); | |
245 | |
246 return (0); | |
247 } | |
248 | |
249 int | |
250 _evsignal_restore_handler(struct event_base *base, int evsignal) | |
251 { | |
252 int ret = 0; | |
253 struct evsignal_info *sig = &base->sig; | |
254 #ifdef HAVE_SIGACTION | |
255 struct sigaction *sh; | |
256 #else | |
257 ev_sighandler_t *sh; | |
258 #endif | |
259 | |
260 /* restore previous handler */ | |
261 sh = sig->sh_old[evsignal]; | |
262 sig->sh_old[evsignal] = NULL; | |
263 #ifdef HAVE_SIGACTION | |
264 if (sigaction(evsignal, sh, NULL) == -1) { | |
265 event_warn("sigaction"); | |
266 ret = -1; | |
267 } | |
268 #else | |
269 if (signal(evsignal, *sh) == SIG_ERR) { | |
270 event_warn("signal"); | |
271 ret = -1; | |
272 } | |
273 #endif | |
274 free(sh); | |
275 | |
276 return ret; | |
277 } | |
278 | |
279 int | |
280 evsignal_del(struct event *ev) | |
281 { | |
282 struct event_base *base = ev->ev_base; | |
283 struct evsignal_info *sig = &base->sig; | |
284 int evsignal = EVENT_SIGNAL(ev); | |
285 | |
286 assert(evsignal >= 0 && evsignal < NSIG); | |
287 | |
288 /* multiple events may listen to the same signal */ | |
289 TAILQ_REMOVE(&sig->evsigevents[evsignal], ev, ev_signal_next); | |
290 | |
291 if (!TAILQ_EMPTY(&sig->evsigevents[evsignal])) | |
292 return (0); | |
293 | |
294 event_debug(("%s: %p: restoring signal handler", __func__, ev)); | |
295 | |
296 return (_evsignal_restore_handler(ev->ev_base, EVENT_SIGNAL(ev))); | |
297 } | |
298 | |
299 static void | |
300 evsignal_handler(int sig) | |
301 { | |
302 int save_errno = errno; | |
303 | |
304 if (evsignal_base == NULL) { | |
305 event_warn( | |
306 "%s: received signal %d, but have no base configured", | |
307 __func__, sig); | |
308 return; | |
309 } | |
310 | |
311 evsignal_base->sig.evsigcaught[sig]++; | |
312 evsignal_base->sig.evsignal_caught = 1; | |
313 | |
314 #ifndef HAVE_SIGACTION | |
315 signal(sig, evsignal_handler); | |
316 #endif | |
317 | |
318 /* Wake up our notification mechanism */ | |
319 send(evsignal_base->sig.ev_signal_pair[0], "a", 1, 0); | |
320 errno = save_errno; | |
321 } | |
322 | |
323 void | |
324 evsignal_process(struct event_base *base) | |
325 { | |
326 struct evsignal_info *sig = &base->sig; | |
327 struct event *ev, *next_ev; | |
328 sig_atomic_t ncalls; | |
329 int i; | |
330 | |
331 base->sig.evsignal_caught = 0; | |
332 for (i = 1; i < NSIG; ++i) { | |
333 ncalls = sig->evsigcaught[i]; | |
334 if (ncalls == 0) | |
335 continue; | |
336 sig->evsigcaught[i] -= ncalls; | |
337 | |
338 for (ev = TAILQ_FIRST(&sig->evsigevents[i]); | |
339 ev != NULL; ev = next_ev) { | |
340 next_ev = TAILQ_NEXT(ev, ev_signal_next); | |
341 if (!(ev->ev_events & EV_PERSIST)) | |
342 event_del(ev); | |
343 event_active(ev, EV_SIGNAL, ncalls); | |
344 } | |
345 | |
346 } | |
347 } | |
348 | |
349 void | |
350 evsignal_dealloc(struct event_base *base) | |
351 { | |
352 int i = 0; | |
353 if (base->sig.ev_signal_added) { | |
354 event_del(&base->sig.ev_signal); | |
355 base->sig.ev_signal_added = 0; | |
356 } | |
357 for (i = 0; i < NSIG; ++i) { | |
358 if (i < base->sig.sh_old_max && base->sig.sh_old[i] != NULL) | |
359 _evsignal_restore_handler(base, i); | |
360 } | |
361 | |
362 if (base->sig.ev_signal_pair[0] != -1) { | |
363 EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[0]); | |
364 base->sig.ev_signal_pair[0] = -1; | |
365 } | |
366 if (base->sig.ev_signal_pair[1] != -1) { | |
367 EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[1]); | |
368 base->sig.ev_signal_pair[1] = -1; | |
369 } | |
370 base->sig.sh_old_max = 0; | |
371 | |
372 /* per index frees are handled in evsig_del() */ | |
373 if (base->sig.sh_old) { | |
374 free(base->sig.sh_old); | |
375 base->sig.sh_old = NULL; | |
376 } | |
377 } | |
OLD | NEW |