summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/sem.c206
-rw-r--r--src/status.c2
-rw-r--r--src/zix_config.h30
3 files changed, 238 insertions, 0 deletions
diff --git a/src/sem.c b/src/sem.c
new file mode 100644
index 0000000..066c592
--- /dev/null
+++ b/src/sem.c
@@ -0,0 +1,206 @@
+// Copyright 2012-2022 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
+#include "zix_config.h"
+
+#include "zix/common.h"
+#include "zix/sem.h"
+
+#ifdef __APPLE__
+# include <mach/mach.h>
+#elif defined(_WIN32)
+# include <limits.h>
+# include <windows.h>
+#else
+# include <errno.h>
+# include <semaphore.h>
+#endif
+
+#include <stdint.h>
+#include <time.h>
+
+#ifdef __APPLE__
+
+ZixStatus
+zix_sem_init(ZixSem* sem, unsigned val)
+{
+ return semaphore_create(
+ mach_task_self(), &sem->sem, SYNC_POLICY_FIFO, (int)val)
+ ? ZIX_STATUS_ERROR
+ : ZIX_STATUS_SUCCESS;
+}
+
+ZixStatus
+zix_sem_destroy(ZixSem* sem)
+{
+ return semaphore_destroy(mach_task_self(), sem->sem) ? ZIX_STATUS_ERROR
+ : ZIX_STATUS_SUCCESS;
+}
+
+ZixStatus
+zix_sem_post(ZixSem* sem)
+{
+ return semaphore_signal(sem->sem) ? ZIX_STATUS_ERROR : ZIX_STATUS_SUCCESS;
+}
+
+ZixStatus
+zix_sem_wait(ZixSem* sem)
+{
+ kern_return_t r = 0;
+ while ((r = semaphore_wait(sem->sem)) && r == KERN_ABORTED) {
+ // Interrupted, try again
+ }
+
+ return r ? ZIX_STATUS_ERROR : ZIX_STATUS_SUCCESS;
+}
+
+ZixStatus
+zix_sem_try_wait(ZixSem* sem)
+{
+ const mach_timespec_t zero = {0, 0};
+ const kern_return_t r = semaphore_timedwait(sem->sem, zero);
+
+ return (r == KERN_SUCCESS) ? ZIX_STATUS_SUCCESS
+ : (r == KERN_OPERATION_TIMED_OUT) ? ZIX_STATUS_TIMEOUT
+ : ZIX_STATUS_ERROR;
+}
+
+ZixStatus
+zix_sem_timed_wait(ZixSem* 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)
+
+ZixStatus
+zix_sem_init(ZixSem* sem, unsigned initial)
+{
+ sem->sem = CreateSemaphore(NULL, (LONG)initial, LONG_MAX, NULL);
+ return sem->sem ? ZIX_STATUS_SUCCESS : ZIX_STATUS_ERROR;
+}
+
+ZixStatus
+zix_sem_destroy(ZixSem* sem)
+{
+ return CloseHandle(sem->sem) ? ZIX_STATUS_SUCCESS : ZIX_STATUS_ERROR;
+}
+
+ZixStatus
+zix_sem_post(ZixSem* sem)
+{
+ return ReleaseSemaphore(sem->sem, 1, NULL) ? ZIX_STATUS_SUCCESS
+ : ZIX_STATUS_ERROR;
+}
+
+ZixStatus
+zix_sem_wait(ZixSem* sem)
+{
+ return WaitForSingleObject(sem->sem, INFINITE) == WAIT_OBJECT_0
+ ? ZIX_STATUS_SUCCESS
+ : ZIX_STATUS_ERROR;
+}
+
+ZixStatus
+zix_sem_try_wait(ZixSem* sem)
+{
+ const DWORD r = WaitForSingleObject(sem->sem, 0);
+
+ return (r == WAIT_OBJECT_0) ? ZIX_STATUS_SUCCESS
+ : (r == WAIT_TIMEOUT) ? ZIX_STATUS_TIMEOUT
+ : ZIX_STATUS_ERROR;
+}
+
+ZixStatus
+zix_sem_timed_wait(ZixSem* 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) */
+
+ZixStatus
+zix_sem_init(ZixSem* sem, unsigned initial)
+{
+ return sem_init(&sem->sem, 0, initial) ? zix_errno_status(errno)
+ : ZIX_STATUS_SUCCESS;
+}
+
+ZixStatus
+zix_sem_destroy(ZixSem* sem)
+{
+ return sem_destroy(&sem->sem) ? zix_errno_status(errno) : ZIX_STATUS_SUCCESS;
+}
+
+ZixStatus
+zix_sem_post(ZixSem* sem)
+{
+ return sem_post(&sem->sem) ? zix_errno_status(errno) : ZIX_STATUS_SUCCESS;
+}
+
+ZixStatus
+zix_sem_wait(ZixSem* sem)
+{
+ int r = 0;
+ while ((r = sem_wait(&sem->sem)) && errno == EINTR) {
+ // Interrupted, try again
+ }
+
+ return r ? zix_errno_status(errno) : ZIX_STATUS_SUCCESS;
+}
+
+ZixStatus
+zix_sem_try_wait(ZixSem* sem)
+{
+ int r = 0;
+ while ((r = sem_trywait(&sem->sem)) && errno == EINTR) {
+ // Interrupted, try again
+ }
+
+ return r ? (errno == EAGAIN ? ZIX_STATUS_TIMEOUT : zix_errno_status(errno))
+ : ZIX_STATUS_SUCCESS;
+}
+
+ZixStatus
+zix_sem_timed_wait(ZixSem* sem,
+ const uint32_t seconds,
+ const uint32_t nanoseconds)
+{
+# if !USE_CLOCK_GETTIME || !USE_SEM_TIMEDWAIT
+ return ZIX_STATUS_NOT_SUPPORTED;
+# else
+
+ struct timespec ts = {0, 0};
+
+ if (clock_gettime(CLOCK_REALTIME, &ts)) {
+ return ZIX_STATUS_ERROR;
+ }
+
+ ts.tv_sec += (time_t)seconds;
+ ts.tv_nsec += (long)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
+}
+
+#endif
diff --git a/src/status.c b/src/status.c
index cbb3d36..a0bb17e 100644
--- a/src/status.c
+++ b/src/status.c
@@ -29,6 +29,8 @@ zix_strerror(const ZixStatus status)
return "Timeout";
case ZIX_STATUS_OVERFLOW:
return "Overflow";
+ case ZIX_STATUS_NOT_SUPPORTED:
+ return "Not supported";
}
return "Unknown error";
}
diff --git a/src/zix_config.h b/src/zix_config.h
index 7be46e4..f4965f8 100644
--- a/src/zix_config.h
+++ b/src/zix_config.h
@@ -39,6 +39,15 @@
# endif
# endif
+// POSIX.1-2001: clock_gettime()
+# ifndef HAVE_CLOCK_GETTIME
+# if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L
+# define HAVE_CLOCK_GETTIME 1
+# else
+# define HAVE_CLOCK_GETTIME 0
+# endif
+# endif
+
// POSIX.1-2001: mlock()
# ifndef HAVE_MLOCK
# if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L
@@ -57,6 +66,15 @@
# endif
# endif
+// POSIX.1-2001: sem_timedwait()
+# ifndef HAVE_SEM_TIMEDWAIT
+# if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L
+# define HAVE_SEM_TIMEDWAIT 1
+# else
+# define HAVE_SEM_TIMEDWAIT 0
+# endif
+# endif
+
#endif // !defined(ZIX_NO_DEFAULT_CONFIG)
/*
@@ -67,6 +85,12 @@
if the build system defines them all.
*/
+#if HAVE_CLOCK_GETTIME
+# define USE_CLOCK_GETTIME 1
+#else
+# define USE_CLOCK_GETTIME 0
+#endif
+
#if HAVE_MLOCK
# define USE_MLOCK 1
#else
@@ -79,4 +103,10 @@
# define USE_POSIX_MEMALIGN 0
#endif
+#if HAVE_SEM_TIMEDWAIT
+# define USE_SEM_TIMEDWAIT 1
+#else
+# define USE_SEM_TIMEDWAIT 0
+#endif
+
#endif // ZIX_CONFIG_H