]> xenbits.xensource.com Git - libvirt.git/commitdiff
virsh: Fix possible deadlock when virsh is about to exit
authorJiri Denemark <jdenemar@redhat.com>
Wed, 30 Nov 2011 19:42:20 +0000 (20:42 +0100)
committerDaniel Veillard <veillard@redhat.com>
Thu, 1 Dec 2011 02:34:43 +0000 (10:34 +0800)
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

index 0fccf885da19b3ebcaac629ec1cc6f1249f6137f..76deaa91ffb35864db50b1560330cf9d124a4f4a 100644 (file)
@@ -251,6 +251,7 @@ typedef struct __vshControl {
     bool useSnapshotOld;        /* cannot use virDomainSnapshotGetParent or
                                    virDomainSnapshotNumChildren */
     virThread eventLoop;
+    virMutex lock;
     bool eventLoopStarted;
     bool quit;
 } __vshControl;
@@ -17040,10 +17041,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);
-        }
     }
 }
 
@@ -17479,13 +17487,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);
@@ -17498,15 +17511,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;
 }
 
@@ -17787,6 +17809,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;