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