Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/lib/librumpclient On Linux, poll signalfd() when waiting for...



details:   https://anonhg.NetBSD.org/src/rev/41d44c111da4
branches:  trunk
changeset: 328401:41d44c111da4
user:      pooka <pooka%NetBSD.org@localhost>
date:      Wed Apr 02 14:48:03 2014 +0000

description:
On Linux, poll signalfd() when waiting for a kernel response.
This allows the same type of race-free handling of signals as kqueue()
allows on NetBSD.  One of the noticeable things is that you can now
interrupt rumprun ping mid-interval on Linux.

per suggestion from Justin Cormack

diffstat:

 lib/librumpclient/rumpclient.c |  162 ++++++++++++++++++++++++++--------------
 1 files changed, 105 insertions(+), 57 deletions(-)

diffs (truncated from 313 to 300 lines):

diff -r 972c11638567 -r 41d44c111da4 lib/librumpclient/rumpclient.c
--- a/lib/librumpclient/rumpclient.c    Wed Apr 02 14:11:25 2014 +0000
+++ b/lib/librumpclient/rumpclient.c    Wed Apr 02 14:48:03 2014 +0000
@@ -1,4 +1,4 @@
-/*      $NetBSD: rumpclient.c,v 1.57 2014/02/26 02:03:40 pooka Exp $   */
+/*      $NetBSD: rumpclient.c,v 1.58 2014/04/02 14:48:03 pooka Exp $   */
 
 /*
  * Copyright (c) 2010, 2011 Antti Kantee.  All Rights Reserved.
@@ -38,17 +38,19 @@
  * notifications but defer their handling to a stage where we do not
  * hold the communication lock.  Taking a signal while holding on to
  * that lock may cause a deadlock.  Therefore, block signals throughout
- * the RPC when using poll.  This unfortunately means that the normal
- * SIGINT way of stopping a process while it is undergoing rump kernel
- * RPC will not work.  If anyone know which Linux system call handles
- * the above scenario correctly, I'm all ears.
+ * the RPC when using poll.  On Linux, we use signalfd in the same role
+ * as kqueue on NetBSD to be able to take signals while waiting for a
+ * response from the server.
  */
 
 #ifdef __NetBSD__
 #define USE_KQUEUE
 #endif
+#ifdef __linux__
+#define USE_SIGNALFD
+#endif
 
-__RCSID("$NetBSD: rumpclient.c,v 1.57 2014/02/26 02:03:40 pooka Exp $");
+__RCSID("$NetBSD: rumpclient.c,v 1.58 2014/04/02 14:48:03 pooka Exp $");
 
 #include <sys/param.h>
 #include <sys/mman.h>
@@ -96,6 +98,12 @@
                       struct kevent *, size_t, const struct timespec *);
 #endif
 
+#ifdef USE_SIGNALFD
+#include <sys/signalfd.h>
+
+int    (*host_signalfd)(int, const sigset_t *, int);
+#endif
+
 int    (*host_execve)(const char *, char *const[], char *const[]);
 
 #include "sp_common.c"
@@ -105,7 +113,7 @@
        .spc_fd = -1,
 };
 
-static int kq = -1;
+static int holyfd;
 static sigset_t fullset;
 
 static int doconnect(void);
@@ -237,7 +245,7 @@
                                 * typically we don't have a frame waiting
                                 * when we come in here, so call kevent now
                                 */
