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