1 /* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
4 * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #define WIN32_LEAN_AND_MEAN
37 #undef WIN32_LEAN_AND_MEAN
39 #include <sys/types.h>
40 #ifdef HAVE_SYS_TIME_H
43 #include <sys/queue.h>
44 #ifdef HAVE_SYS_SOCKET_H
45 #include <sys/socket.h>
61 #include "event-internal.h"
66 struct event_base
*evsignal_base
= NULL
;
68 static void evsignal_handler(int sig
);
70 /* Callback for when the signal handler write a byte to our signaling socket */
72 evsignal_cb(int fd
, short what
, void *arg
)
74 static char signals
[1];
81 n
= recv(fd
, signals
, sizeof(signals
), 0);
83 event_err(1, "%s: read", __func__
);
87 #define FD_CLOSEONEXEC(x) do { \
88 if (fcntl(x, F_SETFD, 1) == -1) \
89 event_warn("fcntl(%d, F_SETFD)", x); \
92 #define FD_CLOSEONEXEC(x)
96 evsignal_init(struct event_base
*base
)
101 * Our signal handler is going to write to one end of the socket
102 * pair to wake up our event loop. The event loop then scans for
103 * signals that got delivered.
105 if (evutil_socketpair(
106 AF_UNIX
, SOCK_STREAM
, 0, base
->sig
.ev_signal_pair
) == -1) {
108 /* Make this nonfatal on win32, where sometimes people
109 have localhost firewalled. */
110 event_warn("%s: socketpair", __func__
);
112 event_err(1, "%s: socketpair", __func__
);
117 FD_CLOSEONEXEC(base
->sig
.ev_signal_pair
[0]);
118 FD_CLOSEONEXEC(base
->sig
.ev_signal_pair
[1]);
119 base
->sig
.sh_old
= NULL
;
120 base
->sig
.sh_old_max
= 0;
121 base
->sig
.evsignal_caught
= 0;
122 memset(&base
->sig
.evsigcaught
, 0, sizeof(sig_atomic_t)*NSIG
);
123 /* initialize the queues for all events */
124 for (i
= 0; i
< NSIG
; ++i
)
125 TAILQ_INIT(&base
->sig
.evsigevents
[i
]);
127 evutil_make_socket_nonblocking(base
->sig
.ev_signal_pair
[0]);
129 event_set(&base
->sig
.ev_signal
, base
->sig
.ev_signal_pair
[1],
130 EV_READ
| EV_PERSIST
, evsignal_cb
, &base
->sig
.ev_signal
);
131 base
->sig
.ev_signal
.ev_base
= base
;
132 base
->sig
.ev_signal
.ev_flags
|= EVLIST_INTERNAL
;
137 /* Helper: set the signal handler for evsignal to handler in base, so that
138 * we can restore the original handler when we clear the current one. */
140 _evsignal_set_handler(struct event_base
*base
,
141 int evsignal
, void (*handler
)(int))
143 #ifdef HAVE_SIGACTION
148 struct evsignal_info
*sig
= &base
->sig
;
152 * resize saved signal handler array up to the highest signal number.
153 * a dynamic array is used to keep footprint on the low side.
155 if (evsignal
>= sig
->sh_old_max
) {
156 int new_max
= evsignal
+ 1;
157 event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing",
158 __func__
, evsignal
, sig
->sh_old_max
));
159 p
= realloc(sig
->sh_old
, new_max
* sizeof(*sig
->sh_old
));
161 event_warn("realloc");
165 memset((char *)p
+ sig
->sh_old_max
* sizeof(*sig
->sh_old
),
166 0, (new_max
- sig
->sh_old_max
) * sizeof(*sig
->sh_old
));
168 sig
->sh_old_max
= new_max
;
172 /* allocate space for previous handler out of dynamic array */
173 sig
->sh_old
[evsignal
] = malloc(sizeof *sig
->sh_old
[evsignal
]);
174 if (sig
->sh_old
[evsignal
] == NULL
) {
175 event_warn("malloc");
179 /* save previous handler and setup new handler */
180 #ifdef HAVE_SIGACTION
181 memset(&sa
, 0, sizeof(sa
));
182 sa
.sa_handler
= handler
;
183 sa
.sa_flags
|= SA_RESTART
;
184 sigfillset(&sa
.sa_mask
);
186 if (sigaction(evsignal
, &sa
, sig
->sh_old
[evsignal
]) == -1) {
187 event_warn("sigaction");
188 free(sig
->sh_old
[evsignal
]);
192 if ((sh
= signal(evsignal
, handler
)) == SIG_ERR
) {
193 event_warn("signal");
194 free(sig
->sh_old
[evsignal
]);
197 *sig
->sh_old
[evsignal
] = sh
;
204 evsignal_add(struct event
*ev
)
207 struct event_base
*base
= ev
->ev_base
;
208 struct evsignal_info
*sig
= &ev
->ev_base
->sig
;
210 if (ev
->ev_events
& (EV_READ
|EV_WRITE
))
211 event_errx(1, "%s: EV_SIGNAL incompatible use", __func__
);
212 evsignal
= EVENT_SIGNAL(ev
);
213 assert(evsignal
>= 0 && evsignal
< NSIG
);
214 if (TAILQ_EMPTY(&sig
->evsigevents
[evsignal
])) {
215 event_debug(("%s: %p: changing signal handler", __func__
, ev
));
216 if (_evsignal_set_handler(
217 base
, evsignal
, evsignal_handler
) == -1)
220 /* catch signals if they happen quickly */
221 evsignal_base
= base
;
223 if (!sig
->ev_signal_added
) {
224 if (event_add(&sig
->ev_signal
, NULL
))
226 sig
->ev_signal_added
= 1;
230 /* multiple events may listen to the same signal */
231 TAILQ_INSERT_TAIL(&sig
->evsigevents
[evsignal
], ev
, ev_signal_next
);
237 _evsignal_restore_handler(struct event_base
*base
, int evsignal
)
240 struct evsignal_info
*sig
= &base
->sig
;
241 #ifdef HAVE_SIGACTION
242 struct sigaction
*sh
;
247 /* restore previous handler */
248 sh
= sig
->sh_old
[evsignal
];
249 sig
->sh_old
[evsignal
] = NULL
;
250 #ifdef HAVE_SIGACTION
251 if (sigaction(evsignal
, sh
, NULL
) == -1) {
252 event_warn("sigaction");
256 if (signal(evsignal
, *sh
) == SIG_ERR
) {
257 event_warn("signal");
267 evsignal_del(struct event
*ev
)
269 struct event_base
*base
= ev
->ev_base
;
270 struct evsignal_info
*sig
= &base
->sig
;
271 int evsignal
= EVENT_SIGNAL(ev
);
273 assert(evsignal
>= 0 && evsignal
< NSIG
);
275 /* multiple events may listen to the same signal */
276 TAILQ_REMOVE(&sig
->evsigevents
[evsignal
], ev
, ev_signal_next
);
278 if (!TAILQ_EMPTY(&sig
->evsigevents
[evsignal
]))
281 event_debug(("%s: %p: restoring signal handler", __func__
, ev
));
283 return (_evsignal_restore_handler(ev
->ev_base
, EVENT_SIGNAL(ev
)));
287 evsignal_handler(int sig
)
289 int save_errno
= errno
;
291 if (evsignal_base
== NULL
) {
293 "%s: received signal %d, but have no base configured",
298 evsignal_base
->sig
.evsigcaught
[sig
]++;
299 evsignal_base
->sig
.evsignal_caught
= 1;
301 #ifndef HAVE_SIGACTION
302 signal(sig
, evsignal_handler
);
305 /* Wake up our notification mechanism */
306 send(evsignal_base
->sig
.ev_signal_pair
[0], "a", 1, 0);
311 evsignal_process(struct event_base
*base
)
313 struct evsignal_info
*sig
= &base
->sig
;
314 struct event
*ev
, *next_ev
;
318 base
->sig
.evsignal_caught
= 0;
319 for (i
= 1; i
< NSIG
; ++i
) {
320 ncalls
= sig
->evsigcaught
[i
];
323 sig
->evsigcaught
[i
] -= ncalls
;
325 for (ev
= TAILQ_FIRST(&sig
->evsigevents
[i
]);
326 ev
!= NULL
; ev
= next_ev
) {
327 next_ev
= TAILQ_NEXT(ev
, ev_signal_next
);
328 if (!(ev
->ev_events
& EV_PERSIST
))
330 event_active(ev
, EV_SIGNAL
, ncalls
);
337 evsignal_dealloc(struct event_base
*base
)
340 if (base
->sig
.ev_signal_added
) {
341 event_del(&base
->sig
.ev_signal
);
342 base
->sig
.ev_signal_added
= 0;
344 for (i
= 0; i
< NSIG
; ++i
) {
345 if (i
< base
->sig
.sh_old_max
&& base
->sig
.sh_old
[i
] != NULL
)
346 _evsignal_restore_handler(base
, i
);
349 EVUTIL_CLOSESOCKET(base
->sig
.ev_signal_pair
[0]);
350 base
->sig
.ev_signal_pair
[0] = -1;
351 EVUTIL_CLOSESOCKET(base
->sig
.ev_signal_pair
[1]);
352 base
->sig
.ev_signal_pair
[1] = -1;
353 base
->sig
.sh_old_max
= 0;
355 /* per index frees are handled in evsignal_del() */
356 free(base
->sig
.sh_old
);