2 /* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
5 * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #define WIN32_LEAN_AND_MEAN
38 #undef WIN32_LEAN_AND_MEAN
40 #include <sys/types.h>
41 #ifdef HAVE_SYS_TIME_H
44 #include <sys/queue.h>
45 #ifdef HAVE_SYS_SOCKET_H
46 #include <sys/socket.h>
62 #include "event-internal.h"
67 struct event_base
*evsignal_base
= NULL
;
69 static void evsignal_handler(int sig
);
71 /* Callback for when the signal handler write a byte to our signaling socket */
73 evsignal_cb(int fd
, short what
, void *arg
)
75 static char signals
[1];
82 n
= recv(fd
, signals
, sizeof(signals
), 0);
84 event_err(1, "%s: read", __func__
);
88 #define FD_CLOSEONEXEC(x) do { \
89 if (fcntl(x, F_SETFD, 1) == -1) \
90 event_warn("fcntl(%d, F_SETFD)", x); \
93 #define FD_CLOSEONEXEC(x)
97 evsignal_init(struct event_base
*base
)
102 * Our signal handler is going to write to one end of the socket
103 * pair to wake up our event loop. The event loop then scans for
104 * signals that got delivered.
106 if (evutil_socketpair(
107 AF_UNIX
, SOCK_STREAM
, 0, base
->sig
.ev_signal_pair
) == -1) {
109 /* Make this nonfatal on win32, where sometimes people
110 have localhost firewalled. */
111 event_warn("%s: socketpair", __func__
);
113 event_err(1, "%s: socketpair", __func__
);
118 FD_CLOSEONEXEC(base
->sig
.ev_signal_pair
[0]);
119 FD_CLOSEONEXEC(base
->sig
.ev_signal_pair
[1]);
120 base
->sig
.sh_old
= NULL
;
121 base
->sig
.sh_old_max
= 0;
122 base
->sig
.evsignal_caught
= 0;
123 memset(&base
->sig
.evsigcaught
, 0, sizeof(sig_atomic_t)*NSIG
);
124 /* initialize the queues for all events */
125 for (i
= 0; i
< NSIG
; ++i
)
126 TAILQ_INIT(&base
->sig
.evsigevents
[i
]);
128 evutil_make_socket_nonblocking(base
->sig
.ev_signal_pair
[0]);
130 event_set(&base
->sig
.ev_signal
, base
->sig
.ev_signal_pair
[1],
131 EV_READ
| EV_PERSIST
, evsignal_cb
, &base
->sig
.ev_signal
);
132 base
->sig
.ev_signal
.ev_base
= base
;
133 base
->sig
.ev_signal
.ev_flags
|= EVLIST_INTERNAL
;
138 /* Helper: set the signal handler for evsignal to handler in base, so that
139 * we can restore the original handler when we clear the current one. */
141 _evsignal_set_handler(struct event_base
*base
,
142 int evsignal
, void (*handler
)(int))
144 #ifdef HAVE_SIGACTION
149 struct evsignal_info
*sig
= &base
->sig
;
153 * resize saved signal handler array up to the highest signal number.
154 * a dynamic array is used to keep footprint on the low side.
156 if (evsignal
>= sig
->sh_old_max
) {
157 int new_max
= evsignal
+ 1;
158 event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing",
159 __func__
, evsignal
, sig
->sh_old_max
));
160 p
= realloc(sig
->sh_old
, new_max
* sizeof(*sig
->sh_old
));
162 event_warn("realloc");
166 memset((char *)p
+ sig
->sh_old_max
* sizeof(*sig
->sh_old
),
167 0, (new_max
- sig
->sh_old_max
) * sizeof(*sig
->sh_old
));
169 sig
->sh_old_max
= new_max
;
173 /* allocate space for previous handler out of dynamic array */
174 sig
->sh_old
[evsignal
] = malloc(sizeof *sig
->sh_old
[evsignal
]);
175 if (sig
->sh_old
[evsignal
] == NULL
) {
176 event_warn("malloc");
180 /* save previous handler and setup new handler */
181 #ifdef HAVE_SIGACTION
182 memset(&sa
, 0, sizeof(sa
));
183 sa
.sa_handler
= handler
;
184 sa
.sa_flags
|= SA_RESTART
;
185 sigfillset(&sa
.sa_mask
);
187 if (sigaction(evsignal
, &sa
, sig
->sh_old
[evsignal
]) == -1) {
188 event_warn("sigaction");
189 free(sig
->sh_old
[evsignal
]);
193 if ((sh
= signal(evsignal
, handler
)) == SIG_ERR
) {
194 event_warn("signal");
195 free(sig
->sh_old
[evsignal
]);
198 *sig
->sh_old
[evsignal
] = sh
;
205 evsignal_add(struct event
*ev
)
208 struct event_base
*base
= ev
->ev_base
;
209 struct evsignal_info
*sig
= &ev
->ev_base
->sig
;
211 if (ev
->ev_events
& (EV_READ
|EV_WRITE
))
212 event_errx(1, "%s: EV_SIGNAL incompatible use", __func__
);
213 evsignal
= EVENT_SIGNAL(ev
);
214 assert(evsignal
>= 0 && evsignal
< NSIG
);
215 if (TAILQ_EMPTY(&sig
->evsigevents
[evsignal
])) {
216 event_debug(("%s: %p: changing signal handler", __func__
, ev
));
217 if (_evsignal_set_handler(
218 base
, evsignal
, evsignal_handler
) == -1)
221 /* catch signals if they happen quickly */
222 evsignal_base
= base
;
224 if (!sig
->ev_signal_added
) {
225 if (event_add(&sig
->ev_signal
, NULL
))
227 sig
->ev_signal_added
= 1;
231 /* multiple events may listen to the same signal */
232 TAILQ_INSERT_TAIL(&sig
->evsigevents
[evsignal
], ev
, ev_signal_next
);
238 _evsignal_restore_handler(struct event_base
*base
, int evsignal
)
241 struct evsignal_info
*sig
= &base
->sig
;
242 #ifdef HAVE_SIGACTION
243 struct sigaction
*sh
;
248 /* restore previous handler */
249 sh
= sig
->sh_old
[evsignal
];
250 sig
->sh_old
[evsignal
] = NULL
;
251 #ifdef HAVE_SIGACTION
252 if (sigaction(evsignal
, sh
, NULL
) == -1) {
253 event_warn("sigaction");
257 if (signal(evsignal
, *sh
) == SIG_ERR
) {
258 event_warn("signal");
268 evsignal_del(struct event
*ev
)
270 struct event_base
*base
= ev
->ev_base
;
271 struct evsignal_info
*sig
= &base
->sig
;
272 int evsignal
= EVENT_SIGNAL(ev
);
274 assert(evsignal
>= 0 && evsignal
< NSIG
);
276 /* multiple events may listen to the same signal */
277 TAILQ_REMOVE(&sig
->evsigevents
[evsignal
], ev
, ev_signal_next
);
279 if (!TAILQ_EMPTY(&sig
->evsigevents
[evsignal
]))
282 event_debug(("%s: %p: restoring signal handler", __func__
, ev
));
284 return (_evsignal_restore_handler(ev
->ev_base
, EVENT_SIGNAL(ev
)));
288 evsignal_handler(int sig
)
290 int save_errno
= errno
;
292 if (evsignal_base
== NULL
) {
294 "%s: received signal %d, but have no base configured",
299 evsignal_base
->sig
.evsigcaught
[sig
]++;
300 evsignal_base
->sig
.evsignal_caught
= 1;
302 #ifndef HAVE_SIGACTION
303 signal(sig
, evsignal_handler
);
306 /* Wake up our notification mechanism */
307 send(evsignal_base
->sig
.ev_signal_pair
[0], "a", 1, 0);
312 evsignal_process(struct event_base
*base
)
314 struct evsignal_info
*sig
= &base
->sig
;
315 struct event
*ev
, *next_ev
;
319 base
->sig
.evsignal_caught
= 0;
320 for (i
= 1; i
< NSIG
; ++i
) {
321 ncalls
= sig
->evsigcaught
[i
];
324 sig
->evsigcaught
[i
] -= ncalls
;
326 for (ev
= TAILQ_FIRST(&sig
->evsigevents
[i
]);
327 ev
!= NULL
; ev
= next_ev
) {
328 next_ev
= TAILQ_NEXT(ev
, ev_signal_next
);
329 if (!(ev
->ev_events
& EV_PERSIST
))
331 event_active(ev
, EV_SIGNAL
, ncalls
);
338 evsignal_dealloc(struct event_base
*base
)
341 if (base
->sig
.ev_signal_added
) {
342 event_del(&base
->sig
.ev_signal
);
343 base
->sig
.ev_signal_added
= 0;
345 for (i
= 0; i
< NSIG
; ++i
) {
346 if (i
< base
->sig
.sh_old_max
&& base
->sig
.sh_old
[i
] != NULL
)
347 _evsignal_restore_handler(base
, i
);
350 EVUTIL_CLOSESOCKET(base
->sig
.ev_signal_pair
[0]);
351 base
->sig
.ev_signal_pair
[0] = -1;
352 EVUTIL_CLOSESOCKET(base
->sig
.ev_signal_pair
[1]);
353 base
->sig
.ev_signal_pair
[1] = -1;
354 base
->sig
.sh_old_max
= 0;
356 /* per index frees are handled in evsignal_del() */
357 free(base
->sig
.sh_old
);