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