xref: /openbsd/lib/libevent/signal.c (revision db3296cf)
1 /*	$OpenBSD: signal.c,v 1.2 2003/07/10 07:48:42 markus Exp $	*/
2 
3 /*
4  * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Niels Provos.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35 
36 #include <sys/types.h>
37 #ifdef HAVE_SYS_TIME_H
38 #include <sys/time.h>
39 #else
40 #include <sys/_time.h>
41 #endif
42 #include <sys/queue.h>
43 #include <signal.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <errno.h>
49 #include <err.h>
50 
51 #ifdef USE_LOG
52 #include "log.h"
53 #else
54 #define LOG_DBG(x)
55 #define log_error(x)	perror(x)
56 #endif
57 
58 #include "event.h"
59 
60 extern struct event_list signalqueue;
61 
62 static short evsigcaught[NSIG];
63 static int needrecalc;
64 volatile sig_atomic_t evsignal_caught = 0;
65 
66 void evsignal_process(void);
67 int evsignal_recalc(sigset_t *);
68 int evsignal_deliver(sigset_t *);
69 
70 void
71 evsignal_init(sigset_t *evsigmask)
72 {
73 	sigemptyset(evsigmask);
74 }
75 
76 int
77 evsignal_add(sigset_t *evsigmask, struct event *ev)
78 {
79 	int signal;
80 
81 	if (ev->ev_events & (EV_READ|EV_WRITE))
82 		errx(1, "%s: EV_SIGNAL incompatible use", __func__);
83 	signal = EVENT_SIGNAL(ev);
84 	sigaddset(evsigmask, signal);
85 
86 	return (0);
87 }
88 
89 /*
90  * Nothing to be done here.
91  */
92 
93 int
94 evsignal_del(sigset_t *evsigmask, struct event *ev)
95 {
96 	int signal;
97 
98 	signal = EVENT_SIGNAL(ev);
99 	sigdelset(evsigmask, signal);
100 	needrecalc = 1;
101 
102 	return (sigaction(EVENT_SIGNAL(ev),(struct sigaction *)SIG_DFL, NULL));
103 }
104 
105 static void
106 evsignal_handler(int sig)
107 {
108 	evsigcaught[sig]++;
109 	evsignal_caught = 1;
110 }
111 
112 int
113 evsignal_recalc(sigset_t *evsigmask)
114 {
115 	struct sigaction sa;
116 	struct event *ev;
117 
118 	if (TAILQ_FIRST(&signalqueue) == NULL && !needrecalc)
119 		return (0);
120 	needrecalc = 0;
121 
122 	if (sigprocmask(SIG_BLOCK, evsigmask, NULL) == -1)
123 		return (-1);
124 
125 	/* Reinstall our signal handler. */
126 	memset(&sa, 0, sizeof(sa));
127 	sa.sa_handler = evsignal_handler;
128 	sa.sa_mask = *evsigmask;
129 	sa.sa_flags |= SA_RESTART;
130 
131 	TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) {
132 		if (sigaction(EVENT_SIGNAL(ev), &sa, NULL) == -1)
133 			return (-1);
134 	}
135 	return (0);
136 }
137 
138 int
139 evsignal_deliver(sigset_t *evsigmask)
140 {
141 	if (TAILQ_FIRST(&signalqueue) == NULL)
142 		return (0);
143 
144 	return (sigprocmask(SIG_UNBLOCK, evsigmask, NULL));
145 	/* XXX - pending signals handled here */
146 }
147 
148 void
149 evsignal_process(void)
150 {
151 	struct event *ev;
152 	short ncalls;
153 
154 	TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) {
155 		ncalls = evsigcaught[EVENT_SIGNAL(ev)];
156 		if (ncalls) {
157 			if (!(ev->ev_events & EV_PERSIST))
158 				event_del(ev);
159 			event_active(ev, EV_SIGNAL, ncalls);
160 		}
161 	}
162 
163 	memset(evsigcaught, 0, sizeof(evsigcaught));
164 	evsignal_caught = 0;
165 }
166 
167