1 /* ==========================================================================
2 * kpoll.c - Brew of Linux epoll, BSD kqueue, and Solaris Ports.
3 * --------------------------------------------------------------------------
4 * Copyright (c) 2012 William Ahern
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to permit
11 * persons to whom the Software is furnished to do so, subject to the
12 * following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
20 * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23 * USE OR OTHER DEALINGS IN THE SOFTWARE.
24 * ==========================================================================
25 */
26 #include <stddef.h> /* NULL offsetof */
27
28 #include <string.h> /* memset(3) */
29
30 #include <time.h> /* struct timespec */
31
32 #include <errno.h> /* errno */
33
34 #include <poll.h> /* POLLIN POLLOUT */
35
36 #include <unistd.h> /* [FEATURES] read(2) write(2) */
37
38 #ifndef __GLIBC_PREREQ
39 #define __GLIBC_PREREQ(m, n) 0
40 #endif
41
42 #ifndef HAVE_KQUEUE
43 #define HAVE_KQUEUE (__FreeBSD__ || __NetBSD__ || __OpenBSD__ || __APPLE__)
44 #endif
45
46 #ifndef HAVE_EPOLL
47 #define HAVE_EPOLL (__linux__)
48 #endif
49
50 #ifndef HAVE_PORTS
51 #define HAVE_PORTS (__sun)
52 #endif
53
54 #ifndef HAVE_EPOLL_CREATE1
55 #define HAVE_EPOLL_CREATE1 (HAVE_EPOLL && __GLIBC_PREREQ(2, 9))
56 #endif
57
58 #ifndef HAVE_PIPE2
59 #define HAVE_PIPE2 __GLIBC_PREREQ(2, 9)
60 #endif
61
62 #if HAVE_EPOLL
63 #include <sys/epoll.h> /* struct epoll_event epoll_create(2) epoll_ctl(2) epoll_wait(2) */
64 #elif HAVE_PORTS
65 #include <port.h> /* PORT_SOURCE_FD port_associate(2) port_disassociate(2) port_getn(2) port_alert(2) */
66 #else
67 #include <sys/event.h> /* EVFILT_READ EVFILT_WRITE EV_SET EV_ADD EV_DELETE struct kevent kqueue(2) kevent(2) */
68 #endif
69
70 #include <sys/queue.h> /* LIST_ENTRY LIST_HEAD LIST_REMOVE LIST_INSERT_HEAD */
71
72 #include <fcntl.h> /* F_GETFL F_SETFL F_GETFD F_SETFD FD_CLOEXEC O_NONBLOCK O_CLOEXEC fcntl(2) */
73
74
75 #define KPOLL_MAXWAIT 32
76
77 #define countof(a) (sizeof (a) / sizeof *(a))
78
79 #if __GNUC__ >= 3
80 #define unlikely(expr) __builtin_expect((expr), 0)
81 #else
82 #define unlikely(expr) (expr)
83 #endif
84
85
setnonblock(int fd)86 static int setnonblock(int fd) {
87 int flags;
88
89 if (-1 == (flags = fcntl(fd, F_GETFL)))
90 return errno;
91
92 if (!(flags & O_NONBLOCK)) {
93 if (-1 == fcntl(fd, F_SETFL, (flags | O_NONBLOCK)))
94 return errno;
95 }
96
97 return 0;
98 } /* setnonblock() */
99
100
setcloexec(int fd)101 static int setcloexec(int fd) {
102 int flags;
103
104 if (-1 == (flags = fcntl(fd, F_GETFD)))
105 return errno;
106
107 if (!(flags & FD_CLOEXEC)) {
108 if (-1 == fcntl(fd, F_SETFD, (flags | FD_CLOEXEC)))
109 return errno;
110 }
111
112 return 0;
113 } /* setcloexec() */
114
115
closefd(int * fd)116 static void closefd(int *fd) {
117 if (*fd >= 0) {
118 while (0 != close(*fd) && errno == EINTR)
119 ;;
120 *fd = -1;
121 }
122 } /* closefd() */
123
124
125 #if HAVE_EPOLL
126 typedef struct epoll_event event_t;
127 #elif HAVE_PORTS
128 typedef port_event_t event_t;
129 #else
130 /* NetBSD uses intptr_t while others use void * for .udata */
131 #define EV_SETx(ev, a, b, c, d, e, f) EV_SET((ev), (a), (b), (c), (d), (e), ((__typeof__((ev)->udata))(f)))
132
133 typedef struct kevent event_t;
134 #endif
135
136
event_udata(const event_t * event)137 static inline void *event_udata(const event_t *event) {
138 #if HAVE_EPOLL
139 return event->data.ptr;
140 #elif HAVE_PORTS
141 return event->portev_user;
142 #else
143 return (void *)event->udata;
144 #endif
145 } /* event_udata() */
146
147
event_pending(const event_t * event)148 static inline short event_pending(const event_t *event) {
149 #if HAVE_EPOLL
150 return event->events;
151 #elif HAVE_PORTS
152 return event->portev_events;
153 #else
154 return (event->filter == EVFILT_READ)? POLLIN : (event->filter == EVFILT_WRITE)? POLLOUT : 0;
155 #endif
156 } /* event_pending() */
157
158
159 struct kpollfd {
160 int fd;
161 short events;
162 short revents;
163 LIST_ENTRY(kpollfd) le;
164 }; /* struct kpollfd */
165
166
167 struct kpoll {
168 int fd;
169
170 LIST_HEAD(, kpollfd) pending;
171 LIST_HEAD(, kpollfd) polling;
172 LIST_HEAD(, kpollfd) dormant;
173
174 struct {
175 struct kpollfd event;
176 int fd[2];
177 } alert;
178 }; /* struct kpoll */
179
180
kpoll_move(struct kpoll * kp,struct kpollfd * fd)181 static void kpoll_move(struct kpoll *kp, struct kpollfd *fd) {
182 LIST_REMOVE(fd, le);
183
184 if (fd->revents)
185 LIST_INSERT_HEAD(&kp->pending, fd, le);
186 else if (fd->events)
187 LIST_INSERT_HEAD(&kp->polling, fd, le);
188 else
189 LIST_INSERT_HEAD(&kp->dormant, fd, le);
190 } /* kpoll_move() */
191
192
kpoll_next(struct kpoll * kp)193 static struct kpollfd *kpoll_next(struct kpoll *kp) {
194 return LIST_FIRST(&kp->pending);
195 } /* kpoll_next() */
196
197
kpoll_ctl(struct kpoll * kp,struct kpollfd * fd,short events)198 static int kpoll_ctl(struct kpoll *kp, struct kpollfd *fd, short events) {
199 int error = 0;
200
201 if (fd->events == events)
202 goto reset;
203
204 #if HAVE_EPOLL
205 struct epoll_event event;
206 int op;
207
208 op = (!fd->events)? EPOLL_CTL_ADD : (!events)? EPOLL_CTL_DEL : EPOLL_CTL_MOD;
209
210 memset(&event, 0, sizeof event);
211
212 event.events = events;
213 event.data.ptr = fd;
214
215 if (0 != epoll_ctl(kp->fd, op, fd->fd, &event))
216 goto error;
217
218 fd->events = events;
219 #elif HAVE_PORTS
220 if (!events) {
221 if (0 != port_dissociate(kp->fd, PORT_SOURCE_FD, fd->fd))
222 goto error;
223 } else {
224 if (0 != port_associate(kp->fd, PORT_SOURCE_FD, fd->fd, events, fd))
225 goto error;
226 }
227
228 fd->events = events;
229 #else
230 struct kevent event;
231
232 if (events & POLLIN) {
233 if (!(fd->events & POLLIN)) {
234 EV_SETx(&event, fd->fd, EVFILT_READ, EV_ADD, 0, 0, fd);
235
236 if (0 != kevent(kp->fd, &event, 1, NULL, 0, &(struct timespec){ 0, 0 }))
237 goto error;
238
239 fd->events |= POLLIN;
240 }
241 } else if (fd->events & POLLIN) {
242 EV_SETx(&event, fd->fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
243
244 if (0 != kevent(kp->fd, &event, 1, NULL, 0, &(struct timespec){ 0, 0 }))
245 goto error;
246
247 fd->events &= ~POLLIN;
248 }
249
250 if (events & POLLOUT) {
251 if (!(fd->events & POLLOUT)) {
252 EV_SETx(&event, fd->fd, EVFILT_WRITE, EV_ADD, 0, 0, fd);
253
254 if (0 != kevent(kp->fd, &event, 1, NULL, 0, &(struct timespec){ 0, 0 }))
255 goto error;
256
257 fd->events |= POLLOUT;
258 }
259 } else if (fd->events & POLLOUT) {
260 EV_SETx(&event, fd->fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
261
262 if (0 != kevent(kp->fd, &event, 1, NULL, 0, &(struct timespec){ 0, 0 }))
263 goto error;
264
265 fd->events &= ~POLLOUT;
266 }
267 #endif
268
269 reset:
270 fd->revents = 0;
271
272 kpoll_move(kp, fd);
273
274 return error;
275 error:
276 error = errno;
277
278 goto reset;
279 } /* kpoll_ctl() */
280
281
kpoll_add(struct kpoll * kp,struct kpollfd * pfd,int fd)282 static void kpoll_add(struct kpoll *kp, struct kpollfd *pfd, int fd) {
283 pfd->fd = fd;
284 pfd->events = 0;
285 pfd->revents = 0;
286
287 LIST_INSERT_HEAD(&kp->dormant, pfd, le);
288 } /* kpoll_add() */
289
290
kpoll_del(struct kpoll * kp,struct kpollfd * fd)291 static void kpoll_del(struct kpoll *kp, struct kpollfd *fd) {
292 kpoll_ctl(kp, fd, 0);
293
294 LIST_REMOVE(fd, le);
295 } /* kpoll_del() */
296
297
kpoll_alert(struct kpoll * kp)298 static int kpoll_alert(struct kpoll *kp) {
299 #if HAVE_PORTS
300 return (!port_alert(kp->fd, PORT_ALERT_SET, POLLIN, &kp->alert.event))? 0 : errno;
301 #else
302 while (1 != write(kp->alert.fd[1], "!", 1)) {
303 switch (errno) {
304 case EINTR:
305 continue;
306 case EAGAIN:
307 return 0;
308 default:
309 return errno;
310 }
311 }
312
313 return kpoll_ctl(kp, &kp->alert.event, POLLIN);
314 #endif
315 } /* kpoll_alert() */
316
317
kpoll_calm(struct kpoll * kp)318 static int kpoll_calm(struct kpoll *kp) {
319 #if HAVE_PORTS
320 return (!port_alert(kp->fd, PORT_ALERT_SET, 0, &kp->alert.event))? 0 : errno;
321 #else
322 char buf[512];
323
324 while (read(kp->alert.fd[0], buf, sizeof buf) > 0)
325 ;;
326
327 return kpoll_ctl(kp, &kp->alert.event, POLLIN);
328 #endif
329 } /* kpoll_calm() */
330
331
ms2ts_(struct timespec * ts,int ms)332 static inline struct timespec *ms2ts_(struct timespec *ts, int ms) {
333 if (ms < 0) return 0;
334 ts->tv_sec = ms / 1000;
335 ts->tv_nsec = (ms % 1000) * 1000000;
336 return ts;
337 } /* ms2ts_() */
338
339 #define ms2ts(ms) (ms2ts_(&(struct timespec){ 0, 0 }, (ms)))
340
341
kpoll_wait(struct kpoll * kp,int timeout)342 static int kpoll_wait(struct kpoll *kp, int timeout) {
343 event_t event[KPOLL_MAXWAIT];
344 struct kpollfd *fd;
345 int error;
346
347 if (!LIST_EMPTY(&kp->pending))
348 return 0;
349
350 #if HAVE_EPOLL
351 int i, n;
352
353 if (-1 == (n = epoll_wait(kp->fd, event, (int)countof(event), timeout)))
354 return (errno == EINTR)? 0 : errno;
355 #elif HAVE_PORTS
356 uint_t i, n = 1;
357
358 if (0 != port_getn(kp->fd, event, countof(event), &n, ms2ts(timeout)))
359 return (errno == ETIME || errno == EINTR)? 0 : errno;
360 #else
361 int i, n;
362
363 if (-1 == (n = kevent(kp->fd, NULL, 0, event, (int)countof(event), ms2ts(timeout))))
364 return (errno == EINTR)? 0 : errno;
365 #endif
366
367 for (i = 0; i < n; i++) {
368 fd = event_udata(&event[i]);
369 #if HAVE_PORTS
370 fd->events = 0;
371 #endif
372
373 if (unlikely(fd == &kp->alert.event)) {
374 if ((error = kpoll_calm(kp)))
375 return error;
376 } else {
377 fd->revents |= event_pending(&event[i]);
378 kpoll_move(kp, fd);
379 }
380 }
381
382 return 0;
383 } /* kpoll_wait() */
384
385
alert_init(struct kpoll * kp)386 static int alert_init(struct kpoll *kp) {
387 #if HAVE_PORTS
388 return 0;
389 #else
390 int error;
391
392 #if HAVE_PIPE2
393 if (0 != pipe2(kp->alert.fd, O_CLOEXEC|O_NONBLOCK))
394 return errno;
395 #else
396 if (0 != pipe(kp->alert.fd))
397 return errno;
398
399 for (int i = 0; i < 2; i++) {
400 if ((error = setcloexec(kp->alert.fd[i]))
401 || (error = setnonblock(kp->alert.fd[i])))
402 return error;
403 }
404 #endif
405
406 kpoll_add(kp, &kp->alert.event, kp->alert.fd[0]);
407
408 return kpoll_ctl(kp, &kp->alert.event, POLLIN);
409 #endif
410 } /* alert_init() */
411
412
alert_destroy(struct kpoll * kp)413 static void alert_destroy(struct kpoll *kp) {
414 #if HAVE_PORTS
415 (void)0;
416 #else
417 closefd(&kp->alert.fd[0]);
418 closefd(&kp->alert.fd[1]);
419 #endif
420 } /* alert_destroy() */
421
422
kpoll_destroy(struct kpoll * kp)423 static void kpoll_destroy(struct kpoll *kp) {
424 closefd(&kp->fd);
425
426 alert_destroy(kp);
427
428 LIST_INIT(&kp->pending);
429 LIST_INIT(&kp->polling);
430 LIST_INIT(&kp->dormant);
431 } /* kpoll_destroy() */
432
433
kpoll_init(struct kpoll * kp)434 static int kpoll_init(struct kpoll *kp) {
435 int error;
436
437 kp->fd = -1;
438 kp->alert.fd[0] = -1;
439 kp->alert.fd[1] = -1;
440
441 LIST_INIT(&kp->pending);
442 LIST_INIT(&kp->polling);
443 LIST_INIT(&kp->dormant);
444
445 #if HAVE_EPOLL_CREATE1
446 if (-1 == (kp->fd = epoll_create1(O_CLOEXEC)))
447 goto syerr;
448 #elif HAVE_EPOLL
449 if (-1 == (kp->fd = epoll_create(0)))
450 goto syerr;
451 #elif HAVE_PORTS
452 if (-1 == (kp->fd = port_create())) {
453 if (errno == EAGAIN) { /* too confusing */
454 error = EMFILE;
455 goto error;
456 } else
457 goto syerr;
458 }
459 #else
460 if (-1 == (kp->fd = kqueue()))
461 goto syerr;
462 #endif
463
464 #if !HAVE_EPOLL_CREATE1
465 if ((error = setcloexec(kp->fd)))
466 goto error;
467 #endif
468
469 if ((error = alert_init(kp)))
470 goto error;
471
472 return 0;
473 syerr:
474 error = errno;
475 error:
476 kpoll_destroy(kp);
477
478 return error;
479 } /* kpoll_init() */
480
481
main(void)482 int main(void) {
483 return 0;
484 }
485