summaryrefslogtreecommitdiffstats
path: root/libdimension/future.c
diff options
context:
space:
mode:
Diffstat (limited to 'libdimension/future.c')
-rw-r--r--libdimension/future.c89
1 files changed, 69 insertions, 20 deletions
diff --git a/libdimension/future.c b/libdimension/future.c
index 6ea15ae..555330f 100644
--- a/libdimension/future.c
+++ b/libdimension/future.c
@@ -41,6 +41,9 @@ dmnsn_new_future(void)
future->progress = 0;
future->total = 1;
+#if DMNSN_SPINLOCK
+ dmnsn_initialize_spinlock(&future->spinlock, PTHREAD_PROCESS_PRIVATE);
+#endif
dmnsn_initialize_mutex(&future->mutex);
dmnsn_initialize_cond(&future->cond);
@@ -67,6 +70,9 @@ dmnsn_future_join(dmnsn_future *future)
/* Free the future object */
dmnsn_destroy_cond(&future->cond);
dmnsn_destroy_mutex(&future->mutex);
+#if DMNSN_SPINLOCK
+ dmnsn_destroy_spinlock(&future->spinlock);
+#endif
dmnsn_free(future);
}
@@ -80,11 +86,49 @@ dmnsn_future_cancel(dmnsn_future *future)
pthread_cancel(future->thread);
}
-/**
- * Get the current progress, without locking anything.
- *
- * future->mutex must be locked for this call to be safe.
- */
+/** Lock the appropriate lock for a future. */
+static inline void
+dmnsn_lock_future(const dmnsn_future *future)
+{
+#if DMNSN_SPINLOCK
+ dmnsn_lock_spinlock(&MUTATE(future)->spinlock);
+#else
+ dmnsn_lock_mutex(&MUTATE(future)->mutex);
+#endif
+}
+
+/** Unlock the appropriate lock for a future. */
+static inline void
+dmnsn_unlock_future(const dmnsn_future *future)
+{
+#if DMNSN_SPINLOCK
+ dmnsn_unlock_spinlock(&MUTATE(future)->spinlock);
+#else
+ dmnsn_unlock_mutex(&MUTATE(future)->mutex);
+#endif
+}
+
+/** Lock the future's mutex specifically, if we have the spinlock already. */
+static inline void
+dmnsn_future_exchange_lock(const dmnsn_future *future)
+{
+#if DMNSN_SPINLOCK
+ dmnsn_unlock_spinlock(&MUTATE(future)->spinlock);
+ dmnsn_lock_mutex(&MUTATE(future)->mutex);
+#endif
+}
+
+/** Unlock the future's mutex specifically, if we have the spinlock already. */
+static inline void
+dmnsn_future_exchange_unlock(const dmnsn_future *future)
+{
+#if DMNSN_SPINLOCK
+ dmnsn_unlock_mutex(&MUTATE(future)->mutex);
+ dmnsn_lock_spinlock(&MUTATE(future)->spinlock);
+#endif
+}
+
+/** Get the current progress, without locking anything. */
static inline double
dmnsn_future_progress_unlocked(const dmnsn_future *future)
{
@@ -95,12 +139,11 @@ dmnsn_future_progress_unlocked(const dmnsn_future *future)
double
dmnsn_future_progress(const dmnsn_future *future)
{
- dmnsn_future *mfuture = MUTATE(future);
double progress;
- dmnsn_lock_mutex(&mfuture->mutex);
- progress = dmnsn_future_progress_unlocked(mfuture);
- dmnsn_unlock_mutex(&mfuture->mutex);
+ dmnsn_lock_future(future);
+ progress = dmnsn_future_progress_unlocked(future);
+ dmnsn_unlock_future(future);
return progress;
}
@@ -111,24 +154,26 @@ dmnsn_future_wait(const dmnsn_future *future, double progress)
{
dmnsn_future *mfuture = MUTATE(future);
- dmnsn_lock_mutex(&mfuture->mutex);
+ dmnsn_lock_future(mfuture);
while (dmnsn_future_progress_unlocked(mfuture) < progress) {
/* Set the minimum waited-on value */
if (progress < mfuture->min_wait)
mfuture->min_wait = progress;
- dmnsn_cond_wait(&mfuture->cond, &mfuture->mutex);
+ dmnsn_future_exchange_lock(mfuture);
+ dmnsn_cond_wait(&mfuture->cond, &mfuture->mutex);
+ dmnsn_future_exchange_unlock(mfuture);
}
- dmnsn_unlock_mutex(&mfuture->mutex);
+ dmnsn_unlock_future(mfuture);
}
/* Set the total number of loop iterations */
void
dmnsn_future_set_total(dmnsn_future *future, size_t total)
{
- dmnsn_lock_mutex(&future->mutex);
+ dmnsn_lock_future(future);
future->total = total;
- dmnsn_unlock_mutex(&future->mutex);
+ dmnsn_unlock_future(future);
}
/* Increment the number of completed loop iterations */
@@ -140,22 +185,26 @@ dmnsn_future_increment(dmnsn_future *future)
on cancellation */
pthread_testcancel();
- dmnsn_lock_mutex(&future->mutex);
+ dmnsn_lock_future(future);
++future->progress;
if (dmnsn_future_progress_unlocked(future) >= future->min_wait) {
future->min_wait = 1.0;
- dmnsn_cond_broadcast(&future->cond);
+ dmnsn_future_exchange_lock(future);
+ dmnsn_cond_broadcast(&future->cond);
+ dmnsn_future_exchange_unlock(future);
}
- dmnsn_unlock_mutex(&future->mutex);
+ dmnsn_unlock_future(future);
}
/* Immediately set to 100% completion */
void
dmnsn_future_done(dmnsn_future *future)
{
- dmnsn_lock_mutex(&future->mutex);
+ dmnsn_lock_future(future);
future->progress = future->total;
- dmnsn_cond_broadcast(&future->cond);
- dmnsn_unlock_mutex(&future->mutex);
+ dmnsn_future_exchange_lock(future);
+ dmnsn_cond_broadcast(&future->cond);
+ dmnsn_future_exchange_unlock(future);
+ dmnsn_unlock_future(future);
}