summaryrefslogtreecommitdiffstats
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
parent93eb717f520d68d27bfe110d48057cdd54a4a2bc (diff)
downloadzix-8b2d6a7f282398aafc8449a625441cc87bbd6c9e.tar.gz
zix-8b2d6a7f282398aafc8449a625441cc87bbd6c9e.tar.bz2
zix-8b2d6a7f282398aafc8449a625441cc87bbd6c9e.zip
Add zix_sem_timed_wait()
-rw-r--r--include/zix/sem.h67
-rw-r--r--meson.build2
-rw-r--r--test/test_sem.c14
3 files changed, 81 insertions, 2 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
/**
diff --git a/meson.build b/meson.build
index 2f442f0..a894d58 100644
--- a/meson.build
+++ b/meson.build
@@ -108,7 +108,7 @@ endif
# Set any additional arguments required for building libraries or programs
library_c_args = platform_c_args + extra_c_args + ['-DZIX_INTERNAL']
library_link_args = []
-program_c_args = extra_c_args
+program_c_args = platform_c_args + extra_c_args
program_link_args = []
if cc.get_id() == 'emscripten'
wasm_c_args = [
diff --git a/test/test_sem.c b/test/test_sem.c
index d43dac8..36f85e0 100644
--- a/test/test_sem.c
+++ b/test/test_sem.c
@@ -52,6 +52,19 @@ test_try_wait(void)
assert(!zix_sem_destroy(&sem));
}
+static void
+test_timed_wait(void)
+{
+ assert(!zix_sem_init(&sem, 0));
+ assert(zix_sem_timed_wait(&sem, 0, 0) == ZIX_STATUS_TIMEOUT);
+ assert(zix_sem_timed_wait(&sem, 0, 5000000) == ZIX_STATUS_TIMEOUT);
+ assert(!zix_sem_post(&sem));
+ assert(!zix_sem_timed_wait(&sem, 0, 5000000));
+ assert(!zix_sem_post(&sem));
+ assert(!zix_sem_timed_wait(&sem, 1000, 0));
+ assert(!zix_sem_destroy(&sem));
+}
+
int
main(int argc, char** argv)
{
@@ -65,6 +78,7 @@ main(int argc, char** argv)
}
test_try_wait();
+ test_timed_wait();
printf("Testing %u signals...\n", n_signals);