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