ipc/chromium/src/third_party/libevent/signal.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
michael@0 2
michael@0 3 /*
michael@0 4 * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
michael@0 5 * Copyright 2007-2012 Niels Provos and Nick Mathewson
michael@0 6 *
michael@0 7 * Redistribution and use in source and binary forms, with or without
michael@0 8 * modification, are permitted provided that the following conditions
michael@0 9 * are met:
michael@0 10 * 1. Redistributions of source code must retain the above copyright
michael@0 11 * notice, this list of conditions and the following disclaimer.
michael@0 12 * 2. Redistributions in binary form must reproduce the above copyright
michael@0 13 * notice, this list of conditions and the following disclaimer in the
michael@0 14 * documentation and/or other materials provided with the distribution.
michael@0 15 * 3. The name of the author may not be used to endorse or promote products
michael@0 16 * derived from this software without specific prior written permission.
michael@0 17 *
michael@0 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
michael@0 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
michael@0 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
michael@0 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
michael@0 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
michael@0 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
michael@0 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
michael@0 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
michael@0 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
michael@0 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 28 */
michael@0 29 #include "event2/event-config.h"
michael@0 30
michael@0 31 #ifdef WIN32
michael@0 32 #define WIN32_LEAN_AND_MEAN
michael@0 33 #include <winsock2.h>
michael@0 34 #include <windows.h>
michael@0 35 #undef WIN32_LEAN_AND_MEAN
michael@0 36 #endif
michael@0 37 #include <sys/types.h>
michael@0 38 #ifdef _EVENT_HAVE_SYS_TIME_H
michael@0 39 #include <sys/time.h>
michael@0 40 #endif
michael@0 41 #include <sys/queue.h>
michael@0 42 #ifdef _EVENT_HAVE_SYS_SOCKET_H
michael@0 43 #include <sys/socket.h>
michael@0 44 #endif
michael@0 45 #include <signal.h>
michael@0 46 #include <stdio.h>
michael@0 47 #include <stdlib.h>
michael@0 48 #include <string.h>
michael@0 49 #ifdef _EVENT_HAVE_UNISTD_H
michael@0 50 #include <unistd.h>
michael@0 51 #endif
michael@0 52 #include <errno.h>
michael@0 53 #ifdef _EVENT_HAVE_FCNTL_H
michael@0 54 #include <fcntl.h>
michael@0 55 #endif
michael@0 56
michael@0 57 #include "event2/event.h"
michael@0 58 #include "event2/event_struct.h"
michael@0 59 #include "event-internal.h"
michael@0 60 #include "event2/util.h"
michael@0 61 #include "evsignal-internal.h"
michael@0 62 #include "log-internal.h"
michael@0 63 #include "evmap-internal.h"
michael@0 64 #include "evthread-internal.h"
michael@0 65
michael@0 66 /*
michael@0 67 signal.c
michael@0 68
michael@0 69 This is the signal-handling implementation we use for backends that don't
michael@0 70 have a better way to do signal handling. It uses sigaction() or signal()
michael@0 71 to set a signal handler, and a socket pair to tell the event base when
michael@0 72
michael@0 73 Note that I said "the event base" : only one event base can be set up to use
michael@0 74 this at a time. For historical reasons and backward compatibility, if you
michael@0 75 add an event for a signal to event_base A, then add an event for a signal
michael@0 76 (any signal!) to event_base B, event_base B will get informed about the
michael@0 77 signal, but event_base A won't.
michael@0 78
michael@0 79 It would be neat to change this behavior in some future version of Libevent.
michael@0 80 kqueue already does something far more sensible. We can make all backends
michael@0 81 on Linux do a reasonable thing using signalfd.
michael@0 82 */
michael@0 83
michael@0 84 #ifndef WIN32
michael@0 85 /* Windows wants us to call our signal handlers as __cdecl. Nobody else
michael@0 86 * expects you to do anything crazy like this. */
michael@0 87 #define __cdecl
michael@0 88 #endif
michael@0 89
michael@0 90 static int evsig_add(struct event_base *, evutil_socket_t, short, short, void *);
michael@0 91 static int evsig_del(struct event_base *, evutil_socket_t, short, short, void *);
michael@0 92
michael@0 93 static const struct eventop evsigops = {
michael@0 94 "signal",
michael@0 95 NULL,
michael@0 96 evsig_add,
michael@0 97 evsig_del,
michael@0 98 NULL,
michael@0 99 NULL,
michael@0 100 0, 0, 0
michael@0 101 };
michael@0 102
michael@0 103 #ifndef _EVENT_DISABLE_THREAD_SUPPORT
michael@0 104 /* Lock for evsig_base and evsig_base_n_signals_added fields. */
michael@0 105 static void *evsig_base_lock = NULL;
michael@0 106 #endif
michael@0 107 /* The event base that's currently getting informed about signals. */
michael@0 108 static struct event_base *evsig_base = NULL;
michael@0 109 /* A copy of evsig_base->sigev_n_signals_added. */
michael@0 110 static int evsig_base_n_signals_added = 0;
michael@0 111 static evutil_socket_t evsig_base_fd = -1;
michael@0 112
michael@0 113 static void __cdecl evsig_handler(int sig);
michael@0 114
michael@0 115 #define EVSIGBASE_LOCK() EVLOCK_LOCK(evsig_base_lock, 0)
michael@0 116 #define EVSIGBASE_UNLOCK() EVLOCK_UNLOCK(evsig_base_lock, 0)
michael@0 117
michael@0 118 void
michael@0 119 evsig_set_base(struct event_base *base)
michael@0 120 {
michael@0 121 EVSIGBASE_LOCK();
michael@0 122 evsig_base = base;
michael@0 123 evsig_base_n_signals_added = base->sig.ev_n_signals_added;
michael@0 124 evsig_base_fd = base->sig.ev_signal_pair[0];
michael@0 125 EVSIGBASE_UNLOCK();
michael@0 126 }
michael@0 127
michael@0 128 /* Callback for when the signal handler write a byte to our signaling socket */
michael@0 129 static void
michael@0 130 evsig_cb(evutil_socket_t fd, short what, void *arg)
michael@0 131 {
michael@0 132 static char signals[1024];
michael@0 133 ev_ssize_t n;
michael@0 134 int i;
michael@0 135 int ncaught[NSIG];
michael@0 136 struct event_base *base;
michael@0 137
michael@0 138 base = arg;
michael@0 139
michael@0 140 memset(&ncaught, 0, sizeof(ncaught));
michael@0 141
michael@0 142 while (1) {
michael@0 143 n = recv(fd, signals, sizeof(signals), 0);
michael@0 144 if (n == -1) {
michael@0 145 int err = evutil_socket_geterror(fd);
michael@0 146 if (! EVUTIL_ERR_RW_RETRIABLE(err))
michael@0 147 event_sock_err(1, fd, "%s: recv", __func__);
michael@0 148 break;
michael@0 149 } else if (n == 0) {
michael@0 150 /* XXX warn? */
michael@0 151 break;
michael@0 152 }
michael@0 153 for (i = 0; i < n; ++i) {
michael@0 154 ev_uint8_t sig = signals[i];
michael@0 155 if (sig < NSIG)
michael@0 156 ncaught[sig]++;
michael@0 157 }
michael@0 158 }
michael@0 159
michael@0 160 EVBASE_ACQUIRE_LOCK(base, th_base_lock);
michael@0 161 for (i = 0; i < NSIG; ++i) {
michael@0 162 if (ncaught[i])
michael@0 163 evmap_signal_active(base, i, ncaught[i]);
michael@0 164 }
michael@0 165 EVBASE_RELEASE_LOCK(base, th_base_lock);
michael@0 166 }
michael@0 167
michael@0 168 int
michael@0 169 evsig_init(struct event_base *base)
michael@0 170 {
michael@0 171 /*
michael@0 172 * Our signal handler is going to write to one end of the socket
michael@0 173 * pair to wake up our event loop. The event loop then scans for
michael@0 174 * signals that got delivered.
michael@0 175 */
michael@0 176 if (evutil_socketpair(
michael@0 177 AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1) {
michael@0 178 #ifdef WIN32
michael@0 179 /* Make this nonfatal on win32, where sometimes people
michael@0 180 have localhost firewalled. */
michael@0 181 event_sock_warn(-1, "%s: socketpair", __func__);
michael@0 182 #else
michael@0 183 event_sock_err(1, -1, "%s: socketpair", __func__);
michael@0 184 #endif
michael@0 185 return -1;
michael@0 186 }
michael@0 187
michael@0 188 evutil_make_socket_closeonexec(base->sig.ev_signal_pair[0]);
michael@0 189 evutil_make_socket_closeonexec(base->sig.ev_signal_pair[1]);
michael@0 190 base->sig.sh_old = NULL;
michael@0 191 base->sig.sh_old_max = 0;
michael@0 192
michael@0 193 evutil_make_socket_nonblocking(base->sig.ev_signal_pair[0]);
michael@0 194 evutil_make_socket_nonblocking(base->sig.ev_signal_pair[1]);
michael@0 195
michael@0 196 event_assign(&base->sig.ev_signal, base, base->sig.ev_signal_pair[1],
michael@0 197 EV_READ | EV_PERSIST, evsig_cb, base);
michael@0 198
michael@0 199 base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL;
michael@0 200 event_priority_set(&base->sig.ev_signal, 0);
michael@0 201
michael@0 202 base->evsigsel = &evsigops;
michael@0 203
michael@0 204 return 0;
michael@0 205 }
michael@0 206
michael@0 207 /* Helper: set the signal handler for evsignal to handler in base, so that
michael@0 208 * we can restore the original handler when we clear the current one. */
michael@0 209 int
michael@0 210 _evsig_set_handler(struct event_base *base,
michael@0 211 int evsignal, void (__cdecl *handler)(int))
michael@0 212 {
michael@0 213 #ifdef _EVENT_HAVE_SIGACTION
michael@0 214 struct sigaction sa;
michael@0 215 #else
michael@0 216 ev_sighandler_t sh;
michael@0 217 #endif
michael@0 218 struct evsig_info *sig = &base->sig;
michael@0 219 void *p;
michael@0 220
michael@0 221 /*
michael@0 222 * resize saved signal handler array up to the highest signal number.
michael@0 223 * a dynamic array is used to keep footprint on the low side.
michael@0 224 */
michael@0 225 if (evsignal >= sig->sh_old_max) {
michael@0 226 int new_max = evsignal + 1;
michael@0 227 event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing",
michael@0 228 __func__, evsignal, sig->sh_old_max));
michael@0 229 p = mm_realloc(sig->sh_old, new_max * sizeof(*sig->sh_old));
michael@0 230 if (p == NULL) {
michael@0 231 event_warn("realloc");
michael@0 232 return (-1);
michael@0 233 }
michael@0 234
michael@0 235 memset((char *)p + sig->sh_old_max * sizeof(*sig->sh_old),
michael@0 236 0, (new_max - sig->sh_old_max) * sizeof(*sig->sh_old));
michael@0 237
michael@0 238 sig->sh_old_max = new_max;
michael@0 239 sig->sh_old = p;
michael@0 240 }
michael@0 241
michael@0 242 /* allocate space for previous handler out of dynamic array */
michael@0 243 sig->sh_old[evsignal] = mm_malloc(sizeof *sig->sh_old[evsignal]);
michael@0 244 if (sig->sh_old[evsignal] == NULL) {
michael@0 245 event_warn("malloc");
michael@0 246 return (-1);
michael@0 247 }
michael@0 248
michael@0 249 /* save previous handler and setup new handler */
michael@0 250 #ifdef _EVENT_HAVE_SIGACTION
michael@0 251 memset(&sa, 0, sizeof(sa));
michael@0 252 sa.sa_handler = handler;
michael@0 253 sa.sa_flags |= SA_RESTART;
michael@0 254 sigfillset(&sa.sa_mask);
michael@0 255
michael@0 256 if (sigaction(evsignal, &sa, sig->sh_old[evsignal]) == -1) {
michael@0 257 event_warn("sigaction");
michael@0 258 mm_free(sig->sh_old[evsignal]);
michael@0 259 sig->sh_old[evsignal] = NULL;
michael@0 260 return (-1);
michael@0 261 }
michael@0 262 #else
michael@0 263 if ((sh = signal(evsignal, handler)) == SIG_ERR) {
michael@0 264 event_warn("signal");
michael@0 265 mm_free(sig->sh_old[evsignal]);
michael@0 266 sig->sh_old[evsignal] = NULL;
michael@0 267 return (-1);
michael@0 268 }
michael@0 269 *sig->sh_old[evsignal] = sh;
michael@0 270 #endif
michael@0 271
michael@0 272 return (0);
michael@0 273 }
michael@0 274
michael@0 275 static int
michael@0 276 evsig_add(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p)
michael@0 277 {
michael@0 278 struct evsig_info *sig = &base->sig;
michael@0 279 (void)p;
michael@0 280
michael@0 281 EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG);
michael@0 282
michael@0 283 /* catch signals if they happen quickly */
michael@0 284 EVSIGBASE_LOCK();
michael@0 285 if (evsig_base != base && evsig_base_n_signals_added) {
michael@0 286 event_warnx("Added a signal to event base %p with signals "
michael@0 287 "already added to event_base %p. Only one can have "
michael@0 288 "signals at a time with the %s backend. The base with "
michael@0 289 "the most recently added signal or the most recent "
michael@0 290 "event_base_loop() call gets preference; do "
michael@0 291 "not rely on this behavior in future Libevent versions.",
michael@0 292 base, evsig_base, base->evsel->name);
michael@0 293 }
michael@0 294 evsig_base = base;
michael@0 295 evsig_base_n_signals_added = ++sig->ev_n_signals_added;
michael@0 296 evsig_base_fd = base->sig.ev_signal_pair[0];
michael@0 297 EVSIGBASE_UNLOCK();
michael@0 298
michael@0 299 event_debug(("%s: %d: changing signal handler", __func__, (int)evsignal));
michael@0 300 if (_evsig_set_handler(base, (int)evsignal, evsig_handler) == -1) {
michael@0 301 goto err;
michael@0 302 }
michael@0 303
michael@0 304
michael@0 305 if (!sig->ev_signal_added) {
michael@0 306 if (event_add(&sig->ev_signal, NULL))
michael@0 307 goto err;
michael@0 308 sig->ev_signal_added = 1;
michael@0 309 }
michael@0 310
michael@0 311 return (0);
michael@0 312
michael@0 313 err:
michael@0 314 EVSIGBASE_LOCK();
michael@0 315 --evsig_base_n_signals_added;
michael@0 316 --sig->ev_n_signals_added;
michael@0 317 EVSIGBASE_UNLOCK();
michael@0 318 return (-1);
michael@0 319 }
michael@0 320
michael@0 321 int
michael@0 322 _evsig_restore_handler(struct event_base *base, int evsignal)
michael@0 323 {
michael@0 324 int ret = 0;
michael@0 325 struct evsig_info *sig = &base->sig;
michael@0 326 #ifdef _EVENT_HAVE_SIGACTION
michael@0 327 struct sigaction *sh;
michael@0 328 #else
michael@0 329 ev_sighandler_t *sh;
michael@0 330 #endif
michael@0 331
michael@0 332 /* restore previous handler */
michael@0 333 sh = sig->sh_old[evsignal];
michael@0 334 sig->sh_old[evsignal] = NULL;
michael@0 335 #ifdef _EVENT_HAVE_SIGACTION
michael@0 336 if (sigaction(evsignal, sh, NULL) == -1) {
michael@0 337 event_warn("sigaction");
michael@0 338 ret = -1;
michael@0 339 }
michael@0 340 #else
michael@0 341 if (signal(evsignal, *sh) == SIG_ERR) {
michael@0 342 event_warn("signal");
michael@0 343 ret = -1;
michael@0 344 }
michael@0 345 #endif
michael@0 346
michael@0 347 mm_free(sh);
michael@0 348
michael@0 349 return ret;
michael@0 350 }
michael@0 351
michael@0 352 static int
michael@0 353 evsig_del(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p)
michael@0 354 {
michael@0 355 EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG);
michael@0 356
michael@0 357 event_debug(("%s: "EV_SOCK_FMT": restoring signal handler",
michael@0 358 __func__, EV_SOCK_ARG(evsignal)));
michael@0 359
michael@0 360 EVSIGBASE_LOCK();
michael@0 361 --evsig_base_n_signals_added;
michael@0 362 --base->sig.ev_n_signals_added;
michael@0 363 EVSIGBASE_UNLOCK();
michael@0 364
michael@0 365 return (_evsig_restore_handler(base, (int)evsignal));
michael@0 366 }
michael@0 367
michael@0 368 static void __cdecl
michael@0 369 evsig_handler(int sig)
michael@0 370 {
michael@0 371 int save_errno = errno;
michael@0 372 #ifdef WIN32
michael@0 373 int socket_errno = EVUTIL_SOCKET_ERROR();
michael@0 374 #endif
michael@0 375 ev_uint8_t msg;
michael@0 376
michael@0 377 if (evsig_base == NULL) {
michael@0 378 event_warnx(
michael@0 379 "%s: received signal %d, but have no base configured",
michael@0 380 __func__, sig);
michael@0 381 return;
michael@0 382 }
michael@0 383
michael@0 384 #ifndef _EVENT_HAVE_SIGACTION
michael@0 385 signal(sig, evsig_handler);
michael@0 386 #endif
michael@0 387
michael@0 388 /* Wake up our notification mechanism */
michael@0 389 msg = sig;
michael@0 390 send(evsig_base_fd, (char*)&msg, 1, 0);
michael@0 391 errno = save_errno;
michael@0 392 #ifdef WIN32
michael@0 393 EVUTIL_SET_SOCKET_ERROR(socket_errno);
michael@0 394 #endif
michael@0 395 }
michael@0 396
michael@0 397 void
michael@0 398 evsig_dealloc(struct event_base *base)
michael@0 399 {
michael@0 400 int i = 0;
michael@0 401 if (base->sig.ev_signal_added) {
michael@0 402 event_del(&base->sig.ev_signal);
michael@0 403 base->sig.ev_signal_added = 0;
michael@0 404 }
michael@0 405 /* debug event is created in evsig_init/event_assign even when
michael@0 406 * ev_signal_added == 0, so unassign is required */
michael@0 407 event_debug_unassign(&base->sig.ev_signal);
michael@0 408
michael@0 409 for (i = 0; i < NSIG; ++i) {
michael@0 410 if (i < base->sig.sh_old_max && base->sig.sh_old[i] != NULL)
michael@0 411 _evsig_restore_handler(base, i);
michael@0 412 }
michael@0 413 EVSIGBASE_LOCK();
michael@0 414 if (base == evsig_base) {
michael@0 415 evsig_base = NULL;
michael@0 416 evsig_base_n_signals_added = 0;
michael@0 417 evsig_base_fd = -1;
michael@0 418 }
michael@0 419 EVSIGBASE_UNLOCK();
michael@0 420
michael@0 421 if (base->sig.ev_signal_pair[0] != -1) {
michael@0 422 evutil_closesocket(base->sig.ev_signal_pair[0]);
michael@0 423 base->sig.ev_signal_pair[0] = -1;
michael@0 424 }
michael@0 425 if (base->sig.ev_signal_pair[1] != -1) {
michael@0 426 evutil_closesocket(base->sig.ev_signal_pair[1]);
michael@0 427 base->sig.ev_signal_pair[1] = -1;
michael@0 428 }
michael@0 429 base->sig.sh_old_max = 0;
michael@0 430
michael@0 431 /* per index frees are handled in evsig_del() */
michael@0 432 if (base->sig.sh_old) {
michael@0 433 mm_free(base->sig.sh_old);
michael@0 434 base->sig.sh_old = NULL;
michael@0 435 }
michael@0 436 }
michael@0 437
michael@0 438 #ifndef _EVENT_DISABLE_THREAD_SUPPORT
michael@0 439 int
michael@0 440 evsig_global_setup_locks_(const int enable_locks)
michael@0 441 {
michael@0 442 EVTHREAD_SETUP_GLOBAL_LOCK(evsig_base_lock, 0);
michael@0 443 return 0;
michael@0 444 }
michael@0 445 #endif

mercurial