From e24c6a39041bd86c45866fc47c267e13e484186d Mon Sep 17 00:00:00 2001 From: davidxu Date: Fri, 23 Nov 2007 05:42:52 +0000 Subject: Simplify code, fix a thread cancellation bug in sem_wait and sem_timedwait. --- lib/libthr/thread/thr_sem.c | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) (limited to 'lib/libthr') diff --git a/lib/libthr/thread/thr_sem.c b/lib/libthr/thread/thr_sem.c index 3953590..ec059f9 100644 --- a/lib/libthr/thread/thr_sem.c +++ b/lib/libthr/thread/thr_sem.c @@ -199,19 +199,17 @@ _sem_wait(sem_t *sem) _pthread_testcancel(); do { - atomic_add_int(&(*sem)->nwaiters, 1); while ((val = (*sem)->count) > 0) { - if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) { - atomic_add_int(&(*sem)->nwaiters, -1); + 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); - atomic_add_int(&(*sem)->nwaiters, -1); _thr_cancel_leave(curthread); THR_CLEANUP_POP(curthread, 0); + atomic_add_int(&(*sem)->nwaiters, -1); } while (retval == 0); errno = retval; return (-1); @@ -242,35 +240,37 @@ _sem_timedwait(sem_t * __restrict sem, */ _pthread_testcancel(); do { - atomic_add_int(&(*sem)->nwaiters, 1); while ((val = (*sem)->count) > 0) { - if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) { - atomic_add_int(&(*sem)->nwaiters, -1); + if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) return (0); - } } if (abstime == NULL) { - atomic_add_int(&(*sem)->nwaiters, -1); errno = EINVAL; return (-1); } - THR_CLEANUP_PUSH(curthread, sem_cancel_handler, sem); 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(&(*sem)->count, 0, &ts2); - atomic_add_int(&(*sem)->nwaiters, -1); _thr_cancel_leave(curthread); THR_CLEANUP_POP(curthread, 0); + atomic_add_int(&(*sem)->nwaiters, -1); } while (retval == 0); errno = retval; return (-1); } +/* + * 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) { - int val, retval = 0; + int retval = 0; if (sem_check_validity(sem) != 0) return (-1); @@ -278,16 +278,10 @@ _sem_post(sem_t *sem) if ((*sem)->syssem != 0) return (ksem_post((*sem)->semid)); - /* - * sem_post() is required to be safe to call from within - * signal handlers, these code should work as that. - */ - do { - val = (*sem)->count; - } while (!atomic_cmpset_rel_int(&(*sem)->count, val, val + 1)); + atomic_add_rel_int(&(*sem)->count, 1); if ((*sem)->nwaiters) { - retval = _thr_umtx_wake(&(*sem)->count, val + 1); + retval = _thr_umtx_wake(&(*sem)->count, 1); if (retval > 0) retval = 0; } -- cgit v1.1