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