X-Git-Url: http://git.archive.openwrt.org/?p=project%2Flibubox.git;a=blobdiff_plain;f=uloop.c;h=9fedcce078e836ebb46c8997838aac7c8f7336c4;hp=bf13199f881db3b6d5cb92fd3002e846fa888304;hb=213122a0830e1ba3a05013b5cb5d17c49af13282;hpb=35cee2c2067246b5e3dede9caac5d8b7a60ccba1 diff --git a/uloop.c b/uloop.c index bf13199..9fedcce 100644 --- a/uloop.c +++ b/uloop.c @@ -43,6 +43,14 @@ struct uloop_fd_event { 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); @@ -50,7 +58,6 @@ 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]; @@ -166,7 +173,8 @@ static int uloop_fetch_events(int timeout) 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) @@ -260,7 +268,8 @@ static int uloop_fetch_events(int timeout) 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))) { @@ -285,6 +294,32 @@ static int uloop_fetch_events(int timeout) #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; @@ -298,17 +333,33 @@ static void uloop_run_events(int timeout) } 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; - fd->cb(fd, cur->events); + 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; } } @@ -333,6 +384,7 @@ int uloop_fd_add(struct uloop_fd *sock, unsigned int flags) sock->registered = true; sock->eof = false; + sock->error = false; out: return ret; @@ -342,16 +394,18 @@ int uloop_fd_delete(struct uloop_fd *fd) { int i; - if (!fd->registered) - return 0; - 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); } @@ -504,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) @@ -569,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); @@ -581,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)