Simplify code, fix a thread cancellation bug in sem_wait and sem_timedwait.

This commit is contained in:
davidxu 2007-11-23 05:42:52 +00:00
parent 7ea038e33e
commit e24c6a3904

View File

@ -199,19 +199,17 @@ _sem_wait(sem_t *sem)
_pthread_testcancel(); _pthread_testcancel();
do { do {
atomic_add_int(&(*sem)->nwaiters, 1);
while ((val = (*sem)->count) > 0) { while ((val = (*sem)->count) > 0) {
if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) { if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
atomic_add_int(&(*sem)->nwaiters, -1);
return (0); return (0);
}
} }
atomic_add_int(&(*sem)->nwaiters, 1);
THR_CLEANUP_PUSH(curthread, sem_cancel_handler, sem); THR_CLEANUP_PUSH(curthread, sem_cancel_handler, sem);
_thr_cancel_enter(curthread); _thr_cancel_enter(curthread);
retval = _thr_umtx_wait_uint(&(*sem)->count, 0, NULL); retval = _thr_umtx_wait_uint(&(*sem)->count, 0, NULL);
atomic_add_int(&(*sem)->nwaiters, -1);
_thr_cancel_leave(curthread); _thr_cancel_leave(curthread);
THR_CLEANUP_POP(curthread, 0); THR_CLEANUP_POP(curthread, 0);
atomic_add_int(&(*sem)->nwaiters, -1);
} while (retval == 0); } while (retval == 0);
errno = retval; errno = retval;
return (-1); return (-1);
@ -242,35 +240,37 @@ _sem_timedwait(sem_t * __restrict sem,
*/ */
_pthread_testcancel(); _pthread_testcancel();
do { do {
atomic_add_int(&(*sem)->nwaiters, 1);
while ((val = (*sem)->count) > 0) { while ((val = (*sem)->count) > 0) {
if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) { if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
atomic_add_int(&(*sem)->nwaiters, -1);
return (0); return (0);
}
} }
if (abstime == NULL) { if (abstime == NULL) {
atomic_add_int(&(*sem)->nwaiters, -1);
errno = EINVAL; errno = EINVAL;
return (-1); return (-1);
} }
THR_CLEANUP_PUSH(curthread, sem_cancel_handler, sem);
clock_gettime(CLOCK_REALTIME, &ts); clock_gettime(CLOCK_REALTIME, &ts);
TIMESPEC_SUB(&ts2, abstime, &ts); TIMESPEC_SUB(&ts2, abstime, &ts);
atomic_add_int(&(*sem)->nwaiters, 1);
THR_CLEANUP_PUSH(curthread, sem_cancel_handler, sem);
_thr_cancel_enter(curthread); _thr_cancel_enter(curthread);
retval = _thr_umtx_wait_uint(&(*sem)->count, 0, &ts2); retval = _thr_umtx_wait_uint(&(*sem)->count, 0, &ts2);
atomic_add_int(&(*sem)->nwaiters, -1);
_thr_cancel_leave(curthread); _thr_cancel_leave(curthread);
THR_CLEANUP_POP(curthread, 0); THR_CLEANUP_POP(curthread, 0);
atomic_add_int(&(*sem)->nwaiters, -1);
} while (retval == 0); } while (retval == 0);
errno = retval; errno = retval;
return (-1); return (-1);
} }
/*
* sem_post() is required to be safe to call from within
* signal handlers, these code should work as that.
*/
int int
_sem_post(sem_t *sem) _sem_post(sem_t *sem)
{ {
int val, retval = 0; int retval = 0;
if (sem_check_validity(sem) != 0) if (sem_check_validity(sem) != 0)
return (-1); return (-1);
@ -278,16 +278,10 @@ _sem_post(sem_t *sem)
if ((*sem)->syssem != 0) if ((*sem)->syssem != 0)
return (ksem_post((*sem)->semid)); return (ksem_post((*sem)->semid));
/* atomic_add_rel_int(&(*sem)->count, 1);
* 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));
if ((*sem)->nwaiters) { if ((*sem)->nwaiters) {
retval = _thr_umtx_wake(&(*sem)->count, val + 1); retval = _thr_umtx_wake(&(*sem)->count, 1);
if (retval > 0) if (retval > 0)
retval = 0; retval = 0;
} }