• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/libubox/uloop.c

  1 /*
  2  * uloop - event loop implementation
  3  *
  4  * Copyright (C) 2010-2016 Felix Fietkau <nbd@openwrt.org>
  5  *
  6  * Permission to use, copy, modify, and/or distribute this software for any
  7  * purpose with or without fee is hereby granted, provided that the above
  8  * copyright notice and this permission notice appear in all copies.
  9  *
 10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 17  */
 18 #include <sys/time.h>
 19 #include <sys/types.h>
 20 
 21 #include <unistd.h>
 22 #include <stdio.h>
 23 #include <stdlib.h>
 24 #include <errno.h>
 25 #include <poll.h>
 26 #include <string.h>
 27 #include <fcntl.h>
 28 #include <stdbool.h>
 29 #include <limits.h>
 30 #include <signal.h>
 31 
 32 #include "uloop.h"
 33 #include "utils.h"
 34 
 35 #ifdef USE_KQUEUE
 36 #include <sys/event.h>
 37 #endif
 38 #ifdef USE_EPOLL
 39 #include <sys/epoll.h>
 40 #include <sys/timerfd.h>
 41 #endif
 42 #include <sys/wait.h>
 43 
 44 struct uloop_fd_event {
 45         struct uloop_fd *fd;
 46         unsigned int events;
 47 };
 48 
 49 struct uloop_fd_stack {
 50         struct uloop_fd_stack *next;
 51         struct uloop_fd *fd;
 52         unsigned int events;
 53 };
 54 
 55 static struct uloop_fd_stack *fd_stack = NULL;
 56 
 57 #define ULOOP_MAX_EVENTS 10
 58 
 59 static struct list_head timeouts = LIST_HEAD_INIT(timeouts);
 60 static struct list_head processes = LIST_HEAD_INIT(processes);
 61 static struct list_head signals = LIST_HEAD_INIT(signals);
 62 
 63 static int poll_fd = -1;
 64 bool uloop_cancelled = false;
 65 bool uloop_handle_sigchld = true;
 66 static int uloop_status = 0;
 67 static volatile sig_atomic_t do_sigchld = 0;
 68 
 69 static struct uloop_fd_event cur_fds[ULOOP_MAX_EVENTS];
 70 static int cur_fd, cur_nfds;
 71 static int uloop_run_depth = 0;
 72 
 73 uloop_fd_handler uloop_fd_set_cb = NULL;
 74 
 75 int uloop_fd_add(struct uloop_fd *sock, unsigned int flags);
 76 
 77 #ifdef USE_KQUEUE
 78 #include "uloop-kqueue.c"
 79 #endif
 80 
 81 #ifdef USE_EPOLL
 82 #include "uloop-epoll.c"
 83 #endif
 84 
 85 static void set_signo(uint64_t *signums, int signo)
 86 {
 87         if (signo >= 1 && signo <= 64)
 88                 *signums |= (UINT64_C(1) << (signo - 1));
 89 }
 90 
 91 static bool get_signo(uint64_t signums, int signo)
 92 {
 93         return (signo >= 1) && (signo <= 64) && (signums & (UINT64_C(1) << (signo - 1)));
 94 }
 95 
 96 static void signal_consume(struct uloop_fd *fd, unsigned int events)
 97 {
 98         struct uloop_signal *usig, *usig_next;
 99         uint64_t signums = 0;
100         uint8_t buf[32];
101         ssize_t nsigs;
102 
103         do {
104                 nsigs = read(fd->fd, buf, sizeof(buf));
105 
106                 for (ssize_t i = 0; i < nsigs; i++)
107                         set_signo(&signums, buf[i]);
108         }
109         while (nsigs > 0);
110 
111         list_for_each_entry_safe(usig, usig_next, &signals, list)
112                 if (get_signo(signums, usig->signo))
113                         usig->cb(usig);
114 }
115 
116 static int waker_pipe = -1;
117 static struct uloop_fd waker_fd = {
118         .fd = -1,
119         .cb = signal_consume,
120 };
121 
122 static void waker_init_fd(int fd)
123 {
124         int flags;
125 
126         flags = fcntl(fd, F_GETFD);
127         if (flags >= 0)
128                 fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
129 
130         flags = fcntl(fd, F_GETFL);
131         if (flags >= 0)
132                 fcntl(fd, F_SETFL, flags | O_NONBLOCK);
133 }
134 
135 static int waker_init(void)
136 {
137         int fds[2];
138 
139         if (waker_pipe >= 0)
140                 return 0;
141 
142         if (pipe(fds) < 0)
143                 return -1;
144 
145         waker_init_fd(fds[0]);
146         waker_init_fd(fds[1]);
147         waker_pipe = fds[1];
148 
149         waker_fd.fd = fds[0];
150         waker_fd.cb = signal_consume;
151         uloop_fd_add(&waker_fd, ULOOP_READ);
152 
153         return 0;
154 }
155 
156 static void uloop_setup_signals(bool add);
157 
158 int uloop_init(void)
159 {
160         if (uloop_init_pollfd() < 0)
161                 return -1;
162 
163         if (waker_init() < 0) {
164                 uloop_done();
165                 return -1;
166         }
167 
168         uloop_setup_signals(true);
169 
170         return 0;
171 }
172 
173 static bool uloop_fd_stack_event(struct uloop_fd *fd, int events)
174 {
175         struct uloop_fd_stack *cur;
176 
177         /*
178          * Do not buffer events for level-triggered fds, they will keep firing.
179          * Caller needs to take care of recursion issues.
180          */
181         if (!(fd->flags & ULOOP_EDGE_TRIGGER))
182                 return false;
183 
184         for (cur = fd_stack; cur; cur = cur->next) {
185                 if (cur->fd != fd)
186                         continue;
187 
188                 if (events < 0)
189                         cur->fd = NULL;
190                 else
191                         cur->events |= events | ULOOP_EVENT_BUFFERED;
192 
193                 return true;
194         }
195 
196         return false;
197 }
198 
199 static void uloop_run_events(int64_t timeout)
200 {
201         struct uloop_fd_event *cur;
202         struct uloop_fd *fd;
203 
204         if (!cur_nfds) {
205                 cur_fd = 0;
206                 cur_nfds = uloop_fetch_events(timeout);
207                 if (cur_nfds < 0)
208                         cur_nfds = 0;
209         }
210 
211         while (cur_nfds > 0) {
212                 struct uloop_fd_stack stack_cur;
213                 unsigned int events;
214 
215                 cur = &cur_fds[cur_fd++];
216                 cur_nfds--;
217 
218                 fd = cur->fd;
219                 events = cur->events;
220                 if (!fd)
221                         continue;
222 
223                 if (!fd->cb)
224                         continue;
225 
226                 if (uloop_fd_stack_event(fd, cur->events))
227                         continue;
228 
229                 stack_cur.next = fd_stack;
230                 stack_cur.fd = fd;
231                 fd_stack = &stack_cur;
232                 do {
233                         stack_cur.events = 0;
234                         fd->cb(fd, events);
235                         events = stack_cur.events & ULOOP_EVENT_MASK;
236                 } while (stack_cur.fd && events);
237                 fd_stack = stack_cur.next;
238 
239                 return;
240         }
241 }
242 
243 int uloop_fd_add(struct uloop_fd *sock, unsigned int flags)
244 {
245         int fl;
246         int ret;
247 
248         if (!(flags & (ULOOP_READ | ULOOP_WRITE | ULOOP_PRIORITY)))
249                 return uloop_fd_delete(sock);
250 
251         if (!sock->registered && !(flags & ULOOP_BLOCKING)) {
252                 fl = fcntl(sock->fd, F_GETFL, 0);
253                 if (fl >= 0)
254                         fcntl(sock->fd, F_SETFL, fl | O_NONBLOCK);
255         }
256 
257         ret = register_poll(sock, flags);
258         if (ret < 0)
259                 goto out;
260 
261         if (uloop_fd_set_cb)
262                 uloop_fd_set_cb(sock, flags);
263 
264         sock->flags = flags;
265         sock->registered = true;
266         sock->eof = false;
267         sock->error = false;
268 
269 out:
270         return ret;
271 }
272 
273 int uloop_fd_delete(struct uloop_fd *fd)
274 {
275         int ret;
276         int i;
277 
278         for (i = 0; i < cur_nfds; i++) {
279                 if (cur_fds[cur_fd + i].fd != fd)
280                         continue;
281 
282                 cur_fds[cur_fd + i].fd = NULL;
283         }
284 
285         if (!fd->registered)
286                 return 0;
287 
288         if (uloop_fd_set_cb)
289                 uloop_fd_set_cb(fd, 0);
290 
291         fd->registered = false;
292         uloop_fd_stack_event(fd, -1);
293         ret = __uloop_fd_delete(fd);
294         fd->flags = 0;
295 
296         return ret;
297 }
298 
299 static int64_t tv_diff(struct timeval *t1, struct timeval *t2)
300 {
301         return
302                 (t1->tv_sec - t2->tv_sec) * 1000 +
303                 (t1->tv_usec - t2->tv_usec) / 1000;
304 }
305 
306 int uloop_timeout_add(struct uloop_timeout *timeout)
307 {
308         struct uloop_timeout *tmp;
309         struct list_head *h = &timeouts;
310 
311         if (timeout->pending)
312                 return -1;
313 
314         list_for_each_entry(tmp, &timeouts, list) {
315                 if (tv_diff(&tmp->time, &timeout->time) > 0) {
316                         h = &tmp->list;
317                         break;
318                 }
319         }
320 
321         list_add_tail(&timeout->list, h);
322         timeout->pending = true;
323 
324         return 0;
325 }
326 
327 static void uloop_gettime(struct timeval *tv)
328 {
329         struct timespec ts;
330 
331         clock_gettime(CLOCK_MONOTONIC, &ts);
332         tv->tv_sec = ts.tv_sec;
333         tv->tv_usec = ts.tv_nsec / 1000;
334 }
335 
336 int uloop_timeout_set(struct uloop_timeout *timeout, int msecs)
337 {
338         struct timeval *time = &timeout->time;
339 
340         if (timeout->pending)
341                 uloop_timeout_cancel(timeout);
342 
343         uloop_gettime(time);
344 
345         time->tv_sec += msecs / 1000;
346         time->tv_usec += (msecs % 1000) * 1000;
347 
348         if (time->tv_usec > 1000000) {
349                 time->tv_sec++;
350                 time->tv_usec -= 1000000;
351         }
352 
353         return uloop_timeout_add(timeout);
354 }
355 
356 int uloop_timeout_cancel(struct uloop_timeout *timeout)
357 {
358         if (!timeout->pending)
359                 return -1;
360 
361         list_del(&timeout->list);
362         timeout->pending = false;
363 
364         return 0;
365 }
366 
367 int uloop_timeout_remaining(struct uloop_timeout *timeout)
368 {
369         int64_t td;
370         struct timeval now;
371 
372         if (!timeout->pending)
373                 return -1;
374 
375         uloop_gettime(&now);
376 
377         td = tv_diff(&timeout->time, &now);
378 
379         if (td > INT_MAX)
380                 return INT_MAX;
381         else if (td < INT_MIN)
382                 return INT_MIN;
383         else
384                 return (int)td;
385 }
386 
387 int64_t uloop_timeout_remaining64(struct uloop_timeout *timeout)
388 {
389         struct timeval now;
390 
391         if (!timeout->pending)
392                 return -1;
393 
394         uloop_gettime(&now);
395 
396         return tv_diff(&timeout->time, &now);
397 }
398 
399 int uloop_process_add(struct uloop_process *p)
400 {
401         struct uloop_process *tmp;
402         struct list_head *h = &processes;
403 
404         if (p->pending)
405                 return -1;
406 
407         list_for_each_entry(tmp, &processes, list) {
408                 if (tmp->pid > p->pid) {
409                         h = &tmp->list;
410                         break;
411                 }
412         }
413 
414         list_add_tail(&p->list, h);
415         p->pending = true;
416 
417         return 0;
418 }
419 
420 int uloop_process_delete(struct uloop_process *p)
421 {
422         if (!p->pending)
423                 return -1;
424 
425         list_del(&p->list);
426         p->pending = false;
427 
428         return 0;
429 }
430 
431 static void uloop_handle_processes(void)
432 {
433         struct uloop_process *p, *tmp;
434         pid_t pid;
435         int ret;
436 
437         do_sigchld = 0;
438 
439         while (1) {
440                 pid = waitpid(-1, &ret, WNOHANG);
441                 if (pid < 0 && errno == EINTR)
442                         continue;
443 
444                 if (pid <= 0)
445                         return;
446 
447                 list_for_each_entry_safe(p, tmp, &processes, list) {
448                         if (p->pid < pid)
449                                 continue;
450 
451                         if (p->pid > pid)
452                                 break;
453 
454                         uloop_process_delete(p);
455                         p->cb(p, ret);
456                 }
457         }
458 
459 }
460 
461 int uloop_interval_set(struct uloop_interval *timer, unsigned int msecs)
462 {
463         return timer_register(timer, msecs);
464 }
465 
466 int uloop_interval_cancel(struct uloop_interval *timer)
467 {
468         return timer_remove(timer);
469 }
470 
471 int64_t uloop_interval_remaining(struct uloop_interval *timer)
472 {
473         return timer_next(timer);
474 }
475 
476 static void uloop_signal_wake(int signo)
477 {
478         uint8_t sigbyte = signo;
479 
480         if (signo == SIGCHLD)
481                 do_sigchld = 1;
482 
483         do {
484                 if (write(waker_pipe, &sigbyte, 1) < 0) {
485                         if (errno == EINTR)
486                                 continue;
487                 }
488                 break;
489         } while (1);
490 }
491 
492 static void uloop_handle_sigint(int signo)
493 {
494         uloop_status = signo;
495         uloop_cancelled = true;
496         uloop_signal_wake(signo);
497 }
498 
499 static void uloop_install_handler(int signum, void (*handler)(int), struct sigaction* old, bool add)
500 {
501         struct sigaction s;
502         struct sigaction *act;
503 
504         act = NULL;
505         sigaction(signum, NULL, &s);
506 
507         if (add) {
508                 if (s.sa_handler == SIG_DFL) { /* Do not override existing custom signal handlers */
509                         memcpy(old, &s, sizeof(struct sigaction));
510                         s.sa_handler = handler;
511                         s.sa_flags = 0;
512                         act = &s;
513                 }
514         }
515         else if (s.sa_handler == handler) { /* Do not restore if someone modified our handler */
516                         act = old;
517         }
518 
519         if (act != NULL)
520                 sigaction(signum, act, NULL);
521 }
522 
523 static void uloop_ignore_signal(int signum, bool ignore)
524 {
525         struct sigaction s;
526         void *new_handler = NULL;
527 
528         sigaction(signum, NULL, &s);
529 
530         if (ignore) {
531                 if (s.sa_handler == SIG_DFL) /* Ignore only if there isn't any custom handler */
532                         new_handler = SIG_IGN;
533         } else {
534                 if (s.sa_handler == SIG_IGN) /* Restore only if noone modified our SIG_IGN */
535                         new_handler = SIG_DFL;
536         }
537 
538         if (new_handler) {
539                 s.sa_handler = new_handler;
540                 s.sa_flags = 0;
541                 sigaction(signum, &s, NULL);
542         }
543 }
544 
545 static void uloop_setup_signals(bool add)
546 {
547         static struct sigaction old_sigint, old_sigchld, old_sigterm;
548 
549         uloop_install_handler(SIGINT, uloop_handle_sigint, &old_sigint, add);
550         uloop_install_handler(SIGTERM, uloop_handle_sigint, &old_sigterm, add);
551 
552         if (uloop_handle_sigchld)
553                 uloop_install_handler(SIGCHLD, uloop_signal_wake, &old_sigchld, add);
554 
555         uloop_ignore_signal(SIGPIPE, add);
556 }
557 
558 int uloop_signal_add(struct uloop_signal *s)
559 {
560         struct list_head *h = &signals;
561         struct uloop_signal *tmp;
562         struct sigaction sa;
563 
564         if (s->pending)
565                 return -1;
566 
567         list_for_each_entry(tmp, &signals, list) {
568                 if (tmp->signo > s->signo) {
569                         h = &tmp->list;
570                         break;
571                 }
572         }
573 
574         list_add_tail(&s->list, h);
575         s->pending = true;
576 
577         sigaction(s->signo, NULL, &s->orig);
578 
579         if (s->orig.sa_handler != uloop_signal_wake) {
580                 sa.sa_handler = uloop_signal_wake;
581                 sa.sa_flags = 0;
582                 sigemptyset(&sa.sa_mask);
583                 sigaction(s->signo, &sa, NULL);
584         }
585 
586         return 0;
587 }
588 
589 int uloop_signal_delete(struct uloop_signal *s)
590 {
591         if (!s->pending)
592                 return -1;
593 
594         list_del(&s->list);
595         s->pending = false;
596 
597         if (s->orig.sa_handler != uloop_signal_wake)
598                 sigaction(s->signo, &s->orig, NULL);
599 
600         return 0;
601 }
602 
603 int uloop_get_next_timeout(void)
604 {
605         struct uloop_timeout *timeout;
606         struct timeval tv;
607         int64_t diff;
608 
609         if (list_empty(&timeouts))
610                 return -1;
611 
612         uloop_gettime(&tv);
613 
614         timeout = list_first_entry(&timeouts, struct uloop_timeout, list);
615         diff = tv_diff(&timeout->time, &tv);
616         if (diff < 0)
617                 return 0;
618         if (diff > INT_MAX)
619                 return INT_MAX;
620 
621         return diff;
622 }
623 
624 static void uloop_process_timeouts(void)
625 {
626         struct uloop_timeout *t;
627         struct timeval tv;
628 
629         if (list_empty(&timeouts))
630                 return;
631 
632         uloop_gettime(&tv);
633         while (!list_empty(&timeouts)) {
634                 t = list_first_entry(&timeouts, struct uloop_timeout, list);
635 
636                 if (tv_diff(&t->time, &tv) > 0)
637                         break;
638 
639                 uloop_timeout_cancel(t);
640                 if (t->cb)
641                         t->cb(t);
642         }
643 }
644 
645 static void uloop_clear_timeouts(void)
646 {
647         struct uloop_timeout *t, *tmp;
648 
649         list_for_each_entry_safe(t, tmp, &timeouts, list)
650                 uloop_timeout_cancel(t);
651 }
652 
653 static void uloop_clear_processes(void)
654 {
655         struct uloop_process *p, *tmp;
656 
657         list_for_each_entry_safe(p, tmp, &processes, list)
658                 uloop_process_delete(p);
659 }
660 
661 bool uloop_cancelling(void)
662 {
663         return uloop_run_depth > 0 && uloop_cancelled;
664 }
665 
666 int uloop_run_timeout(int timeout)
667 {
668         int next_time = 0;
669 
670         uloop_run_depth++;
671 
672         uloop_status = 0;
673         uloop_cancelled = false;
674         do {
675                 uloop_process_timeouts();
676 
677                 if (do_sigchld)
678                         uloop_handle_processes();
679 
680                 if (uloop_cancelled)
681                         break;
682 
683                 next_time = uloop_get_next_timeout();
684                 if (timeout >= 0 && (next_time < 0 || timeout < next_time))
685                                 next_time = timeout;
686                 uloop_run_events(next_time);
687         } while (!uloop_cancelled && timeout < 0);
688 
689         --uloop_run_depth;
690 
691         return uloop_status;
692 }
693 
694 void uloop_done(void)
695 {
696         uloop_setup_signals(false);
697 
698         if (poll_fd >= 0) {
699                 close(poll_fd);
700                 poll_fd = -1;
701         }
702 
703         if (waker_pipe >= 0) {
704                 uloop_fd_delete(&waker_fd);
705                 close(waker_pipe);
706                 close(waker_fd.fd);
707                 waker_pipe = -1;
708         }
709 
710         uloop_clear_timeouts();
711         uloop_clear_processes();
712 }
713 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt