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 <yszhou4t...@gmail.com> --- uloop-epoll.c | 2 +- uloop-kqueue.c | 2 +- uloop.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 63 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..b59c31f 100644 --- a/uloop.c +++ b/uloop.c @@ -63,6 +63,11 @@ static bool do_sigchld = false; static struct uloop_fd_event cur_fds[ULOOP_MAX_EVENTS]; static int cur_fd, cur_nfds; +static int waker_pipe[2] = {-1, -1}; +static struct uloop_fd waker_fd; + +int uloop_fd_add(struct uloop_fd *sock, unsigned int flags); + #ifdef USE_KQUEUE #include "uloop-kqueue.c" #endif @@ -71,6 +76,45 @@ 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_init(void) +{ + if (waker_pipe[0] >= 0 && waker_pipe[1] >= 0) + return 0; + + if (pipe(waker_pipe) < 0) + return -1; + + fcntl(waker_pipe[0], F_SETFD, fcntl(waker_pipe[0], F_GETFD) | O_NONBLOCK); + fcntl(waker_pipe[1], F_SETFD, fcntl(waker_pipe[1], F_GETFD) | O_NONBLOCK); + + waker_fd.fd = waker_pipe[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) { + close(poll_fd); + poll_fd = -1; + return -1; + } + return 0; +} + static bool uloop_fd_stack_event(struct uloop_fd *fd, int events) { struct uloop_fd_stack *cur; @@ -330,12 +374,18 @@ static void uloop_handle_processes(void) static void uloop_handle_sigint(int signo) { + char buf[1] = {'w'}; + uloop_cancelled = true; + write(waker_pipe[1], buf, 1); } static void uloop_sigchld(int signo) { + char buf[1] = {'w'}; + do_sigchld = true; + write(waker_pipe[1], buf, 1); } static void uloop_install_handler(int signum, void (*handler)(int), struct sigaction* old, bool add) @@ -477,11 +527,18 @@ void uloop_run(void) void uloop_done(void) { - if (poll_fd < 0) - return; + int i; - close(poll_fd); - poll_fd = -1; + if (poll_fd >= 0) { + close(poll_fd); + poll_fd = -1; + } + for (i = 0; i < ARRAY_SIZE(waker_pipe); i++) { + if (waker_pipe[i] >= 0) { + close(waker_pipe[i]); + waker_pipe[i] = -1; + } + } uloop_clear_timeouts(); uloop_clear_processes(); -- 2.6.4 _______________________________________________ Lede-dev mailing list Lede-dev@lists.infradead.org http://lists.infradead.org/mailman/listinfo/lede-dev