X-Git-Url: http://git.archive.openwrt.org/?p=project%2Flibubox.git;a=blobdiff_plain;f=uloop.c;h=aa0975051140a9325fbb288fb81b959b9f56296c;hp=e361c370e9aee9d0f10b63f093ff8a93b0178dbb;hb=6e7e8a1a910ec00511acc7c98653f57613ec5d0b;hpb=a8032be64c4d03a98af47e9f4d93ddc137d23733 diff --git a/uloop.c b/uloop.c index e361c37..aa09750 100644 --- a/uloop.c +++ b/uloop.c @@ -39,6 +39,7 @@ #ifdef USE_EPOLL #include #endif +#include #ifndef ARRAY_SIZE @@ -53,6 +54,7 @@ static int poll_fd = -1; bool uloop_cancelled = false; bool uloop_handle_sigchld = true; static bool do_sigchld = false; +static int cur_fd, cur_nfds; #ifdef USE_KQUEUE @@ -83,12 +85,15 @@ static uint16_t get_flags(unsigned int flags, unsigned int mask) return kflags; } +static struct kevent events[ULOOP_MAX_EVENTS]; + static int register_poll(struct uloop_fd *fd, unsigned int flags) { struct timespec timeout = { 0, 0 }; struct kevent ev[2]; unsigned int changed; int nev = 0; + unsigned int fl = 0; changed = fd->kqflags ^ flags; if (changed & ULOOP_EDGE_TRIGGER) @@ -104,7 +109,10 @@ static int register_poll(struct uloop_fd *fd, unsigned int flags) EV_SET(&ev[nev++], fd->fd, EVFILT_WRITE, kflags, 0, 0, fd); } - if (nev && (kevent(poll_fd, ev, nev, NULL, 0, &timeout) == -1)) + if (!flags) + fl |= EV_DELETE; + + if (nev && (kevent(poll_fd, ev, nev, NULL, fl, &timeout) == -1)) return -1; fd->kqflags = flags; @@ -113,13 +121,21 @@ static int register_poll(struct uloop_fd *fd, unsigned int flags) int uloop_fd_delete(struct uloop_fd *sock) { + int i; + + for (i = cur_fd + 1; i < cur_nfds; i++) { + if (events[i].udata != sock) + continue; + + events[i].udata = NULL; + } + sock->registered = false; return register_poll(sock, 0); } static void uloop_run_events(int timeout) { - struct kevent events[ULOOP_MAX_EVENTS]; struct timespec ts; int nfds, n; @@ -134,7 +150,10 @@ static void uloop_run_events(int timeout) struct uloop_fd *u = events[n].udata; unsigned int ev = 0; - if(events[n].flags & EV_ERROR) { + if (!u) + continue; + + if (events[n].flags & EV_ERROR) { u->error = true; uloop_fd_delete(u); } @@ -144,14 +163,18 @@ static void uloop_run_events(int timeout) else if (events[n].filter == EVFILT_WRITE) ev |= ULOOP_WRITE; - if(events[n].flags & EV_EOF) + if (events[n].flags & EV_EOF) u->eof = true; else if (!ev) continue; - if(u->cb) + if (u->cb) { + cur_fd = n; + cur_nfds = nfds; u->cb(u, ev); + } } + cur_nfds = 0; } #endif @@ -200,16 +223,25 @@ static int register_poll(struct uloop_fd *fd, unsigned int flags) return epoll_ctl(poll_fd, op, fd->fd, &ev); } +static struct epoll_event events[ULOOP_MAX_EVENTS]; + int uloop_fd_delete(struct uloop_fd *sock) { + int i; + + for (i = cur_fd + 1; i < cur_nfds; i++) { + if (events[i].data.ptr != sock) + continue; + + events[i].data.ptr = NULL; + } sock->registered = false; return epoll_ctl(poll_fd, EPOLL_CTL_DEL, sock->fd, 0); } static void uloop_run_events(int timeout) { - struct epoll_event events[ULOOP_MAX_EVENTS]; - int nfds, n; + int n, nfds; nfds = epoll_wait(poll_fd, events, ARRAY_SIZE(events), timeout); for(n = 0; n < nfds; ++n) @@ -217,12 +249,15 @@ static void uloop_run_events(int timeout) struct uloop_fd *u = events[n].data.ptr; unsigned int ev = 0; - if(events[n].events & EPOLLERR) { + if (!u) + continue; + + if(events[n].events & (EPOLLERR|EPOLLHUP)) { u->error = true; uloop_fd_delete(u); } - if(!(events[n].events & (EPOLLRDHUP|EPOLLIN|EPOLLOUT|EPOLLERR))) + if(!(events[n].events & (EPOLLRDHUP|EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP))) continue; if(events[n].events & EPOLLRDHUP) @@ -234,9 +269,13 @@ static void uloop_run_events(int timeout) if(events[n].events & EPOLLOUT) ev |= ULOOP_WRITE; - if(u->cb) + if(u->cb) { + cur_fd = n; + cur_nfds = nfds; u->cb(u, ev); + } } + cur_nfds = 0; } #endif @@ -425,9 +464,11 @@ static int uloop_get_next_timeout(struct timeval *tv) static void uloop_process_timeouts(struct timeval *tv) { - struct uloop_timeout *t, *tmp; + struct uloop_timeout *t; + + while (!list_empty(&timeouts)) { + t = list_first_entry(&timeouts, struct uloop_timeout, list); - list_for_each_entry_safe(t, tmp, &timeouts, list) { if (tv_diff(&t->time, tv) > 0) break; @@ -437,6 +478,22 @@ static void uloop_process_timeouts(struct timeval *tv) } } +static void uloop_clear_timeouts(void) +{ + struct uloop_timeout *t, *tmp; + + list_for_each_entry_safe(t, tmp, &timeouts, list) + uloop_timeout_cancel(t); +} + +static void uloop_clear_processes(void) +{ + struct uloop_process *p, *tmp; + + list_for_each_entry_safe(p, tmp, &processes, list) + uloop_process_delete(p); +} + void uloop_run(void) { struct timeval tv; @@ -462,4 +519,7 @@ void uloop_done(void) close(poll_fd); poll_fd = -1; + + uloop_clear_timeouts(); + uloop_clear_processes(); }