diff options
Diffstat (limited to 'lib/libthr/thread/thr_sem.c')
-rw-r--r-- | lib/libthr/thread/thr_sem.c | 258 |
1 files changed, 41 insertions, 217 deletions
diff --git a/lib/libthr/thread/thr_sem.c b/lib/libthr/thread/thr_sem.c index 0dd5599..f20bde3 100644 --- a/lib/libthr/thread/thr_sem.c +++ b/lib/libthr/thread/thr_sem.c @@ -36,7 +36,6 @@ #include <errno.h> #include <fcntl.h> #include <pthread.h> -#include <semaphore.h> #include <stdlib.h> #include <time.h> #include <_semaphore.h> @@ -44,248 +43,73 @@ #include "thr_private.h" - -__weak_reference(_sem_init, sem_init); -__weak_reference(_sem_destroy, sem_destroy); -__weak_reference(_sem_getvalue, sem_getvalue); -__weak_reference(_sem_trywait, sem_trywait); -__weak_reference(_sem_wait, sem_wait); -__weak_reference(_sem_timedwait, sem_timedwait); -__weak_reference(_sem_post, sem_post); - - -static inline int -sem_check_validity(sem_t *sem) -{ - - if ((sem != NULL) && ((*sem)->magic == SEM_MAGIC)) - return (0); - else { - errno = EINVAL; - return (-1); - } -} - -static sem_t -sem_alloc(unsigned int value, semid_t semid, int system_sem) -{ - sem_t sem; - - if (value > SEM_VALUE_MAX) { - errno = EINVAL; - return (NULL); - } - - sem = (sem_t)malloc(sizeof(struct sem)); - if (sem == NULL) { - errno = ENOSPC; - return (NULL); - } - bzero(sem, sizeof(*sem)); - /* - * Fortunatly count and nwaiters are adjacency, so we can - * use umtx_wait to wait on it, umtx_wait needs an address - * can be accessed as a long interger. - */ - sem->count = (u_int32_t)value; - sem->nwaiters = 0; - sem->magic = SEM_MAGIC; - sem->semid = semid; - sem->syssem = system_sem; - return (sem); -} +FB10_COMPAT(_sem_init_compat, sem_init); +FB10_COMPAT(_sem_destroy_compat, sem_destroy); +FB10_COMPAT(_sem_getvalue_compat, sem_getvalue); +FB10_COMPAT(_sem_trywait_compat, sem_trywait); +FB10_COMPAT(_sem_wait_compat, sem_wait); +FB10_COMPAT(_sem_timedwait_compat, sem_timedwait); +FB10_COMPAT(_sem_post_compat, sem_post); + +typedef struct sem *sem_t; + +extern int _libc_sem_init_compat(sem_t *sem, int pshared, unsigned int value); +extern int _libc_sem_destroy_compat(sem_t *sem); +extern int _libc_sem_getvalue_compat(sem_t * __restrict sem, int * __restrict sval); +extern int _libc_sem_trywait_compat(sem_t *sem); +extern int _libc_sem_wait_compat(sem_t *sem); +extern int _libc_sem_timedwait_compat(sem_t * __restrict sem, + const struct timespec * __restrict abstime); +extern int _libc_sem_post_compat(sem_t *sem); + +int _sem_init_compat(sem_t *sem, int pshared, unsigned int value); +int _sem_destroy_compat(sem_t *sem); +int _sem_getvalue_compat(sem_t * __restrict sem, int * __restrict sval); +int _sem_trywait_compat(sem_t *sem); +int _sem_wait_compat(sem_t *sem); +int _sem_timedwait_compat(sem_t * __restrict sem, + const struct timespec * __restrict abstime); +int _sem_post_compat(sem_t *sem); int -_sem_init(sem_t *sem, int pshared, unsigned int value) +_sem_init_compat(sem_t *sem, int pshared, unsigned int value) { - semid_t semid; - - semid = (semid_t)SEM_USER; - if ((pshared != 0) && (ksem_init(&semid, value) != 0)) - return (-1); - - (*sem) = sem_alloc(value, semid, pshared); - if ((*sem) == NULL) { - if (pshared != 0) - ksem_destroy(semid); - return (-1); - } - return (0); + return _libc_sem_init_compat(sem, pshared, value); } int -_sem_destroy(sem_t *sem) +_sem_destroy_compat(sem_t *sem) { - int retval; - - if (sem_check_validity(sem) != 0) - return (-1); - - /* - * If this is a system semaphore let the kernel track it otherwise - * make sure there are no waiters. - */ - if ((*sem)->syssem != 0) - retval = ksem_destroy((*sem)->semid); - else { - retval = 0; - (*sem)->magic = 0; - } - if (retval == 0) - free(*sem); - return (retval); + return _libc_sem_destroy_compat(sem); } int -_sem_getvalue(sem_t * __restrict sem, int * __restrict sval) +_sem_getvalue_compat(sem_t * __restrict sem, int * __restrict sval) { - int retval; - - if (sem_check_validity(sem) != 0) - return (-1); - - if ((*sem)->syssem != 0) - retval = ksem_getvalue((*sem)->semid, sval); - else { - *sval = (int)(*sem)->count; - retval = 0; - } - return (retval); + return _libc_sem_getvalue_compat(sem, sval); } int -_sem_trywait(sem_t *sem) -{ - int val; - - if (sem_check_validity(sem) != 0) - return (-1); - - if ((*sem)->syssem != 0) - return (ksem_trywait((*sem)->semid)); - - while ((val = (*sem)->count) > 0) { - if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) - return (0); - } - errno = EAGAIN; - return (-1); -} - -static void -sem_cancel_handler(void *arg) +_sem_trywait_compat(sem_t *sem) { - sem_t *sem = arg; - - atomic_add_int(&(*sem)->nwaiters, -1); - if ((*sem)->nwaiters && (*sem)->count) - _thr_umtx_wake(&(*sem)->count, 1, 0); + return _libc_sem_trywait_compat(sem); } int -_sem_wait(sem_t *sem) +_sem_wait_compat(sem_t *sem) { - struct pthread *curthread; - int val, retval; - - if (sem_check_validity(sem) != 0) - return (-1); - - curthread = _get_curthread(); - if ((*sem)->syssem != 0) { - _thr_cancel_enter(curthread); - retval = ksem_wait((*sem)->semid); - _thr_cancel_leave(curthread); - return (retval); - } - - _pthread_testcancel(); - do { - while ((val = (*sem)->count) > 0) { - if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) - return (0); - } - atomic_add_int(&(*sem)->nwaiters, 1); - THR_CLEANUP_PUSH(curthread, sem_cancel_handler, sem); - _thr_cancel_enter(curthread); - retval = _thr_umtx_wait_uint(&(*sem)->count, 0, NULL, 0); - _thr_cancel_leave(curthread); - THR_CLEANUP_POP(curthread, 0); - atomic_add_int(&(*sem)->nwaiters, -1); - } while (retval == 0); - errno = retval; - return (-1); + return _libc_sem_wait_compat(sem); } int -_sem_timedwait(sem_t * __restrict sem, +_sem_timedwait_compat(sem_t * __restrict sem, const struct timespec * __restrict abstime) { - struct timespec ts, ts2; - struct pthread *curthread; - int val, retval; - - if (sem_check_validity(sem) != 0) - return (-1); - - curthread = _get_curthread(); - if ((*sem)->syssem != 0) { - _thr_cancel_enter(curthread); - retval = ksem_timedwait((*sem)->semid, abstime); - _thr_cancel_leave(curthread); - return (retval); - } - - /* - * The timeout argument is only supposed to - * be checked if the thread would have blocked. - */ - _pthread_testcancel(); - do { - while ((val = (*sem)->count) > 0) { - if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) - return (0); - } - if (abstime == NULL) { - errno = EINVAL; - return (-1); - } - clock_gettime(CLOCK_REALTIME, &ts); - TIMESPEC_SUB(&ts2, abstime, &ts); - atomic_add_int(&(*sem)->nwaiters, 1); - THR_CLEANUP_PUSH(curthread, sem_cancel_handler, sem); - _thr_cancel_enter(curthread); - retval = _thr_umtx_wait_uint((uint32_t*)&(*sem)->count, 0, &ts2, 0); - _thr_cancel_leave(curthread); - THR_CLEANUP_POP(curthread, 0); - atomic_add_int(&(*sem)->nwaiters, -1); - } while (retval == 0); - errno = retval; - return (-1); + return _libc_sem_timedwait_compat(sem, abstime); } -/* - * sem_post() is required to be safe to call from within - * signal handlers, these code should work as that. - */ - int -_sem_post(sem_t *sem) +_sem_post_compat(sem_t *sem) { - int retval = 0; - - if (sem_check_validity(sem) != 0) - return (-1); - - if ((*sem)->syssem != 0) - return (ksem_post((*sem)->semid)); - - atomic_add_rel_int(&(*sem)->count, 1); - - if ((*sem)->nwaiters) { - retval = _thr_umtx_wake(&(*sem)->count, 1, 0); - if (retval != 0) - retval = -1; - } - return (retval); + return _libc_sem_post_compat(sem); } |