1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2025-03-07 17:28:15 +00:00

virsh: Fix possible deadlock when virsh is about to exit

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.
This commit is contained in:
Jiri Denemark 2011-11-30 20:42:20 +01:00 committed by Daniel Veillard
parent 4c8327994c
commit cb1e7b61c8

View File

@ -251,6 +251,7 @@ typedef struct __vshControl {
bool useSnapshotOld; /* cannot use virDomainSnapshotGetParent or bool useSnapshotOld; /* cannot use virDomainSnapshotGetParent or
virDomainSnapshotNumChildren */ virDomainSnapshotNumChildren */
virThread eventLoop; virThread eventLoop;
virMutex lock;
bool eventLoopStarted; bool eventLoopStarted;
bool quit; bool quit;
} __vshControl; } __vshControl;
@ -17040,10 +17041,17 @@ vshEventLoop(void *opaque)
{ {
vshControl *ctl = opaque; vshControl *ctl = opaque;
while (!ctl->quit) { while (1) {
if (virEventRunDefaultImpl() < 0) { bool quit;
virMutexLock(&ctl->lock);
quit = ctl->quit;
virMutexUnlock(&ctl->lock);
if (quit)
break;
if (virEventRunDefaultImpl() < 0)
virshReportError(ctl); virshReportError(ctl);
}
} }
} }
@ -17479,13 +17487,18 @@ vshReadline (vshControl *ctl, const char *prompt)
#endif /* !USE_READLINE */ #endif /* !USE_READLINE */
static void
vshDeinitTimer(int timer ATTRIBUTE_UNUSED, void *opaque ATTRIBUTE_UNUSED)
{
/* nothing to be done here */
}
/* /*
* Deinitialize virsh * Deinitialize virsh
*/ */
static bool static bool
vshDeinit(vshControl *ctl) vshDeinit(vshControl *ctl)
{ {
ctl->quit = true;
vshReadlineDeinit(ctl); vshReadlineDeinit(ctl);
vshCloseLogFile(ctl); vshCloseLogFile(ctl);
VIR_FREE(ctl->name); VIR_FREE(ctl->name);
@ -17498,15 +17511,24 @@ vshDeinit(vshControl *ctl)
virResetLastError(); virResetLastError();
if (ctl->eventLoopStarted) { if (ctl->eventLoopStarted) {
int timer;
virMutexLock(&ctl->lock);
ctl->quit = true;
/* HACK: Add a dummy timeout to break event loop */ /* 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) if (timer != -1)
virEventRemoveTimeout(timer); virEventRemoveTimeout(timer);
virThreadJoin(&ctl->eventLoop);
ctl->eventLoopStarted = false; ctl->eventLoopStarted = false;
} }
virMutexDestroy(&ctl->lock);
return true; return true;
} }
@ -17787,6 +17809,11 @@ main(int argc, char **argv)
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (virMutexInit(&ctl->lock) < 0) {
vshError(ctl, "%s", _("Failed to initialize mutex"));
return EXIT_FAILURE;
}
if (virInitialize() < 0) { if (virInitialize() < 0) {
vshError(ctl, "%s", _("Failed to initialize libvirt")); vshError(ctl, "%s", _("Failed to initialize libvirt"));
return EXIT_FAILURE; return EXIT_FAILURE;