• 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 /*
 64  * Entries the signal and process dispatch loops are about to visit. A callback
 65  * may delete (and free) an arbitrary sibling entry; the matching *_delete()
 66  * advances these so the loops never dereference a freed entry.
 67  */
 68 static struct uloop_signal *signal_next;
 69 static struct uloop_process *process_next;
 70 
 71 static int poll_fd = -1;
 72 bool uloop_cancelled = false;
 73 bool uloop_handle_sigchld = true;
 74 static int uloop_status = 0;
 75 static volatile sig_atomic_t do_sigchld = 0;
 76 
 77 static struct uloop_fd_event cur_fds[ULOOP_MAX_EVENTS];
 78 static int cur_fd, cur_nfds;
 79 static int uloop_run_depth = 0;
 80 
 81 uloop_fd_handler uloop_fd_set_cb = NULL;
 82 
 83 int uloop_fd_add(struct uloop_fd *sock, unsigned int flags);
 84 
 85 #ifdef USE_KQUEUE
 86 #include "uloop-kqueue.c"
 87 #endif
 88 
 89 #ifdef USE_EPOLL
 90 #include "uloop-epoll.c"
 91 #endif
 92 
 93 static void set_signo(uint64_t *signums, int signo)
 94 {
 95         if (signo >= 1 && signo <= 64)
 96                 *signums |= (UINT64_C(1) << (signo - 1));
 97 }
 98 
 99 static bool get_signo(uint64_t signums, int signo)
