xref: /freebsd/contrib/pf/libevent/signal.c (revision b488428efebda411bad0d9d52c62aa38dfba05f1)
167ecd4f3SMax Laier /*	$OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $	*/
267ecd4f3SMax Laier 
367ecd4f3SMax Laier /*
467ecd4f3SMax Laier  * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
567ecd4f3SMax Laier  * All rights reserved.
667ecd4f3SMax Laier  *
767ecd4f3SMax Laier  * Redistribution and use in source and binary forms, with or without
867ecd4f3SMax Laier  * modification, are permitted provided that the following conditions
967ecd4f3SMax Laier  * are met:
1067ecd4f3SMax Laier  * 1. Redistributions of source code must retain the above copyright
1167ecd4f3SMax Laier  *    notice, this list of conditions and the following disclaimer.
1267ecd4f3SMax Laier  * 2. Redistributions in binary form must reproduce the above copyright
1367ecd4f3SMax Laier  *    notice, this list of conditions and the following disclaimer in the
1467ecd4f3SMax Laier  *    documentation and/or other materials provided with the distribution.
1567ecd4f3SMax Laier  * 3. The name of the author may not be used to endorse or promote products
1667ecd4f3SMax Laier  *    derived from this software without specific prior written permission.
1767ecd4f3SMax Laier  *
1867ecd4f3SMax Laier  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1967ecd4f3SMax Laier  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2067ecd4f3SMax Laier  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2167ecd4f3SMax Laier  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2267ecd4f3SMax Laier  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2367ecd4f3SMax Laier  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2467ecd4f3SMax Laier  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2567ecd4f3SMax Laier  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2667ecd4f3SMax Laier  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2767ecd4f3SMax Laier  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2867ecd4f3SMax Laier  */
2967ecd4f3SMax Laier #ifdef HAVE_CONFIG_H
3067ecd4f3SMax Laier #include "config.h"
3167ecd4f3SMax Laier #endif
3267ecd4f3SMax Laier 
3367ecd4f3SMax Laier #include <sys/types.h>
3467ecd4f3SMax Laier #ifdef HAVE_SYS_TIME_H
3567ecd4f3SMax Laier #include <sys/time.h>
3667ecd4f3SMax Laier #else
3767ecd4f3SMax Laier #include <sys/_time.h>
3867ecd4f3SMax Laier #endif
3967ecd4f3SMax Laier #include <sys/queue.h>
4067ecd4f3SMax Laier #include <sys/socket.h>
4167ecd4f3SMax Laier #include <signal.h>
4267ecd4f3SMax Laier #include <stdio.h>
4367ecd4f3SMax Laier #include <stdlib.h>
4467ecd4f3SMax Laier #include <string.h>
4567ecd4f3SMax Laier #include <unistd.h>
4667ecd4f3SMax Laier #include <errno.h>
4767ecd4f3SMax Laier #ifdef HAVE_FCNTL_H
4867ecd4f3SMax Laier #include <fcntl.h>
4967ecd4f3SMax Laier #endif
5067ecd4f3SMax Laier 
5167ecd4f3SMax Laier #include "event.h"
5267ecd4f3SMax Laier #include "evsignal.h"
5367ecd4f3SMax Laier #include "log.h"
5467ecd4f3SMax Laier 
5567ecd4f3SMax Laier extern struct event_list signalqueue;
5667ecd4f3SMax Laier 
5767ecd4f3SMax Laier static sig_atomic_t evsigcaught[NSIG];
5867ecd4f3SMax Laier volatile sig_atomic_t evsignal_caught = 0;
5967ecd4f3SMax Laier 
6067ecd4f3SMax Laier static struct event ev_signal;
6167ecd4f3SMax Laier static int ev_signal_pair[2];
6267ecd4f3SMax Laier static int ev_signal_added;
6367ecd4f3SMax Laier 
6467ecd4f3SMax Laier static void evsignal_handler(int sig);
6567ecd4f3SMax Laier 
6667ecd4f3SMax Laier /* Callback for when the signal handler write a byte to our signaling socket */
6767ecd4f3SMax Laier static void
evsignal_cb(int fd,short what,void * arg)6867ecd4f3SMax Laier evsignal_cb(int fd, short what, void *arg)
6967ecd4f3SMax Laier {
7067ecd4f3SMax Laier 	static char signals[100];
7167ecd4f3SMax Laier 	struct event *ev = arg;
7267ecd4f3SMax Laier 	ssize_t n;
7367ecd4f3SMax Laier 
7467ecd4f3SMax Laier 	n = read(fd, signals, sizeof(signals));
7567ecd4f3SMax Laier 	if (n == -1)
7667ecd4f3SMax Laier 		event_err(1, "%s: read", __func__);
7767ecd4f3SMax Laier 	event_add(ev, NULL);
7867ecd4f3SMax Laier }
7967ecd4f3SMax Laier 
8067ecd4f3SMax Laier #ifdef HAVE_SETFD
8167ecd4f3SMax Laier #define FD_CLOSEONEXEC(x) do { \
8267ecd4f3SMax Laier         if (fcntl(x, F_SETFD, 1) == -1) \
8367ecd4f3SMax Laier                 event_warn("fcntl(%d, F_SETFD)", x); \
8467ecd4f3SMax Laier } while (0)
8567ecd4f3SMax Laier #else
8667ecd4f3SMax Laier #define FD_CLOSEONEXEC(x)
8767ecd4f3SMax Laier #endif
8867ecd4f3SMax Laier 
8967ecd4f3SMax Laier void
evsignal_init(void)9067ecd4f3SMax Laier evsignal_init(void)
9167ecd4f3SMax Laier {
9267ecd4f3SMax Laier 	/*
9367ecd4f3SMax Laier 	 * Our signal handler is going to write to one end of the socket
9467ecd4f3SMax Laier 	 * pair to wake up our event loop.  The event loop then scans for
9567ecd4f3SMax Laier 	 * signals that got delivered.
9667ecd4f3SMax Laier 	 */
9767ecd4f3SMax Laier 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, ev_signal_pair) == -1)
9867ecd4f3SMax Laier 		event_err(1, "%s: socketpair", __func__);
9967ecd4f3SMax Laier 
10067ecd4f3SMax Laier 	FD_CLOSEONEXEC(ev_signal_pair[0]);
10167ecd4f3SMax Laier 	FD_CLOSEONEXEC(ev_signal_pair[1]);
10267ecd4f3SMax Laier 
10367ecd4f3SMax Laier 	fcntl(ev_signal_pair[0], F_SETFL, O_NONBLOCK);
10467ecd4f3SMax Laier 
10567ecd4f3SMax Laier 	event_set(&ev_signal, ev_signal_pair[1], EV_READ,
10667ecd4f3SMax Laier 	    evsignal_cb, &ev_signal);
10767ecd4f3SMax Laier 	ev_signal.ev_flags |= EVLIST_INTERNAL;
10867ecd4f3SMax Laier }
10967ecd4f3SMax Laier 
11067ecd4f3SMax Laier int
evsignal_add(struct event * ev)11167ecd4f3SMax Laier evsignal_add(struct event *ev)
11267ecd4f3SMax Laier {
11367ecd4f3SMax Laier 	int evsignal;
11467ecd4f3SMax Laier 	struct sigaction sa;
11567ecd4f3SMax Laier 
11667ecd4f3SMax Laier 	if (ev->ev_events & (EV_READ|EV_WRITE))
11767ecd4f3SMax Laier 		event_errx(1, "%s: EV_SIGNAL incompatible use", __func__);
11867ecd4f3SMax Laier 	evsignal = EVENT_SIGNAL(ev);
11967ecd4f3SMax Laier 
12067ecd4f3SMax Laier 	memset(&sa, 0, sizeof(sa));
12167ecd4f3SMax Laier 	sa.sa_handler = evsignal_handler;
12267ecd4f3SMax Laier 	sigfillset(&sa.sa_mask);
12367ecd4f3SMax Laier 	sa.sa_flags |= SA_RESTART;
12467ecd4f3SMax Laier 
12567ecd4f3SMax Laier 	if (sigaction(evsignal, &sa, NULL) == -1)
12667ecd4f3SMax Laier 		return (-1);
12767ecd4f3SMax Laier 
12867ecd4f3SMax Laier 	if (!ev_signal_added) {
12967ecd4f3SMax Laier 		ev_signal_added = 1;
13067ecd4f3SMax Laier 		event_add(&ev_signal, NULL);
13167ecd4f3SMax Laier 	}
13267ecd4f3SMax Laier 
13367ecd4f3SMax Laier 	return (0);
13467ecd4f3SMax Laier }
13567ecd4f3SMax Laier 
13667ecd4f3SMax Laier /*
13767ecd4f3SMax Laier  * Nothing to be done here.
13867ecd4f3SMax Laier  */
13967ecd4f3SMax Laier 
14067ecd4f3SMax Laier int
evsignal_del(struct event * ev)14167ecd4f3SMax Laier evsignal_del(struct event *ev)
14267ecd4f3SMax Laier {
14367ecd4f3SMax Laier 	int evsignal;
14467ecd4f3SMax Laier 
14567ecd4f3SMax Laier 	evsignal = EVENT_SIGNAL(ev);
14667ecd4f3SMax Laier 
147*b488428eSJohn Baldwin 	return (sigaction(evsignal, (struct sigaction *)SIG_DFL, NULL));
14867ecd4f3SMax Laier }
14967ecd4f3SMax Laier 
15067ecd4f3SMax Laier static void
evsignal_handler(int sig)15167ecd4f3SMax Laier evsignal_handler(int sig)
15267ecd4f3SMax Laier {
15367ecd4f3SMax Laier 	int save_errno = errno;
15467ecd4f3SMax Laier 
15567ecd4f3SMax Laier 	evsigcaught[sig]++;
15667ecd4f3SMax Laier 	evsignal_caught = 1;
15767ecd4f3SMax Laier 
15867ecd4f3SMax Laier 	/* Wake up our notification mechanism */
15967ecd4f3SMax Laier 	write(ev_signal_pair[0], "a", 1);
16067ecd4f3SMax Laier 	errno = save_errno;
16167ecd4f3SMax Laier }
16267ecd4f3SMax Laier 
16367ecd4f3SMax Laier void
evsignal_process(void)16467ecd4f3SMax Laier evsignal_process(void)
16567ecd4f3SMax Laier {
16667ecd4f3SMax Laier 	struct event *ev;
16767ecd4f3SMax Laier 	sig_atomic_t ncalls;
16867ecd4f3SMax Laier 
16967ecd4f3SMax Laier 	evsignal_caught = 0;
17067ecd4f3SMax Laier 	TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) {
17167ecd4f3SMax Laier 		ncalls = evsigcaught[EVENT_SIGNAL(ev)];
17267ecd4f3SMax Laier 		if (ncalls) {
17367ecd4f3SMax Laier 			if (!(ev->ev_events & EV_PERSIST))
17467ecd4f3SMax Laier 				event_del(ev);
17567ecd4f3SMax Laier 			event_active(ev, EV_SIGNAL, ncalls);
17667ecd4f3SMax Laier 			evsigcaught[EVENT_SIGNAL(ev)] = 0;
17767ecd4f3SMax Laier 		}
17867ecd4f3SMax Laier 	}
17967ecd4f3SMax Laier }
18067ecd4f3SMax Laier 
181