From: Michael Vrable Date: Fri, 5 Mar 2010 22:25:00 +0000 (-0800) Subject: Do not signal barrier until all notifiers have run. X-Git-Url: https://git.vrable.net/?a=commitdiff_plain;h=e560d8b120a5f2ed5057506f91bc8d9e818229a7;p=bluesky.git Do not signal barrier until all notifiers have run. --- diff --git a/bluesky/bluesky-private.h b/bluesky/bluesky-private.h index 058c5bd..852b04e 100644 --- a/bluesky/bluesky-private.h +++ b/bluesky/bluesky-private.h @@ -47,7 +47,8 @@ typedef enum { } BlueSkyAsyncStatus; struct BlueSkyNotifierList; -typedef struct { +typedef struct _BlueSkyStoreAsync BlueSkyStoreAsync; +struct _BlueSkyStoreAsync { BlueSkyStore *store; GMutex *lock; @@ -65,10 +66,15 @@ typedef struct { struct BlueSkyNotifierList *notifiers; gint notifier_count; + /* The barrier waiting on this operation. Support for more than one + * barrier for a single async is not well-supported and should be avoided + * if possible. */ + BlueSkyStoreAsync *barrier; + bluesky_time_hires start_time; /* Time operation was submitted. */ gpointer store_private; /* For use by the storage implementation */ -} BlueSkyStoreAsync; +}; /* Support for notification lists. These are lists of one-shot functions which * can be called when certain events--primarily, competed storage diff --git a/bluesky/store.c b/bluesky/store.c index 200cd3e..888bd1b 100644 --- a/bluesky/store.c +++ b/bluesky/store.c @@ -97,6 +97,7 @@ BlueSkyStoreAsync *bluesky_store_async_new(BlueSkyStore *store) async->result = -1; async->notifiers = NULL; async->notifier_count = 0; + async->barrier = NULL; async->store_private = NULL; return async; @@ -171,6 +172,22 @@ void bluesky_store_async_add_notifier(BlueSkyStoreAsync *async, g_mutex_unlock(async->lock); } +static void op_complete(gpointer a, gpointer b) +{ + BlueSkyStoreAsync *barrier = (BlueSkyStoreAsync *)b; + + bluesky_store_async_ref(barrier); + g_mutex_lock(barrier->lock); + barrier->store_private + = GINT_TO_POINTER(GPOINTER_TO_INT(barrier->store_private) - 1); + if (GPOINTER_TO_INT(barrier->store_private) == 0 + && barrier->status != ASYNC_NEW) { + bluesky_store_async_mark_complete(barrier); + } + g_mutex_unlock(barrier->lock); + bluesky_store_async_unref(barrier); +} + /* Mark an asynchronous operation as complete. This should only be called by * the store implementations. The lock should be held when calling this * function. Any notifier functions will be called, but in a separate thread @@ -190,6 +207,9 @@ void bluesky_store_async_mark_complete(BlueSkyStoreAsync *async) async->status = ASYNC_COMPLETE; g_cond_broadcast(async->completion_cond); + if (async->barrier != NULL && async->notifiers == NULL) + op_complete(async, async->barrier); + while (async->notifiers != NULL) { struct BlueSkyNotifierList *nl = async->notifiers; async->notifiers = nl->next; @@ -234,31 +254,26 @@ void bluesky_store_async_submit(BlueSkyStoreAsync *async) bluesky_store_async_wait(async); } -static void op_complete(gpointer a, gpointer b) -{ - BlueSkyStoreAsync *barrier = (BlueSkyStoreAsync *)b; - - bluesky_store_async_ref(barrier); - g_mutex_lock(barrier->lock); - barrier->store_private - = GINT_TO_POINTER(GPOINTER_TO_INT(barrier->store_private) - 1); - if (GPOINTER_TO_INT(barrier->store_private) == 0 - && barrier->status != ASYNC_NEW) { - bluesky_store_async_mark_complete(barrier); - } - g_mutex_unlock(barrier->lock); - bluesky_store_async_unref(barrier); -} - /* Add the given operation to the barrier. The barrier will not complete until * all operations added to it have completed. */ void bluesky_store_add_barrier(BlueSkyStoreAsync *barrier, BlueSkyStoreAsync *async) { g_return_if_fail(barrier->op == STORE_OP_BARRIER); + + g_mutex_lock(barrier->lock); barrier->store_private = GINT_TO_POINTER(GPOINTER_TO_INT(barrier->store_private) + 1); - bluesky_store_async_add_notifier(async, op_complete, barrier); + g_mutex_unlock(barrier->lock); + + g_mutex_lock(async->lock); + if (async->barrier == NULL) { + async->barrier = barrier; + } else { + g_warning("Adding async to more than one barrier!\n"); + bluesky_store_async_add_notifier(async, op_complete, barrier); + } + g_mutex_unlock(async->lock); } static void notifier_task(gpointer n, gpointer s) @@ -267,7 +282,11 @@ static void notifier_task(gpointer n, gpointer s) notifier->func(notifier->async, notifier->user_data); if (g_atomic_int_dec_and_test(¬ifier->async->notifier_count)) { + g_mutex_lock(notifier->async->lock); + if (notifier->async->barrier != NULL) + op_complete(notifier->async, notifier->async->barrier); g_cond_broadcast(notifier->async->completion_cond); + g_mutex_unlock(notifier->async->lock); } bluesky_store_async_unref(notifier->async); g_free(notifier);