-                               rv = host_kevent(kq, NULL, 0,
+                               rv = host_kevent(holyfd, NULL, 0,
                                    kev, __arraycount(kev), NULL);
 
                                if (__predict_false(rv == -1)) {
@@ -267,13 +275,19 @@
                                 * determine what happens next.
                                 */
  activity:
-#else /* USE_KQUEUE */
-                               struct pollfd pfd;
+#else /* !USE_KQUEUE */
+                               struct pollfd pfd[2];
 
-                               pfd.fd = clispc.spc_fd;
-                               pfd.events = POLLIN;
+                               pfd[0].fd = clispc.spc_fd;
+                               pfd[0].events = POLLIN;
+                               pfd[1].fd = holyfd;
+                               pfd[1].events = POLLIN;
 
-                               rv = host_poll(&pfd, 1, -1);
+                               rv = host_poll(pfd, 2, -1);
+                               if (pfd[1].revents & POLLIN) {
+                                       dosig = 1;
+                                       goto cleanup;
+                               }
 #endif /* !USE_KQUEUE */
 
                                switch (readframe(spc)) {
@@ -677,6 +691,52 @@
        return myfd;
 }
 
+#if defined(USE_KQUEUE)
+
+static int
+makeholyfd(void)
+{
+       struct kevent kev[NSIG+1];
+       int i, fd;
+
+       /* setup kqueue, we want all signals and the fd */
+       if ((fd = dupgood(host_kqueue(), 0)) == -1) {
+               ERRLOG(("rump_sp: cannot setup kqueue"));
+               return -1;
+       }
+
+       for (i = 0; i < NSIG; i++) {
+               EV_SET(&kev[i], i+1, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0);
+       }
+       EV_SET(&kev[NSIG], clispc.spc_fd,
+           EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
+       if (host_kevent(fd, kev, NSIG+1, NULL, 0, NULL) == -1) {
+               ERRLOG(("rump_sp: kevent() failed"));
+               return -1;
+
+       return fd;
+}
+
+#elif defined(USE_SIGNALFD) /* !USE_KQUEUE */
+
+static int
+makeholyfd(void)
+{
+
+       return host_signalfd(-1, &fullset, 0);
+}
+
+#else /* !USE_KQUEUE && !USE_SIGNALFD */
+
+static int
+makeholyfd(void)
+{
+
+       return -1;
+}
+
+#endif
+
 static int
 doconnect(void)
 {
@@ -686,9 +746,9 @@
        int s, error, flags;
        ssize_t n;
 
-       if (kq != -1)
-               host_close(kq);
-       kq = -1;
+       if (holyfd != -1)
+               host_close(holyfd);
+       holyfd = -1;
        s = -1;
 
        if (clispc.spc_fd != -1)
@@ -759,29 +819,7 @@
        clispc.spc_fd = s;
        clispc.spc_state = SPCSTATE_RUNNING;
        clispc.spc_reconnecting = 0;
-
-#ifdef USE_KQUEUE
-{
-       struct kevent kev[NSIG+1];
-       int i;
-
-       /* setup kqueue, we want all signals and the fd */
-       if ((kq = dupgood(host_kqueue(), 0)) == -1) {
-               ERRLOG(("rump_sp: cannot setup kqueue"));
-               return -1;
-       }
-
-       for (i = 0; i < NSIG; i++) {
-               EV_SET(&kev[i], i+1, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0);
-       }
-       EV_SET(&kev[NSIG], clispc.spc_fd,
-           EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
-       if (host_kevent(kq, kev, NSIG+1, NULL, 0, NULL) == -1) {
-               ERRLOG(("rump_sp: kevent() failed"));
-               return -1;
-       }
-}
-#endif /* USE_KQUEUE */
+       holyfd = makeholyfd();
 
        return 0;
 }
@@ -831,8 +869,10 @@
                return 0;
 
        /* kq does not traverse fork() */
+#ifdef USE_KQUEUE
        if (init_done != 0)
-               kq = -1;
+               holyfd = -1;
+#endif
        init_done = mypid;
 
        sigfillset(&fullset);
@@ -883,6 +923,10 @@
 #endif
 #endif /* USE_KQUEUE */
 
+#ifdef USE_SIGNALFD
+       FINDSYM(signalfd)
+#endif
+
 #undef FINDSYM
 #undef FINDSY2
 
@@ -903,7 +947,7 @@
                goto out;
 
        if ((p = getenv("RUMPCLIENT__EXECFD")) != NULL) {
-               sscanf(p, "%d,%d", &clispc.spc_fd, &kq);
+               sscanf(p, "%d,%d", &clispc.spc_fd, &holyfd);
                unsetenv("RUMPCLIENT__EXECFD");
                hstype = HANDSHAKE_EXEC;
        } else {
@@ -932,7 +976,7 @@
 struct rumpclient_fork {
        uint32_t fork_auth[AUTHLEN];
        struct spclient fork_spc;
-       int fork_kq;
+       int fork_holyfd;
 };
 
 struct rumpclient_fork *
@@ -959,7 +1003,7 @@
        free(resp);
 
        rpf->fork_spc = clispc;
-       rpf->fork_kq = kq;
+       rpf->fork_holyfd = holyfd;
 
  out:
        pthread_sigmask(SIG_SETMASK, &omask, NULL);
@@ -976,7 +1020,14 @@
        memset(&clispc, 0, sizeof(clispc));
        clispc.spc_fd = osock;
 
-       kq = -1; /* kqueue descriptor is not copied over fork() */
+#ifdef USE_KQUEUE
+       holyfd = -1; /* kqueue descriptor is not copied over fork() */
+#else
+       if (holyfd != -1) {
+               host_close(holyfd);
+               holyfd = -1;
+       }
+#endif
 
        if (doinit() == -1)
                return -1;
@@ -1008,7 +1059,7 @@
 {
 
        clispc = rpf->fork_spc;
-       kq = rpf->fork_kq;
+       holyfd = rpf->fork_holyfd;
 }
 
 void
@@ -1030,9 +1081,9 @@
 
        switch (variant) {
        case RUMPCLIENT_CLOSE_FCLOSEM:
-               untilfd = MAX(clispc.spc_fd, kq);
+               untilfd = MAX(clispc.spc_fd, holyfd);
                for (; fd <= untilfd; fd++) {
-                       if (fd == clispc.spc_fd || fd == kq)
+                       if (fd == clispc.spc_fd || fd == holyfd)
                                continue;
                        rv = host_close(fd);
                        if (rv == -1)
@@ -1061,23 +1112,20 @@
                            EVFILT_READ, EV_DELETE, 0, 0, 0);
                        EV_SET(&kev[1], newfd,
                            EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
-                       if (host_kevent(kq, kev, 2, NULL, 0, NULL) == -1) {
+                       if (host_kevent(holyfd, kev, 2, NULL, 0, NULL) == -1) {
                                int sverrno = errno;
                                host_close(newfd);
                                errno = sverrno;
                                return -1;
-                       }
+                       }}
+#endif /* !USE_KQUEUE */
                        clispc.spc_fd = newfd;
-                       }
                }
-               if (fd == kq) {
-                       newfd = dupgood(kq, 1);
+               if (holyfd != -1 && fd == holyfd) {
+                       newfd = dupgood(holyfd, 1);
                        if (newfd == -1)
                                return -1;
-                       kq = newfd;
-#else /* USE_KQUEUE */
-                       clispc.spc_fd = newfd;
-#endif /* !USE_KQUEUE */



Home | Main Index | Thread Index | Old Index