1b3d1c6a8SNiels Provos /* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
2b3d1c6a8SNiels Provos
3b3d1c6a8SNiels Provos /*
4b85b710cSNick Mathewson * Copyright 2000-2007 Niels Provos <[email protected]>
5e49e2891SNick Mathewson * Copyright 2007-2012 Niels Provos and Nick Mathewson
6b3d1c6a8SNiels Provos *
7b3d1c6a8SNiels Provos * Redistribution and use in source and binary forms, with or without
8b3d1c6a8SNiels Provos * modification, are permitted provided that the following conditions
9b3d1c6a8SNiels Provos * are met:
10b3d1c6a8SNiels Provos * 1. Redistributions of source code must retain the above copyright
11b3d1c6a8SNiels Provos * notice, this list of conditions and the following disclaimer.
12b3d1c6a8SNiels Provos * 2. Redistributions in binary form must reproduce the above copyright
13b3d1c6a8SNiels Provos * notice, this list of conditions and the following disclaimer in the
14b3d1c6a8SNiels Provos * documentation and/or other materials provided with the distribution.
15c3f496c7SNiels Provos * 3. The name of the author may not be used to endorse or promote products
16b3d1c6a8SNiels Provos * derived from this software without specific prior written permission.
17b3d1c6a8SNiels Provos *
18b3d1c6a8SNiels Provos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19b3d1c6a8SNiels Provos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20b3d1c6a8SNiels Provos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21b3d1c6a8SNiels Provos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22b3d1c6a8SNiels Provos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23b3d1c6a8SNiels Provos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24b3d1c6a8SNiels Provos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25b3d1c6a8SNiels Provos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26b3d1c6a8SNiels Provos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27b3d1c6a8SNiels Provos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28b3d1c6a8SNiels Provos */
29ec347b92SNick Mathewson #include "event2/event-config.h"
300915ca0aSKevin Bowling #include "evconfig-private.h"
31b3d1c6a8SNiels Provos
329f560bfaSNick Mathewson #ifdef _WIN32
33f0e06d75SNick Mathewson #define WIN32_LEAN_AND_MEAN
34f0e06d75SNick Mathewson #include <winsock2.h>
357868ab5aSNick Mathewson #include <windows.h>
36f0e06d75SNick Mathewson #undef WIN32_LEAN_AND_MEAN
37f0e06d75SNick Mathewson #endif
38b3d1c6a8SNiels Provos #include <sys/types.h>
3968120d9bSNick Mathewson #ifdef EVENT__HAVE_SYS_TIME_H
40b3d1c6a8SNiels Provos #include <sys/time.h>
41b3d1c6a8SNiels Provos #endif
42b3d1c6a8SNiels Provos #include <sys/queue.h>
4368120d9bSNick Mathewson #ifdef EVENT__HAVE_SYS_SOCKET_H
44025d1bc2SNiels Provos #include <sys/socket.h>
45f0e06d75SNick Mathewson #endif
46b3d1c6a8SNiels Provos #include <signal.h>
47b3d1c6a8SNiels Provos #include <stdio.h>
48b3d1c6a8SNiels Provos #include <stdlib.h>
49b3d1c6a8SNiels Provos #include <string.h>
5068120d9bSNick Mathewson #ifdef EVENT__HAVE_UNISTD_H
51b3d1c6a8SNiels Provos #include <unistd.h>
524e1ec3e0SNick Mathewson #endif
53b3d1c6a8SNiels Provos #include <errno.h>
5468120d9bSNick Mathewson #ifdef EVENT__HAVE_FCNTL_H
556df2ede5SNiels Provos #include <fcntl.h>
566df2ede5SNiels Provos #endif
57b3d1c6a8SNiels Provos
580ac73078SNick Mathewson #include "event2/event.h"
590ac73078SNick Mathewson #include "event2/event_struct.h"
6041b7cbc3SNiels Provos #include "event-internal.h"
610ac73078SNick Mathewson #include "event2/util.h"
62169321c9SNick Mathewson #include "evsignal-internal.h"
63169321c9SNick Mathewson #include "log-internal.h"
64169321c9SNick Mathewson #include "evmap-internal.h"
65720bd933SNick Mathewson #include "evthread-internal.h"
66720bd933SNick Mathewson
67720bd933SNick Mathewson /*
68720bd933SNick Mathewson signal.c
69720bd933SNick Mathewson
70720bd933SNick Mathewson This is the signal-handling implementation we use for backends that don't
71720bd933SNick Mathewson have a better way to do signal handling. It uses sigaction() or signal()
72720bd933SNick Mathewson to set a signal handler, and a socket pair to tell the event base when
73720bd933SNick Mathewson
74720bd933SNick Mathewson Note that I said "the event base" : only one event base can be set up to use
75720bd933SNick Mathewson this at a time. For historical reasons and backward compatibility, if you
76720bd933SNick Mathewson add an event for a signal to event_base A, then add an event for a signal
77720bd933SNick Mathewson (any signal!) to event_base B, event_base B will get informed about the
78720bd933SNick Mathewson signal, but event_base A won't.
79720bd933SNick Mathewson
80720bd933SNick Mathewson It would be neat to change this behavior in some future version of Libevent.
81720bd933SNick Mathewson kqueue already does something far more sensible. We can make all backends
82720bd933SNick Mathewson on Linux do a reasonable thing using signalfd.
83720bd933SNick Mathewson */
8402b2b4d1SNiels Provos
859f560bfaSNick Mathewson #ifndef _WIN32
86f0056d04SNick Mathewson /* Windows wants us to call our signal handlers as __cdecl. Nobody else
87f0056d04SNick Mathewson * expects you to do anything crazy like this. */
88*d89045a6SAzat Khuzhin #ifndef __cdecl
89f0056d04SNick Mathewson #define __cdecl
90f0056d04SNick Mathewson #endif
91*d89045a6SAzat Khuzhin #endif
92f0056d04SNick Mathewson
93b81217f7SNick Mathewson static int evsig_add(struct event_base *, evutil_socket_t, short, short, void *);
94b81217f7SNick Mathewson static int evsig_del(struct event_base *, evutil_socket_t, short, short, void *);
9502b2b4d1SNiels Provos
9602b2b4d1SNiels Provos static const struct eventop evsigops = {
9702b2b4d1SNiels Provos "signal",
9802b2b4d1SNiels Provos NULL,
99d776f846SNiels Provos evsig_add,
100d776f846SNiels Provos evsig_del,
10102b2b4d1SNiels Provos NULL,
10202b2b4d1SNiels Provos NULL,
103554e1493SNick Mathewson 0, 0, 0
10402b2b4d1SNiels Provos };
105b3d1c6a8SNiels Provos
10668120d9bSNick Mathewson #ifndef EVENT__DISABLE_THREAD_SUPPORT
107720bd933SNick Mathewson /* Lock for evsig_base and evsig_base_n_signals_added fields. */
108720bd933SNick Mathewson static void *evsig_base_lock = NULL;
109720bd933SNick Mathewson #endif
110720bd933SNick Mathewson /* The event base that's currently getting informed about signals. */
111720bd933SNick Mathewson static struct event_base *evsig_base = NULL;
112720bd933SNick Mathewson /* A copy of evsig_base->sigev_n_signals_added. */
113720bd933SNick Mathewson static int evsig_base_n_signals_added = 0;
11495a7d418SNick Mathewson static evutil_socket_t evsig_base_fd = -1;
115025d1bc2SNiels Provos
116f0056d04SNick Mathewson static void __cdecl evsig_handler(int sig);
1178d94bd03SNiels Provos
118720bd933SNick Mathewson #define EVSIGBASE_LOCK() EVLOCK_LOCK(evsig_base_lock, 0)
119720bd933SNick Mathewson #define EVSIGBASE_UNLOCK() EVLOCK_UNLOCK(evsig_base_lock, 0)
120720bd933SNick Mathewson
121720bd933SNick Mathewson void
evsig_set_base_(struct event_base * base)1228ac3c4c2SNick Mathewson evsig_set_base_(struct event_base *base)
123720bd933SNick Mathewson {
124720bd933SNick Mathewson EVSIGBASE_LOCK();
125720bd933SNick Mathewson evsig_base = base;
126720bd933SNick Mathewson evsig_base_n_signals_added = base->sig.ev_n_signals_added;
127a35f396fSNick Mathewson evsig_base_fd = base->sig.ev_signal_pair[1];
128720bd933SNick Mathewson EVSIGBASE_UNLOCK();
129720bd933SNick Mathewson }
130720bd933SNick Mathewson
131025d1bc2SNiels Provos /* Callback for when the signal handler write a byte to our signaling socket */
13268292e2fSNiels Provos static void
evsig_cb(evutil_socket_t fd,short what,void * arg)133d776f846SNiels Provos evsig_cb(evutil_socket_t fd, short what, void *arg)
134025d1bc2SNiels Provos {
13595a7d418SNick Mathewson static char signals[1024];
1360b22ca19SNick Mathewson ev_ssize_t n;
13795a7d418SNick Mathewson int i;
13895a7d418SNick Mathewson int ncaught[NSIG];
13995a7d418SNick Mathewson struct event_base *base;
1400b22ca19SNick Mathewson
14195a7d418SNick Mathewson base = arg;
142025d1bc2SNiels Provos
14395a7d418SNick Mathewson memset(&ncaught, 0, sizeof(ncaught));
14495a7d418SNick Mathewson
14595a7d418SNick Mathewson while (1) {
146a35f396fSNick Mathewson #ifdef _WIN32
147f0e06d75SNick Mathewson n = recv(fd, signals, sizeof(signals), 0);
148a35f396fSNick Mathewson #else
149a35f396fSNick Mathewson n = read(fd, signals, sizeof(signals));
150a35f396fSNick Mathewson #endif
151970e6ad2SNick Mathewson if (n == -1) {
152970e6ad2SNick Mathewson int err = evutil_socket_geterror(fd);
153970e6ad2SNick Mathewson if (! EVUTIL_ERR_RW_RETRIABLE(err))
154970e6ad2SNick Mathewson event_sock_err(1, fd, "%s: recv", __func__);
15595a7d418SNick Mathewson break;
15695a7d418SNick Mathewson } else if (n == 0) {
15795a7d418SNick Mathewson /* XXX warn? */
15895a7d418SNick Mathewson break;
159970e6ad2SNick Mathewson }
16095a7d418SNick Mathewson for (i = 0; i < n; ++i) {
16195a7d418SNick Mathewson ev_uint8_t sig = signals[i];
16295a7d418SNick Mathewson if (sig < NSIG)
16395a7d418SNick Mathewson ncaught[sig]++;
16495a7d418SNick Mathewson }
16595a7d418SNick Mathewson }
16695a7d418SNick Mathewson
16795a7d418SNick Mathewson EVBASE_ACQUIRE_LOCK(base, th_base_lock);
16895a7d418SNick Mathewson for (i = 0; i < NSIG; ++i) {
16995a7d418SNick Mathewson if (ncaught[i])
1708ac3c4c2SNick Mathewson evmap_signal_active_(base, i, ncaught[i]);
17195a7d418SNick Mathewson }
17295a7d418SNick Mathewson EVBASE_RELEASE_LOCK(base, th_base_lock);
173025d1bc2SNiels Provos }
174025d1bc2SNiels Provos
1758c66eb2eSNick Mathewson int
evsig_init_(struct event_base * base)1768ac3c4c2SNick Mathewson evsig_init_(struct event_base *base)
177b3d1c6a8SNiels Provos {
178025d1bc2SNiels Provos /*
179025d1bc2SNiels Provos * Our signal handler is going to write to one end of the socket
180025d1bc2SNiels Provos * pair to wake up our event loop. The event loop then scans for
181025d1bc2SNiels Provos * signals that got delivered.
182025d1bc2SNiels Provos */
1838ac3c4c2SNick Mathewson if (evutil_make_internal_pipe_(base->sig.ev_signal_pair) == -1) {
1849f560bfaSNick Mathewson #ifdef _WIN32
1858c66eb2eSNick Mathewson /* Make this nonfatal on win32, where sometimes people
1868c66eb2eSNick Mathewson have localhost firewalled. */
1877a844735SNick Mathewson event_sock_warn(-1, "%s: socketpair", __func__);
1888c66eb2eSNick Mathewson #else
189de069b99SNick Mathewson event_sock_err(1, -1, "%s: socketpair", __func__);
1908c66eb2eSNick Mathewson #endif
1918c66eb2eSNick Mathewson return -1;
1928c66eb2eSNick Mathewson }
193025d1bc2SNiels Provos
1942c4b5de1SNick Mathewson if (base->sig.sh_old) {
1952c4b5de1SNick Mathewson mm_free(base->sig.sh_old);
1962c4b5de1SNick Mathewson }
197321dfd55SNick Mathewson base->sig.sh_old = NULL;
198321dfd55SNick Mathewson base->sig.sh_old_max = 0;
1996df2ede5SNiels Provos
200a35f396fSNick Mathewson event_assign(&base->sig.ev_signal, base, base->sig.ev_signal_pair[0],
20195a7d418SNick Mathewson EV_READ | EV_PERSIST, evsig_cb, base);
2025fbc7f0aSNick Mathewson
20341b7cbc3SNiels Provos base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL;
20490651b32SNick Mathewson event_priority_set(&base->sig.ev_signal, 0);
20502b2b4d1SNiels Provos
20602b2b4d1SNiels Provos base->evsigsel = &evsigops;
2078c66eb2eSNick Mathewson
2088c66eb2eSNick Mathewson return 0;
209b3d1c6a8SNiels Provos }
210b3d1c6a8SNiels Provos
2112823cb05SNick Mathewson /* Helper: set the signal handler for evsignal to handler in base, so that
2122823cb05SNick Mathewson * we can restore the original handler when we clear the current one. */
213b3d1c6a8SNiels Provos int
evsig_set_handler_(struct event_base * base,int evsignal,void (__cdecl * handler)(int))214cb9da0bfSNick Mathewson evsig_set_handler_(struct event_base *base,
21547882773SNick Mathewson int evsignal, void (__cdecl *handler)(int))
216b3d1c6a8SNiels Provos {
21768120d9bSNick Mathewson #ifdef EVENT__HAVE_SIGACTION
2188d94bd03SNiels Provos struct sigaction sa;
219321dfd55SNick Mathewson #else
220321dfd55SNick Mathewson ev_sighandler_t sh;
221f0e06d75SNick Mathewson #endif
222d776f846SNiels Provos struct evsig_info *sig = &base->sig;
223321dfd55SNick Mathewson void *p;
224b3d1c6a8SNiels Provos
225321dfd55SNick Mathewson /*
226321dfd55SNick Mathewson * resize saved signal handler array up to the highest signal number.
227321dfd55SNick Mathewson * a dynamic array is used to keep footprint on the low side.
228321dfd55SNick Mathewson */
229321dfd55SNick Mathewson if (evsignal >= sig->sh_old_max) {
2301c164cebSNiels Provos int new_max = evsignal + 1;
23156934d5dSNiels Provos event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing",
232321dfd55SNick Mathewson __func__, evsignal, sig->sh_old_max));
2331c164cebSNiels Provos p = mm_realloc(sig->sh_old, new_max * sizeof(*sig->sh_old));
234321dfd55SNick Mathewson if (p == NULL) {
235321dfd55SNick Mathewson event_warn("realloc");
236321dfd55SNick Mathewson return (-1);
237321dfd55SNick Mathewson }
2381c164cebSNiels Provos
2391c164cebSNiels Provos memset((char *)p + sig->sh_old_max * sizeof(*sig->sh_old),
2401c164cebSNiels Provos 0, (new_max - sig->sh_old_max) * sizeof(*sig->sh_old));
2411c164cebSNiels Provos
2421c164cebSNiels Provos sig->sh_old_max = new_max;
243321dfd55SNick Mathewson sig->sh_old = p;
244321dfd55SNick Mathewson }
245321dfd55SNick Mathewson
246321dfd55SNick Mathewson /* allocate space for previous handler out of dynamic array */
24749868b61SNick Mathewson sig->sh_old[evsignal] = mm_malloc(sizeof *sig->sh_old[evsignal]);
248321dfd55SNick Mathewson if (sig->sh_old[evsignal] == NULL) {
249321dfd55SNick Mathewson event_warn("malloc");
250321dfd55SNick Mathewson return (-1);
251321dfd55SNick Mathewson }
252321dfd55SNick Mathewson
25356934d5dSNiels Provos /* save previous handler and setup new handler */
25468120d9bSNick Mathewson #ifdef EVENT__HAVE_SIGACTION
2558d94bd03SNiels Provos memset(&sa, 0, sizeof(sa));
2562823cb05SNick Mathewson sa.sa_handler = handler;
2578d94bd03SNiels Provos sa.sa_flags |= SA_RESTART;
258321dfd55SNick Mathewson sigfillset(&sa.sa_mask);
259321dfd55SNick Mathewson
260321dfd55SNick Mathewson if (sigaction(evsignal, &sa, sig->sh_old[evsignal]) == -1) {
261321dfd55SNick Mathewson event_warn("sigaction");
26249868b61SNick Mathewson mm_free(sig->sh_old[evsignal]);
263b84b598eSGilad Benjamini sig->sh_old[evsignal] = NULL;
264321dfd55SNick Mathewson return (-1);
265321dfd55SNick Mathewson }
266321dfd55SNick Mathewson #else
2672823cb05SNick Mathewson if ((sh = signal(evsignal, handler)) == SIG_ERR) {
268321dfd55SNick Mathewson event_warn("signal");
26949868b61SNick Mathewson mm_free(sig->sh_old[evsignal]);
270b84b598eSGilad Benjamini sig->sh_old[evsignal] = NULL;
271321dfd55SNick Mathewson return (-1);
272321dfd55SNick Mathewson }
273321dfd55SNick Mathewson *sig->sh_old[evsignal] = sh;
274321dfd55SNick Mathewson #endif
2752823cb05SNick Mathewson
2762823cb05SNick Mathewson return (0);
2772823cb05SNick Mathewson }
2782823cb05SNick Mathewson
27902b2b4d1SNiels Provos static int
evsig_add(struct event_base * base,evutil_socket_t evsignal,short old,short events,void * p)280b81217f7SNick Mathewson evsig_add(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p)
2812823cb05SNick Mathewson {
282d776f846SNiels Provos struct evsig_info *sig = &base->sig;
283554e1493SNick Mathewson (void)p;
2842823cb05SNick Mathewson
2852e36dbe1SNick Mathewson EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG);
28602b2b4d1SNiels Provos
28741b7cbc3SNiels Provos /* catch signals if they happen quickly */
288720bd933SNick Mathewson EVSIGBASE_LOCK();
289720bd933SNick Mathewson if (evsig_base != base && evsig_base_n_signals_added) {
290720bd933SNick Mathewson event_warnx("Added a signal to event base %p with signals "
291720bd933SNick Mathewson "already added to event_base %p. Only one can have "
292720bd933SNick Mathewson "signals at a time with the %s backend. The base with "
293720bd933SNick Mathewson "the most recently added signal or the most recent "
294720bd933SNick Mathewson "event_base_loop() call gets preference; do "
295720bd933SNick Mathewson "not rely on this behavior in future Libevent versions.",
296720bd933SNick Mathewson base, evsig_base, base->evsel->name);
297720bd933SNick Mathewson }
298d776f846SNiels Provos evsig_base = base;
299720bd933SNick Mathewson evsig_base_n_signals_added = ++sig->ev_n_signals_added;
300a35f396fSNick Mathewson evsig_base_fd = base->sig.ev_signal_pair[1];
301720bd933SNick Mathewson EVSIGBASE_UNLOCK();
302720bd933SNick Mathewson
303b81217f7SNick Mathewson event_debug(("%s: %d: changing signal handler", __func__, (int)evsignal));
304cb9da0bfSNick Mathewson if (evsig_set_handler_(base, (int)evsignal, evsig_handler) == -1) {
305720bd933SNick Mathewson goto err;
306720bd933SNick Mathewson }
307720bd933SNick Mathewson
3088d94bd03SNiels Provos
309321dfd55SNick Mathewson if (!sig->ev_signal_added) {
3109cd5acb5SNick Mathewson if (event_add_nolock_(&sig->ev_signal, NULL, 0))
311720bd933SNick Mathewson goto err;
312321dfd55SNick Mathewson sig->ev_signal_added = 1;
3138d94bd03SNiels Provos }
314b3d1c6a8SNiels Provos
315b3d1c6a8SNiels Provos return (0);
316720bd933SNick Mathewson
317720bd933SNick Mathewson err:
318720bd933SNick Mathewson EVSIGBASE_LOCK();
319720bd933SNick Mathewson --evsig_base_n_signals_added;
320720bd933SNick Mathewson --sig->ev_n_signals_added;
321720bd933SNick Mathewson EVSIGBASE_UNLOCK();
322720bd933SNick Mathewson return (-1);
323b3d1c6a8SNiels Provos }
324b3d1c6a8SNiels Provos
325b3d1c6a8SNiels Provos int
evsig_restore_handler_(struct event_base * base,int evsignal)326cb9da0bfSNick Mathewson evsig_restore_handler_(struct event_base *base, int evsignal)
327b3d1c6a8SNiels Provos {
3282823cb05SNick Mathewson int ret = 0;
329d776f846SNiels Provos struct evsig_info *sig = &base->sig;
33068120d9bSNick Mathewson #ifdef EVENT__HAVE_SIGACTION
331321dfd55SNick Mathewson struct sigaction *sh;
332f0e06d75SNick Mathewson #else
333321dfd55SNick Mathewson ev_sighandler_t *sh;
334f0e06d75SNick Mathewson #endif
335321dfd55SNick Mathewson
3362c4b5de1SNick Mathewson if (evsignal >= sig->sh_old_max) {
3372c4b5de1SNick Mathewson /* Can't actually restore. */
3382c4b5de1SNick Mathewson /* XXXX.*/
3392c4b5de1SNick Mathewson return 0;
3402c4b5de1SNick Mathewson }
3412c4b5de1SNick Mathewson
342321dfd55SNick Mathewson /* restore previous handler */
343321dfd55SNick Mathewson sh = sig->sh_old[evsignal];
344321dfd55SNick Mathewson sig->sh_old[evsignal] = NULL;
34568120d9bSNick Mathewson #ifdef EVENT__HAVE_SIGACTION
346321dfd55SNick Mathewson if (sigaction(evsignal, sh, NULL) == -1) {
347321dfd55SNick Mathewson event_warn("sigaction");
348321dfd55SNick Mathewson ret = -1;
349321dfd55SNick Mathewson }
350321dfd55SNick Mathewson #else
351321dfd55SNick Mathewson if (signal(evsignal, *sh) == SIG_ERR) {
352321dfd55SNick Mathewson event_warn("signal");
353321dfd55SNick Mathewson ret = -1;
354321dfd55SNick Mathewson }
355321dfd55SNick Mathewson #endif
3562823cb05SNick Mathewson
35749868b61SNick Mathewson mm_free(sh);
358321dfd55SNick Mathewson
359321dfd55SNick Mathewson return ret;
360b3d1c6a8SNiels Provos }
361b3d1c6a8SNiels Provos
36202b2b4d1SNiels Provos static int
evsig_del(struct event_base * base,evutil_socket_t evsignal,short old,short events,void * p)363b81217f7SNick Mathewson evsig_del(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p)
3642823cb05SNick Mathewson {
3652e36dbe1SNick Mathewson EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG);
366f7e61870SNiels Provos
36762bd2c44SNick Mathewson event_debug(("%s: "EV_SOCK_FMT": restoring signal handler",
36862bd2c44SNick Mathewson __func__, EV_SOCK_ARG(evsignal)));
369f7e61870SNiels Provos
370720bd933SNick Mathewson EVSIGBASE_LOCK();
371720bd933SNick Mathewson --evsig_base_n_signals_added;
372720bd933SNick Mathewson --base->sig.ev_n_signals_added;
373720bd933SNick Mathewson EVSIGBASE_UNLOCK();
374720bd933SNick Mathewson
375cb9da0bfSNick Mathewson return (evsig_restore_handler_(base, (int)evsignal));
3762823cb05SNick Mathewson }
3772823cb05SNick Mathewson
378f0056d04SNick Mathewson static void __cdecl
evsig_handler(int sig)379d776f846SNiels Provos evsig_handler(int sig)
380b3d1c6a8SNiels Provos {
38168292e2fSNiels Provos int save_errno = errno;
3829f560bfaSNick Mathewson #ifdef _WIN32
383de069b99SNick Mathewson int socket_errno = EVUTIL_SOCKET_ERROR();
384de069b99SNick Mathewson #endif
38595a7d418SNick Mathewson ev_uint8_t msg;
38668292e2fSNiels Provos
387d776f846SNiels Provos if (evsig_base == NULL) {
38819c71e74SNick Mathewson event_warnx(
3893206bbcaSNick Mathewson "%s: received signal %d, but have no base configured",
39041b7cbc3SNiels Provos __func__, sig);
39141b7cbc3SNiels Provos return;
39241b7cbc3SNiels Provos }
39341b7cbc3SNiels Provos
39468120d9bSNick Mathewson #ifndef EVENT__HAVE_SIGACTION
395d776f846SNiels Provos signal(sig, evsig_handler);
396f0e06d75SNick Mathewson #endif
397f0e06d75SNick Mathewson
398025d1bc2SNiels Provos /* Wake up our notification mechanism */
39995a7d418SNick Mathewson msg = sig;
400a35f396fSNick Mathewson #ifdef _WIN32
4015b7a3706SNick Mathewson send(evsig_base_fd, (char*)&msg, 1, 0);
402a35f396fSNick Mathewson #else
40365bc91c2SNick Mathewson {
40465bc91c2SNick Mathewson int r = write(evsig_base_fd, (char*)&msg, 1);
40565bc91c2SNick Mathewson (void)r; /* Suppress 'unused return value' and 'unused var' */
40665bc91c2SNick Mathewson }
407a35f396fSNick Mathewson #endif
40868292e2fSNiels Provos errno = save_errno;
4099f560bfaSNick Mathewson #ifdef _WIN32
410fded0a87SNick Mathewson EVUTIL_SET_SOCKET_ERROR(socket_errno);
411de069b99SNick Mathewson #endif
412b3d1c6a8SNiels Provos }
413b3d1c6a8SNiels Provos
414b3d1c6a8SNiels Provos void
evsig_dealloc_(struct event_base * base)4158ac3c4c2SNick Mathewson evsig_dealloc_(struct event_base *base)
41641b7cbc3SNiels Provos {
417f7e61870SNiels Provos int i = 0;
41841b7cbc3SNiels Provos if (base->sig.ev_signal_added) {
41941b7cbc3SNiels Provos event_del(&base->sig.ev_signal);
42041b7cbc3SNiels Provos base->sig.ev_signal_added = 0;
42141b7cbc3SNiels Provos }
4228ac3c4c2SNick Mathewson /* debug event is created in evsig_init_/event_assign even when
4239b724b28SLeonid Evdokimov * ev_signal_added == 0, so unassign is required */
4249b724b28SLeonid Evdokimov event_debug_unassign(&base->sig.ev_signal);
425720bd933SNick Mathewson
4261c164cebSNiels Provos for (i = 0; i < NSIG; ++i) {
4271c164cebSNiels Provos if (i < base->sig.sh_old_max && base->sig.sh_old[i] != NULL)
428cb9da0bfSNick Mathewson evsig_restore_handler_(base, i);
4291c164cebSNiels Provos }
430720bd933SNick Mathewson EVSIGBASE_LOCK();
431720bd933SNick Mathewson if (base == evsig_base) {
432720bd933SNick Mathewson evsig_base = NULL;
433720bd933SNick Mathewson evsig_base_n_signals_added = 0;
43495a7d418SNick Mathewson evsig_base_fd = -1;
435720bd933SNick Mathewson }
436720bd933SNick Mathewson EVSIGBASE_UNLOCK();
43741b7cbc3SNiels Provos
438e1ffbb82SNick Mathewson if (base->sig.ev_signal_pair[0] != -1) {
439899c1dccSSebastian Sjöberg evutil_closesocket(base->sig.ev_signal_pair[0]);
44041b7cbc3SNiels Provos base->sig.ev_signal_pair[0] = -1;
441e1ffbb82SNick Mathewson }
442e1ffbb82SNick Mathewson if (base->sig.ev_signal_pair[1] != -1) {
443899c1dccSSebastian Sjöberg evutil_closesocket(base->sig.ev_signal_pair[1]);
44441b7cbc3SNiels Provos base->sig.ev_signal_pair[1] = -1;
445e1ffbb82SNick Mathewson }
446321dfd55SNick Mathewson base->sig.sh_old_max = 0;
447321dfd55SNick Mathewson
448d776f846SNiels Provos /* per index frees are handled in evsig_del() */
449e1ffbb82SNick Mathewson if (base->sig.sh_old) {
45049868b61SNick Mathewson mm_free(base->sig.sh_old);
451e1ffbb82SNick Mathewson base->sig.sh_old = NULL;
452e1ffbb82SNick Mathewson }
45341b7cbc3SNiels Provos }
454b683cae3SNick Mathewson
455041ca00cSMark Ellzey static void
evsig_free_globals_locks(void)456041ca00cSMark Ellzey evsig_free_globals_locks(void)
457041ca00cSMark Ellzey {
458041ca00cSMark Ellzey #ifndef EVENT__DISABLE_THREAD_SUPPORT
459041ca00cSMark Ellzey if (evsig_base_lock != NULL) {
460041ca00cSMark Ellzey EVTHREAD_FREE_LOCK(evsig_base_lock, 0);
46155e991b2SNick Mathewson evsig_base_lock = NULL;
462041ca00cSMark Ellzey }
463041ca00cSMark Ellzey #endif
464041ca00cSMark Ellzey return;
465041ca00cSMark Ellzey }
466041ca00cSMark Ellzey
467041ca00cSMark Ellzey void
evsig_free_globals_(void)468041ca00cSMark Ellzey evsig_free_globals_(void)
469041ca00cSMark Ellzey {
470041ca00cSMark Ellzey evsig_free_globals_locks();
471041ca00cSMark Ellzey }
472041ca00cSMark Ellzey
47368120d9bSNick Mathewson #ifndef EVENT__DISABLE_THREAD_SUPPORT
474b683cae3SNick Mathewson int
evsig_global_setup_locks_(const int enable_locks)475b683cae3SNick Mathewson evsig_global_setup_locks_(const int enable_locks)
476b683cae3SNick Mathewson {
477b683cae3SNick Mathewson EVTHREAD_SETUP_GLOBAL_LOCK(evsig_base_lock, 0);
478b683cae3SNick Mathewson return 0;
479b683cae3SNick Mathewson }
480041ca00cSMark Ellzey
481b683cae3SNick Mathewson #endif
482