1 /* $NetBSD: signal.c,v 1.1.1.2 2013/04/11 16:43:25 christos Exp $ */
2 /* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
5 * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
6 * Copyright 2007-2012 Niels Provos and Nick Mathewson
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include "event2/event-config.h"
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: signal.c,v 1.1.1.2 2013/04/11 16:43:25 christos Exp $");
35 #define WIN32_LEAN_AND_MEAN
38 #undef WIN32_LEAN_AND_MEAN
40 #include <sys/types.h>
41 #ifdef _EVENT_HAVE_SYS_TIME_H
44 #include <sys/queue.h>
45 #ifdef _EVENT_HAVE_SYS_SOCKET_H
46 #include <sys/socket.h>
52 #ifdef _EVENT_HAVE_UNISTD_H
56 #ifdef _EVENT_HAVE_FCNTL_H
60 #include "event2/event.h"
61 #include "event2/event_struct.h"
62 #include "event-internal.h"
63 #include "event2/util.h"
64 #include "evsignal-internal.h"
65 #include "log-internal.h"
66 #include "evmap-internal.h"
67 #include "evthread-internal.h"
72 This is the signal-handling implementation we use for backends that don't
73 have a better way to do signal handling. It uses sigaction() or signal()
74 to set a signal handler, and a socket pair to tell the event base when
76 Note that I said "the event base" : only one event base can be set up to use
77 this at a time. For historical reasons and backward compatibility, if you
78 add an event for a signal to event_base A, then add an event for a signal
79 (any signal!) to event_base B, event_base B will get informed about the
80 signal, but event_base A won't.
82 It would be neat to change this behavior in some future version of Libevent.
83 kqueue already does something far more sensible. We can make all backends
84 on Linux do a reasonable thing using signalfd.
88 /* Windows wants us to call our signal handlers as __cdecl. Nobody else
89 * expects you to do anything crazy like this. */
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 *);
96 static const struct eventop evsigops
= {
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
;
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;
116 static void __cdecl
evsig_handler(int sig
);
118 #define EVSIGBASE_LOCK() EVLOCK_LOCK(evsig_base_lock, 0)
119 #define EVSIGBASE_UNLOCK() EVLOCK_UNLOCK(evsig_base_lock, 0)
122 evsig_set_base(struct event_base
*base
)
126 evsig_base_n_signals_added
= base
->sig
.ev_n_signals_added
;
127 evsig_base_fd
= base
->sig
.ev_signal_pair
[0];
131 /* Callback for when the signal handler write a byte to our signaling socket */
133 evsig_cb(evutil_socket_t fd
, short what
, void *arg
)
135 static char signals
[1024];
139 struct event_base
*base
;
143 memset(&ncaught
, 0, sizeof(ncaught
));
146 n
= recv(fd
, signals
, sizeof(signals
), 0);
148 int err
= evutil_socket_geterror(fd
);
149 if (! EVUTIL_ERR_RW_RETRIABLE(err
))
150 event_sock_err(1, fd
, "%s: recv", __func__
);
156 for (i
= 0; i
< n
; ++i
) {
157 ev_uint8_t sig
= signals
[i
];
163 EVBASE_ACQUIRE_LOCK(base
, th_base_lock
);
164 for (i
= 0; i
< NSIG
; ++i
) {
166 evmap_signal_active(base
, i
, ncaught
[i
]);
168 EVBASE_RELEASE_LOCK(base
, th_base_lock
);
172 evsig_init(struct event_base
*base
)
175 * Our signal handler is going to write to one end of the socket
176 * pair to wake up our event loop. The event loop then scans for
177 * signals that got delivered.
179 if (evutil_socketpair(
180 AF_UNIX
, SOCK_STREAM
, 0, base
->sig
.ev_signal_pair
) == -1) {
182 /* Make this nonfatal on win32, where sometimes people
183 have localhost firewalled. */
184 event_sock_warn(-1, "%s: socketpair", __func__
);
186 event_sock_err(1, -1, "%s: socketpair", __func__
);
191 evutil_make_socket_closeonexec(base
->sig
.ev_signal_pair
[0]);
192 evutil_make_socket_closeonexec(base
->sig
.ev_signal_pair
[1]);
193 base
->sig
.sh_old
= NULL
;
194 base
->sig
.sh_old_max
= 0;
196 evutil_make_socket_nonblocking(base
->sig
.ev_signal_pair
[0]);
197 evutil_make_socket_nonblocking(base
->sig
.ev_signal_pair
[1]);
199 event_assign(&base
->sig
.ev_signal
, base
, base
->sig
.ev_signal_pair
[1],
200 EV_READ
| EV_PERSIST
, evsig_cb
, base
);
202 base
->sig
.ev_signal
.ev_flags
|= EVLIST_INTERNAL
;
203 event_priority_set(&base
->sig
.ev_signal
, 0);
205 base
->evsigsel
= &evsigops
;
210 /* Helper: set the signal handler for evsignal to handler in base, so that
211 * we can restore the original handler when we clear the current one. */
213 _evsig_set_handler(struct event_base
*base
,
214 int evsignal
, void (__cdecl
*handler
)(int))
216 #ifdef _EVENT_HAVE_SIGACTION
221 struct evsig_info
*sig
= &base
->sig
;
225 * resize saved signal handler array up to the highest signal number.
226 * a dynamic array is used to keep footprint on the low side.
228 if (evsignal
>= sig
->sh_old_max
) {
229 int new_max
= evsignal
+ 1;
230 event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing",
231 __func__
, evsignal
, sig
->sh_old_max
));
232 p
= mm_realloc(sig
->sh_old
, new_max
* sizeof(*sig
->sh_old
));
234 event_warn("realloc");
238 memset((char *)p
+ sig
->sh_old_max
* sizeof(*sig
->sh_old
),
239 0, (new_max
- sig
->sh_old_max
) * sizeof(*sig
->sh_old
));
241 sig
->sh_old_max
= new_max
;
245 /* allocate space for previous handler out of dynamic array */
246 sig
->sh_old
[evsignal
] = mm_malloc(sizeof *sig
->sh_old
[evsignal
]);
247 if (sig
->sh_old
[evsignal
] == NULL
) {
248 event_warn("malloc");
252 /* save previous handler and setup new handler */
253 #ifdef _EVENT_HAVE_SIGACTION
254 memset(&sa
, 0, sizeof(sa
));
255 sa
.sa_handler
= handler
;
256 sa
.sa_flags
|= SA_RESTART
;
257 sigfillset(&sa
.sa_mask
);
259 if (sigaction(evsignal
, &sa
, sig
->sh_old
[evsignal
]) == -1) {
260 event_warn("sigaction");
261 mm_free(sig
->sh_old
[evsignal
]);
262 sig
->sh_old
[evsignal
] = NULL
;
266 if ((sh
= signal(evsignal
, handler
)) == SIG_ERR
) {
267 event_warn("signal");
268 mm_free(sig
->sh_old
[evsignal
]);
269 sig
->sh_old
[evsignal
] = NULL
;
272 *sig
->sh_old
[evsignal
] = sh
;
279 evsig_add(struct event_base
*base
, evutil_socket_t evsignal
, short old
, short events
, void *p
)
281 struct evsig_info
*sig
= &base
->sig
;
284 EVUTIL_ASSERT(evsignal
>= 0 && evsignal
< NSIG
);
286 /* catch signals if they happen quickly */
288 if (evsig_base
!= base
&& evsig_base_n_signals_added
) {
289 event_warnx("Added a signal to event base %p with signals "
290 "already added to event_base %p. Only one can have "
291 "signals at a time with the %s backend. The base with "
292 "the most recently added signal or the most recent "
293 "event_base_loop() call gets preference; do "
294 "not rely on this behavior in future Libevent versions.",
295 base
, evsig_base
, base
->evsel
->name
);
298 evsig_base_n_signals_added
= ++sig
->ev_n_signals_added
;
299 evsig_base_fd
= base
->sig
.ev_signal_pair
[0];
302 event_debug(("%s: %d: changing signal handler", __func__
, (int)evsignal
));
303 if (_evsig_set_handler(base
, (int)evsignal
, evsig_handler
) == -1) {
308 if (!sig
->ev_signal_added
) {
309 if (event_add(&sig
->ev_signal
, NULL
))
311 sig
->ev_signal_added
= 1;
318 --evsig_base_n_signals_added
;
319 --sig
->ev_n_signals_added
;
325 _evsig_restore_handler(struct event_base
*base
, int evsignal
)
328 struct evsig_info
*sig
= &base
->sig
;
329 #ifdef _EVENT_HAVE_SIGACTION
330 struct sigaction
*sh
;
335 /* restore previous handler */
336 sh
= sig
->sh_old
[evsignal
];
337 sig
->sh_old
[evsignal
] = NULL
;
338 #ifdef _EVENT_HAVE_SIGACTION
339 if (sigaction(evsignal
, sh
, NULL
) == -1) {
340 event_warn("sigaction");
344 if (signal(evsignal
, *sh
) == SIG_ERR
) {
345 event_warn("signal");
356 evsig_del(struct event_base
*base
, evutil_socket_t evsignal
, short old
, short events
, void *p
)
358 EVUTIL_ASSERT(evsignal
>= 0 && evsignal
< NSIG
);
360 event_debug(("%s: "EV_SOCK_FMT
": restoring signal handler",
361 __func__
, EV_SOCK_ARG(evsignal
)));
364 --evsig_base_n_signals_added
;
365 --base
->sig
.ev_n_signals_added
;
368 return (_evsig_restore_handler(base
, (int)evsignal
));
372 evsig_handler(int sig
)
374 int save_errno
= errno
;
376 int socket_errno
= EVUTIL_SOCKET_ERROR();
380 if (evsig_base
== NULL
) {
382 "%s: received signal %d, but have no base configured",
387 #ifndef _EVENT_HAVE_SIGACTION
388 signal(sig
, evsig_handler
);
391 /* Wake up our notification mechanism */
393 send(evsig_base_fd
, (char*)&msg
, 1, 0);
396 EVUTIL_SET_SOCKET_ERROR(socket_errno
);
401 evsig_dealloc(struct event_base
*base
)
404 if (base
->sig
.ev_signal_added
) {
405 event_del(&base
->sig
.ev_signal
);
406 base
->sig
.ev_signal_added
= 0;
408 /* debug event is created in evsig_init/event_assign even when
409 * ev_signal_added == 0, so unassign is required */
410 event_debug_unassign(&base
->sig
.ev_signal
);
412 for (i
= 0; i
< NSIG
; ++i
) {
413 if (i
< base
->sig
.sh_old_max
&& base
->sig
.sh_old
[i
] != NULL
)
414 _evsig_restore_handler(base
, i
);
417 if (base
== evsig_base
) {
419 evsig_base_n_signals_added
= 0;
424 if (base
->sig
.ev_signal_pair
[0] != -1) {
425 evutil_closesocket(base
->sig
.ev_signal_pair
[0]);
426 base
->sig
.ev_signal_pair
[0] = -1;
428 if (base
->sig
.ev_signal_pair
[1] != -1) {
429 evutil_closesocket(base
->sig
.ev_signal_pair
[1]);
430 base
->sig
.ev_signal_pair
[1] = -1;
432 base
->sig
.sh_old_max
= 0;
434 /* per index frees are handled in evsig_del() */
435 if (base
->sig
.sh_old
) {
436 mm_free(base
->sig
.sh_old
);
437 base
->sig
.sh_old
= NULL
;
441 #ifndef _EVENT_DISABLE_THREAD_SUPPORT
443 evsig_global_setup_locks_(const int enable_locks
)
445 EVTHREAD_SETUP_GLOBAL_LOCK(evsig_base_lock
, 0);