diff options
author | David Robillard <d@drobilla.net> | 2022-08-19 14:04:49 -0400 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2022-08-19 14:21:28 -0400 |
commit | 1069c63c6ca2713cce2d6153acc1a1ef9f2b7f8f (patch) | |
tree | f6a4710fe2a8e4fe215a53f06c4eef6dc00c588b /src | |
parent | 12cac42e31653323ec607ba3b6512fe9a734d083 (diff) | |
download | zix-1069c63c6ca2713cce2d6153acc1a1ef9f2b7f8f.tar.gz zix-1069c63c6ca2713cce2d6153acc1a1ef9f2b7f8f.tar.bz2 zix-1069c63c6ca2713cce2d6153acc1a1ef9f2b7f8f.zip |
Move sem implementation out of header
This avoids having platform conditionals in public headers, which causes build
problems for dependants.
Diffstat (limited to 'src')
-rw-r--r-- | src/sem.c | 206 | ||||
-rw-r--r-- | src/status.c | 2 | ||||
-rw-r--r-- | src/zix_config.h | 30 |
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 |