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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/ipc/chromium/src/third_party/libevent/signal.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,445 @@
     1.4 +/*	$OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $	*/
     1.5 +
     1.6 +/*
     1.7 + * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
     1.8 + * Copyright 2007-2012 Niels Provos and Nick Mathewson
     1.9 + *
    1.10 + * Redistribution and use in source and binary forms, with or without
    1.11 + * modification, are permitted provided that the following conditions
    1.12 + * are met:
    1.13 + * 1. Redistributions of source code must retain the above copyright
    1.14 + *    notice, this list of conditions and the following disclaimer.
    1.15 + * 2. Redistributions in binary form must reproduce the above copyright
    1.16 + *    notice, this list of conditions and the following disclaimer in the
    1.17 + *    documentation and/or other materials provided with the distribution.
    1.18 + * 3. The name of the author may not be used to endorse or promote products
    1.19 + *    derived from this software without specific prior written permission.
    1.20 + *
    1.21 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
    1.22 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    1.23 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    1.24 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
    1.25 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
    1.26 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    1.27 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    1.28 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    1.29 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    1.30 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.31 + */
    1.32 +#include "event2/event-config.h"
    1.33 +
    1.34 +#ifdef WIN32
    1.35 +#define WIN32_LEAN_AND_MEAN
    1.36 +#include <winsock2.h>
    1.37 +#include <windows.h>
    1.38 +#undef WIN32_LEAN_AND_MEAN
    1.39 +#endif
    1.40 +#include <sys/types.h>
    1.41 +#ifdef _EVENT_HAVE_SYS_TIME_H
    1.42 +#include <sys/time.h>
    1.43 +#endif
    1.44 +#include <sys/queue.h>
    1.45 +#ifdef _EVENT_HAVE_SYS_SOCKET_H
    1.46 +#include <sys/socket.h>
    1.47 +#endif
    1.48 +#include <signal.h>
    1.49 +#include <stdio.h>
    1.50 +#include <stdlib.h>
    1.51 +#include <string.h>
    1.52 +#ifdef _EVENT_HAVE_UNISTD_H
    1.53 +#include <unistd.h>
    1.54 +#endif
    1.55 +#include <errno.h>
    1.56 +#ifdef _EVENT_HAVE_FCNTL_H
    1.57 +#include <fcntl.h>
    1.58 +#endif
    1.59 +
    1.60 +#include "event2/event.h"
    1.61 +#include "event2/event_struct.h"
    1.62 +#include "event-internal.h"
    1.63 +#include "event2/util.h"
    1.64 +#include "evsignal-internal.h"
    1.65 +#include "log-internal.h"
    1.66 +#include "evmap-internal.h"
    1.67 +#include "evthread-internal.h"
    1.68 +
    1.69 +/*
    1.70 +  signal.c
    1.71 +
    1.72 +  This is the signal-handling implementation we use for backends that don't
    1.73 +  have a better way to do signal handling.  It uses sigaction() or signal()
    1.74 +  to set a signal handler, and a socket pair to tell the event base when
    1.75 +
    1.76 +  Note that I said "the event base" : only one event base can be set up to use
    1.77 +  this at a time.  For historical reasons and backward compatibility, if you
    1.78 +  add an event for a signal to event_base A, then add an event for a signal
    1.79 +  (any signal!) to event_base B, event_base B will get informed about the
    1.80 +  signal, but event_base A won't.
    1.81 +
    1.82 +  It would be neat to change this behavior in some future version of Libevent.
    1.83 +  kqueue already does something far more sensible.  We can make all backends
    1.84 +  on Linux do a reasonable thing using signalfd.
    1.85 +*/
    1.86 +
    1.87 +#ifndef WIN32
    1.88 +/* Windows wants us to call our signal handlers as __cdecl.  Nobody else
    1.89 + * expects you to do anything crazy like this. */
    1.90 +#define __cdecl
    1.91 +#endif
    1.92 +
    1.93 +static int evsig_add(struct event_base *, evutil_socket_t, short, short, void *);
    1.94 +static int evsig_del(struct event_base *, evutil_socket_t, short, short, void *);
    1.95 +
    1.96 +static const struct eventop evsigops = {
    1.97 +	"signal",
    1.98 +	NULL,
    1.99 +	evsig_add,
   1.100 +	evsig_del,
   1.101 +	NULL,
   1.102 +	NULL,
   1.103 +	0, 0, 0
   1.104 +};
   1.105 +
   1.106 +#ifndef _EVENT_DISABLE_THREAD_SUPPORT
   1.107 +/* Lock for evsig_base and evsig_base_n_signals_added fields. */
   1.108 +static void *evsig_base_lock = NULL;
   1.109 +#endif
   1.110 +/* The event base that's currently getting informed about signals. */
   1.111 +static struct event_base *evsig_base = NULL;
   1.112 +/* A copy of evsig_base->sigev_n_signals_added. */
   1.113 +static int evsig_base_n_signals_added = 0;
   1.114 +static evutil_socket_t evsig_base_fd = -1;
   1.115 +
   1.116 +static void __cdecl evsig_handler(int sig);
   1.117 +
   1.118 +#define EVSIGBASE_LOCK() EVLOCK_LOCK(evsig_base_lock, 0)
   1.119 +#define EVSIGBASE_UNLOCK() EVLOCK_UNLOCK(evsig_base_lock, 0)
   1.120 +
   1.121 +void
   1.122 +evsig_set_base(struct event_base *base)
   1.123 +{
   1.124 +	EVSIGBASE_LOCK();
   1.125 +	evsig_base = base;
   1.126 +	evsig_base_n_signals_added = base->sig.ev_n_signals_added;
   1.127 +	evsig_base_fd = base->sig.ev_signal_pair[0];
   1.128 +	EVSIGBASE_UNLOCK();
   1.129 +}
   1.130 +
   1.131 +/* Callback for when the signal handler write a byte to our signaling socket */
   1.132 +static void
   1.133 +evsig_cb(evutil_socket_t fd, short what, void *arg)
   1.134 +{
   1.135 +	static char signals[1024];
   1.136 +	ev_ssize_t n;
   1.137 +	int i;
   1.138 +	int ncaught[NSIG];
   1.139 +	struct event_base *base;
   1.140 +
   1.141 +	base = arg;
   1.142 +
   1.143 +	memset(&ncaught, 0, sizeof(ncaught));
   1.144 +
   1.145 +	while (1) {
   1.146 +		n = recv(fd, signals, sizeof(signals), 0);
   1.147 +		if (n == -1) {
   1.148 +			int err = evutil_socket_geterror(fd);
   1.149 +			if (! EVUTIL_ERR_RW_RETRIABLE(err))
   1.150 +				event_sock_err(1, fd, "%s: recv", __func__);
   1.151 +			break;
   1.152 +		} else if (n == 0) {
   1.153 +			/* XXX warn? */
   1.154 +			break;
   1.155 +		}
   1.156 +		for (i = 0; i < n; ++i) {
   1.157 +			ev_uint8_t sig = signals[i];
   1.158 +			if (sig < NSIG)
   1.159 +				ncaught[sig]++;
   1.160 +		}
   1.161 +	}
   1.162 +
   1.163 +	EVBASE_ACQUIRE_LOCK(base, th_base_lock);
   1.164 +	for (i = 0; i < NSIG; ++i) {
   1.165 +		if (ncaught[i])
   1.166 +			evmap_signal_active(base, i, ncaught[i]);
   1.167 +	}
   1.168 +	EVBASE_RELEASE_LOCK(base, th_base_lock);
   1.169 +}
   1.170 +
   1.171 +int
   1.172 +evsig_init(struct event_base *base)
   1.173 +{
   1.174 +	/*
   1.175 +	 * Our signal handler is going to write to one end of the socket
   1.176 +	 * pair to wake up our event loop.  The event loop then scans for
   1.177 +	 * signals that got delivered.
   1.178 +	 */
   1.179 +	if (evutil_socketpair(
   1.180 +		    AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1) {
   1.181 +#ifdef WIN32
   1.182 +		/* Make this nonfatal on win32, where sometimes people
   1.183 +		   have localhost firewalled. */
   1.184 +		event_sock_warn(-1, "%s: socketpair", __func__);
   1.185 +#else
   1.186 +		event_sock_err(1, -1, "%s: socketpair", __func__);
   1.187 +#endif
   1.188 +		return -1;
   1.189 +	}
   1.190 +
   1.191 +	evutil_make_socket_closeonexec(base->sig.ev_signal_pair[0]);
   1.192 +	evutil_make_socket_closeonexec(base->sig.ev_signal_pair[1]);
   1.193 +	base->sig.sh_old = NULL;
   1.194 +	base->sig.sh_old_max = 0;
   1.195 +
   1.196 +	evutil_make_socket_nonblocking(base->sig.ev_signal_pair[0]);
   1.197 +	evutil_make_socket_nonblocking(base->sig.ev_signal_pair[1]);
   1.198 +
   1.199 +	event_assign(&base->sig.ev_signal, base, base->sig.ev_signal_pair[1],
   1.200 +		EV_READ | EV_PERSIST, evsig_cb, base);
   1.201 +
   1.202 +	base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL;
   1.203 +	event_priority_set(&base->sig.ev_signal, 0);
   1.204 +
   1.205 +	base->evsigsel = &evsigops;
   1.206 +
   1.207 +	return 0;
   1.208 +}
   1.209 +
   1.210 +/* Helper: set the signal handler for evsignal to handler in base, so that
   1.211 + * we can restore the original handler when we clear the current one. */
   1.212 +int
   1.213 +_evsig_set_handler(struct event_base *base,
   1.214 +    int evsignal, void (__cdecl *handler)(int))
   1.215 +{
   1.216 +#ifdef _EVENT_HAVE_SIGACTION
   1.217 +	struct sigaction sa;
   1.218 +#else
   1.219 +	ev_sighandler_t sh;
   1.220 +#endif
   1.221 +	struct evsig_info *sig = &base->sig;
   1.222 +	void *p;
   1.223 +
   1.224 +	/*
   1.225 +	 * resize saved signal handler array up to the highest signal number.
   1.226 +	 * a dynamic array is used to keep footprint on the low side.
   1.227 +	 */
   1.228 +	if (evsignal >= sig->sh_old_max) {
   1.229 +		int new_max = evsignal + 1;
   1.230 +		event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing",
   1.231 +			    __func__, evsignal, sig->sh_old_max));
   1.232 +		p = mm_realloc(sig->sh_old, new_max * sizeof(*sig->sh_old));
   1.233 +		if (p == NULL) {
   1.234 +			event_warn("realloc");
   1.235 +			return (-1);
   1.236 +		}
   1.237 +
   1.238 +		memset((char *)p + sig->sh_old_max * sizeof(*sig->sh_old),
   1.239 +		    0, (new_max - sig->sh_old_max) * sizeof(*sig->sh_old));
   1.240 +
   1.241 +		sig->sh_old_max = new_max;
   1.242 +		sig->sh_old = p;
   1.243 +	}
   1.244 +
   1.245 +	/* allocate space for previous handler out of dynamic array */
   1.246 +	sig->sh_old[evsignal] = mm_malloc(sizeof *sig->sh_old[evsignal]);
   1.247 +	if (sig->sh_old[evsignal] == NULL) {
   1.248 +		event_warn("malloc");
   1.249 +		return (-1);
   1.250 +	}
   1.251 +
   1.252 +	/* save previous handler and setup new handler */
   1.253 +#ifdef _EVENT_HAVE_SIGACTION
   1.254 +	memset(&sa, 0, sizeof(sa));
   1.255 +	sa.sa_handler = handler;
   1.256 +	sa.sa_flags |= SA_RESTART;
   1.257 +	sigfillset(&sa.sa_mask);
   1.258 +
   1.259 +	if (sigaction(evsignal, &sa, sig->sh_old[evsignal]) == -1) {
   1.260 +		event_warn("sigaction");
   1.261 +		mm_free(sig->sh_old[evsignal]);
   1.262 +		sig->sh_old[evsignal] = NULL;
   1.263 +		return (-1);
   1.264 +	}
   1.265 +#else
   1.266 +	if ((sh = signal(evsignal, handler)) == SIG_ERR) {
   1.267 +		event_warn("signal");
   1.268 +		mm_free(sig->sh_old[evsignal]);
   1.269 +		sig->sh_old[evsignal] = NULL;
   1.270 +		return (-1);
   1.271 +	}
   1.272 +	*sig->sh_old[evsignal] = sh;
   1.273 +#endif
   1.274 +
   1.275 +	return (0);
   1.276 +}
   1.277 +
   1.278 +static int
   1.279 +evsig_add(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p)
   1.280 +{
   1.281 +	struct evsig_info *sig = &base->sig;
   1.282 +	(void)p;
   1.283 +
   1.284 +	EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG);
   1.285 +
   1.286 +	/* catch signals if they happen quickly */
   1.287 +	EVSIGBASE_LOCK();
   1.288 +	if (evsig_base != base && evsig_base_n_signals_added) {
   1.289 +		event_warnx("Added a signal to event base %p with signals "
   1.290 +		    "already added to event_base %p.  Only one can have "
   1.291 +		    "signals at a time with the %s backend.  The base with "
   1.292 +		    "the most recently added signal or the most recent "
   1.293 +		    "event_base_loop() call gets preference; do "
   1.294 +		    "not rely on this behavior in future Libevent versions.",
   1.295 +		    base, evsig_base, base->evsel->name);
   1.296 +	}
   1.297 +	evsig_base = base;
   1.298 +	evsig_base_n_signals_added = ++sig->ev_n_signals_added;
   1.299 +	evsig_base_fd = base->sig.ev_signal_pair[0];
   1.300 +	EVSIGBASE_UNLOCK();
   1.301 +
   1.302 +	event_debug(("%s: %d: changing signal handler", __func__, (int)evsignal));
   1.303 +	if (_evsig_set_handler(base, (int)evsignal, evsig_handler) == -1) {
   1.304 +		goto err;
   1.305 +	}
   1.306 +
   1.307 +
   1.308 +	if (!sig->ev_signal_added) {
   1.309 +		if (event_add(&sig->ev_signal, NULL))
   1.310 +			goto err;
   1.311 +		sig->ev_signal_added = 1;
   1.312 +	}
   1.313 +
   1.314 +	return (0);
   1.315 +
   1.316 +err:
   1.317 +	EVSIGBASE_LOCK();
   1.318 +	--evsig_base_n_signals_added;
   1.319 +	--sig->ev_n_signals_added;
   1.320 +	EVSIGBASE_UNLOCK();
   1.321 +	return (-1);
   1.322 +}
   1.323 +
   1.324 +int
   1.325 +_evsig_restore_handler(struct event_base *base, int evsignal)
   1.326 +{
   1.327 +	int ret = 0;
   1.328 +	struct evsig_info *sig = &base->sig;
   1.329 +#ifdef _EVENT_HAVE_SIGACTION
   1.330 +	struct sigaction *sh;
   1.331 +#else
   1.332 +	ev_sighandler_t *sh;
   1.333 +#endif
   1.334 +
   1.335 +	/* restore previous handler */
   1.336 +	sh = sig->sh_old[evsignal];
   1.337 +	sig->sh_old[evsignal] = NULL;
   1.338 +#ifdef _EVENT_HAVE_SIGACTION
   1.339 +	if (sigaction(evsignal, sh, NULL) == -1) {
   1.340 +		event_warn("sigaction");
   1.341 +		ret = -1;
   1.342 +	}
   1.343 +#else
   1.344 +	if (signal(evsignal, *sh) == SIG_ERR) {
   1.345 +		event_warn("signal");
   1.346 +		ret = -1;
   1.347 +	}
   1.348 +#endif
   1.349 +
   1.350 +	mm_free(sh);
   1.351 +
   1.352 +	return ret;
   1.353 +}
   1.354 +
   1.355 +static int
   1.356 +evsig_del(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p)
   1.357 +{
   1.358 +	EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG);
   1.359 +
   1.360 +	event_debug(("%s: "EV_SOCK_FMT": restoring signal handler",
   1.361 +		__func__, EV_SOCK_ARG(evsignal)));
   1.362 +
   1.363 +	EVSIGBASE_LOCK();
   1.364 +	--evsig_base_n_signals_added;
   1.365 +	--base->sig.ev_n_signals_added;
   1.366 +	EVSIGBASE_UNLOCK();
   1.367 +
   1.368 +	return (_evsig_restore_handler(base, (int)evsignal));
   1.369 +}
   1.370 +
   1.371 +static void __cdecl
   1.372 +evsig_handler(int sig)
   1.373 +{
   1.374 +	int save_errno = errno;
   1.375 +#ifdef WIN32
   1.376 +	int socket_errno = EVUTIL_SOCKET_ERROR();
   1.377 +#endif
   1.378 +	ev_uint8_t msg;
   1.379 +
   1.380 +	if (evsig_base == NULL) {
   1.381 +		event_warnx(
   1.382 +			"%s: received signal %d, but have no base configured",
   1.383 +			__func__, sig);
   1.384 +		return;
   1.385 +	}
   1.386 +
   1.387 +#ifndef _EVENT_HAVE_SIGACTION
   1.388 +	signal(sig, evsig_handler);
   1.389 +#endif
   1.390 +
   1.391 +	/* Wake up our notification mechanism */
   1.392 +	msg = sig;
   1.393 +	send(evsig_base_fd, (char*)&msg, 1, 0);
   1.394 +	errno = save_errno;
   1.395 +#ifdef WIN32
   1.396 +	EVUTIL_SET_SOCKET_ERROR(socket_errno);
   1.397 +#endif
   1.398 +}
   1.399 +
   1.400 +void
   1.401 +evsig_dealloc(struct event_base *base)
   1.402 +{
   1.403 +	int i = 0;
   1.404 +	if (base->sig.ev_signal_added) {
   1.405 +		event_del(&base->sig.ev_signal);
   1.406 +		base->sig.ev_signal_added = 0;
   1.407 +	}
   1.408 +	/* debug event is created in evsig_init/event_assign even when
   1.409 +	 * ev_signal_added == 0, so unassign is required */
   1.410 +	event_debug_unassign(&base->sig.ev_signal);
   1.411 +
   1.412 +	for (i = 0; i < NSIG; ++i) {
   1.413 +		if (i < base->sig.sh_old_max && base->sig.sh_old[i] != NULL)
   1.414 +			_evsig_restore_handler(base, i);
   1.415 +	}
   1.416 +	EVSIGBASE_LOCK();
   1.417 +	if (base == evsig_base) {
   1.418 +		evsig_base = NULL;
   1.419 +		evsig_base_n_signals_added = 0;
   1.420 +		evsig_base_fd = -1;
   1.421 +	}
   1.422 +	EVSIGBASE_UNLOCK();
   1.423 +
   1.424 +	if (base->sig.ev_signal_pair[0] != -1) {
   1.425 +		evutil_closesocket(base->sig.ev_signal_pair[0]);
   1.426 +		base->sig.ev_signal_pair[0] = -1;
   1.427 +	}
   1.428 +	if (base->sig.ev_signal_pair[1] != -1) {
   1.429 +		evutil_closesocket(base->sig.ev_signal_pair[1]);
   1.430 +		base->sig.ev_signal_pair[1] = -1;
   1.431 +	}
   1.432 +	base->sig.sh_old_max = 0;
   1.433 +
   1.434 +	/* per index frees are handled in evsig_del() */
   1.435 +	if (base->sig.sh_old) {
   1.436 +		mm_free(base->sig.sh_old);
   1.437 +		base->sig.sh_old = NULL;
   1.438 +	}
   1.439 +}
   1.440 +
   1.441 +#ifndef _EVENT_DISABLE_THREAD_SUPPORT
   1.442 +int
   1.443 +evsig_global_setup_locks_(const int enable_locks)
   1.444 +{
   1.445 +	EVTHREAD_SETUP_GLOBAL_LOCK(evsig_base_lock, 0);
   1.446 +	return 0;
   1.447 +}
   1.448 +#endif

mercurial