mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 17:34:18 +03: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:
parent
4c8327994c
commit
cb1e7b61c8
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user