From 4e3a47a4cb438866bc4b9cb2f5d16226ffb48502 Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Thu, 9 Jun 2016 10:20:32 +0800 Subject: [PATCH] uloop: use a waker for notifying sigchld and loop cancel events Fix a race condition when do_sigchld, uloop_cancelled were set just before epoll_wait(timeout=-1), resulting the loop stuck in the syscall without noticing the events just happened Signed-off-by: Yousong Zhou Signed-off-by: Felix Fietkau --- uloop-epoll.c | 2 +- uloop-kqueue.c | 2 +- uloop.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 74 insertions(+), 6 deletions(-) diff --git a/uloop-epoll.c b/uloop-epoll.c index bb652fd..6014bea 100644 --- a/uloop-epoll.c +++ b/uloop-epoll.c @@ -23,7 +23,7 @@ #define EPOLLRDHUP 0x2000 #endif -int uloop_init(void) +static int uloop_init_pollfd(void) { if (poll_fd >= 0) return 0; diff --git a/uloop-kqueue.c b/uloop-kqueue.c index 0cb1c14..ba5595b 100644 --- a/uloop-kqueue.c +++ b/uloop-kqueue.c @@ -15,7 +15,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -int uloop_init(void) +static int uloop_init_pollfd(void) { struct timespec timeout = { 0, 0 }; struct kevent ev = {}; diff --git a/uloop.c b/uloop.c index cd3de85..2612fbd 100644 --- a/uloop.c +++ b/uloop.c @@ -63,6 +63,8 @@ static bool do_sigchld = false; static struct uloop_fd_event cur_fds[ULOOP_MAX_EVENTS]; static int cur_fd, cur_nfds; +int uloop_fd_add(struct uloop_fd *sock, unsigned int flags); + #ifdef USE_KQUEUE #include "uloop-kqueue.c" #endif @@ -71,6 +73,59 @@ static int cur_fd, cur_nfds; #include "uloop-epoll.c" #endif +static void waker_consume(struct uloop_fd *fd, unsigned int events) +{ + char buf[4]; + + while (read(fd->fd, buf, 4) > 0) + ; +} + +static int waker_pipe = -1; +static struct uloop_fd waker_fd = { + .fd = -1, + .cb = waker_consume, +}; + +static void waker_init_fd(int fd) +{ + fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); + fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); +} + +static int waker_init(void) +{ + int fds[2]; + + if (waker_pipe >= 0) + return 0; + + if (pipe(fds) < 0) + return -1; + + waker_init_fd(fds[0]); + waker_init_fd(fds[1]); + + waker_fd.fd = fds[0]; + waker_fd.cb = waker_consume; + uloop_fd_add(&waker_fd, ULOOP_READ); + + return 0; +} + +int uloop_init(void) +{ + if (uloop_init_pollfd() < 0) + return -1; + + if (waker_init() < 0) { + uloop_done(); + return -1; + } + + return 0; +} + static bool uloop_fd_stack_event(struct uloop_fd *fd, int events) { struct uloop_fd_stack *cur; @@ -328,14 +383,21 @@ static void uloop_handle_processes(void) } +static void uloop_signal_wake(void) +{ + write(waker_pipe, "w", 1); +} + static void uloop_handle_sigint(int signo) { uloop_cancelled = true; + uloop_signal_wake(); } static void uloop_sigchld(int signo) { do_sigchld = true; + uloop_signal_wake(); } static void uloop_install_handler(int signum, void (*handler)(int), struct sigaction* old, bool add) @@ -477,11 +539,17 @@ void uloop_run(void) void uloop_done(void) { - if (poll_fd < 0) - return; + if (poll_fd >= 0) { + close(poll_fd); + poll_fd = -1; + } - close(poll_fd); - poll_fd = -1; + if (waker_pipe >= 0) { + uloop_fd_delete(&waker_fd); + close(waker_pipe); + close(waker_fd.fd); + waker_pipe = -1; + } uloop_clear_timeouts(); uloop_clear_processes();