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:
parent
4c8327994c
commit
cb1e7b61c8
@ -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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user