[libvirt] [PATCH v2] events: Propose a separate lock for event queue
Daniel P. Berrange
berrange at redhat.com
Wed Oct 12 20:08:07 UTC 2011
On Wed, Oct 12, 2011 at 01:58:46PM +0200, Michal Privoznik wrote:
> Currently, push & pop from event queue (both server & client side)
> rely on lock from higher levels, e.g. on driver lock (qemu),
> private_data (remote), ...; This alone is not sufficient as not
> every function that interacts with this queue can/does lock,
> esp. in client where we have a different approach, "passing
> the buck".
>
> Therefore we need a separate lock just to protect event queue.
>
> For more info see:
> https://bugzilla.redhat.com/show_bug.cgi?id=743817
> ---
> src/conf/domain_event.c | 54 ++++++++++++++++++++++++++++++++++++++++-------
> src/conf/domain_event.h | 1 +
> 2 files changed, 47 insertions(+), 8 deletions(-)
>
> diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c
> index 3189346..f712c34 100644
> --- a/src/conf/domain_event.c
> +++ b/src/conf/domain_event.c
> @@ -547,6 +547,18 @@ virDomainEventQueuePtr virDomainEventQueueNew(void)
> return ret;
> }
>
> +static void
> +virDomainEventStateLock(virDomainEventStatePtr state)
> +{
> + virMutexLock(&state->lock);
> +}
> +
> +static void
> +virDomainEventStateUnlock(virDomainEventStatePtr state)
> +{
> + virMutexUnlock(&state->lock);
> +}
> +
> /**
> * virDomainEventStateFree:
> * @list: virDomainEventStatePtr to free
> @@ -564,6 +576,8 @@ virDomainEventStateFree(virDomainEventStatePtr state)
>
> if (state->timer != -1)
> virEventRemoveTimeout(state->timer);
> +
> + virMutexDestroy(&state->lock);
> VIR_FREE(state);
> }
>
> @@ -590,6 +604,13 @@ virDomainEventStateNew(virEventTimeoutCallback timeout_cb,
> goto error;
> }
>
> + if (virMutexInit(&state->lock) < 0) {
> + virReportSystemError(errno, "%s",
> + _("unable to initialize state mutex"));
> + VIR_FREE(state);
> + goto error;
> + }
> +
> if (VIR_ALLOC(state->callbacks) < 0) {
> virReportOOMError();
> goto error;
> @@ -1166,6 +1187,8 @@ virDomainEventStateQueue(virDomainEventStatePtr state,
> return;
> }
>
> + virDomainEventStateLock(state);
> +
> if (virDomainEventQueuePush(state->queue, event) < 0) {
> VIR_DEBUG("Error adding event to queue");
> virDomainEventFree(event);
> @@ -1173,6 +1196,7 @@ virDomainEventStateQueue(virDomainEventStatePtr state,
>
> if (state->queue->count == 1)
> virEventUpdateTimeout(state->timer, 0);
> + virDomainEventStateUnlock(state);
> }
>
> void
> @@ -1182,6 +1206,7 @@ virDomainEventStateFlush(virDomainEventStatePtr state,
> {
> virDomainEventQueue tempQueue;
>
> + virDomainEventStateLock(state);
> state->isDispatching = true;
>
> /* Copy the queue, so we're reentrant safe when dispatchFunc drops the
> @@ -1190,17 +1215,20 @@ virDomainEventStateFlush(virDomainEventStatePtr state,
> tempQueue.events = state->queue->events;
> state->queue->count = 0;
> state->queue->events = NULL;
> -
> virEventUpdateTimeout(state->timer, -1);
> + virDomainEventStateUnlock(state);
> +
> virDomainEventQueueDispatch(&tempQueue,
> state->callbacks,
> dispatchFunc,
> opaque);
>
> /* Purge any deleted callbacks */
> + virDomainEventStateLock(state);
> virDomainEventCallbackListPurgeMarked(state->callbacks);
>
> state->isDispatching = false;
> + virDomainEventStateUnlock(state);
> }
>
> int
> @@ -1208,11 +1236,16 @@ virDomainEventStateDeregister(virConnectPtr conn,
> virDomainEventStatePtr state,
> virConnectDomainEventCallback callback)
> {
> + int ret;
> +
> + virDomainEventStateLock(state);
> if (state->isDispatching)
> - return virDomainEventCallbackListMarkDelete(conn,
> - state->callbacks, callback);
> + ret = virDomainEventCallbackListMarkDelete(conn,
> + state->callbacks, callback);
> else
> - return virDomainEventCallbackListRemove(conn, state->callbacks, callback);
> + ret = virDomainEventCallbackListRemove(conn, state->callbacks, callback);
> + virDomainEventStateUnlock(state);
> + return ret;
> }
>
> int
> @@ -1220,10 +1253,15 @@ virDomainEventStateDeregisterAny(virConnectPtr conn,
> virDomainEventStatePtr state,
> int callbackID)
> {
> + int ret;
> +
> + virDomainEventStateLock(state);
> if (state->isDispatching)
> - return virDomainEventCallbackListMarkDeleteID(conn,
> - state->callbacks, callbackID);
> + ret = virDomainEventCallbackListMarkDeleteID(conn,
> + state->callbacks, callbackID);
> else
> - return virDomainEventCallbackListRemoveID(conn,
> - state->callbacks, callbackID);
> + ret = virDomainEventCallbackListRemoveID(conn,
> + state->callbacks, callbackID);
> + virDomainEventStateUnlock(state);
> + return ret;
> }
> diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h
> index b06be16..08930ed 100644
> --- a/src/conf/domain_event.h
> +++ b/src/conf/domain_event.h
> @@ -61,6 +61,7 @@ struct _virDomainEventState {
> int timer;
> /* Flag if we're in process of dispatching */
> bool isDispatching;
> + virMutex lock;
> };
> typedef struct _virDomainEventState virDomainEventState;
> typedef virDomainEventState *virDomainEventStatePtr;
ACK, the locking is correct now.
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
More information about the libvir-list
mailing list