1171169Smlaier/*	$OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $	*/
2171169Smlaier
3171169Smlaier/*
4171169Smlaier * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
5171169Smlaier * All rights reserved.
6171169Smlaier *
7171169Smlaier * Redistribution and use in source and binary forms, with or without
8171169Smlaier * modification, are permitted provided that the following conditions
9171169Smlaier * are met:
10171169Smlaier * 1. Redistributions of source code must retain the above copyright
11171169Smlaier *    notice, this list of conditions and the following disclaimer.
12171169Smlaier * 2. Redistributions in binary form must reproduce the above copyright
13171169Smlaier *    notice, this list of conditions and the following disclaimer in the
14171169Smlaier *    documentation and/or other materials provided with the distribution.
15171169Smlaier * 3. The name of the author may not be used to endorse or promote products
16171169Smlaier *    derived from this software without specific prior written permission.
17171169Smlaier *
18171169Smlaier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19171169Smlaier * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20171169Smlaier * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21171169Smlaier * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22171169Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23171169Smlaier * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24171169Smlaier * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25171169Smlaier * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26171169Smlaier * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27171169Smlaier * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28171169Smlaier */
29171169Smlaier#ifdef HAVE_CONFIG_H
30171169Smlaier#include "config.h"
31171169Smlaier#endif
32171169Smlaier
33171169Smlaier#include <sys/types.h>
34171169Smlaier#ifdef HAVE_SYS_TIME_H
35171169Smlaier#include <sys/time.h>
36171169Smlaier#else
37171169Smlaier#include <sys/_time.h>
38171169Smlaier#endif
39171169Smlaier#include <sys/queue.h>
40171169Smlaier#include <sys/socket.h>
41171169Smlaier#include <signal.h>
42171169Smlaier#include <stdio.h>
43171169Smlaier#include <stdlib.h>
44171169Smlaier#include <string.h>
45171169Smlaier#include <unistd.h>
46171169Smlaier#include <errno.h>
47171169Smlaier#ifdef HAVE_FCNTL_H
48171169Smlaier#include <fcntl.h>
49171169Smlaier#endif
50171169Smlaier
51171169Smlaier#include "event.h"
52171169Smlaier#include "evsignal.h"
53171169Smlaier#include "log.h"
54171169Smlaier
55171169Smlaierextern struct event_list signalqueue;
56171169Smlaier
57171169Smlaierstatic sig_atomic_t evsigcaught[NSIG];
58171169Smlaiervolatile sig_atomic_t evsignal_caught = 0;
59171169Smlaier
60171169Smlaierstatic struct event ev_signal;
61171169Smlaierstatic int ev_signal_pair[2];
62171169Smlaierstatic int ev_signal_added;
63171169Smlaier
64171169Smlaierstatic void evsignal_handler(int sig);
65171169Smlaier
66171169Smlaier/* Callback for when the signal handler write a byte to our signaling socket */
67171169Smlaierstatic void
68171169Smlaierevsignal_cb(int fd, short what, void *arg)
69171169Smlaier{
70171169Smlaier	static char signals[100];
71171169Smlaier	struct event *ev = arg;
72171169Smlaier	ssize_t n;
73171169Smlaier
74171169Smlaier	n = read(fd, signals, sizeof(signals));
75171169Smlaier	if (n == -1)
76171169Smlaier		event_err(1, "%s: read", __func__);
77171169Smlaier	event_add(ev, NULL);
78171169Smlaier}
79171169Smlaier
80171169Smlaier#ifdef HAVE_SETFD
81171169Smlaier#define FD_CLOSEONEXEC(x) do { \
82171169Smlaier        if (fcntl(x, F_SETFD, 1) == -1) \
83171169Smlaier                event_warn("fcntl(%d, F_SETFD)", x); \
84171169Smlaier} while (0)
85171169Smlaier#else
86171169Smlaier#define FD_CLOSEONEXEC(x)
87171169Smlaier#endif
88171169Smlaier
89171169Smlaiervoid
90171169Smlaierevsignal_init(void)
91171169Smlaier{
92171169Smlaier	/*
93171169Smlaier	 * Our signal handler is going to write to one end of the socket
94171169Smlaier	 * pair to wake up our event loop.  The event loop then scans for
95171169Smlaier	 * signals that got delivered.
96171169Smlaier	 */
97171169Smlaier	if (socketpair(AF_UNIX, SOCK_STREAM, 0, ev_signal_pair) == -1)
98171169Smlaier		event_err(1, "%s: socketpair", __func__);
99171169Smlaier
100171169Smlaier	FD_CLOSEONEXEC(ev_signal_pair[0]);
101171169Smlaier	FD_CLOSEONEXEC(ev_signal_pair[1]);
102171169Smlaier
103171169Smlaier	fcntl(ev_signal_pair[0], F_SETFL, O_NONBLOCK);
104171169Smlaier
105171169Smlaier	event_set(&ev_signal, ev_signal_pair[1], EV_READ,
106171169Smlaier	    evsignal_cb, &ev_signal);
107171169Smlaier	ev_signal.ev_flags |= EVLIST_INTERNAL;
108171169Smlaier}
109171169Smlaier
110171169Smlaierint
111171169Smlaierevsignal_add(struct event *ev)
112171169Smlaier{
113171169Smlaier	int evsignal;
114171169Smlaier	struct sigaction sa;
115171169Smlaier
116171169Smlaier	if (ev->ev_events & (EV_READ|EV_WRITE))
117171169Smlaier		event_errx(1, "%s: EV_SIGNAL incompatible use", __func__);
118171169Smlaier	evsignal = EVENT_SIGNAL(ev);
119171169Smlaier
120171169Smlaier	memset(&sa, 0, sizeof(sa));
121171169Smlaier	sa.sa_handler = evsignal_handler;
122171169Smlaier	sigfillset(&sa.sa_mask);
123171169Smlaier	sa.sa_flags |= SA_RESTART;
124171169Smlaier
125171169Smlaier	if (sigaction(evsignal, &sa, NULL) == -1)
126171169Smlaier		return (-1);
127171169Smlaier
128171169Smlaier	if (!ev_signal_added) {
129171169Smlaier		ev_signal_added = 1;
130171169Smlaier		event_add(&ev_signal, NULL);
131171169Smlaier	}
132171169Smlaier
133171169Smlaier	return (0);
134171169Smlaier}
135171169Smlaier
136171169Smlaier/*
137171169Smlaier * Nothing to be done here.
138171169Smlaier */
139171169Smlaier
140171169Smlaierint
141171169Smlaierevsignal_del(struct event *ev)
142171169Smlaier{
143171169Smlaier	int evsignal;
144171169Smlaier
145171169Smlaier	evsignal = EVENT_SIGNAL(ev);
146171169Smlaier
147171169Smlaier	return (sigaction(EVENT_SIGNAL(ev),(struct sigaction *)SIG_DFL, NULL));
148171169Smlaier}
149171169Smlaier
150171169Smlaierstatic void
151171169Smlaierevsignal_handler(int sig)
152171169Smlaier{
153171169Smlaier	int save_errno = errno;
154171169Smlaier
155171169Smlaier	evsigcaught[sig]++;
156171169Smlaier	evsignal_caught = 1;
157171169Smlaier
158171169Smlaier	/* Wake up our notification mechanism */
159171169Smlaier	write(ev_signal_pair[0], "a", 1);
160171169Smlaier	errno = save_errno;
161171169Smlaier}
162171169Smlaier
163171169Smlaiervoid
164171169Smlaierevsignal_process(void)
165171169Smlaier{
166171169Smlaier	struct event *ev;
167171169Smlaier	sig_atomic_t ncalls;
168171169Smlaier
169171169Smlaier	evsignal_caught = 0;
170171169Smlaier	TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) {
171171169Smlaier		ncalls = evsigcaught[EVENT_SIGNAL(ev)];
172171169Smlaier		if (ncalls) {
173171169Smlaier			if (!(ev->ev_events & EV_PERSIST))
174171169Smlaier				event_del(ev);
175171169Smlaier			event_active(ev, EV_SIGNAL, ncalls);
176171169Smlaier			evsigcaught[EVENT_SIGNAL(ev)] = 0;
177171169Smlaier		}
178171169Smlaier	}
179171169Smlaier}
180171169Smlaier
181