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
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;