about summary refs log tree commit diff
path: root/libevent/signal.c
diff options
context:
space:
mode:
authorRichard Nyberg <rnyberg@murmeldjur.se>2006-11-07 09:40:25 +0000
committerRichard Nyberg <rnyberg@murmeldjur.se>2006-11-07 09:40:25 +0000
commit5ccf414cbff49636a365a6bce2d2641be90ea412 (patch)
treea4305df50e7893cecb60822d6e1b50403e45e8be /libevent/signal.c
parent568d1163350f81be1f71b6c8b2c7b59fc4a4db86 (diff)
downloadbtpd-5ccf414cbff49636a365a6bce2d2641be90ea412.tar.gz
btpd-5ccf414cbff49636a365a6bce2d2641be90ea412.zip
Include libevent 1.2 in btpd.
Diffstat (limited to 'libevent/signal.c')
-rw-r--r--libevent/signal.c212
1 files changed, 212 insertions, 0 deletions
diff --git a/libevent/signal.c b/libevent/signal.c
new file mode 100644
index 0000000..8a6963b
--- /dev/null
+++ b/libevent/signal.c
@@ -0,0 +1,212 @@
+/*	$OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $	*/
+
+/*
+ * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <sys/_time.h>
+#endif
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include "event.h"
+#include "evsignal.h"
+#include "log.h"
+
+extern struct event_list signalqueue;
+
+static sig_atomic_t evsigcaught[NSIG];
+static int needrecalc;
+volatile sig_atomic_t evsignal_caught = 0;
+
+static struct event ev_signal;
+static int ev_signal_pair[2];
+static int ev_signal_added;
+
+/* Callback for when the signal handler write a byte to our signaling socket */
+static void
+evsignal_cb(int fd, short what, void *arg)
+{
+	static char signals[100];
+	struct event *ev = arg;
+	ssize_t n;
+
+	n = read(fd, signals, sizeof(signals));
+	if (n == -1)
+		event_err(1, "%s: read", __func__);
+	event_add(ev, NULL);
+}
+
+#ifdef HAVE_SETFD
+#define FD_CLOSEONEXEC(x) do { \
+        if (fcntl(x, F_SETFD, 1) == -1) \
+                event_warn("fcntl(%d, F_SETFD)", x); \
+} while (0)
+#else
+#define FD_CLOSEONEXEC(x)
+#endif
+
+void
+evsignal_init(sigset_t *evsigmask)
+{
+	sigemptyset(evsigmask);
+
+	/* 
+	 * Our signal handler is going to write to one end of the socket
+	 * pair to wake up our event loop.  The event loop then scans for
+	 * signals that got delivered.
+	 */
+	if (socketpair(AF_UNIX, SOCK_STREAM, 0, ev_signal_pair) == -1)
+		event_err(1, "%s: socketpair", __func__);
+
+	FD_CLOSEONEXEC(ev_signal_pair[0]);
+	FD_CLOSEONEXEC(ev_signal_pair[1]);
+
+	fcntl(ev_signal_pair[0], F_SETFL, O_NONBLOCK);
+
+	event_set(&ev_signal, ev_signal_pair[1], EV_READ,
+	    evsignal_cb, &ev_signal);
+	ev_signal.ev_flags |= EVLIST_INTERNAL;
+}
+
+int
+evsignal_add(sigset_t *evsigmask, struct event *ev)
+{
+	int evsignal;
+
+	if (ev->ev_events & (EV_READ|EV_WRITE))
+		event_errx(1, "%s: EV_SIGNAL incompatible use", __func__);
+	evsignal = EVENT_SIGNAL(ev);
+	sigaddset(evsigmask, evsignal);
+
+	return (0);
+}
+
+/*
+ * Nothing to be done here.
+ */
+
+int
+evsignal_del(sigset_t *evsigmask, struct event *ev)
+{
+	int evsignal;
+
+	evsignal = EVENT_SIGNAL(ev);
+	sigdelset(evsigmask, evsignal);
+	needrecalc = 1;
+
+	return (sigaction(EVENT_SIGNAL(ev),(struct sigaction *)SIG_DFL, NULL));
+}
+
+static void
+evsignal_handler(int sig)
+{
+	int save_errno = errno;
+
+	evsigcaught[sig]++;
+	evsignal_caught = 1;
+
+	/* Wake up our notification mechanism */
+	write(ev_signal_pair[0], "a", 1);
+	errno = save_errno;
+}
+
+int
+evsignal_recalc(sigset_t *evsigmask)
+{
+	struct sigaction sa;
+	struct event *ev;
+
+	if (!ev_signal_added) {
+		ev_signal_added = 1;
+		event_add(&ev_signal, NULL);
+	}
+
+	if (TAILQ_FIRST(&signalqueue) == NULL && !needrecalc)
+		return (0);
+	needrecalc = 0;
+
+	if (sigprocmask(SIG_BLOCK, evsigmask, NULL) == -1)
+		return (-1);
+
+	/* Reinstall our signal handler. */
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = evsignal_handler;
+	sa.sa_mask = *evsigmask;
+	sa.sa_flags |= SA_RESTART;
+
+	TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) {
+		if (sigaction(EVENT_SIGNAL(ev), &sa, NULL) == -1)
+			return (-1);
+	}
+	return (0);
+}
+
+int
+evsignal_deliver(sigset_t *evsigmask)
+{
+	if (TAILQ_FIRST(&signalqueue) == NULL)
+		return (0);
+
+	return (sigprocmask(SIG_UNBLOCK, evsigmask, NULL));
+	/* XXX - pending signals handled here */
+}
+
+void
+evsignal_process(void)
+{
+	struct event *ev;
+	sig_atomic_t ncalls;
+
+	TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) {
+		ncalls = evsigcaught[EVENT_SIGNAL(ev)];
+		if (ncalls) {
+			if (!(ev->ev_events & EV_PERSIST))
+				event_del(ev);
+			event_active(ev, EV_SIGNAL, ncalls);
+		}
+	}
+
+	memset(evsigcaught, 0, sizeof(evsigcaught));
+	evsignal_caught = 0;
+}
+