85e65a98f14d65736db16d6483626e2ce0b4af99
[dhcpcd-ui] / src / dhcpcd-curses / eloop.c
1 /*
2  * dhcpcd - DHCP client daemon
3  * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
4  * All rights reserved
5
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/time.h>
29
30 #include <assert.h>
31 #include <errno.h>
32 #include <limits.h>
33 #include <signal.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37
38 /* config.h should define HAVE_KQUEUE, HAVE_EPOLL, etc */
39 #include "config.h"
40 #include "eloop.h"
41
42 #ifndef UNUSED
43 #define UNUSED(a) (void)((a))
44 #endif
45 #ifndef __unused
46 #ifdef __GNUC__
47 #define __unused   __attribute__((__unused__))
48 #else
49 #define __unused
50 #endif
51 #endif
52
53 #ifndef MSEC_PER_SEC
54 #define MSEC_PER_SEC    1000L
55 #define NSEC_PER_MSEC   1000000L
56 #endif
57
58 #if defined(HAVE_KQUEUE)
59 #include <sys/event.h>
60 #include <fcntl.h>
61 #ifdef __NetBSD__
62 /* udata is void * except on NetBSD
63  * lengths are int except on NetBSD */
64 #define UPTR(x) ((intptr_t)(x))
65 #define LENC(x) (x)
66 #else
67 #define UPTR(x) (x)
68 #define LENC(x) ((int)(x))
69 #endif
70 #define eloop_event_setup_fds(eloop)
71 #elif defined(HAVE_EPOLL)
72 #include <sys/epoll.h>
73 #define eloop_event_setup_fds(eloop)
74 #else
75 #include <poll.h>
76 static void
77 eloop_event_setup_fds(struct eloop *eloop)
78 {
79         struct eloop_event *e;
80         size_t i;
81
82         i = 0;
83         TAILQ_FOREACH(e, &eloop->events, next) {
84                 eloop->fds[i].fd = e->fd;
85                 eloop->fds[i].events = 0;
86                 if (e->read_cb)
87                         eloop->fds[i].events |= POLLIN;
88                 if (e->write_cb)
89                         eloop->fds[i].events |= POLLOUT;
90                 eloop->fds[i].revents = 0;
91                 e->pollfd = &eloop->fds[i];
92                 i++;
93         }
94 }
95
96 #ifndef pollts
97 /* Wrapper around pselect, to imitate the NetBSD pollts call. */
98 static int
99 pollts(struct pollfd * fds, nfds_t nfds,
100     const struct timespec *ts, const sigset_t *sigmask)
101 {
102         fd_set read_fds;
103         nfds_t n;
104         int maxfd, r;
105
106         FD_ZERO(&read_fds);
107         maxfd = 0;
108         for (n = 0; n < nfds; n++) {
109                 if (fds[n].events & POLLIN) {
110                         FD_SET(fds[n].fd, &read_fds);
111                         if (fds[n].fd > maxfd)
112                                 maxfd = fds[n].fd;
113                 }
114         }
115
116         r = pselect(maxfd + 1, &read_fds, NULL, NULL, ts, sigmask);
117         if (r > 0) {
118                 for (n = 0; n < nfds; n++) {
119                         fds[n].revents =
120                             FD_ISSET(fds[n].fd, &read_fds) ? POLLIN : 0;
121                 }
122         }
123
124         return r;
125 }
126 #endif
127 #endif
128
129 int
130 eloop_event_add(struct eloop *eloop, int fd,
131     void (*read_cb)(void *), void *read_cb_arg,
132     void (*write_cb)(void *), void *write_cb_arg)
133 {
134         struct eloop_event *e;
135 #if defined(HAVE_KQUEUE)
136         struct kevent ke[2];
137 #elif defined(HAVE_EPOLL)
138         struct epoll_event epe;
139 #else
140         struct pollfd *nfds;
141 #endif
142
143 #ifdef HAVE_EPOLL
144         memset(&epe, 0, sizeof(epe));
145         epe.data.fd = fd;
146         epe.events = EPOLLIN;
147         if (write_cb)
148                 epe.events |= EPOLLOUT;
149 #endif
150
151         /* We should only have one callback monitoring the fd */
152         TAILQ_FOREACH(e, &eloop->events, next) {
153                 if (e->fd == fd) {
154                         int error;
155
156 #if defined(HAVE_KQUEUE)
157                         EV_SET(&ke[0], (uintptr_t)fd, EVFILT_READ, EV_ADD,
158                             0, 0, UPTR(e));
159                         if (write_cb)
160                                 EV_SET(&ke[1], (uintptr_t)fd, EVFILT_WRITE,
161                                     EV_ADD, 0, 0, UPTR(e));
162                         else if (e->write_cb)
163                                 EV_SET(&ke[1], (uintptr_t)fd, EVFILT_WRITE,
164                                     EV_DELETE, 0, 0, UPTR(e));
165                         error = kevent(eloop->poll_fd, ke,
166                             e->write_cb || write_cb ? 2 : 1, NULL, 0, NULL);
167 #elif defined(HAVE_EPOLL)
168                         epe.data.ptr = e;
169                         error = epoll_ctl(eloop->poll_fd, EPOLL_CTL_MOD,
170                             fd, &epe);
171 #else
172                         error = 0;
173 #endif
174                         if (read_cb) {
175                                 e->read_cb = read_cb;
176                                 e->read_cb_arg = read_cb_arg;
177                         }
178                         if (write_cb) {
179                                 e->write_cb = write_cb;
180                                 e->write_cb_arg = write_cb_arg;
181                         }
182                         eloop_event_setup_fds(eloop);
183                         return error;
184                 }
185         }
186
187         /* Allocate a new event if no free ones already allocated */
188         if ((e = TAILQ_FIRST(&eloop->free_events))) {
189                 TAILQ_REMOVE(&eloop->free_events, e, next);
190         } else {
191                 e = malloc(sizeof(*e));
192                 if (e == NULL)
193                         goto err;
194         }
195
196         /* Ensure we can actually listen to it */
197         eloop->events_len++;
198 #if !defined(HAVE_KQUEUE) && !defined(HAVE_EPOLL)
199         if (eloop->events_len > eloop->fds_len) {
200                 nfds = realloc(eloop->fds,
201                     sizeof(*eloop->fds) * (eloop->fds_len + 5));
202                 if (nfds == NULL)
203                         goto err;
204                 eloop->fds_len += 5;
205                 eloop->fds = nfds;
206         }
207 #endif
208
209         /* Now populate the structure and add it to the list */
210         e->fd = fd;
211         e->read_cb = read_cb;
212         e->read_cb_arg = read_cb_arg;
213         e->write_cb = write_cb;
214         e->write_cb_arg = write_cb_arg;
215
216 #if defined(HAVE_KQUEUE)
217         EV_SET(&ke[0], (uintptr_t)fd, EVFILT_READ, EV_ADD, 0, 0, UPTR(e));
218         if (write_cb)
219                 EV_SET(&ke[1], (uintptr_t)fd, EVFILT_WRITE,
220                     EV_ADD, 0, 0, UPTR(e));
221         if (kevent(eloop->poll_fd, ke, write_cb ? 2 : 1, NULL, 0, NULL) == -1)
222                 goto err;
223 #elif defined(HAVE_EPOLL)
224         epe.data.ptr = e;
225         if (epoll_ctl(eloop->poll_fd, EPOLL_CTL_ADD, fd, &epe) == -1)
226                 goto err;
227 #endif
228
229         /* The order of events should not matter.
230          * However, some PPP servers love to close the link right after
231          * sending their final message. So to ensure dhcpcd processes this
232          * message (which is likely to be that the DHCP addresses are wrong)
233          * we insert new events at the queue head as the link fd will be
234          * the first event added. */
235         TAILQ_INSERT_HEAD(&eloop->events, e, next);
236         eloop_event_setup_fds(eloop);
237         return 0;
238
239 err:
240         if (e) {
241                 eloop->events_len--;
242                 TAILQ_INSERT_TAIL(&eloop->free_events, e, next);
243         }
244         return -1;
245 }
246
247 void
248 eloop_event_delete(struct eloop *eloop, int fd, int write_only)
249 {
250         struct eloop_event *e;
251 #if defined(HAVE_KQUEUE)
252         struct kevent ke[2];
253 #elif defined(HAVE_EPOLL)
254         struct epoll_event epe;
255 #endif
256
257         TAILQ_FOREACH(e, &eloop->events, next) {
258                 if (e->fd == fd) {
259                         if (write_only) {
260                                 if (e->write_cb) {
261                                         e->write_cb = NULL;
262                                         e->write_cb_arg = NULL;
263 #if defined(HAVE_KQUEUE)
264                                         EV_SET(&ke[0], (uintptr_t)fd,
265                                             EVFILT_WRITE, EV_DELETE,
266                                             0, 0, UPTR(NULL));
267                                         kevent(eloop->poll_fd, ke, 1, NULL, 0,
268                                             NULL);
269 #elif defined(HAVE_EPOLL)
270                                         memset(&epe, 0, sizeof(epe));
271                                         epe.data.fd = e->fd;
272                                         epe.data.ptr = e;
273                                         epe.events = EPOLLIN;
274                                         epoll_ctl(eloop->poll_fd,
275                                             EPOLL_CTL_MOD, fd, &epe);
276 #endif
277                                 }
278
279                         } else {
280                                 TAILQ_REMOVE(&eloop->events, e, next);
281 #if defined(HAVE_KQUEUE)
282                                 EV_SET(&ke[0], (uintptr_t)fd, EVFILT_READ,
283                                     EV_DELETE, 0, 0, UPTR(NULL));
284                                 if (e->write_cb)
285                                         EV_SET(&ke[1], (uintptr_t)fd,
286                                             EVFILT_WRITE, EV_DELETE,
287                                             0, 0, UPTR(NULL));
288                                 kevent(eloop->poll_fd, ke, e->write_cb ? 2 : 1,
289                                     NULL, 0, NULL);
290 #elif defined(HAVE_EPOLL)
291                                 /* NULL event is safe because we
292                                  * rely on epoll_pwait which as added
293                                  * after the delete without event was fixed. */
294                                 epoll_ctl(eloop->poll_fd, EPOLL_CTL_DEL,
295                                     fd, NULL);
296 #endif
297                                 TAILQ_INSERT_TAIL(&eloop->free_events, e, next);
298                                 eloop->events_len--;
299                         }
300                         eloop_event_setup_fds(eloop);
301                         break;
302                 }
303         }
304 }
305
306 int
307 eloop_q_timeout_add_tv(struct eloop *eloop, int queue,
308     const struct timespec *when, void (*callback)(void *), void *arg)
309 {
310         struct timespec now, w;
311         struct eloop_timeout *t, *tt = NULL;
312
313         clock_gettime(CLOCK_MONOTONIC, &now);
314         timespecadd(&now, when, &w);
315         /* Check for time_t overflow. */
316         if (timespeccmp(&w, &now, <)) {
317                 errno = ERANGE;
318                 return -1;
319         }
320
321         /* Remove existing timeout if present */
322         TAILQ_FOREACH(t, &eloop->timeouts, next) {
323                 if (t->callback == callback && t->arg == arg) {
324                         TAILQ_REMOVE(&eloop->timeouts, t, next);
325                         break;
326                 }
327         }
328
329         if (t == NULL) {
330                 /* No existing, so allocate or grab one from the free pool */
331                 if ((t = TAILQ_FIRST(&eloop->free_timeouts))) {
332                         TAILQ_REMOVE(&eloop->free_timeouts, t, next);
333                 } else {
334                         if ((t = malloc(sizeof(*t))) == NULL)
335                                 return -1;
336                 }
337         }
338
339         t->when = w;
340         t->callback = callback;
341         t->arg = arg;
342         t->queue = queue;
343
344         /* The timeout list should be in chronological order,
345          * soonest first. */
346         TAILQ_FOREACH(tt, &eloop->timeouts, next) {
347                 if (timespeccmp(&t->when, &tt->when, <)) {
348                         TAILQ_INSERT_BEFORE(tt, t, next);
349                         return 0;
350                 }
351         }
352         TAILQ_INSERT_TAIL(&eloop->timeouts, t, next);
353         return 0;
354 }
355
356 int
357 eloop_q_timeout_add_sec(struct eloop *eloop, int queue, time_t when,
358     void (*callback)(void *), void *arg)
359 {
360         struct timespec tv;
361
362         tv.tv_sec = when;
363         tv.tv_nsec = 0;
364         return eloop_q_timeout_add_tv(eloop, queue, &tv, callback, arg);
365 }
366
367 int
368 eloop_q_timeout_add_msec(struct eloop *eloop, int queue, long when,
369     void (*callback)(void *), void *arg)
370 {
371         struct timespec tv;
372
373         tv.tv_sec = when / MSEC_PER_SEC;
374         tv.tv_nsec = (when % MSEC_PER_SEC) * NSEC_PER_MSEC;
375         return eloop_q_timeout_add_tv(eloop, queue, &tv, callback, arg);
376 }
377
378 #if !defined(HAVE_KQUEUE)
379 static int
380 eloop_timeout_add_now(struct eloop *eloop,
381     void (*callback)(void *), void *arg)
382 {
383
384         assert(eloop->timeout0 == NULL);
385         eloop->timeout0 = callback;
386         eloop->timeout0_arg = arg;
387         return 0;
388 }
389 #endif
390
391 void
392 eloop_q_timeout_delete(struct eloop *eloop, int queue,
393     void (*callback)(void *), void *arg)
394 {
395         struct eloop_timeout *t, *tt;
396
397         TAILQ_FOREACH_SAFE(t, &eloop->timeouts, next, tt) {
398                 if ((queue == 0 || t->queue == queue) &&
399                     t->arg == arg &&
400                     (!callback || t->callback == callback))
401                 {
402                         TAILQ_REMOVE(&eloop->timeouts, t, next);
403                         TAILQ_INSERT_TAIL(&eloop->free_timeouts, t, next);
404                 }
405         }
406 }
407
408 void
409 eloop_exit(struct eloop *eloop, int code)
410 {
411
412         eloop->exitcode = code;
413         eloop->exitnow = 1;
414 }
415
416 #if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
417 static int
418 eloop_open(struct eloop *eloop)
419 {
420 #if defined(HAVE_KQUEUE1)
421         return (eloop->poll_fd = kqueue1(O_CLOEXEC));
422 #elif defined(HAVE_KQUEUE)
423         int i;
424
425         if ((eloop->poll_fd = kqueue()) == -1)
426                 return -1;
427         if ((i = fcntl(eloop->poll_fd, F_GETFD, 0)) == -1 ||
428             fcntl(eloop->poll_fd, F_SETFD, i | FD_CLOEXEC) == -1)
429         {
430                 close(eloop->poll_fd);
431                 eloop->poll_fd = -1;
432                 return -1;
433         }
434
435         return eloop->poll_fd;
436 #elif defined (HAVE_EPOLL)
437         return (eloop->poll_fd = epoll_create1(EPOLL_CLOEXEC));
438 #endif
439 }
440
441 int
442 eloop_requeue(struct eloop *eloop)
443 {
444         struct eloop_event *e;
445         int error;
446 #if defined(HAVE_KQUEUE)
447         size_t i;
448         struct kevent *ke;
449 #elif defined(HAVE_EPOLL)
450         struct epoll_event epe;
451 #endif
452
453         if (eloop->poll_fd != -1)
454                 close(eloop->poll_fd);
455         if (eloop_open(eloop) == -1)
456                 return -1;
457 #if defined (HAVE_KQUEUE)
458         i = 0;
459         while (eloop->signals[i] != 0)
460                 i++;
461         TAILQ_FOREACH(e, &eloop->events, next) {
462                 i++;
463                 if (e->write_cb)
464                         i++;
465         }
466
467         if ((ke = malloc(sizeof(*ke) * i)) == NULL)
468                 return -1;
469
470         for (i = 0; eloop->signals[i] != 0; i++)
471                 EV_SET(&ke[i], (uintptr_t)eloop->signals[i],
472                     EVFILT_SIGNAL, EV_ADD, 0, 0, UPTR(NULL));
473
474         TAILQ_FOREACH(e, &eloop->events, next) {
475                 EV_SET(&ke[i], (uintptr_t)e->fd, EVFILT_READ,
476                     EV_ADD, 0, 0, UPTR(e));
477                 i++;
478                 if (e->write_cb) {
479                         EV_SET(&ke[i], (uintptr_t)e->fd, EVFILT_WRITE,
480                             EV_ADD, 0, 0, UPTR(e));
481                         i++;
482                 }
483         }
484
485         error =  kevent(eloop->poll_fd, ke, LENC(i), NULL, 0, NULL);
486         free(ke);
487
488 #elif defined(HAVE_EPOLL)
489
490         error = 0;
491         TAILQ_FOREACH(e, &eloop->events, next) {
492                 memset(&epe, 0, sizeof(epe));
493                 epe.data.fd = e->fd;
494                 epe.events = EPOLLIN;
495                 if (e->write_cb)
496                         epe.events |= EPOLLOUT;
497                 epe.data.ptr = e;
498                 if (epoll_ctl(eloop->poll_fd, EPOLL_CTL_ADD, e->fd, &epe) == -1)
499                         error = -1;
500         }
501 #endif
502
503         return error;
504 }
505 #endif
506
507 int
508 eloop_signal_set_cb(struct eloop *eloop,
509     const int *signals, void (*signal_cb)(int, void *), void *signal_cb_ctx)
510 {
511
512         assert(eloop);
513         eloop->signals = signals;
514         eloop->signal_cb = signal_cb;
515         eloop->signal_cb_ctx = signal_cb_ctx;
516         return eloop_requeue(eloop);
517 }
518
519 #ifndef HAVE_KQUEUE
520 struct eloop_siginfo {
521         int sig;
522         struct eloop *eloop;
523 };
524 static struct eloop_siginfo _eloop_siginfo;
525 static struct eloop *_eloop;
526
527 static void
528 eloop_signal1(void *arg)
529 {
530         struct eloop_siginfo *si = arg;
531
532         si->eloop->signal_cb(si->sig, si->eloop->signal_cb_ctx);
533 }
534
535 static void
536 eloop_signal3(int sig, __unused siginfo_t *siginfo, __unused void *arg)
537 {
538
539         /* So that we can operate safely under a signal we instruct
540          * eloop to pass a copy of the siginfo structure to handle_signal1
541          * as the very first thing to do. */
542         _eloop_siginfo.eloop = _eloop;
543         _eloop_siginfo.sig = sig;
544         eloop_timeout_add_now(_eloop_siginfo.eloop,
545             eloop_signal1, &_eloop_siginfo);
546 }
547 #endif
548
549 int
550 eloop_signal_mask(struct eloop *eloop, sigset_t *oldset)
551 {
552         sigset_t newset;
553 #ifndef HAVE_KQUEUE
554         int i;
555         struct sigaction sa;
556 #endif
557
558         sigfillset(&newset);
559         if (sigprocmask(SIG_SETMASK, &newset, oldset) == -1)
560                 return -1;
561
562 #ifdef HAVE_KQUEUE
563         UNUSED(eloop);
564 #else
565         memset(&sa, 0, sizeof(sa));
566         sa.sa_sigaction = eloop_signal3;
567         sa.sa_flags = SA_SIGINFO;
568         sigemptyset(&sa.sa_mask);
569
570         for (i = 0; eloop->signals[i]; i++) {
571                 if (sigaction(eloop->signals[i], &sa, NULL) == -1)
572                         return -1;
573         }
574 #endif
575         return 0;
576 }
577
578 struct eloop *
579 eloop_new(void)
580 {
581         struct eloop *eloop;
582         struct timespec now;
583
584         /* Check we have a working monotonic clock. */
585         if (clock_gettime(CLOCK_MONOTONIC, &now) == -1)
586                 return NULL;
587
588         eloop = calloc(1, sizeof(*eloop));
589         if (eloop) {
590                 TAILQ_INIT(&eloop->events);
591                 TAILQ_INIT(&eloop->free_events);
592                 TAILQ_INIT(&eloop->timeouts);
593                 TAILQ_INIT(&eloop->free_timeouts);
594                 eloop->exitcode = EXIT_FAILURE;
595 #if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
596                 eloop->poll_fd = -1;
597 #endif
598         }
599
600         return eloop;
601 }
602
603 void eloop_free(struct eloop *eloop)
604 {
605         struct eloop_event *e;
606         struct eloop_timeout *t;
607
608         if (eloop == NULL)
609                 return;
610
611         while ((e = TAILQ_FIRST(&eloop->events))) {
612                 TAILQ_REMOVE(&eloop->events, e, next);
613                 free(e);
614         }
615         while ((e = TAILQ_FIRST(&eloop->free_events))) {
616                 TAILQ_REMOVE(&eloop->free_events, e, next);
617                 free(e);
618         }
619         while ((t = TAILQ_FIRST(&eloop->timeouts))) {
620                 TAILQ_REMOVE(&eloop->timeouts, t, next);
621                 free(t);
622         }
623         while ((t = TAILQ_FIRST(&eloop->free_timeouts))) {
624                 TAILQ_REMOVE(&eloop->free_timeouts, t, next);
625                 free(t);
626         }
627 #if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
628         close(eloop->poll_fd);
629 #else
630         free(eloop->fds);
631 #endif
632         free(eloop);
633 }
634
635 int
636 eloop_start(struct eloop *eloop, sigset_t *signals)
637 {
638         int n;
639         struct eloop_event *e;
640         struct eloop_timeout *t;
641         struct timespec now, ts, *tsp;
642         void (*t0)(void *);
643 #if defined(HAVE_KQUEUE)
644         struct kevent ke;
645         UNUSED(signals);
646 #elif defined(HAVE_EPOLL)
647         struct epoll_event epe;
648 #endif
649 #ifndef HAVE_KQUEUE
650         int timeout;
651
652         _eloop = eloop;
653 #endif
654
655         for (;;) {
656                 if (eloop->exitnow)
657                         break;
658
659                 /* Run all timeouts first */
660                 if (eloop->timeout0) {
661                         t0 = eloop->timeout0;
662                         eloop->timeout0 = NULL;
663                         t0(eloop->timeout0_arg);
664                         continue;
665                 }
666                 if ((t = TAILQ_FIRST(&eloop->timeouts))) {
667                         clock_gettime(CLOCK_MONOTONIC, &now);
668                         if (timespeccmp(&now, &t->when, >)) {
669                                 TAILQ_REMOVE(&eloop->timeouts, t, next);
670                                 t->callback(t->arg);
671                                 TAILQ_INSERT_TAIL(&eloop->free_timeouts, t, next);
672                                 continue;
673                         }
674                         timespecsub(&t->when, &now, &ts);
675                         tsp = &ts;
676                 } else
677                         /* No timeouts, so wait forever */
678                         tsp = NULL;
679
680                 if (tsp == NULL && eloop->events_len == 0)
681                         break;
682
683 #ifndef HAVE_KQUEUE
684                 if (tsp == NULL)
685                         timeout = -1;
686                 else if (tsp->tv_sec > INT_MAX / 1000 ||
687                     (tsp->tv_sec == INT_MAX / 1000 &&
688                     (tsp->tv_nsec + 999999) / 1000000 > INT_MAX % 1000000))
689                         timeout = INT_MAX;
690                 else
691                         timeout = (int)(tsp->tv_sec * 1000 +
692                             (tsp->tv_nsec + 999999) / 1000000);
693 #endif
694
695 #if defined(HAVE_KQUEUE)
696                 n = kevent(eloop->poll_fd, NULL, 0, &ke, 1, tsp);
697 #elif defined(HAVE_EPOLL)
698                 if (signals)
699                         n = epoll_pwait(eloop->poll_fd, &epe, 1,
700                             timeout, signals);
701                 else
702                         n = epoll_wait(eloop->poll_fd, &epe, 1, timeout);
703 #else
704                 if (signals)
705                         n = pollts(eloop->fds, (nfds_t)eloop->events_len,
706                             tsp, signals);
707                 else
708                         n = poll(eloop->fds, (nfds_t)eloop->events_len,
709                             timeout);
710 #endif
711                 if (n == -1) {
712                         if (errno == EINTR)
713                                 continue;
714                         return -errno;
715                 }
716
717                 /* Process any triggered events.
718                  * We go back to the start after calling each callback incase
719                  * the current event or next event is removed. */
720 #if defined(HAVE_KQUEUE)
721                 if (n) {
722                         if (ke.filter == EVFILT_SIGNAL) {
723                                 eloop->signal_cb((int)ke.ident,
724                                     eloop->signal_cb_ctx);
725                                 continue;
726                         }
727                         e = (struct eloop_event *)ke.udata;
728                         if (ke.filter == EVFILT_WRITE) {
729                                 e->write_cb(e->write_cb_arg);
730                                 continue;
731                         } else if (ke.filter == EVFILT_READ) {
732                                 e->read_cb(e->read_cb_arg);
733                                 continue;
734                         }
735                 }
736 #elif defined(HAVE_EPOLL)
737                 if (n) {
738                         e = (struct eloop_event *)epe.data.ptr;
739                         if (epe.events & EPOLLOUT && e->write_cb) {
740                                 e->write_cb(e->write_cb_arg);
741                                 continue;
742                         }
743                         if (epe.events &
744                             (EPOLLIN | EPOLLERR | EPOLLHUP))
745                         {
746                                 e->read_cb(e->read_cb_arg);
747                                 continue;
748                         }
749                 }
750 #else
751                 if (n > 0) {
752                         TAILQ_FOREACH(e, &eloop->events, next) {
753                                 if (e->pollfd->revents & POLLOUT &&
754                                     e->write_cb)
755                                 {
756                                         e->write_cb(e->write_cb_arg);
757                                         break;
758                                 }
759                                 if (e->pollfd->revents) {
760                                         e->read_cb(e->read_cb_arg);
761                                         break;
762                                 }
763                         }
764                 }
765 #endif
766         }
767
768         return eloop->exitcode;
769 }