From 6a75b3b6437d3c98d852c1bca131c8f81646f2f5 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 17 May 2016 13:23:28 +0200 Subject: uloop: try to use signalfd for signal handling if available Signed-off-by: Felix Fietkau --- uloop-epoll.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'uloop-epoll.c') 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; } -- cgit v1.2.3