"Fossies" - the Fresh Open Source Software Archive 
Member "dhcpcd-9.4.1/src/eloop.c" (22 Oct 2021, 17426 Bytes) of package /linux/misc/dhcpcd-9.4.1.tar.xz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "eloop.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
9.4.0_vs_9.4.1.
1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3 * eloop - portable event based main loop.
4 * Copyright (c) 2006-2021 Roy Marples <roy@marples.name>
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 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/time.h>
30
31 #include <assert.h>
32 #include <errno.h>
33 #include <limits.h>
34 #include <poll.h>
35 #include <stdbool.h>
36 #include <signal.h>
37 #include <stdint.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41
42 /* config.h should define HAVE_PPOLL, etc. */
43 #if defined(HAVE_CONFIG_H) && !defined(NO_CONFIG_H)
44 #include "config.h"
45 #endif
46
47 #if defined(HAVE_PPOLL)
48 #elif defined(HAVE_POLLTS)
49 #define ppoll pollts
50 #elif !defined(HAVE_PSELECT)
51 #pragma message("Compiling eloop with pselect(2) support.")
52 #define HAVE_PSELECT
53 #define ppoll eloop_ppoll
54 #endif
55
56 #include "eloop.h"
57
58 #ifndef UNUSED
59 #define UNUSED(a) (void)((a))
60 #endif
61 #ifndef __unused
62 #ifdef __GNUC__
63 #define __unused __attribute__((__unused__))
64 #else
65 #define __unused
66 #endif
67 #endif
68
69 #ifdef HAVE_PSELECT
70 #include <sys/select.h>
71 #endif
72
73 /* Our structures require TAILQ macros, which really every libc should
74 * ship as they are useful beyond belief.
75 * Sadly some libc's don't have sys/queue.h and some that do don't have
76 * the TAILQ_FOREACH macro. For those that don't, the application using
77 * this implementation will need to ship a working queue.h somewhere.
78 * If we don't have sys/queue.h found in config.h, then
79 * allow QUEUE_H to override loading queue.h in the current directory. */
80 #ifndef TAILQ_FOREACH
81 #ifdef HAVE_SYS_QUEUE_H
82 #include <sys/queue.h>
83 #elif defined(QUEUE_H)
84 #define __QUEUE_HEADER(x) #x
85 #define _QUEUE_HEADER(x) __QUEUE_HEADER(x)
86 #include _QUEUE_HEADER(QUEUE_H)
87 #else
88 #include "queue.h"
89 #endif
90 #endif
91
92 #ifdef ELOOP_DEBUG
93 #include <stdio.h>
94 #endif
95
96 /*
97 * Allow a backlog of signals.
98 * If you use many eloops in the same process, they should all
99 * use the same signal handler or have the signal handler unset.
100 * Otherwise the signal might not behave as expected.
101 */
102 #define ELOOP_NSIGNALS 5
103
104 /*
105 * time_t is a signed integer of an unspecified size.
106 * To adjust for time_t wrapping, we need to work the maximum signed
107 * value and use that as a maximum.
108 */
109 #ifndef TIME_MAX
110 #define TIME_MAX ((1ULL << (sizeof(time_t) * NBBY - 1)) - 1)
111 #endif
112 /* The unsigned maximum is then simple - multiply by two and add one. */
113 #ifndef UTIME_MAX
114 #define UTIME_MAX (TIME_MAX * 2) + 1
115 #endif
116
117 struct eloop_event {
118 TAILQ_ENTRY(eloop_event) next;
119 int fd;
120 void (*read_cb)(void *);
121 void *read_cb_arg;
122 void (*write_cb)(void *);
123 void *write_cb_arg;
124 struct pollfd *pollfd;
125 };
126
127 struct eloop_timeout {
128 TAILQ_ENTRY(eloop_timeout) next;
129 unsigned int seconds;
130 unsigned int nseconds;
131 void (*callback)(void *);
132 void *arg;
133 int queue;
134 };
135
136 struct eloop {
137 TAILQ_HEAD (event_head, eloop_event) events;
138 size_t nevents;
139 struct event_head free_events;
140 bool events_need_setup;
141
142 struct timespec now;
143 TAILQ_HEAD (timeout_head, eloop_timeout) timeouts;
144 struct timeout_head free_timeouts;
145
146 const int *signals;
147 size_t signals_len;
148 void (*signal_cb)(int, void *);
149 void *signal_cb_ctx;
150
151 struct pollfd *fds;
152 size_t nfds;
153
154 int exitnow;
155 int exitcode;
156 };
157
158 #ifdef HAVE_REALLOCARRAY
159 #define eloop_realloca reallocarray
160 #else
161 /* Handy routing to check for potential overflow.
162 * reallocarray(3) and reallocarr(3) are not portable. */
163 #define SQRT_SIZE_MAX (((size_t)1) << (sizeof(size_t) * CHAR_BIT / 2))
164 static void *
165 eloop_realloca(void *ptr, size_t n, size_t size)
166 {
167
168 if ((n | size) >= SQRT_SIZE_MAX && n > SIZE_MAX / size) {
169 errno = EOVERFLOW;
170 return NULL;
171 }
172 return realloc(ptr, n * size);
173 }
174 #endif
175
176 #ifdef HAVE_PSELECT
177 /* Wrapper around pselect, to imitate the ppoll call. */
178 static int
179 eloop_ppoll(struct pollfd * fds, nfds_t nfds,
180 const struct timespec *ts, const sigset_t *sigmask)
181 {
182 fd_set read_fds, write_fds;
183 nfds_t n;
184 int maxfd, r;
185
186 FD_ZERO(&read_fds);
187 FD_ZERO(&write_fds);
188 maxfd = 0;
189 for (n = 0; n < nfds; n++) {
190 if (fds[n].events & POLLIN) {
191 FD_SET(fds[n].fd, &read_fds);
192 if (fds[n].fd > maxfd)
193 maxfd = fds[n].fd;
194 }
195 if (fds[n].events & POLLOUT) {
196 FD_SET(fds[n].fd, &write_fds);
197 if (fds[n].fd > maxfd)
198 maxfd = fds[n].fd;
199 }
200 }
201
202 r = pselect(maxfd + 1, &read_fds, &write_fds, NULL, ts, sigmask);
203 if (r > 0) {
204 for (n = 0; n < nfds; n++) {
205 fds[n].revents =
206 FD_ISSET(fds[n].fd, &read_fds) ? POLLIN : 0;
207 if (FD_ISSET(fds[n].fd, &write_fds))
208 fds[n].revents |= POLLOUT;
209 }
210 }
211
212 return r;
213 }
214 #endif
215
216 unsigned long long
217 eloop_timespec_diff(const struct timespec *tsp, const struct timespec *usp,
218 unsigned int *nsp)
219 {
220 unsigned long long tsecs, usecs, secs;
221 long nsecs;
222
223 if (tsp->tv_sec < 0) /* time wreapped */
224 tsecs = UTIME_MAX - (unsigned long long)(-tsp->tv_sec);
225 else
226 tsecs = (unsigned long long)tsp->tv_sec;
227 if (usp->tv_sec < 0) /* time wrapped */
228 usecs = UTIME_MAX - (unsigned long long)(-usp->tv_sec);
229 else
230 usecs = (unsigned long long)usp->tv_sec;
231
232 if (usecs > tsecs) /* time wrapped */
233 secs = (UTIME_MAX - usecs) + tsecs;
234 else
235 secs = tsecs - usecs;
236
237 nsecs = tsp->tv_nsec - usp->tv_nsec;
238 if (nsecs < 0) {
239 if (secs == 0)
240 nsecs = 0;
241 else {
242 secs--;
243 nsecs += NSEC_PER_SEC;
244 }
245 }
246 if (nsp != NULL)
247 *nsp = (unsigned int)nsecs;
248 return secs;
249 }
250
251 static void
252 eloop_reduce_timers(struct eloop *eloop)
253 {
254 struct timespec now;
255 unsigned long long secs;
256 unsigned int nsecs;
257 struct eloop_timeout *t;
258
259 clock_gettime(CLOCK_MONOTONIC, &now);
260 secs = eloop_timespec_diff(&now, &eloop->now, &nsecs);
261
262 TAILQ_FOREACH(t, &eloop->timeouts, next) {
263 if (secs > t->seconds) {
264 t->seconds = 0;
265 t->nseconds = 0;
266 } else {
267 t->seconds -= (unsigned int)secs;
268 if (nsecs > t->nseconds) {
269 if (t->seconds == 0)
270 t->nseconds = 0;
271 else {
272 t->seconds--;
273 t->nseconds = NSEC_PER_SEC
274 - (nsecs - t->nseconds);
275 }
276 } else
277 t->nseconds -= nsecs;
278 }
279 }
280
281 eloop->now = now;
282 }
283
284 static void
285 eloop_event_setup_fds(struct eloop *eloop)
286 {
287 struct eloop_event *e, *ne;
288 struct pollfd *pfd;
289
290 pfd = eloop->fds;
291 TAILQ_FOREACH_SAFE(e, &eloop->events, next, ne) {
292 if (e->fd == -1) {
293 TAILQ_REMOVE(&eloop->events, e, next);
294 TAILQ_INSERT_TAIL(&eloop->free_events, e, next);
295 continue;
296 }
297 #ifdef ELOOP_DEBUG
298 fprintf(stderr, "%s(%d) fd=%d, rcb=%p, wcb=%p\n",
299 __func__, getpid(), e->fd, e->read_cb, e->write_cb);
300 #endif
301 e->pollfd = pfd;
302 pfd->fd = e->fd;
303 pfd->events = 0;
304 if (e->read_cb != NULL)
305 pfd->events |= POLLIN;
306 if (e->write_cb != NULL)
307 pfd->events |= POLLOUT;
308 pfd->revents = 0;
309 pfd++;
310 }
311 eloop->events_need_setup = false;
312 }
313
314 size_t
315 eloop_event_count(const struct eloop *eloop)
316 {
317
318 return eloop->nevents;
319 }
320
321 int
322 eloop_event_add_rw(struct eloop *eloop, int fd,
323 void (*read_cb)(void *), void *read_cb_arg,
324 void (*write_cb)(void *), void *write_cb_arg)
325 {
326 struct eloop_event *e;
327 struct pollfd *pfd;
328
329 assert(eloop != NULL);
330 assert(read_cb != NULL || write_cb != NULL);
331 if (fd == -1) {
332 errno = EINVAL;
333 return -1;
334 }
335
336 TAILQ_FOREACH(e, &eloop->events, next) {
337 if (e->fd == fd)
338 break;
339 }
340
341 if (e == NULL) {
342 if (eloop->nevents + 1 > eloop->nfds) {
343 pfd = eloop_realloca(eloop->fds, eloop->nevents + 1,
344 sizeof(*pfd));
345 if (pfd == NULL)
346 return -1;
347 eloop->fds = pfd;
348 eloop->nfds++;
349 }
350
351 e = TAILQ_FIRST(&eloop->free_events);
352 if (e != NULL)
353 TAILQ_REMOVE(&eloop->free_events, e, next);
354 else {
355 e = malloc(sizeof(*e));
356 if (e == NULL)
357 return -1;
358 }
359 TAILQ_INSERT_HEAD(&eloop->events, e, next);
360 eloop->nevents++;
361 e->fd = fd;
362 e->read_cb = read_cb;
363 e->read_cb_arg = read_cb_arg;
364 e->write_cb = write_cb;
365 e->write_cb_arg = write_cb_arg;
366 goto setup;
367 }
368
369 if (read_cb) {
370 e->read_cb = read_cb;
371 e->read_cb_arg = read_cb_arg;
372 }
373 if (write_cb) {
374 e->write_cb = write_cb;
375 e->write_cb_arg = write_cb_arg;
376 }
377
378 setup:
379 e->pollfd = NULL;
380 eloop->events_need_setup = true;
381 return 0;
382 }
383
384 int
385 eloop_event_add(struct eloop *eloop, int fd,
386 void (*read_cb)(void *), void *read_cb_arg)
387 {
388
389 return eloop_event_add_rw(eloop, fd, read_cb, read_cb_arg, NULL, NULL);
390 }
391
392 int
393 eloop_event_add_w(struct eloop *eloop, int fd,
394 void (*write_cb)(void *), void *write_cb_arg)
395 {
396
397 return eloop_event_add_rw(eloop, fd, NULL,NULL, write_cb, write_cb_arg);
398 }
399
400 int
401 eloop_event_delete_write(struct eloop *eloop, int fd, int write_only)
402 {
403 struct eloop_event *e;
404
405 assert(eloop != NULL);
406 if (fd == -1) {
407 errno = EINVAL;
408 return -1;
409 }
410
411 TAILQ_FOREACH(e, &eloop->events, next) {
412 if (e->fd == fd)
413 break;
414 }
415 if (e == NULL) {
416 errno = ENOENT;
417 return -1;
418 }
419
420 if (write_only) {
421 if (e->read_cb == NULL)
422 goto remove;
423 e->write_cb = NULL;
424 e->write_cb_arg = NULL;
425 if (e->pollfd != NULL) {
426 e->pollfd->events &= ~POLLOUT;
427 e->pollfd->revents &= ~POLLOUT;
428 }
429 return 1;
430 }
431
432 remove:
433 e->fd = -1;
434 eloop->nevents--;
435 eloop->events_need_setup = true;
436 return 1;
437 }
438
439 /*
440 * This implementation should cope with UINT_MAX seconds on a system
441 * where time_t is INT32_MAX. It should also cope with the monotonic timer
442 * wrapping, although this is highly unlikely.
443 * unsigned int should match or be greater than any on wire specified timeout.
444 */
445 static int
446 eloop_q_timeout_add(struct eloop *eloop, int queue,
447 unsigned int seconds, unsigned int nseconds,
448 void (*callback)(void *), void *arg)
449 {
450 struct eloop_timeout *t, *tt = NULL;
451
452 assert(eloop != NULL);
453 assert(callback != NULL);
454 assert(nseconds <= NSEC_PER_SEC);
455
456 /* Remove existing timeout if present. */
457 TAILQ_FOREACH(t, &eloop->timeouts, next) {
458 if (t->callback == callback && t->arg == arg) {
459 TAILQ_REMOVE(&eloop->timeouts, t, next);
460 break;
461 }
462 }
463
464 if (t == NULL) {
465 /* No existing, so allocate or grab one from the free pool. */
466 if ((t = TAILQ_FIRST(&eloop->free_timeouts))) {
467 TAILQ_REMOVE(&eloop->free_timeouts, t, next);
468 } else {
469 if ((t = malloc(sizeof(*t))) == NULL)
470 return -1;
471 }
472 }
473
474 eloop_reduce_timers(eloop);
475
476 t->seconds = seconds;
477 t->nseconds = nseconds;
478 t->callback = callback;
479 t->arg = arg;
480 t->queue = queue;
481
482 /* The timeout list should be in chronological order,
483 * soonest first. */
484 TAILQ_FOREACH(tt, &eloop->timeouts, next) {
485 if (t->seconds < tt->seconds ||
486 (t->seconds == tt->seconds && t->nseconds < tt->nseconds))
487 {
488 TAILQ_INSERT_BEFORE(tt, t, next);
489 return 0;
490 }
491 }
492 TAILQ_INSERT_TAIL(&eloop->timeouts, t, next);
493 return 0;
494 }
495
496 int
497 eloop_q_timeout_add_tv(struct eloop *eloop, int queue,
498 const struct timespec *when, void (*callback)(void *), void *arg)
499 {
500
501 if (when->tv_sec < 0 || (unsigned long)when->tv_sec > UINT_MAX) {
502 errno = EINVAL;
503 return -1;
504 }
505 if (when->tv_nsec < 0 || when->tv_nsec > NSEC_PER_SEC) {
506 errno = EINVAL;
507 return -1;
508 }
509
510 return eloop_q_timeout_add(eloop, queue,
511 (unsigned int)when->tv_sec, (unsigned int)when->tv_sec,
512 callback, arg);
513 }
514
515 int
516 eloop_q_timeout_add_sec(struct eloop *eloop, int queue, unsigned int seconds,
517 void (*callback)(void *), void *arg)
518 {
519
520 return eloop_q_timeout_add(eloop, queue, seconds, 0, callback, arg);
521 }
522
523 int
524 eloop_q_timeout_add_msec(struct eloop *eloop, int queue, unsigned long when,
525 void (*callback)(void *), void *arg)
526 {
527 unsigned long seconds, nseconds;
528
529 seconds = when / MSEC_PER_SEC;
530 if (seconds > UINT_MAX) {
531 errno = EINVAL;
532 return -1;
533 }
534
535 nseconds = (when % MSEC_PER_SEC) * NSEC_PER_MSEC;
536 return eloop_q_timeout_add(eloop, queue,
537 (unsigned int)seconds, (unsigned int)nseconds, callback, arg);
538 }
539
540 int
541 eloop_q_timeout_delete(struct eloop *eloop, int queue,
542 void (*callback)(void *), void *arg)
543 {
544 struct eloop_timeout *t, *tt;
545 int n;
546
547 assert(eloop != NULL);
548
549 n = 0;
550 TAILQ_FOREACH_SAFE(t, &eloop->timeouts, next, tt) {
551 if ((queue == 0 || t->queue == queue) &&
552 t->arg == arg &&
553 (!callback || t->callback == callback))
554 {
555 TAILQ_REMOVE(&eloop->timeouts, t, next);
556 TAILQ_INSERT_TAIL(&eloop->free_timeouts, t, next);
557 n++;
558 }
559 }
560 return n;
561 }
562
563 void
564 eloop_exit(struct eloop *eloop, int code)
565 {
566
567 assert(eloop != NULL);
568
569 eloop->exitcode = code;
570 eloop->exitnow = 1;
571 }
572
573 void
574 eloop_enter(struct eloop *eloop)
575 {
576
577 eloop->exitnow = 0;
578 }
579
580 void
581 eloop_signal_set_cb(struct eloop *eloop,
582 const int *signals, size_t signals_len,
583 void (*signal_cb)(int, void *), void *signal_cb_ctx)
584 {
585
586 assert(eloop != NULL);
587
588 eloop->signals = signals;
589 eloop->signals_len = signals_len;
590 eloop->signal_cb = signal_cb;
591 eloop->signal_cb_ctx = signal_cb_ctx;
592 }
593
594 static volatile int _eloop_sig[ELOOP_NSIGNALS];
595 static volatile size_t _eloop_nsig;
596
597 static void
598 eloop_signal3(int sig, __unused siginfo_t *siginfo, __unused void *arg)
599 {
600
601 if (_eloop_nsig == __arraycount(_eloop_sig)) {
602 #ifdef ELOOP_DEBUG
603 fprintf(stderr, "%s: signal storm, discarding signal %d\n",
604 __func__, sig);
605 #endif
606 return;
607 }
608
609 _eloop_sig[_eloop_nsig++] = sig;
610 }
611
612 int
613 eloop_signal_mask(struct eloop *eloop, sigset_t *oldset)
614 {
615 sigset_t newset;
616 size_t i;
617 struct sigaction sa = {
618 .sa_sigaction = eloop_signal3,
619 .sa_flags = SA_SIGINFO,
620 };
621
622 assert(eloop != NULL);
623
624 sigemptyset(&newset);
625 for (i = 0; i < eloop->signals_len; i++)
626 sigaddset(&newset, eloop->signals[i]);
627 if (sigprocmask(SIG_SETMASK, &newset, oldset) == -1)
628 return -1;
629
630 sigemptyset(&sa.sa_mask);
631
632 for (i = 0; i < eloop->signals_len; i++) {
633 if (sigaction(eloop->signals[i], &sa, NULL) == -1)
634 return -1;
635 }
636 return 0;
637 }
638
639 struct eloop *
640 eloop_new(void)
641 {
642 struct eloop *eloop;
643
644 eloop = calloc(1, sizeof(*eloop));
645 if (eloop == NULL)
646 return NULL;
647
648 /* Check we have a working monotonic clock. */
649 if (clock_gettime(CLOCK_MONOTONIC, &eloop->now) == -1) {
650 free(eloop);
651 return NULL;
652 }
653
654 TAILQ_INIT(&eloop->events);
655 TAILQ_INIT(&eloop->free_events);
656 TAILQ_INIT(&eloop->timeouts);
657 TAILQ_INIT(&eloop->free_timeouts);
658 eloop->exitcode = EXIT_FAILURE;
659
660 return eloop;
661 }
662
663 void
664 eloop_clear(struct eloop *eloop)
665 {
666 struct eloop_event *e;
667 struct eloop_timeout *t;
668
669 if (eloop == NULL)
670 return;
671
672 eloop->nevents = 0;
673 eloop->signals = NULL;
674 eloop->signals_len = 0;
675
676 while ((e = TAILQ_FIRST(&eloop->events))) {
677 TAILQ_REMOVE(&eloop->events, e, next);
678 free(e);
679 }
680 while ((e = TAILQ_FIRST(&eloop->free_events))) {
681 TAILQ_REMOVE(&eloop->free_events, e, next);
682 free(e);
683 }
684 while ((t = TAILQ_FIRST(&eloop->timeouts))) {
685 TAILQ_REMOVE(&eloop->timeouts, t, next);
686 free(t);
687 }
688 while ((t = TAILQ_FIRST(&eloop->free_timeouts))) {
689 TAILQ_REMOVE(&eloop->free_timeouts, t, next);
690 free(t);
691 }
692
693 free(eloop->fds);
694 eloop->fds = NULL;
695 eloop->nfds = 0;
696 }
697
698 void
699 eloop_free(struct eloop *eloop)
700 {
701
702 eloop_clear(eloop);
703 free(eloop);
704 }
705
706 int
707 eloop_start(struct eloop *eloop, sigset_t *signals)
708 {
709 int n;
710 struct eloop_event *e;
711 struct eloop_timeout *t;
712 struct timespec ts, *tsp;
713
714 assert(eloop != NULL);
715
716 for (;;) {
717 if (eloop->exitnow)
718 break;
719
720 if (_eloop_nsig != 0) {
721 n = _eloop_sig[--_eloop_nsig];
722 if (eloop->signal_cb != NULL)
723 eloop->signal_cb(n, eloop->signal_cb_ctx);
724 continue;
725 }
726
727 t = TAILQ_FIRST(&eloop->timeouts);
728 if (t == NULL && eloop->nevents == 0)
729 break;
730
731 if (t != NULL)
732 eloop_reduce_timers(eloop);
733
734 if (t != NULL && t->seconds == 0 && t->nseconds == 0) {
735 TAILQ_REMOVE(&eloop->timeouts, t, next);
736 t->callback(t->arg);
737 TAILQ_INSERT_TAIL(&eloop->free_timeouts, t, next);
738 continue;
739 }
740
741 if (t != NULL) {
742 if (t->seconds > INT_MAX) {
743 ts.tv_sec = (time_t)INT_MAX;
744 ts.tv_nsec = 0;
745 } else {
746 ts.tv_sec = (time_t)t->seconds;
747 ts.tv_nsec = (long)t->nseconds;
748 }
749 tsp = &ts;
750 } else
751 tsp = NULL;
752
753 if (eloop->events_need_setup)
754 eloop_event_setup_fds(eloop);
755
756 n = ppoll(eloop->fds, (nfds_t)eloop->nevents, tsp, signals);
757 if (n == -1) {
758 if (errno == EINTR)
759 continue;
760 return -errno;
761 }
762 if (n == 0)
763 continue;
764
765 TAILQ_FOREACH(e, &eloop->events, next) {
766 /* Skip freshly added events */
767 if (e->pollfd == NULL)
768 continue;
769 if (e->pollfd->revents)
770 n--;
771 if (e->fd != -1 && e->pollfd->revents & POLLOUT) {
772 if (e->write_cb != NULL)
773 e->write_cb(e->write_cb_arg);
774 }
775 if (e->fd != -1 &&
776 e->pollfd != NULL && e->pollfd->revents)
777 {
778 if (e->read_cb != NULL)
779 e->read_cb(e->read_cb_arg);
780 }
781 if (n == 0)
782 break;
783 }
784 }
785
786 return eloop->exitcode;
787 }