[libvirt] [PATCH v2 7/9] rpc: Alter virNetDaemonQuit processing

John Ferlan jferlan at redhat.com
Sat Jul 7 12:11:05 UTC 2018


When virNetDaemonQuit is called from libvirtd's shutdown
handler (daemonShutdownHandler) we need to perform the quit
in multiple steps. The first part is to "request" the quit
and notify the NetServer's of the impending quit which causes
the NetServers to inform their workers that a quit was requested.

Still because we cannot guarantee a quit will happen or it's
possible there's no workers pending, use a virNetDaemonQuitTimer
to not only break the event loop but keep track of how long we're
waiting and we've waited too long, force an ungraceful exit so
that we don't hang waiting forever or cause some sort of SEGV
because something is still pending and we Unref things.

Signed-off-by: John Ferlan <jferlan at redhat.com>
---
 src/libvirt_remote.syms    |  1 +
 src/remote/remote_daemon.c |  1 +
 src/rpc/virnetdaemon.c     | 68 +++++++++++++++++++++++++++++++++++++-
 src/rpc/virnetdaemon.h     |  4 +++
 4 files changed, 73 insertions(+), 1 deletion(-)

diff --git a/src/libvirt_remote.syms b/src/libvirt_remote.syms
index a8f937f32e..e416cfec44 100644
--- a/src/libvirt_remote.syms
+++ b/src/libvirt_remote.syms
@@ -87,6 +87,7 @@ virNetDaemonPreExecRestart;
 virNetDaemonQuit;
 virNetDaemonRemoveShutdownInhibition;
 virNetDaemonRun;
+virNetDaemonSetQuitTimeout;
 virNetDaemonUpdateServices;
 
 
diff --git a/src/remote/remote_daemon.c b/src/remote/remote_daemon.c
index dee634d7e1..d11adf422f 100644
--- a/src/remote/remote_daemon.c
+++ b/src/remote/remote_daemon.c
@@ -1273,6 +1273,7 @@ int main(int argc, char **argv) {
         ret = VIR_DAEMON_ERR_DRIVER;
         goto cleanup;
     }
+    virNetDaemonSetQuitTimeout(dmn, config->quit_timeout);
 
     if (!(srv = virNetServerNew("libvirtd", 1,
                                 config->min_workers,
diff --git a/src/rpc/virnetdaemon.c b/src/rpc/virnetdaemon.c
index 329f116a6c..c6ed65c8c3 100644
--- a/src/rpc/virnetdaemon.c
+++ b/src/rpc/virnetdaemon.c
@@ -73,6 +73,8 @@ struct _virNetDaemon {
     virHashTablePtr servers;
     virJSONValuePtr srvObject;
 
+    unsigned int quitTimeout;
+    bool quitRequested;
     bool quit;
 
     unsigned int autoShutdownTimeout;
@@ -153,6 +155,14 @@ virNetDaemonNew(void)
 }
 
 
+void
+virNetDaemonSetQuitTimeout(virNetDaemonPtr dmn,
+                           unsigned int quitTimeout)
+{
+    dmn->quitTimeout = quitTimeout;
+}
+
+
 int
 virNetDaemonAddServer(virNetDaemonPtr dmn,
                       virNetServerPtr srv)
@@ -791,11 +801,50 @@ daemonServerProcessClients(void *payload,
     return 0;
 }
 
+
+static int
+daemonServerWorkerCount(void *payload,
+                        const void *key ATTRIBUTE_UNUSED,
+                        void *opaque)
+{
+    size_t *workerCount = opaque;
+    virNetServerPtr srv = payload;
+
+    *workerCount += virNetServerWorkerCount(srv);
+
+    return 0;
+}
+
+
+static bool
+daemonServerWorkersDone(virNetDaemonPtr dmn)
+{
+    size_t workerCount = 0;
+
+    virHashForEach(dmn->servers, daemonServerWorkerCount, &workerCount);
+
+    return workerCount == 0;
+}
+
+
+static void
+virNetDaemonQuitTimer(int timer ATTRIBUTE_UNUSED,
+                      void *opaque)
+{
+    int *quitCount = opaque;
+
+    (*quitCount)++;
+    VIR_DEBUG("quitCount=%d", *quitCount);
+}
+
+
 void
 virNetDaemonRun(virNetDaemonPtr dmn)
 {
     int timerid = -1;
     bool timerActive = false;
+    int quitTimer = -1;
+    int quitCount = 0;
 
     virObjectLock(dmn);
 
@@ -855,10 +904,27 @@ virNetDaemonRun(virNetDaemonPtr dmn)
         virObjectLock(dmn);
 
         virHashForEach(dmn->servers, daemonServerProcessClients, NULL);
+
+        /* HACK: Add a dummy timeout to break event loop */
+        if (dmn->quitRequested && quitTimer == -1)
+            quitTimer = virEventAddTimeout(500, virNetDaemonQuitTimer,
+                                           &quitCount, NULL);
+
+        if (dmn->quitRequested && daemonServerWorkersDone(dmn)) {
+            dmn->quit = true;
+        } else {
+            /* Firing every 1/2 second and quitTimeout in seconds, force
+             * an exit when there are still worker threads running and we
+             * have waited long enough */
+            if (quitCount > dmn->quitTimeout * 2)
+                _exit(EXIT_FAILURE);
+        }
     }
 
  cleanup:
     virObjectUnlock(dmn);
+    if (quitTimer != -1)
+        virEventRemoveTimeout(quitTimer);
 }
 
 
@@ -880,7 +946,7 @@ virNetDaemonQuit(virNetDaemonPtr dmn)
     virObjectLock(dmn);
 
     VIR_DEBUG("Quit requested %p", dmn);
-    dmn->quit = true;
+    dmn->quitRequested = true;
     virHashForEach(dmn->servers, daemonServerQuitRequested, NULL);
 
     virObjectUnlock(dmn);
diff --git a/src/rpc/virnetdaemon.h b/src/rpc/virnetdaemon.h
index 09ed5adf36..8433d6a09d 100644
--- a/src/rpc/virnetdaemon.h
+++ b/src/rpc/virnetdaemon.h
@@ -35,6 +35,10 @@
 
 virNetDaemonPtr virNetDaemonNew(void);
 
+void
+virNetDaemonSetQuitTimeout(virNetDaemonPtr dmn,
+                           unsigned int quitTimeout);
+
 int virNetDaemonAddServer(virNetDaemonPtr dmn,
                           virNetServerPtr srv);
 
-- 
2.17.1




More information about the libvir-list mailing list