1 /* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
4 * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
5 * Copyright 2007-2012 Niels Provos and Nick Mathewson
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "event2/event-config.h"
32 #define WIN32_LEAN_AND_MEAN
35 #undef WIN32_LEAN_AND_MEAN
37 #include <sys/types.h>
38 #ifdef _EVENT_HAVE_SYS_TIME_H
41 #include <sys/queue.h>
42 #ifdef _EVENT_HAVE_SYS_SOCKET_H
43 #include <sys/socket.h>
49 #ifdef _EVENT_HAVE_UNISTD_H
53 #ifdef _EVENT_HAVE_FCNTL_H
57 #include "event2/event.h"
58 #include "event2/event_struct.h"
59 #include "event-internal.h"
60 #include "event2/util.h"
61 #include "evsignal-internal.h"
62 #include "log-internal.h"
63 #include "evmap-internal.h"
64 #include "evthread-internal.h"
69 This is the signal-handling implementation we use for backends that don't
70 have a better way to do signal handling. It uses sigaction() or signal()
71 to set a signal handler, and a socket pair to tell the event base when
73 Note that I said "the event base" : only one event base can be set up to use
74 this at a time. For historical reasons and backward compatibility, if you
75 add an event for a signal to event_base A, then add an event for a signal
76 (any signal!) to event_base B, event_base B will get informed about the
77 signal, but event_base A won't.
79 It would be neat to change this behavior in some future version of Libevent.
80 kqueue already does something far more sensible. We can make all backends
81 on Linux do a reasonable thing using signalfd.
85 /* Windows wants us to call our signal handlers as __cdecl. Nobody else
86 * expects you to do anything crazy like this. */
90 static int evsig_add(struct event_base
*, evutil_socket_t
, short, short, void *);
91 static int evsig_del(struct event_base
*, evutil_socket_t
, short, short, void *);
93 static const struct eventop evsigops
= {
103 #ifndef _EVENT_DISABLE_THREAD_SUPPORT
104 /* Lock for evsig_base and evsig_base_n_signals_added fields. */
105 static void *evsig_base_lock
= NULL
;
107 /* The event base that's currently getting informed about signals. */
108 static struct event_base
*evsig_base
= NULL
;
109 /* A copy of evsig_base->sigev_n_signals_added. */
110 static int evsig_base_n_signals_added
= 0;
111 static evutil_socket_t evsig_base_fd
= -1;
113 static void __cdecl
evsig_handler(int sig
);
115 #define EVSIGBASE_LOCK() EVLOCK_LOCK(evsig_base_lock, 0)
116 #define EVSIGBASE_UNLOCK() EVLOCK_UNLOCK(evsig_base_lock, 0)
119 evsig_set_base(struct event_base
*base
)
123 evsig_base_n_signals_added
= base
->sig
.ev_n_signals_added
;
124 evsig_base_fd
= base
->sig
.ev_signal_pair
[0];
128 /* Callback for when the signal handler write a byte to our signaling socket */
130 evsig_cb(evutil_socket_t fd
, short what
, void *arg
)
132 static char signals
[1024];
136 struct event_base
*base
;
140 memset(&ncaught
, 0, sizeof(ncaught
));
143 n
= recv(fd
, signals
, sizeof(signals
), 0);
145 int err
= evutil_socket_geterror(fd
);
146 if (! EVUTIL_ERR_RW_RETRIABLE(err
))
147 event_sock_err(1, fd
, "%s: recv", __func__
);
153 for (i
= 0; i
< n
; ++i
) {
154 ev_uint8_t sig
= signals
[i
];
160 EVBASE_ACQUIRE_LOCK(base
, th_base_lock
);
161 for (i
= 0; i
< NSIG
; ++i
) {
163 evmap_signal_active(base
, i
, ncaught
[i
]);
165 EVBASE_RELEASE_LOCK(base
, th_base_lock
);
169 evsig_init(struct event_base
*base
)
172 * Our signal handler is going to write to one end of the socket
173 * pair to wake up our event loop. The event loop then scans for
174 * signals that got delivered.
176 if (evutil_socketpair(
177 AF_UNIX
, SOCK_STREAM
, 0, base
->sig
.ev_signal_pair
) == -1) {
179 /* Make this nonfatal on win32, where sometimes people
180 have localhost firewalled. */
181 event_sock_warn(-1, "%s: socketpair", __func__
);
183 event_sock_err(1, -1, "%s: socketpair", __func__
);
188 evutil_make_socket_closeonexec(base
->sig
.ev_signal_pair
[0]);
189 evutil_make_socket_closeonexec(base
->sig
.ev_signal_pair
[1]);
190 base
->sig
.sh_old
= NULL
;
191 base
->sig
.sh_old_max
= 0;
193 evutil_make_socket_nonblocking(base
->sig
.ev_signal_pair
[0]);
194 evutil_make_socket_nonblocking(base
->sig
.ev_signal_pair
[1]);
196 event_assign(&base
->sig
.ev_signal
, base
, base
->sig
.ev_signal_pair
[1],
197 EV_READ
| EV_PERSIST
, evsig_cb
, base
);
199 base
->sig
.ev_signal
.ev_flags
|= EVLIST_INTERNAL
;
200 event_priority_set(&base
->sig
.ev_signal
, 0);
202 base
->evsigsel
= &evsigops
;
207 /* Helper: set the signal handler for evsignal to handler in base, so that
208 * we can restore the original handler when we clear the current one. */
210 _evsig_set_handler(struct event_base
*base
,
211 int evsignal
, void (__cdecl
*handler
)(int))
213 #ifdef _EVENT_HAVE_SIGACTION
218 struct evsig_info
*sig
= &base
->sig
;
222 * resize saved signal handler array up to the highest signal number.
223 * a dynamic array is used to keep footprint on the low side.
225 if (evsignal
>= sig
->sh_old_max
) {
226 int new_max
= evsignal
+ 1;
227 event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing",
228 __func__
, evsignal
, sig
->sh_old_max
));
229 p
= mm_realloc(sig
->sh_old
, new_max
* sizeof(*sig
->sh_old
));
231 event_warn("realloc");
235 memset((char *)p
+ sig
->sh_old_max
* sizeof(*sig
->sh_old
),
236 0, (new_max
- sig
->sh_old_max
) * sizeof(*sig
->sh_old
));
238 sig
->sh_old_max
= new_max
;
242 /* allocate space for previous handler out of dynamic array */
243 sig
->sh_old
[evsignal
] = mm_malloc(sizeof *sig
->sh_old
[evsignal
]);
244 if (sig
->sh_old
[evsignal
] == NULL
) {
245 event_warn("malloc");
249 /* save previous handler and setup new handler */
250 #ifdef _EVENT_HAVE_SIGACTION
251 memset(&sa
, 0, sizeof(sa
));
252 sa
.sa_handler
= handler
;
253 sa
.sa_flags
|= SA_RESTART
;
254 sigfillset(&sa
.sa_mask
);
256 if (sigaction(evsignal
, &sa
, sig
->sh_old
[evsignal
]) == -1) {
257 event_warn("sigaction");
258 mm_free(sig
->sh_old
[evsignal
]);
259 sig
->sh_old
[evsignal
] = NULL
;
263 if ((sh
= signal(evsignal
, handler
)) == SIG_ERR
) {
264 event_warn("signal");
265 mm_free(sig
->sh_old
[evsignal
]);
266 sig
->sh_old
[evsignal
] = NULL
;
269 *sig
->sh_old
[evsignal
] = sh
;
276 evsig_add(struct event_base
*base
, evutil_socket_t evsignal
, short old
, short events
, void *p
)
278 struct evsig_info
*sig
= &base
->sig
;
281 EVUTIL_ASSERT(evsignal
>= 0 && evsignal
< NSIG
);
283 /* catch signals if they happen quickly */
285 if (evsig_base
!= base
&& evsig_base_n_signals_added
) {
286 event_warnx("Added a signal to event base %p with signals "
287 "already added to event_base %p. Only one can have "
288 "signals at a time with the %s backend. The base with "
289 "the most recently added signal or the most recent "
290 "event_base_loop() call gets preference; do "
291 "not rely on this behavior in future Libevent versions.",
292 base
, evsig_base
, base
->evsel
->name
);
295 evsig_base_n_signals_added
= ++sig
->ev_n_signals_added
;
296 evsig_base_fd
= base
->sig
.ev_signal_pair
[0];
299 event_debug(("%s: %d: changing signal handler", __func__
, (int)evsignal
));
300 if (_evsig_set_handler(base
, (int)evsignal
, evsig_handler
) == -1) {
305 if (!sig
->ev_signal_added
) {
306 if (event_add(&sig
->ev_signal
, NULL
))
308 sig
->ev_signal_added
= 1;
315 --evsig_base_n_signals_added
;
316 --sig
->ev_n_signals_added
;
322 _evsig_restore_handler(struct event_base
*base
, int evsignal
)
325 struct evsig_info
*sig
= &base
->sig
;
326 #ifdef _EVENT_HAVE_SIGACTION
327 struct sigaction
*sh
;
332 /* restore previous handler */
333 sh
= sig
->sh_old
[evsignal
];
334 sig
->sh_old
[evsignal
] = NULL
;
335 #ifdef _EVENT_HAVE_SIGACTION
336 if (sigaction(evsignal
, sh
, NULL
) == -1) {
337 event_warn("sigaction");
341 if (signal(evsignal
, *sh
) == SIG_ERR
) {
342 event_warn("signal");
353 evsig_del(struct event_base
*base
, evutil_socket_t evsignal
, short old
, short events
, void *p
)
355 EVUTIL_ASSERT(evsignal
>= 0 && evsignal
< NSIG
);
357 event_debug(("%s: "EV_SOCK_FMT
": restoring signal handler",
358 __func__
, EV_SOCK_ARG(evsignal
)));
361 --evsig_base_n_signals_added
;
362 --base
->sig
.ev_n_signals_added
;
365 return (_evsig_restore_handler(base
, (int)evsignal
));
369 evsig_handler(int sig
)
371 int save_errno
= errno
;
373 int socket_errno
= EVUTIL_SOCKET_ERROR();
377 if (evsig_base
== NULL
) {
379 "%s: received signal %d, but have no base configured",
384 #ifndef _EVENT_HAVE_SIGACTION
385 signal(sig
, evsig_handler
);
388 /* Wake up our notification mechanism */
390 send(evsig_base_fd
, (char*)&msg
, 1, 0);
393 EVUTIL_SET_SOCKET_ERROR(socket_errno
);
398 evsig_dealloc(struct event_base
*base
)
401 if (base
->sig
.ev_signal_added
) {
402 event_del(&base
->sig
.ev_signal
);
403 base
->sig
.ev_signal_added
= 0;
405 /* debug event is created in evsig_init/event_assign even when
406 * ev_signal_added == 0, so unassign is required */
407 event_debug_unassign(&base
->sig
.ev_signal
);
409 for (i
= 0; i
< NSIG
; ++i
) {
410 if (i
< base
->sig
.sh_old_max
&& base
->sig
.sh_old
[i
] != NULL
)
411 _evsig_restore_handler(base
, i
);
414 if (base
== evsig_base
) {
416 evsig_base_n_signals_added
= 0;
421 if (base
->sig
.ev_signal_pair
[0] != -1) {
422 evutil_closesocket(base
->sig
.ev_signal_pair
[0]);
423 base
->sig
.ev_signal_pair
[0] = -1;
425 if (base
->sig
.ev_signal_pair
[1] != -1) {
426 evutil_closesocket(base
->sig
.ev_signal_pair
[1]);
427 base
->sig
.ev_signal_pair
[1] = -1;
429 base
->sig
.sh_old_max
= 0;
431 /* per index frees are handled in evsig_del() */
432 if (base
->sig
.sh_old
) {
433 mm_free(base
->sig
.sh_old
);
434 base
->sig
.sh_old
= NULL
;
438 #ifndef _EVENT_DISABLE_THREAD_SUPPORT
440 evsig_global_setup_locks_(const int enable_locks
)
442 EVTHREAD_SETUP_GLOBAL_LOCK(evsig_base_lock
, 0);