1275970Scy/* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */ 2275970Scy 3275970Scy/* 4275970Scy * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu> 5275970Scy * Copyright 2007-2012 Niels Provos and Nick Mathewson 6275970Scy * 7275970Scy * Redistribution and use in source and binary forms, with or without 8275970Scy * modification, are permitted provided that the following conditions 9275970Scy * are met: 10275970Scy * 1. Redistributions of source code must retain the above copyright 11275970Scy * notice, this list of conditions and the following disclaimer. 12275970Scy * 2. Redistributions in binary form must reproduce the above copyright 13275970Scy * notice, this list of conditions and the following disclaimer in the 14275970Scy * documentation and/or other materials provided with the distribution. 15275970Scy * 3. The name of the author may not be used to endorse or promote products 16275970Scy * derived from this software without specific prior written permission. 17275970Scy * 18275970Scy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19275970Scy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20275970Scy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21275970Scy * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22275970Scy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23275970Scy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24275970Scy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25275970Scy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26275970Scy * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27275970Scy * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28275970Scy */ 29275970Scy#include "event2/event-config.h" 30275970Scy#include "evconfig-private.h" 31275970Scy 32275970Scy#ifdef _WIN32 33275970Scy#define WIN32_LEAN_AND_MEAN 34275970Scy#include <winsock2.h> 35275970Scy#include <windows.h> 36275970Scy#undef WIN32_LEAN_AND_MEAN 37275970Scy#endif 38275970Scy#include <sys/types.h> 39275970Scy#ifdef EVENT__HAVE_SYS_TIME_H 40275970Scy#include <sys/time.h> 41275970Scy#endif 42275970Scy#include <sys/queue.h> 43275970Scy#ifdef EVENT__HAVE_SYS_SOCKET_H 44275970Scy#include <sys/socket.h> 45275970Scy#endif 46275970Scy#include <signal.h> 47275970Scy#include <stdio.h> 48275970Scy#include <stdlib.h> 49275970Scy#include <string.h> 50275970Scy#ifdef EVENT__HAVE_UNISTD_H 51275970Scy#include <unistd.h> 52275970Scy#endif 53275970Scy#include <errno.h> 54275970Scy#ifdef EVENT__HAVE_FCNTL_H 55275970Scy#include <fcntl.h> 56275970Scy#endif 57275970Scy 58275970Scy#include "event2/event.h" 59275970Scy#include "event2/event_struct.h" 60275970Scy#include "event-internal.h" 61275970Scy#include "event2/util.h" 62275970Scy#include "evsignal-internal.h" 63275970Scy#include "log-internal.h" 64275970Scy#include "evmap-internal.h" 65275970Scy#include "evthread-internal.h" 66275970Scy 67275970Scy/* 68275970Scy signal.c 69275970Scy 70275970Scy This is the signal-handling implementation we use for backends that don't 71275970Scy have a better way to do signal handling. It uses sigaction() or signal() 72275970Scy to set a signal handler, and a socket pair to tell the event base when 73275970Scy 74275970Scy Note that I said "the event base" : only one event base can be set up to use 75275970Scy this at a time. For historical reasons and backward compatibility, if you 76275970Scy add an event for a signal to event_base A, then add an event for a signal 77275970Scy (any signal!) to event_base B, event_base B will get informed about the 78275970Scy signal, but event_base A won't. 79275970Scy 80275970Scy It would be neat to change this behavior in some future version of Libevent. 81275970Scy kqueue already does something far more sensible. We can make all backends 82275970Scy on Linux do a reasonable thing using signalfd. 83275970Scy*/ 84275970Scy 85275970Scy#ifndef _WIN32 86275970Scy/* Windows wants us to call our signal handlers as __cdecl. Nobody else 87275970Scy * expects you to do anything crazy like this. */ 88275970Scy#define __cdecl 89275970Scy#endif 90275970Scy 91275970Scystatic int evsig_add(struct event_base *, evutil_socket_t, short, short, void *); 92275970Scystatic int evsig_del(struct event_base *, evutil_socket_t, short, short, void *); 93275970Scy 94275970Scystatic const struct eventop evsigops = { 95275970Scy "signal", 96275970Scy NULL, 97275970Scy evsig_add, 98275970Scy evsig_del, 99275970Scy NULL, 100275970Scy NULL, 101275970Scy 0, 0, 0 102275970Scy}; 103275970Scy 104275970Scy#ifndef EVENT__DISABLE_THREAD_SUPPORT 105275970Scy/* Lock for evsig_base and evsig_base_n_signals_added fields. */ 106275970Scystatic void *evsig_base_lock = NULL; 107275970Scy#endif 108275970Scy/* The event base that's currently getting informed about signals. */ 109275970Scystatic struct event_base *evsig_base = NULL; 110275970Scy/* A copy of evsig_base->sigev_n_signals_added. */ 111275970Scystatic int evsig_base_n_signals_added = 0; 112275970Scystatic evutil_socket_t evsig_base_fd = -1; 113275970Scy 114275970Scystatic void __cdecl evsig_handler(int sig); 115275970Scy 116275970Scy#define EVSIGBASE_LOCK() EVLOCK_LOCK(evsig_base_lock, 0) 117275970Scy#define EVSIGBASE_UNLOCK() EVLOCK_UNLOCK(evsig_base_lock, 0) 118275970Scy 119275970Scyvoid 120275970Scyevsig_set_base_(struct event_base *base) 121275970Scy{ 122275970Scy EVSIGBASE_LOCK(); 123275970Scy evsig_base = base; 124275970Scy evsig_base_n_signals_added = base->sig.ev_n_signals_added; 125275970Scy evsig_base_fd = base->sig.ev_signal_pair[1]; 126275970Scy EVSIGBASE_UNLOCK(); 127275970Scy} 128275970Scy 129275970Scy/* Callback for when the signal handler write a byte to our signaling socket */ 130275970Scystatic void 131275970Scyevsig_cb(evutil_socket_t fd, short what, void *arg) 132275970Scy{ 133275970Scy static char signals[1024]; 134275970Scy ev_ssize_t n; 135275970Scy int i; 136275970Scy int ncaught[NSIG]; 137275970Scy struct event_base *base; 138275970Scy 139275970Scy base = arg; 140275970Scy 141275970Scy memset(&ncaught, 0, sizeof(ncaught)); 142275970Scy 143275970Scy while (1) { 144275970Scy#ifdef _WIN32 145275970Scy n = recv(fd, signals, sizeof(signals), 0); 146275970Scy#else 147275970Scy n = read(fd, signals, sizeof(signals)); 148275970Scy#endif 149275970Scy if (n == -1) { 150275970Scy int err = evutil_socket_geterror(fd); 151275970Scy if (! EVUTIL_ERR_RW_RETRIABLE(err)) 152275970Scy event_sock_err(1, fd, "%s: recv", __func__); 153275970Scy break; 154275970Scy } else if (n == 0) { 155275970Scy /* XXX warn? */ 156275970Scy break; 157275970Scy } 158275970Scy for (i = 0; i < n; ++i) { 159275970Scy ev_uint8_t sig = signals[i]; 160275970Scy if (sig < NSIG) 161275970Scy ncaught[sig]++; 162275970Scy } 163275970Scy } 164275970Scy 165275970Scy EVBASE_ACQUIRE_LOCK(base, th_base_lock); 166275970Scy for (i = 0; i < NSIG; ++i) { 167275970Scy if (ncaught[i]) 168275970Scy evmap_signal_active_(base, i, ncaught[i]); 169275970Scy } 170275970Scy EVBASE_RELEASE_LOCK(base, th_base_lock); 171275970Scy} 172275970Scy 173275970Scyint 174275970Scyevsig_init_(struct event_base *base) 175275970Scy{ 176275970Scy /* 177275970Scy * Our signal handler is going to write to one end of the socket 178275970Scy * pair to wake up our event loop. The event loop then scans for 179275970Scy * signals that got delivered. 180275970Scy */ 181275970Scy if (evutil_make_internal_pipe_(base->sig.ev_signal_pair) == -1) { 182275970Scy#ifdef _WIN32 183275970Scy /* Make this nonfatal on win32, where sometimes people 184275970Scy have localhost firewalled. */ 185275970Scy event_sock_warn(-1, "%s: socketpair", __func__); 186275970Scy#else 187275970Scy event_sock_err(1, -1, "%s: socketpair", __func__); 188275970Scy#endif 189275970Scy return -1; 190275970Scy } 191275970Scy 192275970Scy if (base->sig.sh_old) { 193275970Scy mm_free(base->sig.sh_old); 194275970Scy } 195275970Scy base->sig.sh_old = NULL; 196275970Scy base->sig.sh_old_max = 0; 197275970Scy 198275970Scy event_assign(&base->sig.ev_signal, base, base->sig.ev_signal_pair[0], 199275970Scy EV_READ | EV_PERSIST, evsig_cb, base); 200275970Scy 201275970Scy base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL; 202275970Scy event_priority_set(&base->sig.ev_signal, 0); 203275970Scy 204275970Scy base->evsigsel = &evsigops; 205275970Scy 206275970Scy return 0; 207275970Scy} 208275970Scy 209275970Scy/* Helper: set the signal handler for evsignal to handler in base, so that 210275970Scy * we can restore the original handler when we clear the current one. */ 211275970Scyint 212275970Scyevsig_set_handler_(struct event_base *base, 213275970Scy int evsignal, void (__cdecl *handler)(int)) 214275970Scy{ 215275970Scy#ifdef EVENT__HAVE_SIGACTION 216275970Scy struct sigaction sa; 217275970Scy#else 218275970Scy ev_sighandler_t sh; 219275970Scy#endif 220275970Scy struct evsig_info *sig = &base->sig; 221275970Scy void *p; 222275970Scy 223275970Scy /* 224275970Scy * resize saved signal handler array up to the highest signal number. 225275970Scy * a dynamic array is used to keep footprint on the low side. 226275970Scy */ 227275970Scy if (evsignal >= sig->sh_old_max) { 228275970Scy int new_max = evsignal + 1; 229275970Scy event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing", 230275970Scy __func__, evsignal, sig->sh_old_max)); 231275970Scy p = mm_realloc(sig->sh_old, new_max * sizeof(*sig->sh_old)); 232275970Scy if (p == NULL) { 233275970Scy event_warn("realloc"); 234275970Scy return (-1); 235275970Scy } 236275970Scy 237275970Scy memset((char *)p + sig->sh_old_max * sizeof(*sig->sh_old), 238275970Scy 0, (new_max - sig->sh_old_max) * sizeof(*sig->sh_old)); 239275970Scy 240275970Scy sig->sh_old_max = new_max; 241275970Scy sig->sh_old = p; 242275970Scy } 243275970Scy 244275970Scy /* allocate space for previous handler out of dynamic array */ 245275970Scy sig->sh_old[evsignal] = mm_malloc(sizeof *sig->sh_old[evsignal]); 246275970Scy if (sig->sh_old[evsignal] == NULL) { 247275970Scy event_warn("malloc"); 248275970Scy return (-1); 249275970Scy } 250275970Scy 251275970Scy /* save previous handler and setup new handler */ 252275970Scy#ifdef EVENT__HAVE_SIGACTION 253275970Scy memset(&sa, 0, sizeof(sa)); 254275970Scy sa.sa_handler = handler; 255275970Scy sa.sa_flags |= SA_RESTART; 256275970Scy sigfillset(&sa.sa_mask); 257275970Scy 258275970Scy if (sigaction(evsignal, &sa, sig->sh_old[evsignal]) == -1) { 259275970Scy event_warn("sigaction"); 260275970Scy mm_free(sig->sh_old[evsignal]); 261275970Scy sig->sh_old[evsignal] = NULL; 262275970Scy return (-1); 263275970Scy } 264275970Scy#else 265275970Scy if ((sh = signal(evsignal, handler)) == SIG_ERR) { 266275970Scy event_warn("signal"); 267275970Scy mm_free(sig->sh_old[evsignal]); 268275970Scy sig->sh_old[evsignal] = NULL; 269275970Scy return (-1); 270275970Scy } 271275970Scy *sig->sh_old[evsignal] = sh; 272275970Scy#endif 273275970Scy 274275970Scy return (0); 275275970Scy} 276275970Scy 277275970Scystatic int 278275970Scyevsig_add(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p) 279275970Scy{ 280275970Scy struct evsig_info *sig = &base->sig; 281275970Scy (void)p; 282275970Scy 283275970Scy EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG); 284275970Scy 285275970Scy /* catch signals if they happen quickly */ 286275970Scy EVSIGBASE_LOCK(); 287275970Scy if (evsig_base != base && evsig_base_n_signals_added) { 288275970Scy event_warnx("Added a signal to event base %p with signals " 289275970Scy "already added to event_base %p. Only one can have " 290275970Scy "signals at a time with the %s backend. The base with " 291275970Scy "the most recently added signal or the most recent " 292275970Scy "event_base_loop() call gets preference; do " 293275970Scy "not rely on this behavior in future Libevent versions.", 294275970Scy base, evsig_base, base->evsel->name); 295275970Scy } 296275970Scy evsig_base = base; 297275970Scy evsig_base_n_signals_added = ++sig->ev_n_signals_added; 298275970Scy evsig_base_fd = base->sig.ev_signal_pair[1]; 299275970Scy EVSIGBASE_UNLOCK(); 300275970Scy 301275970Scy event_debug(("%s: %d: changing signal handler", __func__, (int)evsignal)); 302275970Scy if (evsig_set_handler_(base, (int)evsignal, evsig_handler) == -1) { 303275970Scy goto err; 304275970Scy } 305275970Scy 306275970Scy 307275970Scy if (!sig->ev_signal_added) { 308275970Scy if (event_add_nolock_(&sig->ev_signal, NULL, 0)) 309275970Scy goto err; 310275970Scy sig->ev_signal_added = 1; 311275970Scy } 312275970Scy 313275970Scy return (0); 314275970Scy 315275970Scyerr: 316275970Scy EVSIGBASE_LOCK(); 317275970Scy --evsig_base_n_signals_added; 318275970Scy --sig->ev_n_signals_added; 319275970Scy EVSIGBASE_UNLOCK(); 320275970Scy return (-1); 321275970Scy} 322275970Scy 323275970Scyint 324275970Scyevsig_restore_handler_(struct event_base *base, int evsignal) 325275970Scy{ 326275970Scy int ret = 0; 327275970Scy struct evsig_info *sig = &base->sig; 328275970Scy#ifdef EVENT__HAVE_SIGACTION 329275970Scy struct sigaction *sh; 330275970Scy#else 331275970Scy ev_sighandler_t *sh; 332275970Scy#endif 333275970Scy 334275970Scy if (evsignal >= sig->sh_old_max) { 335275970Scy /* Can't actually restore. */ 336275970Scy /* XXXX.*/ 337275970Scy return 0; 338275970Scy } 339275970Scy 340275970Scy /* restore previous handler */ 341275970Scy sh = sig->sh_old[evsignal]; 342275970Scy sig->sh_old[evsignal] = NULL; 343275970Scy#ifdef EVENT__HAVE_SIGACTION 344275970Scy if (sigaction(evsignal, sh, NULL) == -1) { 345275970Scy event_warn("sigaction"); 346275970Scy ret = -1; 347275970Scy } 348275970Scy#else 349275970Scy if (signal(evsignal, *sh) == SIG_ERR) { 350275970Scy event_warn("signal"); 351275970Scy ret = -1; 352275970Scy } 353275970Scy#endif 354275970Scy 355275970Scy mm_free(sh); 356275970Scy 357275970Scy return ret; 358275970Scy} 359275970Scy 360275970Scystatic int 361275970Scyevsig_del(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p) 362275970Scy{ 363275970Scy EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG); 364275970Scy 365275970Scy event_debug(("%s: "EV_SOCK_FMT": restoring signal handler", 366275970Scy __func__, EV_SOCK_ARG(evsignal))); 367275970Scy 368275970Scy EVSIGBASE_LOCK(); 369275970Scy --evsig_base_n_signals_added; 370275970Scy --base->sig.ev_n_signals_added; 371275970Scy EVSIGBASE_UNLOCK(); 372275970Scy 373275970Scy return (evsig_restore_handler_(base, (int)evsignal)); 374275970Scy} 375275970Scy 376275970Scystatic void __cdecl 377275970Scyevsig_handler(int sig) 378275970Scy{ 379275970Scy int save_errno = errno; 380275970Scy#ifdef _WIN32 381275970Scy int socket_errno = EVUTIL_SOCKET_ERROR(); 382275970Scy#endif 383275970Scy ev_uint8_t msg; 384275970Scy 385275970Scy if (evsig_base == NULL) { 386275970Scy event_warnx( 387275970Scy "%s: received signal %d, but have no base configured", 388275970Scy __func__, sig); 389275970Scy return; 390275970Scy } 391275970Scy 392275970Scy#ifndef EVENT__HAVE_SIGACTION 393275970Scy signal(sig, evsig_handler); 394275970Scy#endif 395275970Scy 396275970Scy /* Wake up our notification mechanism */ 397275970Scy msg = sig; 398275970Scy#ifdef _WIN32 399275970Scy send(evsig_base_fd, (char*)&msg, 1, 0); 400275970Scy#else 401275970Scy { 402275970Scy int r = write(evsig_base_fd, (char*)&msg, 1); 403275970Scy (void)r; /* Suppress 'unused return value' and 'unused var' */ 404275970Scy } 405275970Scy#endif 406275970Scy errno = save_errno; 407275970Scy#ifdef _WIN32 408275970Scy EVUTIL_SET_SOCKET_ERROR(socket_errno); 409275970Scy#endif 410275970Scy} 411275970Scy 412275970Scyvoid 413275970Scyevsig_dealloc_(struct event_base *base) 414275970Scy{ 415275970Scy int i = 0; 416275970Scy if (base->sig.ev_signal_added) { 417275970Scy event_del(&base->sig.ev_signal); 418275970Scy base->sig.ev_signal_added = 0; 419275970Scy } 420275970Scy /* debug event is created in evsig_init_/event_assign even when 421275970Scy * ev_signal_added == 0, so unassign is required */ 422275970Scy event_debug_unassign(&base->sig.ev_signal); 423275970Scy 424275970Scy for (i = 0; i < NSIG; ++i) { 425275970Scy if (i < base->sig.sh_old_max && base->sig.sh_old[i] != NULL) 426275970Scy evsig_restore_handler_(base, i); 427275970Scy } 428275970Scy EVSIGBASE_LOCK(); 429275970Scy if (base == evsig_base) { 430275970Scy evsig_base = NULL; 431275970Scy evsig_base_n_signals_added = 0; 432275970Scy evsig_base_fd = -1; 433275970Scy } 434275970Scy EVSIGBASE_UNLOCK(); 435275970Scy 436275970Scy if (base->sig.ev_signal_pair[0] != -1) { 437275970Scy evutil_closesocket(base->sig.ev_signal_pair[0]); 438275970Scy base->sig.ev_signal_pair[0] = -1; 439275970Scy } 440275970Scy if (base->sig.ev_signal_pair[1] != -1) { 441275970Scy evutil_closesocket(base->sig.ev_signal_pair[1]); 442275970Scy base->sig.ev_signal_pair[1] = -1; 443275970Scy } 444275970Scy base->sig.sh_old_max = 0; 445275970Scy 446275970Scy /* per index frees are handled in evsig_del() */ 447275970Scy if (base->sig.sh_old) { 448275970Scy mm_free(base->sig.sh_old); 449275970Scy base->sig.sh_old = NULL; 450275970Scy } 451275970Scy} 452275970Scy 453275970Scystatic void 454275970Scyevsig_free_globals_locks(void) 455275970Scy{ 456275970Scy#ifndef EVENT__DISABLE_THREAD_SUPPORT 457275970Scy if (evsig_base_lock != NULL) { 458275970Scy EVTHREAD_FREE_LOCK(evsig_base_lock, 0); 459275970Scy evsig_base_lock = NULL; 460275970Scy } 461275970Scy#endif 462275970Scy return; 463275970Scy} 464275970Scy 465275970Scyvoid 466275970Scyevsig_free_globals_(void) 467275970Scy{ 468275970Scy evsig_free_globals_locks(); 469275970Scy} 470275970Scy 471275970Scy#ifndef EVENT__DISABLE_THREAD_SUPPORT 472275970Scyint 473275970Scyevsig_global_setup_locks_(const int enable_locks) 474275970Scy{ 475275970Scy EVTHREAD_SETUP_GLOBAL_LOCK(evsig_base_lock, 0); 476275970Scy return 0; 477275970Scy} 478275970Scy 479275970Scy#endif 480