X-Git-Url: http://git.archive.openwrt.org/?p=project%2Flibubox.git;a=blobdiff_plain;f=uloop.c;h=f226f505b417b479bc8d215bd77d4830055cbec6;hp=a263a01c5f3ed457d54dcbebdcea45f8ea92d934;hb=309d7d456f1934a75755504791ad23554a3359d6;hpb=cd086c7c1558eb5816711f4fdc6e21524a01ddca diff --git a/uloop.c b/uloop.c index a263a01..f226f50 100644 --- a/uloop.c +++ b/uloop.c @@ -22,6 +22,15 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include + #include "uloop.h" #ifdef USE_KQUEUE @@ -30,30 +39,29 @@ #ifdef USE_EPOLL #include #endif +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #ifndef ARRAY_SIZE #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #endif #define ULOOP_MAX_EVENTS 10 -struct uloop_timeout *first_timeout; -static int poll_fd; -static bool cancel; +static struct list_head timeouts = LIST_HEAD_INIT(timeouts); +static struct list_head processes = LIST_HEAD_INIT(processes); + +static int poll_fd = -1; +bool uloop_cancelled = false; +bool uloop_handle_sigchld = true; +static bool do_sigchld = false; #ifdef USE_KQUEUE int uloop_init(void) { + if (poll_fd >= 0) + return 0; + poll_fd = kqueue(); if (poll_fd < 0) return -1; @@ -94,7 +102,7 @@ static int register_poll(struct uloop_fd *fd, unsigned int flags) if (changed & ULOOP_WRITE) { uint16_t kflags = get_flags(flags, ULOOP_WRITE); - EV_SET(&ev[nev++], fd->fd, EVFILT_READ, kflags, 0, 0, fd); + EV_SET(&ev[nev++], fd->fd, EVFILT_WRITE, kflags, 0, 0, fd); } if (nev && (kevent(poll_fd, ev, nev, NULL, 0, &timeout) == -1)) @@ -118,7 +126,7 @@ static void uloop_run_events(int timeout) if (timeout > 0) { ts.tv_sec = timeout / 1000; - ts.tv_nsec = timeout * 1000000; + ts.tv_nsec = (timeout % 1000) * 1000000; } nfds = kevent(poll_fd, NULL, 0, events, ARRAY_SIZE(events), timeout > 0 ? &ts : NULL); @@ -160,6 +168,9 @@ static void uloop_run_events(int timeout) int uloop_init(void) { + if (poll_fd >= 0) + return 0; + poll_fd = epoll_create(32); if (poll_fd < 0) return -1; @@ -263,25 +274,20 @@ static int tv_diff(struct timeval *t1, struct timeval *t2) int uloop_timeout_add(struct uloop_timeout *timeout) { - struct uloop_timeout **head = &first_timeout; - struct uloop_timeout *prev = NULL; + struct uloop_timeout *tmp; + struct list_head *h = &timeouts; if (timeout->pending) return -1; - while (*head) { - if (tv_diff(&(*head)->time, &timeout->time) > 0) + list_for_each_entry(tmp, &timeouts, list) { + if (tv_diff(&tmp->time, &timeout->time) > 0) { + h = &tmp->list; break; - - prev = *head; - head = &(*head)->next; + } } - timeout->prev = prev; - timeout->next = *head; - if (timeout->next) - timeout->next->prev = timeout; - *head = timeout; + list_add_tail(&timeout->list, h); timeout->pending = true; return 0; @@ -312,41 +318,106 @@ int uloop_timeout_cancel(struct uloop_timeout *timeout) if (!timeout->pending) return -1; - if (timeout->prev) - timeout->prev->next = timeout->next; - else - first_timeout = timeout->next; + list_del(&timeout->list); + timeout->pending = false; + + return 0; +} - if (timeout->next) - timeout->next->prev = timeout->prev; +int uloop_process_add(struct uloop_process *p) +{ + struct uloop_process *tmp; + struct list_head *h = &processes; - timeout->pending = false; + if (p->pending) + return -1; + + list_for_each_entry(tmp, &processes, list) { + if (tmp->pid > p->pid) { + h = &tmp->list; + break; + } + } + + list_add_tail(&p->list, h); + p->pending = true; return 0; } +int uloop_process_delete(struct uloop_process *p) +{ + if (!p->pending) + return -1; + + list_del(&p->list); + p->pending = false; + + return 0; +} + +static void uloop_handle_processes(void) +{ + struct uloop_process *p, *tmp; + pid_t pid; + int ret; + + do_sigchld = false; + + while (1) { + pid = waitpid(-1, &ret, WNOHANG); + if (pid <= 0) + return; + + list_for_each_entry_safe(p, tmp, &processes, list) { + if (p->pid < pid) + continue; + + if (p->pid > pid) + break; + + uloop_process_delete(p); + p->cb(p, ret); + } + } + +} + static void uloop_handle_sigint(int signo) { - cancel = true; + uloop_cancelled = true; +} + +static void uloop_sigchld(int signo) +{ + do_sigchld = true; } static void uloop_setup_signals(void) { struct sigaction s; + memset(&s, 0, sizeof(struct sigaction)); s.sa_handler = uloop_handle_sigint; s.sa_flags = 0; sigaction(SIGINT, &s, NULL); + + if (uloop_handle_sigchld) { + s.sa_handler = uloop_sigchld; + sigaction(SIGCHLD, &s, NULL); + } } static int uloop_get_next_timeout(struct timeval *tv) { + struct uloop_timeout *timeout; int diff; - if (!first_timeout) + if (list_empty(&timeouts)) return -1; - diff = tv_diff(&first_timeout->time, tv); + timeout = list_first_entry(&timeouts, struct uloop_timeout, list); + diff = tv_diff(&timeout->time, tv); if (diff < 0) return 0; @@ -355,38 +426,41 @@ static int uloop_get_next_timeout(struct timeval *tv) static void uloop_process_timeouts(struct timeval *tv) { - struct uloop_timeout *timeout; + struct uloop_timeout *t, *tmp; - while (first_timeout) { - if (tv_diff(&first_timeout->time, tv) > 0) + list_for_each_entry_safe(t, tmp, &timeouts, list) { + if (tv_diff(&t->time, tv) > 0) break; - timeout = first_timeout; - uloop_timeout_cancel(timeout); - if (timeout->cb) - timeout->cb(timeout); + uloop_timeout_cancel(t); + if (t->cb) + t->cb(t); } } -void uloop_end(void) -{ - cancel = true; -} - void uloop_run(void) { struct timeval tv; uloop_setup_signals(); - while(!cancel) + while(!uloop_cancelled) { gettimeofday(&tv, NULL); uloop_process_timeouts(&tv); + if (uloop_cancelled) + break; + + if (do_sigchld) + uloop_handle_processes(); uloop_run_events(uloop_get_next_timeout(&tv)); } } void uloop_done(void) { + if (poll_fd < 0) + return; + close(poll_fd); + poll_fd = -1; }