1/* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */ 2 3/* 4 * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 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. 17 * 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. 28 */ 29#ifdef HAVE_CONFIG_H 30#include "config.h" 31#endif 32 33#ifdef WIN32 34#define WIN32_LEAN_AND_MEAN 35#include <winsock2.h> 36#include <windows.h> 37#undef WIN32_LEAN_AND_MEAN 38#endif 39#include <sys/types.h> 40#ifdef HAVE_SYS_TIME_H 41#include <sys/time.h> 42#endif 43#include <sys/queue.h> 44#ifdef HAVE_SYS_SOCKET_H 45#include <sys/socket.h> 46#endif 47#include <signal.h> 48#include <stdio.h> 49#include <stdlib.h> 50#include <string.h> 51#ifdef HAVE_UNISTD_H 52#include <unistd.h> 53#endif 54#include <errno.h> 55#ifdef HAVE_FCNTL_H 56#include <fcntl.h> 57#endif 58#include <assert.h> 59 60#include "event.h" 61#include "event-internal.h" 62#include "evsignal.h" 63#include "evutil.h" 64#include "log.h" 65 66struct event_base *evsignal_base = NULL; 67 68static void evsignal_handler(int sig); 69 70/* Callback for when the signal handler write a byte to our signaling socket */ 71static void 72evsignal_cb(int fd, short what, void *arg) 73{ 74 static char signals[1]; 75#ifdef WIN32 76 SSIZE_T n; 77#else 78 ssize_t n; 79#endif 80 81 n = recv(fd, signals, sizeof(signals), 0); 82 if (n == -1) 83 event_err(1, "%s: read", __func__); 84} 85 86#ifdef HAVE_SETFD 87#define FD_CLOSEONEXEC(x) do { \ 88 if (fcntl(x, F_SETFD, 1) == -1) \ 89 event_warn("fcntl(%d, F_SETFD)", x); \ 90} while (0) 91#else 92#define FD_CLOSEONEXEC(x) 93#endif 94 95int 96evsignal_init(struct event_base *base) 97{ 98 int i; 99 100 /* 101 * Our signal handler is going to write to one end of the socket 102 * pair to wake up our event loop. The event loop then scans for 103 * signals that got delivered. 104 */ 105 if (evutil_socketpair( 106 AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1) { 107#ifdef WIN32 108 /* Make this nonfatal on win32, where sometimes people 109 have localhost firewalled. */ 110 event_warn("%s: socketpair", __func__); 111#else 112 event_err(1, "%s: socketpair", __func__); 113#endif 114 return -1; 115 } 116 117 FD_CLOSEONEXEC(base->sig.ev_signal_pair[0]); 118 FD_CLOSEONEXEC(base->sig.ev_signal_pair[1]); 119 base->sig.sh_old = NULL; 120 base->sig.sh_old_max = 0; 121 base->sig.evsignal_caught = 0; 122 memset(&base->sig.evsigcaught, 0, sizeof(sig_atomic_t)*NSIG); 123 /* initialize the queues for all events */ 124 for (i = 0; i < NSIG; ++i) 125 TAILQ_INIT(&base->sig.evsigevents[i]); 126 127 evutil_make_socket_nonblocking(base->sig.ev_signal_pair[0]); 128 129 event_set(&base->sig.ev_signal, base->sig.ev_signal_pair[1], 130 EV_READ | EV_PERSIST, evsignal_cb, &base->sig.ev_signal); 131 base->sig.ev_signal.ev_base = base; 132 base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL; 133 134 return 0; 135} 136 137/* Helper: set the signal handler for evsignal to handler in base, so that 138 * we can restore the original handler when we clear the current one. */ 139int 140_evsignal_set_handler(struct event_base *base, 141 int evsignal, void (*handler)(int)) 142{ 143#ifdef HAVE_SIGACTION 144 struct sigaction sa; 145#else 146 ev_sighandler_t sh; 147#endif 148 struct evsignal_info *sig = &base->sig; 149 void *p; 150 151 /* 152 * resize saved signal handler array up to the highest signal number. 153 * a dynamic array is used to keep footprint on the low side. 154 */ 155 if (evsignal >= sig->sh_old_max) { 156 int new_max = evsignal + 1; 157 event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing", 158 __func__, evsignal, sig->sh_old_max)); 159 p = realloc(sig->sh_old, new_max * sizeof(*sig->sh_old)); 160 if (p == NULL) { 161 event_warn("realloc"); 162 return (-1); 163 } 164 165 memset((char *)p + sig->sh_old_max * sizeof(*sig->sh_old), 166 0, (new_max - sig->sh_old_max) * sizeof(*sig->sh_old)); 167 168 sig->sh_old_max = new_max; 169 sig->sh_old = p; 170 } 171 172 /* allocate space for previous handler out of dynamic array */ 173 sig->sh_old[evsignal] = malloc(sizeof *sig->sh_old[evsignal]); 174 if (sig->sh_old[evsignal] == NULL) { 175 event_warn("malloc"); 176 return (-1); 177 } 178 179 /* save previous handler and setup new handler */ 180#ifdef HAVE_SIGACTION 181 memset(&sa, 0, sizeof(sa)); 182 sa.sa_handler = handler; 183 sa.sa_flags |= SA_RESTART; 184 sigfillset(&sa.sa_mask); 185 186 if (sigaction(evsignal, &sa, sig->sh_old[evsignal]) == -1) { 187 event_warn("sigaction"); 188 free(sig->sh_old[evsignal]); 189 return (-1); 190 } 191#else 192 if ((sh = signal(evsignal, handler)) == SIG_ERR) { 193 event_warn("signal"); 194 free(sig->sh_old[evsignal]); 195 return (-1); 196 } 197 *sig->sh_old[evsignal] = sh; 198#endif 199 200 return (0); 201} 202 203int 204evsignal_add(struct event *ev) 205{ 206 int evsignal; 207 struct event_base *base = ev->ev_base; 208 struct evsignal_info *sig = &ev->ev_base->sig; 209 210 if (ev->ev_events & (EV_READ|EV_WRITE)) 211 event_errx(1, "%s: EV_SIGNAL incompatible use", __func__); 212 evsignal = EVENT_SIGNAL(ev); 213 assert(evsignal >= 0 && evsignal < NSIG); 214 if (TAILQ_EMPTY(&sig->evsigevents[evsignal])) { 215 event_debug(("%s: %p: changing signal handler", __func__, ev)); 216 if (_evsignal_set_handler( 217 base, evsignal, evsignal_handler) == -1) 218 return (-1); 219 220 /* catch signals if they happen quickly */ 221 evsignal_base = base; 222 223 if (!sig->ev_signal_added) { 224 if (event_add(&sig->ev_signal, NULL)) 225 return (-1); 226 sig->ev_signal_added = 1; 227 } 228 } 229 230 /* multiple events may listen to the same signal */ 231 TAILQ_INSERT_TAIL(&sig->evsigevents[evsignal], ev, ev_signal_next); 232 233 return (0); 234} 235 236int 237_evsignal_restore_handler(struct event_base *base, int evsignal) 238{ 239 int ret = 0; 240 struct evsignal_info *sig = &base->sig; 241#ifdef HAVE_SIGACTION 242 struct sigaction *sh; 243#else 244 ev_sighandler_t *sh; 245#endif 246 247 /* restore previous handler */ 248 sh = sig->sh_old[evsignal]; 249 sig->sh_old[evsignal] = NULL; 250#ifdef HAVE_SIGACTION 251 if (sigaction(evsignal, sh, NULL) == -1) { 252 event_warn("sigaction"); 253 ret = -1; 254 } 255#else 256 if (signal(evsignal, *sh) == SIG_ERR) { 257 event_warn("signal"); 258 ret = -1; 259 } 260#endif 261 free(sh); 262 263 return ret; 264} 265 266int 267evsignal_del(struct event *ev) 268{ 269 struct event_base *base = ev->ev_base; 270 struct evsignal_info *sig = &base->sig; 271 int evsignal = EVENT_SIGNAL(ev); 272 273 assert(evsignal >= 0 && evsignal < NSIG); 274 275 /* multiple events may listen to the same signal */ 276 TAILQ_REMOVE(&sig->evsigevents[evsignal], ev, ev_signal_next); 277 278 if (!TAILQ_EMPTY(&sig->evsigevents[evsignal])) 279 return (0); 280 281 event_debug(("%s: %p: restoring signal handler", __func__, ev)); 282 283 return (_evsignal_restore_handler(ev->ev_base, EVENT_SIGNAL(ev))); 284} 285 286static void 287evsignal_handler(int sig) 288{ 289 int save_errno = errno; 290 291 if (evsignal_base == NULL) { 292 event_warn( 293 "%s: received signal %d, but have no base configured", 294 __func__, sig); 295 return; 296 } 297 298 evsignal_base->sig.evsigcaught[sig]++; 299 evsignal_base->sig.evsignal_caught = 1; 300 301#ifndef HAVE_SIGACTION 302 signal(sig, evsignal_handler); 303#endif 304 305 /* Wake up our notification mechanism */ 306 send(evsignal_base->sig.ev_signal_pair[0], "a", 1, 0); 307 errno = save_errno; 308} 309 310void 311evsignal_process(struct event_base *base) 312{ 313 struct evsignal_info *sig = &base->sig; 314 struct event *ev, *next_ev; 315 sig_atomic_t ncalls; 316 int i; 317 318 base->sig.evsignal_caught = 0; 319 for (i = 1; i < NSIG; ++i) { 320 ncalls = sig->evsigcaught[i]; 321 if (ncalls == 0) 322 continue; 323 sig->evsigcaught[i] -= ncalls; 324 325 for (ev = TAILQ_FIRST(&sig->evsigevents[i]); 326 ev != NULL; ev = next_ev) { 327 next_ev = TAILQ_NEXT(ev, ev_signal_next); 328 if (!(ev->ev_events & EV_PERSIST)) 329 event_del(ev); 330 event_active(ev, EV_SIGNAL, ncalls); 331 } 332 333 } 334} 335 336void 337evsignal_dealloc(struct event_base *base) 338{ 339 int i = 0; 340 if (base->sig.ev_signal_added) { 341 event_del(&base->sig.ev_signal); 342 base->sig.ev_signal_added = 0; 343 } 344 for (i = 0; i < NSIG; ++i) { 345 if (i < base->sig.sh_old_max && base->sig.sh_old[i] != NULL) 346 _evsignal_restore_handler(base, i); 347 } 348 349 EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[0]); 350 base->sig.ev_signal_pair[0] = -1; 351 EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[1]); 352 base->sig.ev_signal_pair[1] = -1; 353 base->sig.sh_old_max = 0; 354 355 /* per index frees are handled in evsignal_del() */ 356 free(base->sig.sh_old); 357} 358