X-Git-Url: http://git.archive.openwrt.org/?p=project%2Flibubox.git;a=blobdiff_plain;f=uloop.c;h=9fedcce078e836ebb46c8997838aac7c8f7336c4;hp=a3ba3ad550c6a8c7383b7e167c697e2fd5a08835;hb=213122a0830e1ba3a05013b5cb5d17c49af13282;hpb=8b0d9331547b7d784278e38564f416d61387082c diff --git a/uloop.c b/uloop.c index a3ba3ad..9fedcce 100644 --- a/uloop.c +++ b/uloop.c @@ -38,6 +38,19 @@ #endif #include +struct uloop_fd_event { + struct uloop_fd *fd; + unsigned int events; +}; + +struct uloop_fd_stack { + struct uloop_fd_stack *next; + struct uloop_fd *fd; + unsigned int events; +}; + +static struct uloop_fd_stack *fd_stack = NULL; + #define ULOOP_MAX_EVENTS 10 static struct list_head timeouts = LIST_HEAD_INIT(timeouts); @@ -45,8 +58,9 @@ 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; + +static struct uloop_fd_event cur_fds[ULOOP_MAX_EVENTS]; static int cur_fd, cur_nfds; #ifdef USE_KQUEUE @@ -132,22 +146,12 @@ static int register_poll(struct uloop_fd *fd, unsigned int flags) return register_kevent(fd, flags); } -int uloop_fd_delete(struct uloop_fd *sock) +static int __uloop_fd_delete(struct uloop_fd *fd) { - 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); + return register_poll(fd, 0); } -static void uloop_run_events(int timeout) +static int uloop_fetch_events(int timeout) { struct timespec ts; int nfds, n; @@ -158,17 +162,19 @@ static void uloop_run_events(int timeout) } nfds = kevent(poll_fd, NULL, 0, events, ARRAY_SIZE(events), timeout >= 0 ? &ts : NULL); - for(n = 0; n < nfds; ++n) - { + for (n = 0; n < nfds; n++) { + struct uloop_fd_event *cur = &cur_fds[n]; struct uloop_fd *u = events[n].udata; unsigned int ev = 0; + cur->fd = u; if (!u) continue; if (events[n].flags & EV_ERROR) { u->error = true; - uloop_fd_delete(u); + if (!(u->flags & ULOOP_ERROR_CB)) + uloop_fd_delete(u); } if(events[n].filter == EVFILT_READ) @@ -179,19 +185,16 @@ static void uloop_run_events(int timeout) if (events[n].flags & EV_EOF) u->eof = true; else if (!ev) - continue; + cur->fd = NULL; - if (u->cb) { - cur_fd = n; - cur_nfds = nfds; - u->cb(u, ev); - if (u->flags & ULOOP_EDGE_DEFER) { - u->flags &= ~ULOOP_EDGE_DEFER; - register_kevent(u, u->flags); - } + cur->events = ev; + if (u->flags & ULOOP_EDGE_DEFER) { + u->flags &= ~ULOOP_EDGE_DEFER; + u->flags |= ULOOP_EDGE_TRIGGER; + register_kevent(u, u->flags); } } - cur_nfds = 0; + return nfds; } #endif @@ -236,46 +239,43 @@ static int register_poll(struct uloop_fd *fd, unsigned int flags) ev.data.fd = fd->fd; ev.data.ptr = fd; + fd->flags = 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) +static 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; + sock->flags = 0; return epoll_ctl(poll_fd, EPOLL_CTL_DEL, sock->fd, 0); } -static void uloop_run_events(int timeout) +static int uloop_fetch_events(int timeout) { int n, nfds; nfds = epoll_wait(poll_fd, events, ARRAY_SIZE(events), timeout); - for(n = 0; n < nfds; ++n) - { + for (n = 0; n < nfds; ++n) { + struct uloop_fd_event *cur = &cur_fds[n]; struct uloop_fd *u = events[n].data.ptr; unsigned int ev = 0; + cur->fd = u; if (!u) continue; - if(events[n].events & (EPOLLERR|EPOLLHUP)) { + if (events[n].events & (EPOLLERR|EPOLLHUP)) { u->error = true; - uloop_fd_delete(u); + if (!(u->flags & ULOOP_ERROR_CB)) + uloop_fd_delete(u); } - if(!(events[n].events & (EPOLLRDHUP|EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP))) + if(!(events[n].events & (EPOLLRDHUP|EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP))) { + cur->fd = NULL; continue; + } if(events[n].events & EPOLLRDHUP) u->eof = true; @@ -286,22 +286,92 @@ static void uloop_run_events(int timeout) if(events[n].events & EPOLLOUT) ev |= ULOOP_WRITE; - if(u->cb) { - cur_fd = n; - cur_nfds = nfds; - u->cb(u, ev); - } + cur->events = ev; } - cur_nfds = 0; + + return nfds; } #endif +static bool uloop_fd_stack_event(struct uloop_fd *fd, int events) +{ + struct uloop_fd_stack *cur; + + /* + * Do not buffer events for level-triggered fds, they will keep firing. + * Caller needs to take care of recursion issues. + */ + if (!(fd->flags & ULOOP_EDGE_TRIGGER)) + return false; + + for (cur = fd_stack; cur; cur = cur->next) { + if (cur->fd != fd) + continue; + + if (events < 0) + cur->fd = NULL; + else + cur->events |= events | ULOOP_EVENT_BUFFERED; + + return true; + } + + return false; +} + +static void uloop_run_events(int timeout) +{ + struct uloop_fd_event *cur; + struct uloop_fd *fd; + + if (!cur_nfds) { + cur_fd = 0; + cur_nfds = uloop_fetch_events(timeout); + if (cur_nfds < 0) + cur_nfds = 0; + } + + while (cur_nfds > 0) { + struct uloop_fd_stack stack_cur; + unsigned int events; + + cur = &cur_fds[cur_fd++]; + cur_nfds--; + + fd = cur->fd; + events = cur->events; + if (!fd) + continue; + + if (!fd->cb) + continue; + + if (uloop_fd_stack_event(fd, cur->events)) + continue; + + stack_cur.next = fd_stack; + stack_cur.fd = fd; + fd_stack = &stack_cur; + do { + stack_cur.events = 0; + fd->cb(fd, events); + events = stack_cur.events & ULOOP_EVENT_MASK; + } while (stack_cur.fd && events); + fd_stack = stack_cur.next; + + return; + } +} + int uloop_fd_add(struct uloop_fd *sock, unsigned int flags) { unsigned int fl; int ret; + if (!(flags & (ULOOP_READ | ULOOP_WRITE))) + return uloop_fd_delete(sock); + if (!sock->registered && !(flags & ULOOP_BLOCKING)) { fl = fcntl(sock->fd, F_GETFL, 0); fl |= O_NONBLOCK; @@ -314,11 +384,31 @@ int uloop_fd_add(struct uloop_fd *sock, unsigned int flags) sock->registered = true; sock->eof = false; + sock->error = false; out: return ret; } +int uloop_fd_delete(struct uloop_fd *fd) +{ + int i; + + for (i = 0; i < cur_nfds; i++) { + if (cur_fds[cur_fd + i].fd != fd) + continue; + + cur_fds[cur_fd + i].fd = NULL; + } + + if (!fd->registered) + return 0; + + fd->registered = false; + uloop_fd_stack_event(fd, -1); + return __uloop_fd_delete(fd); +} + static int tv_diff(struct timeval *t1, struct timeval *t2) { return @@ -468,19 +558,28 @@ static void uloop_sigchld(int signo) do_sigchld = true; } -static void uloop_setup_signals(void) +static void uloop_setup_signals(bool add) { + static struct sigaction old_sigint, old_sigchld; 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); + if (add) { + s.sa_handler = uloop_handle_sigint; + s.sa_flags = 0; + } else { + s = old_sigint; } + + sigaction(SIGINT, &s, &old_sigint); + + if (add) + s.sa_handler = uloop_sigchld; + else + s = old_sigchld; + + sigaction(SIGCHLD, &s, &old_sigchld); } static int uloop_get_next_timeout(struct timeval *tv) @@ -533,9 +632,17 @@ static void uloop_clear_processes(void) void uloop_run(void) { + static int recursive_calls = 0; struct timeval tv; - uloop_setup_signals(); + /* + * Handlers are only updated for the first call to uloop_run() (and restored + * when this call is done). + */ + if (!recursive_calls++) + uloop_setup_signals(true); + + uloop_cancelled = false; while(!uloop_cancelled) { uloop_gettime(&tv); @@ -545,8 +652,12 @@ void uloop_run(void) if (do_sigchld) uloop_handle_processes(); + uloop_gettime(&tv); uloop_run_events(uloop_get_next_timeout(&tv)); } + + if (!--recursive_calls) + uloop_setup_signals(false); } void uloop_done(void)