diff --git a/uloop-epoll.c b/uloop-epoll.c index bb652fd..9581e12 100644 --- a/uloop-epoll.c +++ b/uloop-epoll.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include + /** * FIXME: uClibc < 0.9.30.3 does not define EPOLLRDHUP for Linux >= 2.6.17 */ @@ -23,8 +25,63 @@ #define EPOLLRDHUP 0x2000 #endif +static void +uloop_signal_fd_cb(struct uloop_fd *fd, unsigned int events) +{ + struct signalfd_siginfo fdsi; + int ret; + +retry: + ret = read(fd->fd, &fdsi, sizeof(fdsi)); + if (ret < 0 && errno == EINTR) + goto retry; + + if (ret != sizeof(fdsi)) + return; + + uloop_handle_signal(fdsi.ssi_signo); +} + +static bool +uloop_setup_signalfd(bool add) +{ + static struct uloop_fd sfd = { + .cb = uloop_signal_fd_cb + }; + static sigset_t prev_mask; + sigset_t mask; + + if (signal_fd < 0) + return false; + + sigemptyset(&mask); + + if (!add) { + uloop_fd_delete(&sfd); + sigprocmask(SIG_BLOCK, &prev_mask, NULL); + } else { + sigaddset(&mask, SIGQUIT); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGTERM); + sigaddset(&mask, SIGCHLD); + sigprocmask(SIG_BLOCK, &mask, &prev_mask); + + sfd.fd = signal_fd; + uloop_fd_add(&sfd, ULOOP_READ | ULOOP_EDGE_TRIGGER); + } + + if (signalfd(signal_fd, &mask, SFD_NONBLOCK | SFD_CLOEXEC) < 0) { + sigprocmask(SIG_BLOCK, &prev_mask, NULL); + return false; + } + + return true; +} + int uloop_init(void) { + sigset_t mask; + if (poll_fd >= 0) return 0; @@ -33,6 +90,10 @@ int uloop_init(void) return -1; fcntl(poll_fd, F_SETFD, fcntl(poll_fd, F_GETFD) | FD_CLOEXEC); + + sigemptyset(&mask); + signal_fd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC); + return 0; } diff --git a/uloop-kqueue.c b/uloop-kqueue.c index 0cb1c14..e93bc82 100644 --- a/uloop-kqueue.c +++ b/uloop-kqueue.c @@ -15,6 +15,13 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +static bool +uloop_setup_signalfd(bool add) +{ + return false; +} + int uloop_init(void) { struct timespec timeout = { 0, 0 }; diff --git a/uloop.c b/uloop.c index d2784b7..6ef7210 100644 --- a/uloop.c +++ b/uloop.c @@ -56,6 +56,7 @@ static struct uloop_fd_stack *fd_stack = NULL; static struct list_head timeouts = LIST_HEAD_INIT(timeouts); static struct list_head processes = LIST_HEAD_INIT(processes); +static int signal_fd = -1; static int poll_fd = -1; bool uloop_cancelled = false; static bool do_sigchld = false; @@ -63,6 +64,8 @@ static bool do_sigchld = false; static struct uloop_fd_event cur_fds[ULOOP_MAX_EVENTS]; static int cur_fd, cur_nfds; +static void uloop_handle_signal(int signo); + #ifdef USE_KQUEUE #include "uloop-kqueue.c" #endif @@ -325,14 +328,17 @@ static void uloop_handle_processes(void) } -static void uloop_handle_sigint(int signo) +static void uloop_handle_signal(int signo) { - uloop_cancelled = true; -} - -static void uloop_sigchld(int signo) -{ - do_sigchld = true; + switch (signo) { + case SIGINT: + case SIGQUIT: + case SIGTERM: + uloop_cancelled = true; + break; + case SIGCHLD: + do_sigchld = true; + } } static void uloop_install_handler(int signum, void (*handler)(int), struct sigaction* old, bool add) @@ -385,9 +391,13 @@ static void uloop_setup_signals(bool add) { static struct sigaction old_sigint, old_sigchld, old_sigterm; - uloop_install_handler(SIGINT, uloop_handle_sigint, &old_sigint, add); - uloop_install_handler(SIGTERM, uloop_handle_sigint, &old_sigterm, add); - uloop_install_handler(SIGCHLD, uloop_sigchld, &old_sigchld, add); + if (uloop_setup_signalfd(add)) + return; + + uloop_install_handler(SIGINT, uloop_handle_signal, &old_sigint, add); + uloop_install_handler(SIGTERM, uloop_handle_signal, &old_sigterm, add); + uloop_install_handler(SIGQUIT, uloop_handle_signal, &old_sigterm, add); + uloop_install_handler(SIGCHLD, uloop_handle_signal, &old_sigchld, add); uloop_ignore_signal(SIGPIPE, add); } @@ -474,6 +484,11 @@ void uloop_run(void) void uloop_done(void) { + if (signal_fd >= 0) { + close(signal_fd); + signal_fd = -1; + } + if (poll_fd < 0) return;