xref: /netbsd-src/external/bsd/ntp/dist/sntp/libevent/signal.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
1*eabc0478Schristos /*	$NetBSD: signal.c,v 1.6 2024/08/18 20:47:21 christos Exp $	*/
28585484eSchristos 
38585484eSchristos /*	$OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $	*/
48585484eSchristos 
58585484eSchristos /*
68585484eSchristos  * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
78585484eSchristos  * Copyright 2007-2012 Niels Provos and Nick Mathewson
88585484eSchristos  *
98585484eSchristos  * Redistribution and use in source and binary forms, with or without
108585484eSchristos  * modification, are permitted provided that the following conditions
118585484eSchristos  * are met:
128585484eSchristos  * 1. Redistributions of source code must retain the above copyright
138585484eSchristos  *    notice, this list of conditions and the following disclaimer.
148585484eSchristos  * 2. Redistributions in binary form must reproduce the above copyright
158585484eSchristos  *    notice, this list of conditions and the following disclaimer in the
168585484eSchristos  *    documentation and/or other materials provided with the distribution.
178585484eSchristos  * 3. The name of the author may not be used to endorse or promote products
188585484eSchristos  *    derived from this software without specific prior written permission.
198585484eSchristos  *
208585484eSchristos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
218585484eSchristos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
228585484eSchristos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
238585484eSchristos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
248585484eSchristos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
258585484eSchristos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
268585484eSchristos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
278585484eSchristos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
288585484eSchristos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
298585484eSchristos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
308585484eSchristos  */
318585484eSchristos #include "event2/event-config.h"
328585484eSchristos #include "evconfig-private.h"
338585484eSchristos 
348585484eSchristos #ifdef _WIN32
358585484eSchristos #define WIN32_LEAN_AND_MEAN
368585484eSchristos #include <winsock2.h>
378585484eSchristos #include <windows.h>
388585484eSchristos #undef WIN32_LEAN_AND_MEAN
398585484eSchristos #endif
408585484eSchristos #include <sys/types.h>
418585484eSchristos #ifdef EVENT__HAVE_SYS_TIME_H
428585484eSchristos #include <sys/time.h>
438585484eSchristos #endif
448585484eSchristos #include <sys/queue.h>
458585484eSchristos #ifdef EVENT__HAVE_SYS_SOCKET_H
468585484eSchristos #include <sys/socket.h>
478585484eSchristos #endif
488585484eSchristos #include <signal.h>
498585484eSchristos #include <stdio.h>
508585484eSchristos #include <stdlib.h>
518585484eSchristos #include <string.h>
528585484eSchristos #ifdef EVENT__HAVE_UNISTD_H
538585484eSchristos #include <unistd.h>
548585484eSchristos #endif
558585484eSchristos #include <errno.h>
568585484eSchristos #ifdef EVENT__HAVE_FCNTL_H
578585484eSchristos #include <fcntl.h>
588585484eSchristos #endif
598585484eSchristos 
608585484eSchristos #include "event2/event.h"
618585484eSchristos #include "event2/event_struct.h"
628585484eSchristos #include "event-internal.h"
638585484eSchristos #include "event2/util.h"
648585484eSchristos #include "evsignal-internal.h"
658585484eSchristos #include "log-internal.h"
668585484eSchristos #include "evmap-internal.h"
678585484eSchristos #include "evthread-internal.h"
688585484eSchristos 
698585484eSchristos /*
708585484eSchristos   signal.c
718585484eSchristos 
728585484eSchristos   This is the signal-handling implementation we use for backends that don't
738585484eSchristos   have a better way to do signal handling.  It uses sigaction() or signal()
748585484eSchristos   to set a signal handler, and a socket pair to tell the event base when
758585484eSchristos 
768585484eSchristos   Note that I said "the event base" : only one event base can be set up to use
778585484eSchristos   this at a time.  For historical reasons and backward compatibility, if you
788585484eSchristos   add an event for a signal to event_base A, then add an event for a signal
798585484eSchristos   (any signal!) to event_base B, event_base B will get informed about the
808585484eSchristos   signal, but event_base A won't.
818585484eSchristos 
828585484eSchristos   It would be neat to change this behavior in some future version of Libevent.
838585484eSchristos   kqueue already does something far more sensible.  We can make all backends
848585484eSchristos   on Linux do a reasonable thing using signalfd.
858585484eSchristos */
868585484eSchristos 
878585484eSchristos #ifndef _WIN32
888585484eSchristos /* Windows wants us to call our signal handlers as __cdecl.  Nobody else
898585484eSchristos  * expects you to do anything crazy like this. */
90*eabc0478Schristos #ifndef __cdecl
918585484eSchristos #define __cdecl
928585484eSchristos #endif
93*eabc0478Schristos #endif
948585484eSchristos 
958585484eSchristos static int evsig_add(struct event_base *, evutil_socket_t, short, short, void *);
968585484eSchristos static int evsig_del(struct event_base *, evutil_socket_t, short, short, void *);
978585484eSchristos 
988585484eSchristos static const struct eventop evsigops = {
998585484eSchristos 	"signal",
1008585484eSchristos 	NULL,
1018585484eSchristos 	evsig_add,
1028585484eSchristos 	evsig_del,
1038585484eSchristos 	NULL,
1048585484eSchristos 	NULL,
1058585484eSchristos 	0, 0, 0
1068585484eSchristos };
1078585484eSchristos 
1088585484eSchristos #ifndef EVENT__DISABLE_THREAD_SUPPORT
1098585484eSchristos /* Lock for evsig_base and evsig_base_n_signals_added fields. */
1108585484eSchristos static void *evsig_base_lock = NULL;
1118585484eSchristos #endif
1128585484eSchristos /* The event base that's currently getting informed about signals. */
1138585484eSchristos static struct event_base *evsig_base = NULL;
1148585484eSchristos /* A copy of evsig_base->sigev_n_signals_added. */
1158585484eSchristos static int evsig_base_n_signals_added = 0;
1168585484eSchristos static evutil_socket_t evsig_base_fd = -1;
1178585484eSchristos 
1188585484eSchristos static void __cdecl evsig_handler(int sig);
1198585484eSchristos 
1208585484eSchristos #define EVSIGBASE_LOCK() EVLOCK_LOCK(evsig_base_lock, 0)
1218585484eSchristos #define EVSIGBASE_UNLOCK() EVLOCK_UNLOCK(evsig_base_lock, 0)
1228585484eSchristos 
1238585484eSchristos void
1248585484eSchristos evsig_set_base_(struct event_base *base)
1258585484eSchristos {
1268585484eSchristos 	EVSIGBASE_LOCK();
1278585484eSchristos 	evsig_base = base;
1288585484eSchristos 	evsig_base_n_signals_added = base->sig.ev_n_signals_added;
1298585484eSchristos 	evsig_base_fd = base->sig.ev_signal_pair[1];
1308585484eSchristos 	EVSIGBASE_UNLOCK();
1318585484eSchristos }
1328585484eSchristos 
1338585484eSchristos /* Callback for when the signal handler write a byte to our signaling socket */
1348585484eSchristos static void
1358585484eSchristos evsig_cb(evutil_socket_t fd, short what, void *arg)
1368585484eSchristos {
1378585484eSchristos 	static char signals[1024];
1388585484eSchristos 	ev_ssize_t n;
1398585484eSchristos 	int i;
1408585484eSchristos 	int ncaught[NSIG];
1418585484eSchristos 	struct event_base *base;
1428585484eSchristos 
1438585484eSchristos 	base = arg;
1448585484eSchristos 
1458585484eSchristos 	memset(&ncaught, 0, sizeof(ncaught));
1468585484eSchristos 
1478585484eSchristos 	while (1) {
1488585484eSchristos #ifdef _WIN32
1498585484eSchristos 		n = recv(fd, signals, sizeof(signals), 0);
1508585484eSchristos #else
1518585484eSchristos 		n = read(fd, signals, sizeof(signals));
1528585484eSchristos #endif
1538585484eSchristos 		if (n == -1) {
1548585484eSchristos 			int err = evutil_socket_geterror(fd);
1558585484eSchristos 			if (! EVUTIL_ERR_RW_RETRIABLE(err))
1568585484eSchristos 				event_sock_err(1, fd, "%s: recv", __func__);
1578585484eSchristos 			break;
1588585484eSchristos 		} else if (n == 0) {
1598585484eSchristos 			/* XXX warn? */
1608585484eSchristos 			break;
1618585484eSchristos 		}
1628585484eSchristos 		for (i = 0; i < n; ++i) {
1638585484eSchristos 			ev_uint8_t sig = signals[i];
1648585484eSchristos 			if (sig < NSIG)
1658585484eSchristos 				ncaught[sig]++;
1668585484eSchristos 		}
1678585484eSchristos 	}
1688585484eSchristos 
1698585484eSchristos 	EVBASE_ACQUIRE_LOCK(base, th_base_lock);
1708585484eSchristos 	for (i = 0; i < NSIG; ++i) {
1718585484eSchristos 		if (ncaught[i])
1728585484eSchristos 			evmap_signal_active_(base, i, ncaught[i]);
1738585484eSchristos 	}
1748585484eSchristos 	EVBASE_RELEASE_LOCK(base, th_base_lock);
1758585484eSchristos }
1768585484eSchristos 
1778585484eSchristos int
1788585484eSchristos evsig_init_(struct event_base *base)
1798585484eSchristos {
1808585484eSchristos 	/*
1818585484eSchristos 	 * Our signal handler is going to write to one end of the socket
1828585484eSchristos 	 * pair to wake up our event loop.  The event loop then scans for
1838585484eSchristos 	 * signals that got delivered.
1848585484eSchristos 	 */
1858585484eSchristos 	if (evutil_make_internal_pipe_(base->sig.ev_signal_pair) == -1) {
1868585484eSchristos #ifdef _WIN32
1878585484eSchristos 		/* Make this nonfatal on win32, where sometimes people
1888585484eSchristos 		   have localhost firewalled. */
1898585484eSchristos 		event_sock_warn(-1, "%s: socketpair", __func__);
1908585484eSchristos #else
1918585484eSchristos 		event_sock_err(1, -1, "%s: socketpair", __func__);
1928585484eSchristos #endif
1938585484eSchristos 		return -1;
1948585484eSchristos 	}
1958585484eSchristos 
1968585484eSchristos 	if (base->sig.sh_old) {
1978585484eSchristos 		mm_free(base->sig.sh_old);
1988585484eSchristos 	}
1998585484eSchristos 	base->sig.sh_old = NULL;
2008585484eSchristos 	base->sig.sh_old_max = 0;
2018585484eSchristos 
2028585484eSchristos 	event_assign(&base->sig.ev_signal, base, base->sig.ev_signal_pair[0],
2038585484eSchristos 		EV_READ | EV_PERSIST, evsig_cb, base);
2048585484eSchristos 
2058585484eSchristos 	base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL;
2068585484eSchristos 	event_priority_set(&base->sig.ev_signal, 0);
2078585484eSchristos 
2088585484eSchristos 	base->evsigsel = &evsigops;
2098585484eSchristos 
2108585484eSchristos 	return 0;
2118585484eSchristos }
2128585484eSchristos 
2138585484eSchristos /* Helper: set the signal handler for evsignal to handler in base, so that
2148585484eSchristos  * we can restore the original handler when we clear the current one. */
2158585484eSchristos int
2168585484eSchristos evsig_set_handler_(struct event_base *base,
2178585484eSchristos     int evsignal, void (__cdecl *handler)(int))
2188585484eSchristos {
2198585484eSchristos #ifdef EVENT__HAVE_SIGACTION
2208585484eSchristos 	struct sigaction sa;
2218585484eSchristos #else
2228585484eSchristos 	ev_sighandler_t sh;
2238585484eSchristos #endif
2248585484eSchristos 	struct evsig_info *sig = &base->sig;
2258585484eSchristos 	void *p;
2268585484eSchristos 
2278585484eSchristos 	/*
2288585484eSchristos 	 * resize saved signal handler array up to the highest signal number.
2298585484eSchristos 	 * a dynamic array is used to keep footprint on the low side.
2308585484eSchristos 	 */
2318585484eSchristos 	if (evsignal >= sig->sh_old_max) {
2328585484eSchristos 		int new_max = evsignal + 1;
2338585484eSchristos 		event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing",
2348585484eSchristos 			    __func__, evsignal, sig->sh_old_max));
2358585484eSchristos 		p = mm_realloc(sig->sh_old, new_max * sizeof(*sig->sh_old));
2368585484eSchristos 		if (p == NULL) {
2378585484eSchristos 			event_warn("realloc");
2388585484eSchristos 			return (-1);
2398585484eSchristos 		}
2408585484eSchristos 
2418585484eSchristos 		memset((char *)p + sig->sh_old_max * sizeof(*sig->sh_old),
2428585484eSchristos 		    0, (new_max - sig->sh_old_max) * sizeof(*sig->sh_old));
2438585484eSchristos 
2448585484eSchristos 		sig->sh_old_max = new_max;
2458585484eSchristos 		sig->sh_old = p;
2468585484eSchristos 	}
2478585484eSchristos 
2488585484eSchristos 	/* allocate space for previous handler out of dynamic array */
2498585484eSchristos 	sig->sh_old[evsignal] = mm_malloc(sizeof *sig->sh_old[evsignal]);
2508585484eSchristos 	if (sig->sh_old[evsignal] == NULL) {
2518585484eSchristos 		event_warn("malloc");
2528585484eSchristos 		return (-1);
2538585484eSchristos 	}
2548585484eSchristos 
2558585484eSchristos 	/* save previous handler and setup new handler */
2568585484eSchristos #ifdef EVENT__HAVE_SIGACTION
2578585484eSchristos 	memset(&sa, 0, sizeof(sa));
2588585484eSchristos 	sa.sa_handler = handler;
2598585484eSchristos 	sa.sa_flags |= SA_RESTART;
2608585484eSchristos 	sigfillset(&sa.sa_mask);
2618585484eSchristos 
2628585484eSchristos 	if (sigaction(evsignal, &sa, sig->sh_old[evsignal]) == -1) {
2638585484eSchristos 		event_warn("sigaction");
2648585484eSchristos 		mm_free(sig->sh_old[evsignal]);
2658585484eSchristos 		sig->sh_old[evsignal] = NULL;
2668585484eSchristos 		return (-1);
2678585484eSchristos 	}
2688585484eSchristos #else
2698585484eSchristos 	if ((sh = signal(evsignal, handler)) == SIG_ERR) {
2708585484eSchristos 		event_warn("signal");
2718585484eSchristos 		mm_free(sig->sh_old[evsignal]);
2728585484eSchristos 		sig->sh_old[evsignal] = NULL;
2738585484eSchristos 		return (-1);
2748585484eSchristos 	}
2758585484eSchristos 	*sig->sh_old[evsignal] = sh;
2768585484eSchristos #endif
2778585484eSchristos 
2788585484eSchristos 	return (0);
2798585484eSchristos }
2808585484eSchristos 
2818585484eSchristos static int
2828585484eSchristos evsig_add(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p)
2838585484eSchristos {
2848585484eSchristos 	struct evsig_info *sig = &base->sig;
2858585484eSchristos 	(void)p;
2868585484eSchristos 
2878585484eSchristos 	EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG);
2888585484eSchristos 
2898585484eSchristos 	/* catch signals if they happen quickly */
2908585484eSchristos 	EVSIGBASE_LOCK();
2918585484eSchristos 	if (evsig_base != base && evsig_base_n_signals_added) {
2928585484eSchristos 		event_warnx("Added a signal to event base %p with signals "
2938585484eSchristos 		    "already added to event_base %p.  Only one can have "
2948585484eSchristos 		    "signals at a time with the %s backend.  The base with "
2958585484eSchristos 		    "the most recently added signal or the most recent "
2968585484eSchristos 		    "event_base_loop() call gets preference; do "
2978585484eSchristos 		    "not rely on this behavior in future Libevent versions.",
2988585484eSchristos 		    base, evsig_base, base->evsel->name);
2998585484eSchristos 	}
3008585484eSchristos 	evsig_base = base;
3018585484eSchristos 	evsig_base_n_signals_added = ++sig->ev_n_signals_added;
3028585484eSchristos 	evsig_base_fd = base->sig.ev_signal_pair[1];
3038585484eSchristos 	EVSIGBASE_UNLOCK();
3048585484eSchristos 
3058585484eSchristos 	event_debug(("%s: %d: changing signal handler", __func__, (int)evsignal));
3068585484eSchristos 	if (evsig_set_handler_(base, (int)evsignal, evsig_handler) == -1) {
3078585484eSchristos 		goto err;
3088585484eSchristos 	}
3098585484eSchristos 
3108585484eSchristos 
3118585484eSchristos 	if (!sig->ev_signal_added) {
3128585484eSchristos 		if (event_add_nolock_(&sig->ev_signal, NULL, 0))
3138585484eSchristos 			goto err;
3148585484eSchristos 		sig->ev_signal_added = 1;
3158585484eSchristos 	}
3168585484eSchristos 
3178585484eSchristos 	return (0);
3188585484eSchristos 
3198585484eSchristos err:
3208585484eSchristos 	EVSIGBASE_LOCK();
3218585484eSchristos 	--evsig_base_n_signals_added;
3228585484eSchristos 	--sig->ev_n_signals_added;
3238585484eSchristos 	EVSIGBASE_UNLOCK();
3248585484eSchristos 	return (-1);
3258585484eSchristos }
3268585484eSchristos 
3278585484eSchristos int
3288585484eSchristos evsig_restore_handler_(struct event_base *base, int evsignal)
3298585484eSchristos {
3308585484eSchristos 	int ret = 0;
3318585484eSchristos 	struct evsig_info *sig = &base->sig;
3328585484eSchristos #ifdef EVENT__HAVE_SIGACTION
3338585484eSchristos 	struct sigaction *sh;
3348585484eSchristos #else
3358585484eSchristos 	ev_sighandler_t *sh;
3368585484eSchristos #endif
3378585484eSchristos 
3388585484eSchristos 	if (evsignal >= sig->sh_old_max) {
3398585484eSchristos 		/* Can't actually restore. */
3408585484eSchristos 		/* XXXX.*/
3418585484eSchristos 		return 0;
3428585484eSchristos 	}
3438585484eSchristos 
3448585484eSchristos 	/* restore previous handler */
3458585484eSchristos 	sh = sig->sh_old[evsignal];
3468585484eSchristos 	sig->sh_old[evsignal] = NULL;
3478585484eSchristos #ifdef EVENT__HAVE_SIGACTION
3488585484eSchristos 	if (sigaction(evsignal, sh, NULL) == -1) {
3498585484eSchristos 		event_warn("sigaction");
3508585484eSchristos 		ret = -1;
3518585484eSchristos 	}
3528585484eSchristos #else
3538585484eSchristos 	if (signal(evsignal, *sh) == SIG_ERR) {
3548585484eSchristos 		event_warn("signal");
3558585484eSchristos 		ret = -1;
3568585484eSchristos 	}
3578585484eSchristos #endif
3588585484eSchristos 
3598585484eSchristos 	mm_free(sh);
3608585484eSchristos 
3618585484eSchristos 	return ret;
3628585484eSchristos }
3638585484eSchristos 
3648585484eSchristos static int
3658585484eSchristos evsig_del(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p)
3668585484eSchristos {
3678585484eSchristos 	EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG);
3688585484eSchristos 
3698585484eSchristos 	event_debug(("%s: "EV_SOCK_FMT": restoring signal handler",
3708585484eSchristos 		__func__, EV_SOCK_ARG(evsignal)));
3718585484eSchristos 
3728585484eSchristos 	EVSIGBASE_LOCK();
3738585484eSchristos 	--evsig_base_n_signals_added;
3748585484eSchristos 	--base->sig.ev_n_signals_added;
3758585484eSchristos 	EVSIGBASE_UNLOCK();
3768585484eSchristos 
3778585484eSchristos 	return (evsig_restore_handler_(base, (int)evsignal));
3788585484eSchristos }
3798585484eSchristos 
3808585484eSchristos static void __cdecl
3818585484eSchristos evsig_handler(int sig)
3828585484eSchristos {
3838585484eSchristos 	int save_errno = errno;
3848585484eSchristos #ifdef _WIN32
3858585484eSchristos 	int socket_errno = EVUTIL_SOCKET_ERROR();
3868585484eSchristos #endif
3878585484eSchristos 	ev_uint8_t msg;
3888585484eSchristos 
3898585484eSchristos 	if (evsig_base == NULL) {
3908585484eSchristos 		event_warnx(
3918585484eSchristos 			"%s: received signal %d, but have no base configured",
3928585484eSchristos 			__func__, sig);
3938585484eSchristos 		return;
3948585484eSchristos 	}
3958585484eSchristos 
3968585484eSchristos #ifndef EVENT__HAVE_SIGACTION
3978585484eSchristos 	signal(sig, evsig_handler);
3988585484eSchristos #endif
3998585484eSchristos 
4008585484eSchristos 	/* Wake up our notification mechanism */
4018585484eSchristos 	msg = sig;
4028585484eSchristos #ifdef _WIN32
4038585484eSchristos 	send(evsig_base_fd, (char*)&msg, 1, 0);
4048585484eSchristos #else
4058585484eSchristos 	{
4068585484eSchristos 		int r = write(evsig_base_fd, (char*)&msg, 1);
4078585484eSchristos 		(void)r; /* Suppress 'unused return value' and 'unused var' */
4088585484eSchristos 	}
4098585484eSchristos #endif
4108585484eSchristos 	errno = save_errno;
4118585484eSchristos #ifdef _WIN32
4128585484eSchristos 	EVUTIL_SET_SOCKET_ERROR(socket_errno);
4138585484eSchristos #endif
4148585484eSchristos }
4158585484eSchristos 
4168585484eSchristos void
4178585484eSchristos evsig_dealloc_(struct event_base *base)
4188585484eSchristos {
4198585484eSchristos 	int i = 0;
4208585484eSchristos 	if (base->sig.ev_signal_added) {
4218585484eSchristos 		event_del(&base->sig.ev_signal);
4228585484eSchristos 		base->sig.ev_signal_added = 0;
4238585484eSchristos 	}
4248585484eSchristos 	/* debug event is created in evsig_init_/event_assign even when
4258585484eSchristos 	 * ev_signal_added == 0, so unassign is required */
4268585484eSchristos 	event_debug_unassign(&base->sig.ev_signal);
4278585484eSchristos 
4288585484eSchristos 	for (i = 0; i < NSIG; ++i) {
4298585484eSchristos 		if (i < base->sig.sh_old_max && base->sig.sh_old[i] != NULL)
4308585484eSchristos 			evsig_restore_handler_(base, i);
4318585484eSchristos 	}
4328585484eSchristos 	EVSIGBASE_LOCK();
4338585484eSchristos 	if (base == evsig_base) {
4348585484eSchristos 		evsig_base = NULL;
4358585484eSchristos 		evsig_base_n_signals_added = 0;
4368585484eSchristos 		evsig_base_fd = -1;
4378585484eSchristos 	}
4388585484eSchristos 	EVSIGBASE_UNLOCK();
4398585484eSchristos 
4408585484eSchristos 	if (base->sig.ev_signal_pair[0] != -1) {
4418585484eSchristos 		evutil_closesocket(base->sig.ev_signal_pair[0]);
4428585484eSchristos 		base->sig.ev_signal_pair[0] = -1;
4438585484eSchristos 	}
4448585484eSchristos 	if (base->sig.ev_signal_pair[1] != -1) {
4458585484eSchristos 		evutil_closesocket(base->sig.ev_signal_pair[1]);
4468585484eSchristos 		base->sig.ev_signal_pair[1] = -1;
4478585484eSchristos 	}
4488585484eSchristos 	base->sig.sh_old_max = 0;
4498585484eSchristos 
4508585484eSchristos 	/* per index frees are handled in evsig_del() */
4518585484eSchristos 	if (base->sig.sh_old) {
4528585484eSchristos 		mm_free(base->sig.sh_old);
4538585484eSchristos 		base->sig.sh_old = NULL;
4548585484eSchristos 	}
4558585484eSchristos }
4568585484eSchristos 
4578585484eSchristos static void
4588585484eSchristos evsig_free_globals_locks(void)
4598585484eSchristos {
4608585484eSchristos #ifndef EVENT__DISABLE_THREAD_SUPPORT
4618585484eSchristos 	if (evsig_base_lock != NULL) {
4628585484eSchristos 		EVTHREAD_FREE_LOCK(evsig_base_lock, 0);
4638585484eSchristos 		evsig_base_lock = NULL;
4648585484eSchristos 	}
4658585484eSchristos #endif
4668585484eSchristos 	return;
4678585484eSchristos }
4688585484eSchristos 
4698585484eSchristos void
4708585484eSchristos evsig_free_globals_(void)
4718585484eSchristos {
4728585484eSchristos 	evsig_free_globals_locks();
4738585484eSchristos }
4748585484eSchristos 
4758585484eSchristos #ifndef EVENT__DISABLE_THREAD_SUPPORT
4768585484eSchristos int
4778585484eSchristos evsig_global_setup_locks_(const int enable_locks)
4788585484eSchristos {
4798585484eSchristos 	EVTHREAD_SETUP_GLOBAL_LOCK(evsig_base_lock, 0);
4808585484eSchristos 	return 0;
4818585484eSchristos }
4828585484eSchristos 
4838585484eSchristos #endif
484