summaryrefslogtreecommitdiffstats
path: root/include/zix
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2022-08-18 19:11:09 -0400
committerDavid Robillard <d@drobilla.net>2022-08-18 19:24:19 -0400
commit8b2d6a7f282398aafc8449a625441cc87bbd6c9e (patch)
treeff11e264ccae305a7fc2656b35d105c1bf7b7d09 /include/zix
parent93eb717f520d68d27bfe110d48057cdd54a4a2bc (diff)
downloadzix-8b2d6a7f282398aafc8449a625441cc87bbd6c9e.tar.gz
zix-8b2d6a7f282398aafc8449a625441cc87bbd6c9e.tar.bz2
zix-8b2d6a7f282398aafc8449a625441cc87bbd6c9e.zip
Add zix_sem_timed_wait()
Diffstat (limited to 'include/zix')
-rw-r--r--include/zix/sem.h67
1 files changed, 66 insertions, 1 deletions
diff --git a/include/zix/sem.h b/include/zix/sem.h
index b782761..fd85aab 100644
--- a/include/zix/sem.h
+++ b/include/zix/sem.h
@@ -22,6 +22,8 @@ extern "C" {
#endif
#include <stdbool.h>
+#include <stdint.h>
+#include <time.h>
/**
@addtogroup zix
@@ -35,7 +37,7 @@ struct ZixSemImpl;
/**
A counting semaphore.
- This is an integer that is always positive, and has two main operations:
+ This is an integer that is never negative, and has two main operations:
increment (post) and decrement (wait). If a decrement can not be performed
(i.e. the value is 0) the caller will be blocked until another thread posts
and the operation can succeed.
@@ -100,6 +102,20 @@ static inline ZixStatus
zix_sem_try_wait(ZixSem* ZIX_NONNULL sem);
/**
+ Wait for an amount of time until count is > 0, then decrement if possible.
+
+ Obviously not realtime safe.
+
+ @return #ZIX_STATUS_SUCCESS if `sem` was decremented, #ZIX_STATUS_TIMEOUT if
+ it was still zero when the timeout was reached, or #ZIX_STATUS_BAD_ARG if
+ `sem` is invalid.
+*/
+static inline ZixStatus
+zix_sem_timed_wait(ZixSem* ZIX_NONNULL sem,
+ uint32_t seconds,
+ uint32_t nanoseconds);
+
+/**
@cond
*/
@@ -153,6 +169,19 @@ zix_sem_try_wait(ZixSem* ZIX_NONNULL sem)
: ZIX_STATUS_ERROR;
}
+static inline ZixStatus
+zix_sem_timed_wait(ZixSem* ZIX_NONNULL sem,
+ const uint32_t seconds,
+ const uint32_t nanoseconds)
+{
+ const mach_timespec_t interval = {seconds, (clock_res_t)nanoseconds};
+ const kern_return_t r = semaphore_timedwait(sem->sem, interval);
+
+ return (r == KERN_SUCCESS) ? ZIX_STATUS_SUCCESS
+ : (r == KERN_OPERATION_TIMED_OUT) ? ZIX_STATUS_TIMEOUT
+ : ZIX_STATUS_ERROR;
+}
+
#elif defined(_WIN32)
struct ZixSemImpl {
@@ -197,6 +226,19 @@ zix_sem_try_wait(ZixSem* ZIX_NONNULL sem)
: ZIX_STATUS_ERROR;
}
+static inline ZixStatus
+zix_sem_timed_wait(ZixSem* ZIX_NONNULL sem,
+ const uint32_t seconds,
+ const uint32_t nanoseconds)
+{
+ const uint32_t milliseconds = seconds * 1000U + nanoseconds / 1000000U;
+ const DWORD r = WaitForSingleObject(sem->sem, milliseconds);
+
+ return (r == WAIT_OBJECT_0) ? ZIX_STATUS_SUCCESS
+ : (r == WAIT_TIMEOUT) ? ZIX_STATUS_TIMEOUT
+ : ZIX_STATUS_ERROR;
+}
+
#else /* !defined(__APPLE__) && !defined(_WIN32) */
struct ZixSemImpl {
@@ -245,6 +287,29 @@ zix_sem_try_wait(ZixSem* ZIX_NONNULL sem)
: ZIX_STATUS_SUCCESS;
}
+static inline ZixStatus
+zix_sem_timed_wait(ZixSem* ZIX_NONNULL sem,
+ const uint32_t seconds,
+ const uint32_t nanoseconds)
+{
+ struct timespec ts = {0, 0};
+
+ if (clock_gettime(CLOCK_REALTIME, &ts)) {
+ return ZIX_STATUS_ERROR;
+ }
+
+ ts.tv_sec += seconds;
+ ts.tv_nsec += nanoseconds;
+
+ int r = 0;
+ while ((r = sem_timedwait(&sem->sem, &ts)) && errno == EINTR) {
+ // Interrupted, try again
+ }
+
+ return r ? (errno == ETIMEDOUT ? ZIX_STATUS_TIMEOUT : zix_errno_status(errno))
+ : ZIX_STATUS_SUCCESS;
+}
+
#endif
/**