1 /* $OpenBSD: signal.c,v 1.12 2008/05/02 06:09:11 brad 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. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 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. 28 */ 29 #ifdef HAVE_CONFIG_H 30 #include "config.h" 31 #endif 32 33 #include <sys/types.h> 34 #include <sys/tree.h> 35 #ifdef HAVE_SYS_TIME_H 36 #include <sys/time.h> 37 #else 38 #include <sys/_time.h> 39 #endif 40 #include <sys/queue.h> 41 #include <sys/socket.h> 42 #include <signal.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <unistd.h> 47 #include <errno.h> 48 #ifdef HAVE_FCNTL_H 49 #include <fcntl.h> 50 #endif 51 #include <assert.h> 52 53 #include "event.h" 54 #include "event-internal.h" 55 #include "evsignal.h" 56 #include "log.h" 57 58 struct event_base *evsignal_base = NULL; 59 60 static void evsignal_handler(int sig); 61 62 /* Callback for when the signal handler write a byte to our signaling socket */ 63 static void 64 evsignal_cb(int fd, short what, void *arg) 65 { 66 static char signals[100]; 67 struct event *ev = arg; 68 ssize_t n; 69 70 n = read(fd, signals, sizeof(signals)); 71 if (n == -1) 72 event_err(1, "%s: read", __func__); 73 event_add(ev, NULL); 74 } 75 76 #ifdef HAVE_SETFD 77 #define FD_CLOSEONEXEC(x) do { \ 78 if (fcntl(x, F_SETFD, 1) == -1) \ 79 event_warn("fcntl(%d, F_SETFD)", x); \ 80 } while (0) 81 #else 82 #define FD_CLOSEONEXEC(x) 83 #endif 84 85 void 86 evsignal_init(struct event_base *base) 87 { 88 /* 89 * Our signal handler is going to write to one end of the socket 90 * pair to wake up our event loop. The event loop then scans for 91 * signals that got delivered. 92 */ 93 if (socketpair(AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1) 94 event_err(1, "%s: socketpair", __func__); 95 96 FD_CLOSEONEXEC(base->sig.ev_signal_pair[0]); 97 FD_CLOSEONEXEC(base->sig.ev_signal_pair[1]); 98 base->sig.evsignal_caught = 0; 99 memset(&base->sig.evsigcaught, 0, sizeof(sig_atomic_t)*NSIG); 100 101 fcntl(base->sig.ev_signal_pair[0], F_SETFL, O_NONBLOCK); 102 103 event_set(&base->sig.ev_signal, base->sig.ev_signal_pair[1], EV_READ, 104 evsignal_cb, &base->sig.ev_signal); 105 base->sig.ev_signal.ev_base = base; 106 base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL; 107 } 108 109 int 110 evsignal_add(struct event *ev) 111 { 112 int evsignal; 113 struct sigaction sa; 114 struct event_base *base = ev->ev_base; 115 116 if (ev->ev_events & (EV_READ|EV_WRITE)) 117 event_errx(1, "%s: EV_SIGNAL incompatible use", __func__); 118 evsignal = EVENT_SIGNAL(ev); 119 120 memset(&sa, 0, sizeof(sa)); 121 sa.sa_handler = evsignal_handler; 122 sigfillset(&sa.sa_mask); 123 sa.sa_flags |= SA_RESTART; 124 /* catch signals if they happen quickly */ 125 evsignal_base = base; 126 127 if (sigaction(evsignal, &sa, NULL) == -1) 128 return (-1); 129 130 if (!base->sig.ev_signal_added) { 131 base->sig.ev_signal_added = 1; 132 event_add(&base->sig.ev_signal, NULL); 133 } 134 135 return (0); 136 } 137 138 int 139 evsignal_del(struct event *ev) 140 { 141 return (sigaction(EVENT_SIGNAL(ev),(struct sigaction *)SIG_DFL, NULL)); 142 } 143 144 static void 145 evsignal_handler(int sig) 146 { 147 int save_errno = errno; 148 149 if(evsignal_base == NULL) { 150 event_warn( 151 "%s: received signal %s, but have no base configured", 152 __func__, sig); 153 return; 154 } 155 156 evsignal_base->sig.evsigcaught[sig]++; 157 evsignal_base->sig.evsignal_caught = 1; 158 159 /* Wake up our notification mechanism */ 160 write(evsignal_base->sig.ev_signal_pair[0], "a", 1); 161 errno = save_errno; 162 } 163 164 void 165 evsignal_process(struct event_base *base) 166 { 167 struct event *ev; 168 sig_atomic_t ncalls; 169 170 base->sig.evsignal_caught = 0; 171 TAILQ_FOREACH(ev, &base->sig.signalqueue, ev_signal_next) { 172 ncalls = base->sig.evsigcaught[EVENT_SIGNAL(ev)]; 173 if (ncalls) { 174 if (!(ev->ev_events & EV_PERSIST)) 175 event_del(ev); 176 event_active(ev, EV_SIGNAL, ncalls); 177 base->sig.evsigcaught[EVENT_SIGNAL(ev)] = 0; 178 } 179 } 180 } 181 182 void 183 evsignal_dealloc(struct event_base *base) 184 { 185 if(base->sig.ev_signal_added) { 186 event_del(&base->sig.ev_signal); 187 base->sig.ev_signal_added = 0; 188 } 189 assert(TAILQ_EMPTY(&base->sig.signalqueue)); 190 191 close(base->sig.ev_signal_pair[0]); 192 base->sig.ev_signal_pair[0] = -1; 193 close(base->sig.ev_signal_pair[1]); 194 base->sig.ev_signal_pair[1] = -1; 195 } 196