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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt