[libvirt] [PATCH] virsh: Fix possible deadlock when virsh is about to exit

Jiri Denemark jdenemar at redhat.com
Wed Nov 30 19:42:20 UTC 2011


Not only was ctl->quit accessed without a mutex but unfortunately,
virEventAddTimeout only interrupts the poll when event loop is running
so the hack needs to add a timeout that will make next poll return
immediately without blocking.
---
 tools/virsh.c |   39 +++++++++++++++++++++++++++++++++------
 1 files changed, 33 insertions(+), 6 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index 618b0c1..723ec65 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -251,6 +251,7 @@ typedef struct __vshControl {
     bool useSnapshotOld;        /* cannot use virDomainSnapshotGetParent or
                                    virDomainSnapshotNumChildren */
     virThread eventLoop;
+    virMutex lock;
     bool eventLoopStarted;
     bool quit;
 } __vshControl;
@@ -16796,10 +16797,17 @@ vshEventLoop(void *opaque)
 {
     vshControl *ctl = opaque;
 
-    while (!ctl->quit) {
-        if (virEventRunDefaultImpl() < 0) {
+    while (1) {
+        bool quit;
+        virMutexLock(&ctl->lock);
+        quit = ctl->quit;
+        virMutexUnlock(&ctl->lock);
+
+        if (quit)
+            break;
+
+        if (virEventRunDefaultImpl() < 0)
             virshReportError(ctl);
-        }
     }
 }
 
@@ -17235,13 +17243,18 @@ vshReadline (vshControl *ctl, const char *prompt)
 
 #endif /* !USE_READLINE */
 
+static void
+vshDeinitTimer(int timer ATTRIBUTE_UNUSED, void *opaque ATTRIBUTE_UNUSED)
+{
+    /* nothing to be done here */
+}
+
 /*
  * Deinitialize virsh
  */
 static bool
 vshDeinit(vshControl *ctl)
 {
-    ctl->quit = true;
     vshReadlineDeinit(ctl);
     vshCloseLogFile(ctl);
     VIR_FREE(ctl->name);
@@ -17254,15 +17267,24 @@ vshDeinit(vshControl *ctl)
     virResetLastError();
 
     if (ctl->eventLoopStarted) {
+        int timer;
+
+        virMutexLock(&ctl->lock);
+        ctl->quit = true;
         /* HACK: Add a dummy timeout to break event loop */
-        int timer = virEventAddTimeout(-1, NULL, NULL, NULL);
+        timer = virEventAddTimeout(0, vshDeinitTimer, NULL, NULL);
+        virMutexUnlock(&ctl->lock);
+
+        virThreadJoin(&ctl->eventLoop);
+
         if (timer != -1)
             virEventRemoveTimeout(timer);
 
-        virThreadJoin(&ctl->eventLoop);
         ctl->eventLoopStarted = false;
     }
 
+    virMutexDestroy(&ctl->lock);
+
     return true;
 }
 
@@ -17543,6 +17565,11 @@ main(int argc, char **argv)
         return EXIT_FAILURE;
     }
 
+    if (virMutexInit(&ctl->lock) < 0) {
+        vshError(ctl, "%s", _("Failed to initialize mutex"));
+        return EXIT_FAILURE;
+    }
+
     if (virInitialize() < 0) {
         vshError(ctl, "%s", _("Failed to initialize libvirt"));
         return EXIT_FAILURE;
-- 
1.7.8.rc4




More information about the libvir-list mailing list