mirror of
https://github.com/libvirt/libvirt.git
synced 2025-02-25 18:55:26 -06:00
Fix deadlock in remote driver domain events
* src/remote_internal.c: Release driver lock when dispatching events to callbacks
This commit is contained in:
parent
abe3ee9cc5
commit
664085ab74
@ -167,6 +167,8 @@ struct private_data {
|
|||||||
virDomainEventQueuePtr domainEvents;
|
virDomainEventQueuePtr domainEvents;
|
||||||
/* Timer for flushing domainEvents queue */
|
/* Timer for flushing domainEvents queue */
|
||||||
int eventFlushTimer;
|
int eventFlushTimer;
|
||||||
|
/* Flag if we're in process of dispatching */
|
||||||
|
int domainEventDispatching;
|
||||||
|
|
||||||
/* Self-pipe to wakeup threads waiting in poll() */
|
/* Self-pipe to wakeup threads waiting in poll() */
|
||||||
int wakeupSendFD;
|
int wakeupSendFD;
|
||||||
@ -6288,18 +6290,26 @@ static int remoteDomainEventDeregister (virConnectPtr conn,
|
|||||||
|
|
||||||
remoteDriverLock(priv);
|
remoteDriverLock(priv);
|
||||||
|
|
||||||
if (virDomainEventCallbackListRemove(conn, priv->callbackList,
|
if (priv->domainEventDispatching) {
|
||||||
callback) < 0) {
|
if (virDomainEventCallbackListMarkDelete(conn, priv->callbackList,
|
||||||
error (conn, VIR_ERR_RPC, _("removing cb fron list"));
|
callback) < 0) {
|
||||||
goto done;
|
error (conn, VIR_ERR_RPC, _("marking cb for deletion"));
|
||||||
}
|
|
||||||
|
|
||||||
if ( priv->callbackList->count == 0 ) {
|
|
||||||
/* Tell the server when we are the last callback deregistering */
|
|
||||||
if (call (conn, priv, 0, REMOTE_PROC_DOMAIN_EVENTS_DEREGISTER,
|
|
||||||
(xdrproc_t) xdr_void, (char *) NULL,
|
|
||||||
(xdrproc_t) xdr_void, (char *) NULL) == -1)
|
|
||||||
goto done;
|
goto done;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (virDomainEventCallbackListRemove(conn, priv->callbackList,
|
||||||
|
callback) < 0) {
|
||||||
|
error (conn, VIR_ERR_RPC, _("removing cb from list"));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( priv->callbackList->count == 0 ) {
|
||||||
|
/* Tell the server when we are the last callback deregistering */
|
||||||
|
if (call (conn, priv, 0, REMOTE_PROC_DOMAIN_EVENTS_DEREGISTER,
|
||||||
|
(xdrproc_t) xdr_void, (char *) NULL,
|
||||||
|
(xdrproc_t) xdr_void, (char *) NULL) == -1)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = 0;
|
rv = 0;
|
||||||
@ -7309,18 +7319,54 @@ done:
|
|||||||
remoteDriverUnlock(priv);
|
remoteDriverUnlock(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void remoteDomainEventDispatchFunc(virConnectPtr conn,
|
||||||
|
virDomainEventPtr event,
|
||||||
|
virConnectDomainEventCallback cb,
|
||||||
|
void *cbopaque,
|
||||||
|
void *opaque)
|
||||||
|
{
|
||||||
|
struct private_data *priv = opaque;
|
||||||
|
|
||||||
|
/* Drop the lock whle dispatching, for sake of re-entrancy */
|
||||||
|
remoteDriverUnlock(priv);
|
||||||
|
virDomainEventDispatchDefaultFunc(conn, event, cb, cbopaque, NULL);
|
||||||
|
remoteDriverLock(priv);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
remoteDomainEventQueueFlush(int timer ATTRIBUTE_UNUSED, void *opaque)
|
remoteDomainEventQueueFlush(int timer ATTRIBUTE_UNUSED, void *opaque)
|
||||||
{
|
{
|
||||||
virConnectPtr conn = opaque;
|
virConnectPtr conn = opaque;
|
||||||
struct private_data *priv = conn->privateData;
|
struct private_data *priv = conn->privateData;
|
||||||
|
virDomainEventQueue tempQueue;
|
||||||
|
|
||||||
remoteDriverLock(priv);
|
remoteDriverLock(priv);
|
||||||
|
|
||||||
virDomainEventQueueDispatch(priv->domainEvents, priv->callbackList,
|
priv->domainEventDispatching = 1;
|
||||||
virDomainEventDispatchDefaultFunc, NULL);
|
|
||||||
|
/* Copy the queue, so we're reentrant safe */
|
||||||
|
tempQueue.count = priv->domainEvents->count;
|
||||||
|
tempQueue.events = priv->domainEvents->events;
|
||||||
|
priv->domainEvents->count = 0;
|
||||||
|
priv->domainEvents->events = NULL;
|
||||||
|
|
||||||
|
virDomainEventQueueDispatch(&tempQueue, priv->callbackList,
|
||||||
|
remoteDomainEventDispatchFunc, priv);
|
||||||
virEventUpdateTimeout(priv->eventFlushTimer, -1);
|
virEventUpdateTimeout(priv->eventFlushTimer, -1);
|
||||||
|
|
||||||
|
/* Purge any deleted callbacks */
|
||||||
|
virDomainEventCallbackListPurgeMarked(priv->callbackList);
|
||||||
|
|
||||||
|
if ( priv->callbackList->count == 0 ) {
|
||||||
|
/* Tell the server when we are the last callback deregistering */
|
||||||
|
if (call (conn, priv, 0, REMOTE_PROC_DOMAIN_EVENTS_DEREGISTER,
|
||||||
|
(xdrproc_t) xdr_void, (char *) NULL,
|
||||||
|
(xdrproc_t) xdr_void, (char *) NULL) == -1)
|
||||||
|
VIR_WARN0("Failed to de-register events");
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->domainEventDispatching = 0;
|
||||||
|
|
||||||
remoteDriverUnlock(priv);
|
remoteDriverUnlock(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user