Imported Upstream version 2.1.10
[platform/upstream/libevent.git] / signal.c
1 /*      $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $       */
2
3 /*
4  * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
5  * Copyright 2007-2012 Niels Provos and Nick Mathewson
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 #include "event2/event-config.h"
30 #include "evconfig-private.h"
31
32 #ifdef _WIN32
33 #define WIN32_LEAN_AND_MEAN
34 #include <winsock2.h>
35 #include <windows.h>
36 #undef WIN32_LEAN_AND_MEAN
37 #endif
38 #include <sys/types.h>
39 #ifdef EVENT__HAVE_SYS_TIME_H
40 #include <sys/time.h>
41 #endif
42 #include <sys/queue.h>
43 #ifdef EVENT__HAVE_SYS_SOCKET_H
44 #include <sys/socket.h>
45 #endif
46 #include <signal.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #ifdef EVENT__HAVE_UNISTD_H
51 #include <unistd.h>
52 #endif
53 #include <errno.h>
54 #ifdef EVENT__HAVE_FCNTL_H
55 #include <fcntl.h>
56 #endif
57
58 #include "event2/event.h"
59 #include "event2/event_struct.h"
60 #include "event-internal.h"
61 #include "event2/util.h"
62 #include "evsignal-internal.h"
63 #include "log-internal.h"
64 #include "evmap-internal.h"
65 #include "evthread-internal.h"
66
67 /*
68   signal.c
69
70   This is the signal-handling implementation we use for backends that don't
71   have a better way to do signal handling.  It uses sigaction() or signal()
72   to set a signal handler, and a socket pair to tell the event base when
73
74   Note that I said "the event base" : only one event base can be set up to use
75   this at a time.  For historical reasons and backward compatibility, if you
76   add an event for a signal to event_base A, then add an event for a signal
77   (any signal!) to event_base B, event_base B will get informed about the
78   signal, but event_base A won't.
79
80   It would be neat to change this behavior in some future version of Libevent.
81   kqueue already does something far more sensible.  We can make all backends
82   on Linux do a reasonable thing using signalfd.
83 */
84
85 #ifndef _WIN32
86 /* Windows wants us to call our signal handlers as __cdecl.  Nobody else
87  * expects you to do anything crazy like this. */
88 #ifndef __cdecl
89 #define __cdecl
90 #endif
91 #endif
92
93 static int evsig_add(struct event_base *, evutil_socket_t, short, short, void *);
94 static int evsig_del(struct event_base *, evutil_socket_t, short, short, void *);
95
96 static const struct eventop evsigops = {
97         "signal",
98         NULL,
99         evsig_add,
100         evsig_del,
101         NULL,
102         NULL,
103         0, 0, 0
104 };
105
106 #ifndef EVENT__DISABLE_THREAD_SUPPORT
107 /* Lock for evsig_base and evsig_base_n_signals_added fields. */
108 static void *evsig_base_lock = NULL;
109 #endif
110 /* The event base that's currently getting informed about signals. */
111 static struct event_base *evsig_base = NULL;
112 /* A copy of evsig_base->sigev_n_signals_added. */
113 static int evsig_base_n_signals_added = 0;
114 static evutil_socket_t evsig_base_fd = -1;
115
116 static void __cdecl evsig_handler(int sig);
117
118 #define EVSIGBASE_LOCK() EVLOCK_LOCK(evsig_base_lock, 0)
119 #define EVSIGBASE_UNLOCK() EVLOCK_UNLOCK(evsig_base_lock, 0)
120
121 void
122 evsig_set_base_(struct event_base *base)
123 {
124         EVSIGBASE_LOCK();
125         evsig_base = base;
126         evsig_base_n_signals_added = base->sig.ev_n_signals_added;
127         evsig_base_fd = base->sig.ev_signal_pair[1];
128         EVSIGBASE_UNLOCK();
129 }
130
131 /* Callback for when the signal handler write a byte to our signaling socket */
132 static void
133 evsig_cb(evutil_socket_t fd, short what, void *arg)
134 {
135         static char signals[1024];
136         ev_ssize_t n;
137         int i;
138         int ncaught[NSIG];
139         struct event_base *base;
140
141         base = arg;
142
143         memset(&ncaught, 0, sizeof(ncaught));
144
145         while (1) {
146 #ifdef _WIN32
147                 n = recv(fd, signals, sizeof(signals), 0);
148 #else
149                 n = read(fd, signals, sizeof(signals));
150 #endif
151                 if (n == -1) {
152                         int err = evutil_socket_geterror(fd);
153                         if (! EVUTIL_ERR_RW_RETRIABLE(err))
154                                 event_sock_err(1, fd, "%s: recv", __func__);
155                         break;
156                 } else if (n == 0) {
157                         /* XXX warn? */
158                         break;
159                 }
160                 for (i = 0; i < n; ++i) {
161                         ev_uint8_t sig = signals[i];
162                         if (sig < NSIG)
163                                 ncaught[sig]++;
164                 }
165         }
166
167         EVBASE_ACQUIRE_LOCK(base, th_base_lock);
168         for (i = 0; i < NSIG; ++i) {
169                 if (ncaught[i])
170                         evmap_signal_active_(base, i, ncaught[i]);
171         }
172         EVBASE_RELEASE_LOCK(base, th_base_lock);
173 }
174
175 int
176 evsig_init_(struct event_base *base)
177 {
178         /*
179          * Our signal handler is going to write to one end of the socket
180          * pair to wake up our event loop.  The event loop then scans for
181          * signals that got delivered.
182          */
183         if (evutil_make_internal_pipe_(base->sig.ev_signal_pair) == -1) {
184 #ifdef _WIN32
185                 /* Make this nonfatal on win32, where sometimes people
186                    have localhost firewalled. */
187                 event_sock_warn(-1, "%s: socketpair", __func__);
188 #else
189                 event_sock_err(1, -1, "%s: socketpair", __func__);
190 #endif
191                 return -1;
192         }
193
194         if (base->sig.sh_old) {
195                 mm_free(base->sig.sh_old);
196         }
197         base->sig.sh_old = NULL;
198         base->sig.sh_old_max = 0;
199
200         event_assign(&base->sig.ev_signal, base, base->sig.ev_signal_pair[0],
201                 EV_READ | EV_PERSIST, evsig_cb, base);
202
203         base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL;
204         event_priority_set(&base->sig.ev_signal, 0);
205
206         base->evsigsel = &evsigops;
207
208         return 0;
209 }
210
211 /* Helper: set the signal handler for evsignal to handler in base, so that
212  * we can restore the original handler when we clear the current one. */
213 int
214 evsig_set_handler_(struct event_base *base,
215     int evsignal, void (__cdecl *handler)(int))
216 {
217 #ifdef EVENT__HAVE_SIGACTION
218         struct sigaction sa;
219 #else
220         ev_sighandler_t sh;
221 #endif
222         struct evsig_info *sig = &base->sig;
223         void *p;
224
225         /*
226          * resize saved signal handler array up to the highest signal number.
227          * a dynamic array is used to keep footprint on the low side.
228          */
229         if (evsignal >= sig->sh_old_max) {
230                 int new_max = evsignal + 1;
231                 event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing",
232                             __func__, evsignal, sig->sh_old_max));
233                 p = mm_realloc(sig->sh_old, new_max * sizeof(*sig->sh_old));
234                 if (p == NULL) {
235                         event_warn("realloc");
236                         return (-1);
237                 }
238
239                 memset((char *)p + sig->sh_old_max * sizeof(*sig->sh_old),
240                     0, (new_max - sig->sh_old_max) * sizeof(*sig->sh_old));
241
242                 sig->sh_old_max = new_max;
243                 sig->sh_old = p;
244         }
245
246         /* allocate space for previous handler out of dynamic array */
247         sig->sh_old[evsignal] = mm_malloc(sizeof *sig->sh_old[evsignal]);
248         if (sig->sh_old[evsignal] == NULL) {
249                 event_warn("malloc");
250                 return (-1);
251         }
252
253         /* save previous handler and setup new handler */
254 #ifdef EVENT__HAVE_SIGACTION
255         memset(&sa, 0, sizeof(sa));
256         sa.sa_handler = handler;
257         sa.sa_flags |= SA_RESTART;
258         sigfillset(&sa.sa_mask);
259
260         if (sigaction(evsignal, &sa, sig->sh_old[evsignal]) == -1) {
261                 event_warn("sigaction");
262                 mm_free(sig->sh_old[evsignal]);
263                 sig->sh_old[evsignal] = NULL;
264                 return (-1);
265         }
266 #else
267         if ((sh = signal(evsignal, handler)) == SIG_ERR) {
268                 event_warn("signal");
269                 mm_free(sig->sh_old[evsignal]);
270                 sig->sh_old[evsignal] = NULL;
271                 return (-1);
272         }
273         *sig->sh_old[evsignal] = sh;
274 #endif
275
276         return (0);
277 }
278
279 static int
280 evsig_add(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p)
281 {
282         struct evsig_info *sig = &base->sig;
283         (void)p;
284
285         EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG);
286
287         /* catch signals if they happen quickly */
288         EVSIGBASE_LOCK();
289         if (evsig_base != base && evsig_base_n_signals_added) {
290                 event_warnx("Added a signal to event base %p with signals "
291                     "already added to event_base %p.  Only one can have "
292                     "signals at a time with the %s backend.  The base with "
293                     "the most recently added signal or the most recent "
294                     "event_base_loop() call gets preference; do "
295                     "not rely on this behavior in future Libevent versions.",
296                     base, evsig_base, base->evsel->name);
297         }
298         evsig_base = base;
299         evsig_base_n_signals_added = ++sig->ev_n_signals_added;
300         evsig_base_fd = base->sig.ev_signal_pair[1];
301         EVSIGBASE_UNLOCK();
302
303         event_debug(("%s: %d: changing signal handler", __func__, (int)evsignal));
304         if (evsig_set_handler_(base, (int)evsignal, evsig_handler) == -1) {
305                 goto err;
306         }
307
308
309         if (!sig->ev_signal_added) {
310                 if (event_add_nolock_(&sig->ev_signal, NULL, 0))
311                         goto err;
312                 sig->ev_signal_added = 1;
313         }
314
315         return (0);
316
317 err:
318         EVSIGBASE_LOCK();
319         --evsig_base_n_signals_added;
320         --sig->ev_n_signals_added;
321         EVSIGBASE_UNLOCK();
322         return (-1);
323 }
324
325 int
326 evsig_restore_handler_(struct event_base *base, int evsignal)
327 {
328         int ret = 0;
329         struct evsig_info *sig = &base->sig;
330 #ifdef EVENT__HAVE_SIGACTION
331         struct sigaction *sh;
332 #else
333         ev_sighandler_t *sh;
334 #endif
335
336         if (evsignal >= sig->sh_old_max) {
337                 /* Can't actually restore. */
338                 /* XXXX.*/
339                 return 0;
340         }
341
342         /* restore previous handler */
343         sh = sig->sh_old[evsignal];
344         sig->sh_old[evsignal] = NULL;
345 #ifdef EVENT__HAVE_SIGACTION
346         if (sigaction(evsignal, sh, NULL) == -1) {
347                 event_warn("sigaction");
348                 ret = -1;
349         }
350 #else
351         if (signal(evsignal, *sh) == SIG_ERR) {
352                 event_warn("signal");
353                 ret = -1;
354         }
355 #endif
356
357         mm_free(sh);
358
359         return ret;
360 }
361
362 static int
363 evsig_del(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p)
364 {
365         EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG);
366
367         event_debug(("%s: "EV_SOCK_FMT": restoring signal handler",
368                 __func__, EV_SOCK_ARG(evsignal)));
369
370         EVSIGBASE_LOCK();
371         --evsig_base_n_signals_added;
372         --base->sig.ev_n_signals_added;
373         EVSIGBASE_UNLOCK();
374
375         return (evsig_restore_handler_(base, (int)evsignal));
376 }
377
378 static void __cdecl
379 evsig_handler(int sig)
380 {
381         int save_errno = errno;
382 #ifdef _WIN32
383         int socket_errno = EVUTIL_SOCKET_ERROR();
384 #endif
385         ev_uint8_t msg;
386
387         if (evsig_base == NULL) {
388                 event_warnx(
389                         "%s: received signal %d, but have no base configured",
390                         __func__, sig);
391                 return;
392         }
393
394 #ifndef EVENT__HAVE_SIGACTION
395         signal(sig, evsig_handler);
396 #endif
397
398         /* Wake up our notification mechanism */
399         msg = sig;
400 #ifdef _WIN32
401         send(evsig_base_fd, (char*)&msg, 1, 0);
402 #else
403         {
404                 int r = write(evsig_base_fd, (char*)&msg, 1);
405                 (void)r; /* Suppress 'unused return value' and 'unused var' */
406         }
407 #endif
408         errno = save_errno;
409 #ifdef _WIN32
410         EVUTIL_SET_SOCKET_ERROR(socket_errno);
411 #endif
412 }
413
414 void
415 evsig_dealloc_(struct event_base *base)
416 {
417         int i = 0;
418         if (base->sig.ev_signal_added) {
419                 event_del(&base->sig.ev_signal);
420                 base->sig.ev_signal_added = 0;
421         }
422         /* debug event is created in evsig_init_/event_assign even when
423          * ev_signal_added == 0, so unassign is required */
424         event_debug_unassign(&base->sig.ev_signal);
425
426         for (i = 0; i < NSIG; ++i) {
427                 if (i < base->sig.sh_old_max && base->sig.sh_old[i] != NULL)
428                         evsig_restore_handler_(base, i);
429         }
430         EVSIGBASE_LOCK();
431         if (base == evsig_base) {
432                 evsig_base = NULL;
433                 evsig_base_n_signals_added = 0;
434                 evsig_base_fd = -1;
435         }
436         EVSIGBASE_UNLOCK();
437
438         if (base->sig.ev_signal_pair[0] != -1) {
439                 evutil_closesocket(base->sig.ev_signal_pair[0]);
440                 base->sig.ev_signal_pair[0] = -1;
441         }
442         if (base->sig.ev_signal_pair[1] != -1) {
443                 evutil_closesocket(base->sig.ev_signal_pair[1]);
444                 base->sig.ev_signal_pair[1] = -1;
445         }
446         base->sig.sh_old_max = 0;
447
448         /* per index frees are handled in evsig_del() */
449         if (base->sig.sh_old) {
450                 mm_free(base->sig.sh_old);
451                 base->sig.sh_old = NULL;
452         }
453 }
454
455 static void
456 evsig_free_globals_locks(void)
457 {
458 #ifndef EVENT__DISABLE_THREAD_SUPPORT
459         if (evsig_base_lock != NULL) {
460                 EVTHREAD_FREE_LOCK(evsig_base_lock, 0);
461                 evsig_base_lock = NULL;
462         }
463 #endif
464         return;
465 }
466
467 void
468 evsig_free_globals_(void)
469 {
470         evsig_free_globals_locks();
471 }
472
473 #ifndef EVENT__DISABLE_THREAD_SUPPORT
474 int
475 evsig_global_setup_locks_(const int enable_locks)
476 {
477         EVTHREAD_SETUP_GLOBAL_LOCK(evsig_base_lock, 0);
478         return 0;
479 }
480
481 #endif