100 {
101         return (signo >= 1) && (signo <= 64) && (signums & (UINT64_C(1) << (signo - 1)));
102 }
103 
104 static struct uloop_signal *uloop_signal_next_entry(struct uloop_signal *s)
105 {
106         if (list_is_last(&s->list, &signals))
107                 return NULL;
108 
109         return list_next_entry(s, list);
110 }
111 
112 static void signal_consume(struct uloop_fd *fd, unsigned int events)
113 {
114         struct uloop_signal *usig;
115         uint64_t signums = 0;
116         uint8_t buf[32];
117         ssize_t nsigs;
118 
119         do {
120                 nsigs = read(fd->fd, buf, sizeof(buf));
121 
122                 for (ssize_t i = 0; i < nsigs; i++)
123                         set_signo(&signums, buf[i]);
124         }
125         while (nsigs > 0);
126 
127         signal_next = list_empty(&signals) ? NULL :
128                 list_first_entry(&signals, struct uloop_signal, list);
129 
130         while ((usig = signal_next) != NULL) {
131                 signal_next = uloop_signal_next_entry(usig);
132                 if (get_signo(signums, usig->signo))
133                         usig->cb(usig);
134         }
135 }
136 
137 static int waker_pipe = -1;
138 static struct uloop_fd waker_fd = {
139         .fd = -1,
140         .cb = signal_consume,
141 };
142 
143 static void waker_init_fd(int fd)
144 {
145         int flags;
146 
147         flags = fcntl(fd, F_GETFD);
148         if (flags >= 0)
149                 fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
150 
151         flags = fcntl(fd, F_GETFL);
152         if (flags >= 0)
153                 fcntl(fd, F_SETFL, flags | O_NONBLOCK);
154 }
155 
156 static int waker_init(void)
157 {
158         int fds[2];
159 
160         if (waker_pipe >= 0)
161                 return 0;
162 
163         if (pipe(fds) < 0)
164                 return -1;
165 
166         waker_init_fd(fds[0]);
167         waker_init_fd(fds[1]);
168         waker_pipe = fds[1];
169 
170         waker_fd.fd = fds[0];
171         waker_fd.cb = signal_consume;
172         uloop_fd_add(&waker_fd, ULOOP_READ);
173 
174         return 0;
175 }
176 
177 static void uloop_setup_signals(bool add);
178 
179 int uloop_init(void)
180 {
181         if (uloop_init_pollfd() < 0)
182                 return -1;
183 
184         if (waker_init() < 0) {
185                 uloop_done();
186                 return -1;
187         }
188 
189         uloop_setup_signals(true);
190 
191         return 0;
192 }
193 
194 static bool uloop_fd_stack_event(struct uloop_fd *fd, int events)
195 {
196         struct uloop_fd_stack *cur;
197 
198         /*
199          * Do not buffer events for level-triggered fds, they will keep firing.
200          * Caller needs to take care of recursion issues.
201          */
202         if (!(fd->flags & ULOOP_EDGE_TRIGGER))
203                 return false;
204 
205         for (cur = fd_stack; cur; cur = cur->next) {
206                 if (cur->fd != fd)
207                         continue;
208 
209                 if (events < 0)
210                         cur->fd = NULL;
211                 else
212                         cur->events |= events | ULOOP_EVENT_BUFFERED;
213 
214                 return true;
215         }
216 
217         return false;
218 }
219 
220 static void uloop_run_events(int64_t timeout)
221 {
222         struct uloop_fd_event *cur;
223         struct uloop_fd *fd;
224 
225         if (!cur_nfds) {
226                 cur_fd = 0;
227                 cur_nfds = uloop_fetch_events(timeout);
228                 if (cur_nfds < 0)
229                         cur_nfds = 0;
230         }
231 
232         while (cur_nfds > 0) {
233                 struct uloop_fd_stack stack_cur;
234                 unsigned int events;
235 
236                 cur = &cur_fds[cur_fd++];
237                 cur_nfds--;
238 
239                 fd = cur->fd;
240                 events = cur->events;
241                 if (!fd)
242                         continue;
243 
244                 if (!fd->cb)
245                         continue;
246 
247                 if (uloop_fd_stack_event(fd, cur->events))
248                         continue;
249 
250                 stack_cur.next = fd_stack;
251                 stack_cur.fd = fd;
252                 fd_stack = &stack_cur;
253                 do {
254                         stack_cur.events = 0;
255                         fd->cb(fd, events);
256                         events = stack_cur.events & ULOOP_EVENT_MASK;
257                 } while (stack_cur.fd && events);
258                 fd_stack = stack_cur.next;
259 
260                 return;
261         }
262 }
263 
264 int uloop_fd_add(struct uloop_fd *sock, unsigned int flags)
265 {
266         int fl;
267         int ret;
268 
269         if (!(flags & (ULOOP_READ | ULOOP_WRITE | ULOOP_PRIORITY)))
270                 return uloop_fd_delete(sock);
271 
272         if (!sock->registered && !(flags & ULOOP_BLOCKING)) {
273                 fl = fcntl(sock->fd, F_GETFL, 0);
274                 if (fl >= 0)
275                         fcntl(sock->fd, F_SETFL, fl | O_NONBLOCK);
276         }
277 
278         ret = register_poll(sock, flags);
279         if (ret < 0)
280                 goto out;
281 
282         if (uloop_fd_set_cb)
283                 uloop_fd_set_cb(sock, flags);
284 
285         sock->flags = flags;
286         sock->registered = true;
287         sock->eof = false;
288         sock->error = false;
289 
290 out:
291         return ret;
292 }
293 
294 int uloop_fd_delete(struct uloop_fd *fd)
295 {
296         int ret;
297         int i;
298 
299         for (i = 0; i < cur_nfds; i++) {
300                 if (cur_fds[cur_fd + i].fd != fd)
301                         continue;
302 
303                 cur_fds[cur_fd + i].fd = NULL;
304         }
305 
306         if (!fd->registered)
307                 return 0;
308 
309         if (uloop_fd_set_cb)
310                 uloop_fd_set_cb(fd, 0);
311 
312         fd->registered = false;
313         uloop_fd_stack_event(fd, -1);
314         ret = __uloop_fd_delete(fd);
315         fd->flags = 0;
316 
317         return ret;
318 }
319 
320 static int64_t tv_diff(struct timeval *t1, struct timeval *t2)
321 {
322         return
323                 (t1->tv_sec - t2->tv_sec) * 1000 +
324                 (t1->tv_usec - t2->tv_usec) / 1000;
325 }
326 
327 int uloop_timeout_add(struct uloop_timeout *timeout)
328 {
329         struct uloop_timeout *tmp;
330         struct list_head *h = &timeouts;
331 
332         if (timeout->pending)
333                 return -1;
334 
335         list_for_each_entry(tmp, &timeouts, list) {
336                 if (tv_diff(&tmp->time, &timeout->time) > 0) {
337                         h = &tmp->list;
338                         break;
339                 }
340         }
341 
342         list_add_tail(&timeout->list, h);
343         timeout->pending = true;
344 
345         return 0;
346 }
347 
348 static void uloop_gettime(struct timeval *tv)
349 {
350         struct timespec ts;
351 
352         clock_gettime(CLOCK_MONOTONIC, &ts);
353         tv->tv_sec = ts.tv_sec;
354         tv->tv_usec = ts.tv_nsec / 1000;
355 }
356 
357 int uloop_timeout_set(struct uloop_timeout *timeout, int msecs)
358 {
359         struct timeval *time = &timeout->time;
360 
361         if (timeout->pending)
362                 uloop_timeout_cancel(timeout);
363 
364         uloop_gettime(time);
365 
366         time->tv_sec += msecs / 1000;
367         time->tv_usec += (msecs % 1000) * 1000;
368 
369         if (time->tv_usec > 1000000) {
370                 time->tv_sec++;
371                 time->tv_usec -= 1000000;
372         }
373 
374         return uloop_timeout_add(timeout);
375 }
376 
377 int uloop_timeout_cancel(struct uloop_timeout *timeout)
378 {
379         if (!timeout->pending)
380                 return -1;
381 
382         list_del(&timeout->list);
383         timeout->pending = false;
384 
385         return 0;
386 }
387 
388 int uloop_timeout_remaining(struct uloop_timeout *timeout)
389 {
390         int64_t td;
391         struct timeval now;
392 
393         if (!timeout->pending)
394                 return -1;
395 
396         uloop_gettime(&now);
397 
398         td = tv_diff(&timeout->time, &now);
399 
400         if (td > INT_MAX)
401                 return INT_MAX;
402         else if (td < INT_MIN)
403                 return INT_MIN;
404         else
405                 return (int)td;
406 }
407 
408 int64_t uloop_timeout_remaining64(struct uloop_timeout *timeout)
409 {
410         struct timeval now;
411 
412         if (!timeout->pending)
413                 return -1;
414 
415         uloop_gettime(&now);
416 
417         return tv_diff(&timeout->time, &now);
418 }
419 
420 int uloop_process_add(struct uloop_process *p)
421 {
422         struct uloop_process *tmp;
423         struct list_head *h = &processes;
424 
425         if (p->pending)
426                 return -1;
427 
428         list_for_each_entry(tmp, &processes, list) {
429                 if (tmp->pid > p->pid) {
430                         h = &tmp->list;
431                         break;
432                 }
433         }
434 
435         list_add_tail(&p->list, h);
436         p->pending = true;
437 
438         return 0;
439 }
440 
441 static struct uloop_process *uloop_process_next_entry(struct uloop_process *p)
442 {
443         if (list_is_last(&p->list, &processes))
444                 return NULL;
445 
446         return list_next_entry(p, list);
447 }
448 
449 int uloop_process_delete(struct uloop_process *p)
450 {
451         if (!p->pending)
452                 return -1;
453 
454         if (process_next == p)
455                 process_next = uloop_process_next_entry(p);
456 
457         list_del(&p->list);
458         p->pending = false;
459 
460         return 0;
461 }
462 
463 static void uloop_handle_processes(void)
464 {
465         struct uloop_process *p;
466         pid_t pid;
467         int ret;
468 
469         do_sigchld = 0;
470 
471         while (1) {
472                 pid = waitpid(-1, &ret, WNOHANG);
473                 if (pid < 0 && errno == EINTR)
474                         continue;
475 
476                 if (pid <= 0)
477                         break;
478 
479                 process_next = list_empty(&processes) ? NULL :
480                         list_first_entry(&processes, struct uloop_process, list);
481 
482                 while ((p = process_next) != NULL) {
483                         process_next = uloop_process_next_entry(p);
484 
485                         if (p->pid < pid)
486                                 continue;
487 
488                         if (p->pid > pid)
489                                 break;
490 
491                         uloop_process_delete(p);
492                         p->cb(p, ret);
493                 }
494         }
495 
496         process_next = NULL;
497 }
498 
499 int uloop_interval_set(struct uloop_interval *timer, unsigned int msecs)
500 {
501         return timer_register(timer, msecs);
502 }
503 
504 int uloop_interval_cancel(struct uloop_interval *timer)
505 {
506         return timer_remove(timer);
507 }
508 
509 int64_t uloop_interval_remaining(struct uloop_interval *timer)
510 {
511         return timer_next(timer);
512 }
513 
514 static void uloop_signal_wake(int signo)
515 {
516         uint8_t sigbyte = signo;
517 
518         if (signo == SIGCHLD)
519                 do_sigchld = 1;
520 
521         do {
522                 if (write(waker_pipe, &sigbyte, 1) < 0) {
523                         if (errno == EINTR)
524                                 continue;
525                 }
526                 break;
527         } while (1);
528 }
529 
530 static void uloop_handle_sigint(int signo)
531 {
532         uloop_status = signo;
533         uloop_cancelled = true;
534         uloop_signal_wake(signo);
535 }
536 
537 static void uloop_install_handler(int signum, void (*handler)(int), struct sigaction* old, bool add)
538 {
539         struct sigaction s;
540         struct sigaction *act;
541 
542         act = NULL;
543         sigaction(signum, NULL, &s);
544 
545         if (add) {
546                 if (s.sa_handler == SIG_DFL) { /* Do not override existing custom signal handlers */
547                         memcpy(old, &s, sizeof(struct sigaction));
548                         s.sa_handler = handler;
549                         s.sa_flags = 0;
550                         act = &s;
551                 }
552         }
553         else if (s.sa_handler == handler) { /* Do not restore if someone modified our handler */
554                         act = old;
555         }
556 
557         if (act != NULL)
558                 sigaction(signum, act, NULL);
559 }
560 
561 static void uloop_ignore_signal(int signum, bool ignore)
562 {
563         struct sigaction s;
564         void *new_handler = NULL;
565 
566         sigaction(signum, NULL, &s);
567 
568         if (ignore) {
569                 if (s.sa_handler == SIG_DFL) /* Ignore only if there isn't any custom handler */
570                         new_handler = SIG_IGN;
571         } else {
572                 if (s.sa_handler == SIG_IGN) /* Restore only if noone modified our SIG_IGN */
573                         new_handler = SIG_DFL;
574         }
575 
576         if (new_handler) {
577                 s.sa_handler = new_handler;
578                 s.sa_flags = 0;
579                 sigaction(signum, &s, NULL);
580         }
581 }
582 
583 static void uloop_setup_signals(bool add)
584 {
585         static struct sigaction old_sigint, old_sigchld, old_sigterm;
586 
587         uloop_install_handler(SIGINT, uloop_handle_sigint, &old_sigint, add);
588         uloop_install_handler(SIGTERM, uloop_handle_sigint, &old_sigterm, add);
589 
590         if (uloop_handle_sigchld)
591                 uloop_install_handler(SIGCHLD, uloop_signal_wake, &old_sigchld, add);
592 
593         uloop_ignore_signal(SIGPIPE, add);
594 }
595 
596 int uloop_signal_add(struct uloop_signal *s)
597 {
598         struct list_head *h = &signals;
599         struct uloop_signal *tmp;
600         struct sigaction sa;
601 
602         if (s->pending)
603                 return -1;
604 
605         list_for_each_entry(tmp, &signals, list) {
606                 if (tmp->signo > s->signo) {
607                         h = &tmp->list;
608                         break;
609                 }
610         }
611 
612         list_add_tail(&s->list, h);
613         s->pending = true;
614 
615         sigaction(s->signo, NULL, &s->orig);
616 
617         if (s->orig.sa_handler != uloop_signal_wake) {
618                 sa.sa_handler = uloop_signal_wake;
619                 sa.sa_flags = 0;
620                 sigemptyset(&sa.sa_mask);
621                 sigaction(s->signo, &sa, NULL);
622         }
623 
624         return 0;
625 }
626 
627 int uloop_signal_delete(struct uloop_signal *s)
628 {
629         struct uloop_signal *tmp;
630 
631         if (!s->pending)
632                 return -1;
633 
634         if (signal_next == s)
635                 signal_next = uloop_signal_next_entry(s);
636 
637         list_del(&s->list);
638         s->pending = false;
639 
640         /* Only the first watcher registered for a signal saved the real
641          * original disposition; later ones saved uloop_signal_wake. */
642         if (s->orig.sa_handler == uloop_signal_wake)
643                 return 0;
644 
645         list_for_each_entry(tmp, &signals, list) {
646                 if (tmp->signo != s->signo)
647                         continue;
648 
649                 /* Other watchers remain for this signal, hand the saved
650                  * disposition over to one of them so it can be restored once
651                  * the last watcher is removed. */
652                 tmp->orig = s->orig;
653                 return 0;
654         }
655 
656         sigaction(s->signo, &s->orig, NULL);
657 
658         return 0;
659 }
660 
661 int uloop_get_next_timeout(void)
662 {
663         struct uloop_timeout *timeout;
664         struct timeval tv;
665         int64_t diff;
666 
667         if (list_empty(&timeouts))
668                 return -1;
669 
670         uloop_gettime(&tv);
671 
672         timeout = list_first_entry(&timeouts, struct uloop_timeout, list);
673         diff = tv_diff(&timeout->time, &tv);
674         if (diff < 0)
675                 return 0;
676         if (diff > INT_MAX)
677                 return INT_MAX;
678 
679         return diff;
680 }
681 
682 static void uloop_process_timeouts(void)
683 {
684         struct uloop_timeout *t;
685         struct timeval tv;
686 
687         if (list_empty(&timeouts))
688                 return;
689 
690         uloop_gettime(&tv);
691         while (!list_empty(&timeouts)) {
692                 t = list_first_entry(&timeouts, struct uloop_timeout, list);
693 
694                 if (tv_diff(&t->time, &tv) > 0)
695                         break;
696 
697                 uloop_timeout_cancel(t);
698                 if (t->cb)
699                         t->cb(t);
700         }
701 }
702 
703 static void uloop_clear_timeouts(void)
704 {
705         struct uloop_timeout *t, *tmp;
706 
707         list_for_each_entry_safe(t, tmp, &timeouts, list)
708                 uloop_timeout_cancel(t);
709 }
710 
711 static void uloop_clear_processes(void)
712 {
713         struct uloop_process *p, *tmp;
714 
715         list_for_each_entry_safe(p, tmp, &processes, list)
716                 uloop_process_delete(p);
717 }
718 
719 bool uloop_cancelling(void)
720 {
721         return uloop_run_depth > 0 && uloop_cancelled;
722 }
723 
724 int uloop_run_timeout(int timeout)
725 {
726         int next_time = 0;
727 
728         uloop_run_depth++;
729 
730         uloop_status = 0;
731         uloop_cancelled = false;
732         do {
733                 uloop_process_timeouts();
734 
735                 if (do_sigchld)
736                         uloop_handle_processes();
737 
738                 if (uloop_cancelled)
739                         break;
740 
741                 next_time = uloop_get_next_timeout();
742                 if (timeout >= 0 && (next_time < 0 || timeout < next_time))
743                                 next_time = timeout;
744                 uloop_run_events(next_time);
745         } while (!uloop_cancelled && timeout < 0);
746 
747         --uloop_run_depth;
748 
749         return uloop_status;
750 }
751 
752 void uloop_done(void)
753 {
754         uloop_setup_signals(false);
755 
756         if (poll_fd >= 0) {
757                 close(poll_fd);
758                 poll_fd = -1;
759         }
760 
761         if (waker_pipe >= 0) {
762                 uloop_fd_delete(&waker_fd);
763                 close(waker_pipe);
764                 close(waker_fd.fd);
765                 waker_pipe = -1;
766         }
767 
768         uloop_clear_timeouts();
769         uloop_clear_processes();
770 }
771 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt