1 /* $OpenBSD: poll.c,v 1.2 2003/10/01 09:10:30 markus Exp $ */ 2 3 /* 4 * Copyright 2000-2003 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 <poll.h> 44 #include <signal.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <unistd.h> 49 #include <errno.h> 50 #include <err.h> 51 52 #ifdef USE_LOG 53 #include "log.h" 54 #else 55 #define LOG_DBG(x) 56 #define log_error(x) perror(x) 57 #endif 58 59 #include "event.h" 60 #include "evsignal.h" 61 62 extern struct event_list eventqueue; 63 64 extern volatile sig_atomic_t evsignal_caught; 65 66 struct pollop { 67 int event_count; /* Highest number alloc */ 68 struct pollfd *event_set; 69 struct event **event_back; 70 sigset_t evsigmask; 71 } pop; 72 73 void *poll_init (void); 74 int poll_add (void *, struct event *); 75 int poll_del (void *, struct event *); 76 int poll_recalc (void *, int); 77 int poll_dispatch (void *, struct timeval *); 78 79 struct eventop pollops = { 80 "poll", 81 poll_init, 82 poll_add, 83 poll_del, 84 poll_recalc, 85 poll_dispatch 86 }; 87 88 void * 89 poll_init(void) 90 { 91 /* Disable kqueue when this environment variable is set */ 92 if (!issetugid() && getenv("EVENT_NOPOLL")) 93 return (NULL); 94 95 memset(&pop, 0, sizeof(pop)); 96 97 evsignal_init(&pop.evsigmask); 98 99 return (&pop); 100 } 101 102 /* 103 * Called with the highest fd that we know about. If it is 0, completely 104 * recalculate everything. 105 */ 106 107 int 108 poll_recalc(void *arg, int max) 109 { 110 struct pollop *pop = arg; 111 112 return (evsignal_recalc(&pop->evsigmask)); 113 } 114 115 int 116 poll_dispatch(void *arg, struct timeval *tv) 117 { 118 int res, i, count, sec, nfds; 119 struct event *ev; 120 struct pollop *pop = arg; 121 122 count = pop->event_count; 123 nfds = 0; 124 TAILQ_FOREACH(ev, &eventqueue, ev_next) { 125 if (nfds + 1 >= count) { 126 if (count < 32) 127 count = 32; 128 else 129 count *= 2; 130 131 /* We need more file descriptors */ 132 pop->event_set = realloc(pop->event_set, 133 count * sizeof(struct pollfd)); 134 if (pop->event_set == NULL) { 135 log_error("realloc"); 136 return (-1); 137 } 138 pop->event_back = realloc(pop->event_back, 139 count * sizeof(struct event *)); 140 if (pop->event_back == NULL) { 141 log_error("realloc"); 142 return (-1); 143 } 144 pop->event_count = count; 145 } 146 if (ev->ev_events & EV_WRITE) { 147 struct pollfd *pfd = &pop->event_set[nfds]; 148 pfd->fd = ev->ev_fd; 149 pfd->events = POLLOUT; 150 pfd->revents = 0; 151 152 pop->event_back[nfds] = ev; 153 154 nfds++; 155 } 156 if (ev->ev_events & EV_READ) { 157 struct pollfd *pfd = &pop->event_set[nfds]; 158 159 pfd->fd = ev->ev_fd; 160 pfd->events = POLLIN; 161 pfd->revents = 0; 162 163 pop->event_back[nfds] = ev; 164 165 nfds++; 166 } 167 } 168 169 if (evsignal_deliver(&pop->evsigmask) == -1) 170 return (-1); 171 172 sec = tv->tv_sec * 1000 + tv->tv_usec / 1000; 173 res = poll(pop->event_set, nfds, sec); 174 175 if (evsignal_recalc(&pop->evsigmask) == -1) 176 return (-1); 177 178 if (res == -1) { 179 if (errno != EINTR) { 180 log_error("poll"); 181 return (-1); 182 } 183 184 evsignal_process(); 185 return (0); 186 } else if (evsignal_caught) 187 evsignal_process(); 188 189 LOG_DBG((LOG_MISC, 80, "%s: poll reports %d", __func__, res)); 190 191 if (res == 0) 192 return (0); 193 194 for (i = 0; i < nfds; i++) { 195 res = 0; 196 /* If the file gets closed notify */ 197 if (pop->event_set[i].revents & POLLHUP) 198 pop->event_set[i].revents = POLLIN|POLLOUT; 199 if (pop->event_set[i].revents & POLLIN) 200 res |= EV_READ; 201 if (pop->event_set[i].revents & POLLOUT) 202 res |= EV_WRITE; 203 if (res == 0) 204 continue; 205 206 ev = pop->event_back[i]; 207 res &= ev->ev_events; 208 209 if (res) { 210 if (!(ev->ev_events & EV_PERSIST)) 211 event_del(ev); 212 event_active(ev, res, 1); 213 } 214 } 215 216 return (0); 217 } 218 219 int 220 poll_add(void *arg, struct event *ev) 221 { 222 struct pollop *pop = arg; 223 224 if (ev->ev_events & EV_SIGNAL) 225 return (evsignal_add(&pop->evsigmask, ev)); 226 227 return (0); 228 } 229 230 /* 231 * Nothing to be done here. 232 */ 233 234 int 235 poll_del(void *arg, struct event *ev) 236 { 237 struct pollop *pop = arg; 238 239 if (!(ev->ev_events & EV_SIGNAL)) 240 return (0); 241 242 return (evsignal_del(&pop->evsigmask, ev)); 243 } 244