1290001Sglebius/* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */ 2290001Sglebius 3290001Sglebius/* 4290001Sglebius * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu> 5290001Sglebius * Copyright 2007-2012 Niels Provos and Nick Mathewson 6290001Sglebius * 7290001Sglebius * Redistribution and use in source and binary forms, with or without 8290001Sglebius * modification, are permitted provided that the following conditions 9290001Sglebius * are met: 10290001Sglebius * 1. Redistributions of source code must retain the above copyright 11290001Sglebius * notice, this list of conditions and the following disclaimer. 12290001Sglebius * 2. Redistributions in binary form must reproduce the above copyright 13290001Sglebius * notice, this list of conditions and the following disclaimer in the 14290001Sglebius * documentation and/or other materials provided with the distribution. 15290001Sglebius * 3. The name of the author may not be used to endorse or promote products 16290001Sglebius * derived from this software without specific prior written permission. 17290001Sglebius * 18290001Sglebius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19290001Sglebius * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20290001Sglebius * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21290001Sglebius * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22290001Sglebius * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23290001Sglebius * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24290001Sglebius * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25290001Sglebius * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26290001Sglebius * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27290001Sglebius * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28290001Sglebius */ 29290001Sglebius#include "event2/event-config.h" 30290001Sglebius#include "evconfig-private.h" 31290001Sglebius 32290001Sglebius#ifdef _WIN32 33290001Sglebius#define WIN32_LEAN_AND_MEAN 34290001Sglebius#include <winsock2.h> 35290001Sglebius#include <windows.h> 36290001Sglebius#undef WIN32_LEAN_AND_MEAN 37290001Sglebius#endif 38290001Sglebius#include <sys/types.h> 39290001Sglebius#ifdef EVENT__HAVE_SYS_TIME_H 40290001Sglebius#include <sys/time.h> 41290001Sglebius#endif 42290001Sglebius#include <sys/queue.h> 43290001Sglebius#ifdef EVENT__HAVE_SYS_SOCKET_H 44290001Sglebius#include <sys/socket.h> 45290001Sglebius#endif 46290001Sglebius#include <signal.h> 47290001Sglebius#include <stdio.h> 48290001Sglebius#include <stdlib.h> 49290001Sglebius#include <string.h> 50290001Sglebius#ifdef EVENT__HAVE_UNISTD_H 51290001Sglebius#include <unistd.h> 52290001Sglebius#endif 53290001Sglebius#include <errno.h> 54290001Sglebius#ifdef EVENT__HAVE_FCNTL_H 55290001Sglebius#include <fcntl.h> 56290001Sglebius#endif 57290001Sglebius 58290001Sglebius#include "event2/event.h" 59290001Sglebius#include "event2/event_struct.h" 60290001Sglebius#include "event-internal.h" 61290001Sglebius#include "event2/util.h" 62290001Sglebius#include "evsignal-internal.h" 63290001Sglebius#include "log-internal.h" 64290001Sglebius#include "evmap-internal.h" 65290001Sglebius#include "evthread-internal.h" 66290001Sglebius 67290001Sglebius/* 68290001Sglebius signal.c 69290001Sglebius 70290001Sglebius This is the signal-handling implementation we use for backends that don't 71290001Sglebius have a better way to do signal handling. It uses sigaction() or signal() 72290001Sglebius to set a signal handler, and a socket pair to tell the event base when 73290001Sglebius 74290001Sglebius Note that I said "the event base" : only one event base can be set up to use 75290001Sglebius this at a time. For historical reasons and backward compatibility, if you 76290001Sglebius add an event for a signal to event_base A, then add an event for a signal 77290001Sglebius (any signal!) to event_base B, event_base B will get informed about the 78290001Sglebius signal, but event_base A won't. 79290001Sglebius 80290001Sglebius It would be neat to change this behavior in some future version of Libevent. 81290001Sglebius kqueue already does something far more sensible. We can make all backends 82290001Sglebius on Linux do a reasonable thing using signalfd. 83290001Sglebius*/ 84290001Sglebius 85290001Sglebius#ifndef _WIN32 86290001Sglebius/* Windows wants us to call our signal handlers as __cdecl. Nobody else 87290001Sglebius * expects you to do anything crazy like this. */ 88290001Sglebius#define __cdecl 89290001Sglebius#endif 90290001Sglebius 91290001Sglebiusstatic int evsig_add(struct event_base *, evutil_socket_t, short, short, void *); 92290001Sglebiusstatic int evsig_del(struct event_base *, evutil_socket_t, short, short, void *); 93290001Sglebius 94290001Sglebiusstatic const struct eventop evsigops = { 95290001Sglebius "signal", 96290001Sglebius NULL, 97290001Sglebius evsig_add, 98290001Sglebius evsig_del, 99290001Sglebius NULL, 100290001Sglebius NULL, 101290001Sglebius 0, 0, 0 102290001Sglebius}; 103290001Sglebius 104290001Sglebius#ifndef EVENT__DISABLE_THREAD_SUPPORT 105290001Sglebius/* Lock for evsig_base and evsig_base_n_signals_added fields. */ 106290001Sglebiusstatic void *evsig_base_lock = NULL; 107290001Sglebius#endif 108290001Sglebius/* The event base that's currently getting informed about signals. */ 109290001Sglebiusstatic struct event_base *evsig_base = NULL; 110290001Sglebius/* A copy of evsig_base->sigev_n_signals_added. */ 111290001Sglebiusstatic int evsig_base_n_signals_added = 0; 112290001Sglebiusstatic evutil_socket_t evsig_base_fd = -1; 113290001Sglebius 114290001Sglebiusstatic void __cdecl evsig_handler(int sig); 115290001Sglebius 116290001Sglebius#define EVSIGBASE_LOCK() EVLOCK_LOCK(evsig_base_lock, 0) 117290001Sglebius#define EVSIGBASE_UNLOCK() EVLOCK_UNLOCK(evsig_base_lock, 0) 118290001Sglebius 119290001Sglebiusvoid 120290001Sglebiusevsig_set_base_(struct event_base *base) 121290001Sglebius{ 122290001Sglebius EVSIGBASE_LOCK(); 123290001Sglebius evsig_base = base; 124290001Sglebius evsig_base_n_signals_added = base->sig.ev_n_signals_added; 125290001Sglebius evsig_base_fd = base->sig.ev_signal_pair[1]; 126290001Sglebius EVSIGBASE_UNLOCK(); 127290001Sglebius} 128290001Sglebius 129290001Sglebius/* Callback for when the signal handler write a byte to our signaling socket */ 130290001Sglebiusstatic void 131290001Sglebiusevsig_cb(evutil_socket_t fd, short what, void *arg) 132290001Sglebius{ 133290001Sglebius static char signals[1024]; 134290001Sglebius ev_ssize_t n; 135290001Sglebius int i; 136290001Sglebius int ncaught[NSIG]; 137290001Sglebius struct event_base *base; 138290001Sglebius 139290001Sglebius base = arg; 140290001Sglebius 141290001Sglebius memset(&ncaught, 0, sizeof(ncaught)); 142290001Sglebius 143290001Sglebius while (1) { 144290001Sglebius#ifdef _WIN32 145290001Sglebius n = recv(fd, signals, sizeof(signals), 0); 146290001Sglebius#else 147290001Sglebius n = read(fd, signals, sizeof(signals)); 148290001Sglebius#endif 149290001Sglebius if (n == -1) { 150290001Sglebius int err = evutil_socket_geterror(fd); 151290001Sglebius if (! EVUTIL_ERR_RW_RETRIABLE(err)) 152290001Sglebius event_sock_err(1, fd, "%s: recv", __func__); 153290001Sglebius break; 154290001Sglebius } else if (n == 0) { 155290001Sglebius /* XXX warn? */ 156290001Sglebius break; 157290001Sglebius } 158290001Sglebius for (i = 0; i < n; ++i) { 159290001Sglebius ev_uint8_t sig = signals[i]; 160290001Sglebius if (sig < NSIG) 161290001Sglebius ncaught[sig]++; 162290001Sglebius } 163290001Sglebius } 164290001Sglebius 165290001Sglebius EVBASE_ACQUIRE_LOCK(base, th_base_lock); 166290001Sglebius for (i = 0; i < NSIG; ++i) { 167290001Sglebius if (ncaught[i]) 168290001Sglebius evmap_signal_active_(base, i, ncaught[i]); 169290001Sglebius } 170290001Sglebius EVBASE_RELEASE_LOCK(base, th_base_lock); 171290001Sglebius} 172290001Sglebius 173290001Sglebiusint 174290001Sglebiusevsig_init_(struct event_base *base) 175290001Sglebius{ 176290001Sglebius /* 177290001Sglebius * Our signal handler is going to write to one end of the socket 178290001Sglebius * pair to wake up our event loop. The event loop then scans for 179290001Sglebius * signals that got delivered. 180290001Sglebius */ 181290001Sglebius if (evutil_make_internal_pipe_(base->sig.ev_signal_pair) == -1) { 182290001Sglebius#ifdef _WIN32 183290001Sglebius /* Make this nonfatal on win32, where sometimes people 184290001Sglebius have localhost firewalled. */ 185290001Sglebius event_sock_warn(-1, "%s: socketpair", __func__); 186290001Sglebius#else 187290001Sglebius event_sock_err(1, -1, "%s: socketpair", __func__); 188290001Sglebius#endif 189290001Sglebius return -1; 190290001Sglebius } 191290001Sglebius 192290001Sglebius if (base->sig.sh_old) { 193290001Sglebius mm_free(base->sig.sh_old); 194290001Sglebius } 195290001Sglebius base->sig.sh_old = NULL; 196290001Sglebius base->sig.sh_old_max = 0; 197290001Sglebius 198290001Sglebius event_assign(&base->sig.ev_signal, base, base->sig.ev_signal_pair[0], 199290001Sglebius EV_READ | EV_PERSIST, evsig_cb, base); 200290001Sglebius 201290001Sglebius base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL; 202290001Sglebius event_priority_set(&base->sig.ev_signal, 0); 203290001Sglebius 204290001Sglebius base->evsigsel = &evsigops; 205290001Sglebius 206290001Sglebius return 0; 207290001Sglebius} 208290001Sglebius 209290001Sglebius/* Helper: set the signal handler for evsignal to handler in base, so that 210290001Sglebius * we can restore the original handler when we clear the current one. */ 211290001Sglebiusint 212290001Sglebiusevsig_set_handler_(struct event_base *base, 213290001Sglebius int evsignal, void (__cdecl *handler)(int)) 214290001Sglebius{ 215290001Sglebius#ifdef EVENT__HAVE_SIGACTION 216290001Sglebius struct sigaction sa; 217290001Sglebius#else 218290001Sglebius ev_sighandler_t sh; 219290001Sglebius#endif 220290001Sglebius struct evsig_info *sig = &base->sig; 221290001Sglebius void *p; 222290001Sglebius 223290001Sglebius /* 224290001Sglebius * resize saved signal handler array up to the highest signal number. 225290001Sglebius * a dynamic array is used to keep footprint on the low side. 226290001Sglebius */ 227290001Sglebius if (evsignal >= sig->sh_old_max) { 228290001Sglebius int new_max = evsignal + 1; 229290001Sglebius event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing", 230290001Sglebius __func__, evsignal, sig->sh_old_max)); 231290001Sglebius p = mm_realloc(sig->sh_old, new_max * sizeof(*sig->sh_old)); 232290001Sglebius if (p == NULL) { 233290001Sglebius event_warn("realloc"); 234290001Sglebius return (-1); 235290001Sglebius } 236290001Sglebius 237290001Sglebius memset((char *)p + sig->sh_old_max * sizeof(*sig->sh_old), 238290001Sglebius 0, (new_max - sig->sh_old_max) * sizeof(*sig->sh_old)); 239290001Sglebius 240290001Sglebius sig->sh_old_max = new_max; 241290001Sglebius sig->sh_old = p; 242290001Sglebius } 243290001Sglebius 244290001Sglebius /* allocate space for previous handler out of dynamic array */ 245290001Sglebius sig->sh_old[evsignal] = mm_malloc(sizeof *sig->sh_old[evsignal]); 246290001Sglebius if (sig->sh_old[evsignal] == NULL) { 247290001Sglebius event_warn("malloc"); 248290001Sglebius return (-1); 249290001Sglebius } 250290001Sglebius 251290001Sglebius /* save previous handler and setup new handler */ 252290001Sglebius#ifdef EVENT__HAVE_SIGACTION 253290001Sglebius memset(&sa, 0, sizeof(sa)); 254290001Sglebius sa.sa_handler = handler; 255290001Sglebius sa.sa_flags |= SA_RESTART; 256290001Sglebius sigfillset(&sa.sa_mask); 257290001Sglebius 258290001Sglebius if (sigaction(evsignal, &sa, sig->sh_old[evsignal]) == -1) { 259290001Sglebius event_warn("sigaction"); 260290001Sglebius mm_free(sig->sh_old[evsignal]); 261290001Sglebius sig->sh_old[evsignal] = NULL; 262290001Sglebius return (-1); 263290001Sglebius } 264290001Sglebius#else 265290001Sglebius if ((sh = signal(evsignal, handler)) == SIG_ERR) { 266290001Sglebius event_warn("signal"); 267290001Sglebius mm_free(sig->sh_old[evsignal]); 268290001Sglebius sig->sh_old[evsignal] = NULL; 269290001Sglebius return (-1); 270290001Sglebius } 271290001Sglebius *sig->sh_old[evsignal] = sh; 272290001Sglebius#endif 273290001Sglebius 274290001Sglebius return (0); 275290001Sglebius} 276290001Sglebius 277290001Sglebiusstatic int 278290001Sglebiusevsig_add(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p) 279290001Sglebius{ 280290001Sglebius struct evsig_info *sig = &base->sig; 281290001Sglebius (void)p; 282290001Sglebius 283290001Sglebius EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG); 284290001Sglebius 285290001Sglebius /* catch signals if they happen quickly */ 286290001Sglebius EVSIGBASE_LOCK(); 287290001Sglebius if (evsig_base != base && evsig_base_n_signals_added) { 288290001Sglebius event_warnx("Added a signal to event base %p with signals " 289290001Sglebius "already added to event_base %p. Only one can have " 290290001Sglebius "signals at a time with the %s backend. The base with " 291290001Sglebius "the most recently added signal or the most recent " 292290001Sglebius "event_base_loop() call gets preference; do " 293290001Sglebius "not rely on this behavior in future Libevent versions.", 294290001Sglebius base, evsig_base, base->evsel->name); 295290001Sglebius } 296290001Sglebius evsig_base = base; 297290001Sglebius evsig_base_n_signals_added = ++sig->ev_n_signals_added; 298290001Sglebius evsig_base_fd = base->sig.ev_signal_pair[1]; 299290001Sglebius EVSIGBASE_UNLOCK(); 300290001Sglebius 301290001Sglebius event_debug(("%s: %d: changing signal handler", __func__, (int)evsignal)); 302290001Sglebius if (evsig_set_handler_(base, (int)evsignal, evsig_handler) == -1) { 303290001Sglebius goto err; 304290001Sglebius } 305290001Sglebius 306290001Sglebius 307290001Sglebius if (!sig->ev_signal_added) { 308290001Sglebius if (event_add_nolock_(&sig->ev_signal, NULL, 0)) 309290001Sglebius goto err; 310290001Sglebius sig->ev_signal_added = 1; 311290001Sglebius } 312290001Sglebius 313290001Sglebius return (0); 314290001Sglebius 315290001Sglebiuserr: 316290001Sglebius EVSIGBASE_LOCK(); 317290001Sglebius --evsig_base_n_signals_added; 318290001Sglebius --sig->ev_n_signals_added; 319290001Sglebius EVSIGBASE_UNLOCK(); 320290001Sglebius return (-1); 321290001Sglebius} 322290001Sglebius 323290001Sglebiusint 324290001Sglebiusevsig_restore_handler_(struct event_base *base, int evsignal) 325290001Sglebius{ 326290001Sglebius int ret = 0; 327290001Sglebius struct evsig_info *sig = &base->sig; 328290001Sglebius#ifdef EVENT__HAVE_SIGACTION 329290001Sglebius struct sigaction *sh; 330290001Sglebius#else 331290001Sglebius ev_sighandler_t *sh; 332290001Sglebius#endif 333290001Sglebius 334290001Sglebius if (evsignal >= sig->sh_old_max) { 335290001Sglebius /* Can't actually restore. */ 336290001Sglebius /* XXXX.*/ 337290001Sglebius return 0; 338290001Sglebius } 339290001Sglebius 340290001Sglebius /* restore previous handler */ 341290001Sglebius sh = sig->sh_old[evsignal]; 342290001Sglebius sig->sh_old[evsignal] = NULL; 343290001Sglebius#ifdef EVENT__HAVE_SIGACTION 344290001Sglebius if (sigaction(evsignal, sh, NULL) == -1) { 345290001Sglebius event_warn("sigaction"); 346290001Sglebius ret = -1; 347290001Sglebius } 348290001Sglebius#else 349290001Sglebius if (signal(evsignal, *sh) == SIG_ERR) { 350290001Sglebius event_warn("signal"); 351290001Sglebius ret = -1; 352290001Sglebius } 353290001Sglebius#endif 354290001Sglebius 355290001Sglebius mm_free(sh); 356290001Sglebius 357290001Sglebius return ret; 358290001Sglebius} 359290001Sglebius 360290001Sglebiusstatic int 361290001Sglebiusevsig_del(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p) 362290001Sglebius{ 363290001Sglebius EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG); 364290001Sglebius 365290001Sglebius event_debug(("%s: "EV_SOCK_FMT": restoring signal handler", 366290001Sglebius __func__, EV_SOCK_ARG(evsignal))); 367290001Sglebius 368290001Sglebius EVSIGBASE_LOCK(); 369290001Sglebius --evsig_base_n_signals_added; 370290001Sglebius --base->sig.ev_n_signals_added; 371290001Sglebius EVSIGBASE_UNLOCK(); 372290001Sglebius 373290001Sglebius return (evsig_restore_handler_(base, (int)evsignal)); 374290001Sglebius} 375290001Sglebius 376290001Sglebiusstatic void __cdecl 377290001Sglebiusevsig_handler(int sig) 378290001Sglebius{ 379290001Sglebius int save_errno = errno; 380290001Sglebius#ifdef _WIN32 381290001Sglebius int socket_errno = EVUTIL_SOCKET_ERROR(); 382290001Sglebius#endif 383290001Sglebius ev_uint8_t msg; 384290001Sglebius 385290001Sglebius if (evsig_base == NULL) { 386290001Sglebius event_warnx( 387290001Sglebius "%s: received signal %d, but have no base configured", 388290001Sglebius __func__, sig); 389290001Sglebius return; 390290001Sglebius } 391290001Sglebius 392290001Sglebius#ifndef EVENT__HAVE_SIGACTION 393290001Sglebius signal(sig, evsig_handler); 394290001Sglebius#endif 395290001Sglebius 396290001Sglebius /* Wake up our notification mechanism */ 397290001Sglebius msg = sig; 398290001Sglebius#ifdef _WIN32 399290001Sglebius send(evsig_base_fd, (char*)&msg, 1, 0); 400290001Sglebius#else 401290001Sglebius { 402290001Sglebius int r = write(evsig_base_fd, (char*)&msg, 1); 403290001Sglebius (void)r; /* Suppress 'unused return value' and 'unused var' */ 404290001Sglebius } 405290001Sglebius#endif 406290001Sglebius errno = save_errno; 407290001Sglebius#ifdef _WIN32 408290001Sglebius EVUTIL_SET_SOCKET_ERROR(socket_errno); 409290001Sglebius#endif 410290001Sglebius} 411290001Sglebius 412290001Sglebiusvoid 413290001Sglebiusevsig_dealloc_(struct event_base *base) 414290001Sglebius{ 415290001Sglebius int i = 0; 416290001Sglebius if (base->sig.ev_signal_added) { 417290001Sglebius event_del(&base->sig.ev_signal); 418290001Sglebius base->sig.ev_signal_added = 0; 419290001Sglebius } 420290001Sglebius /* debug event is created in evsig_init_/event_assign even when 421290001Sglebius * ev_signal_added == 0, so unassign is required */ 422290001Sglebius event_debug_unassign(&base->sig.ev_signal); 423290001Sglebius 424290001Sglebius for (i = 0; i < NSIG; ++i) { 425290001Sglebius if (i < base->sig.sh_old_max && base->sig.sh_old[i] != NULL) 426290001Sglebius evsig_restore_handler_(base, i); 427290001Sglebius } 428290001Sglebius EVSIGBASE_LOCK(); 429290001Sglebius if (base == evsig_base) { 430290001Sglebius evsig_base = NULL; 431290001Sglebius evsig_base_n_signals_added = 0; 432290001Sglebius evsig_base_fd = -1; 433290001Sglebius } 434290001Sglebius EVSIGBASE_UNLOCK(); 435290001Sglebius 436290001Sglebius if (base->sig.ev_signal_pair[0] != -1) { 437290001Sglebius evutil_closesocket(base->sig.ev_signal_pair[0]); 438290001Sglebius base->sig.ev_signal_pair[0] = -1; 439290001Sglebius } 440290001Sglebius if (base->sig.ev_signal_pair[1] != -1) { 441290001Sglebius evutil_closesocket(base->sig.ev_signal_pair[1]); 442290001Sglebius base->sig.ev_signal_pair[1] = -1; 443290001Sglebius } 444290001Sglebius base->sig.sh_old_max = 0; 445290001Sglebius 446290001Sglebius /* per index frees are handled in evsig_del() */ 447290001Sglebius if (base->sig.sh_old) { 448290001Sglebius mm_free(base->sig.sh_old); 449290001Sglebius base->sig.sh_old = NULL; 450290001Sglebius } 451290001Sglebius} 452290001Sglebius 453290001Sglebiusstatic void 454290001Sglebiusevsig_free_globals_locks(void) 455290001Sglebius{ 456290001Sglebius#ifndef EVENT__DISABLE_THREAD_SUPPORT 457290001Sglebius if (evsig_base_lock != NULL) { 458290001Sglebius EVTHREAD_FREE_LOCK(evsig_base_lock, 0); 459290001Sglebius evsig_base_lock = NULL; 460290001Sglebius } 461290001Sglebius#endif 462290001Sglebius return; 463290001Sglebius} 464290001Sglebius 465290001Sglebiusvoid 466290001Sglebiusevsig_free_globals_(void) 467290001Sglebius{ 468290001Sglebius evsig_free_globals_locks(); 469290001Sglebius} 470290001Sglebius 471290001Sglebius#ifndef EVENT__DISABLE_THREAD_SUPPORT 472290001Sglebiusint 473290001Sglebiusevsig_global_setup_locks_(const int enable_locks) 474290001Sglebius{ 475290001Sglebius EVTHREAD_SETUP_GLOBAL_LOCK(evsig_base_lock, 0); 476290001Sglebius return 0; 477290001Sglebius} 478290001Sglebius 479290001Sglebius#endif 480