diff options
author | davidxu <davidxu@FreeBSD.org> | 2012-04-05 03:05:02 +0000 |
---|---|---|
committer | davidxu <davidxu@FreeBSD.org> | 2012-04-05 03:05:02 +0000 |
commit | cc55f4943b841b3772901d62a327ad4f9edb2c95 (patch) | |
tree | c3b9f33711c130d7a58e15afe974452d99fe010a /lib/libc | |
parent | 8c31e244f2179705d23a9bc680f47ba978ff9bcb (diff) | |
download | FreeBSD-src-cc55f4943b841b3772901d62a327ad4f9edb2c95.zip FreeBSD-src-cc55f4943b841b3772901d62a327ad4f9edb2c95.tar.gz |
In sem_post, the field _has_waiters is no longer used, because some
application destroys semaphore after sem_wait returns. Just enter
kernel to wake up sleeping threads, only update _has_waiters if
it is safe. While here, check if the value exceed SEM_VALUE_MAX and
return EOVERFLOW if this is true.
Diffstat (limited to 'lib/libc')
-rw-r--r-- | lib/libc/gen/sem_new.c | 24 |
1 files changed, 8 insertions, 16 deletions
diff --git a/lib/libc/gen/sem_new.c b/lib/libc/gen/sem_new.c index af64310..222a465 100644 --- a/lib/libc/gen/sem_new.c +++ b/lib/libc/gen/sem_new.c @@ -332,9 +332,6 @@ _sem_getvalue(sem_t * __restrict sem, int * __restrict sval) static __inline int usem_wake(struct _usem *sem) { - rmb(); - if (!sem->_has_waiters) - return (0); return _umtx_op(sem, UMTX_OP_SEM_WAKE, 0, NULL, NULL); } @@ -374,17 +371,6 @@ _sem_trywait(sem_t *sem) return (-1); } -#define TIMESPEC_SUB(dst, src, val) \ - do { \ - (dst)->tv_sec = (src)->tv_sec - (val)->tv_sec; \ - (dst)->tv_nsec = (src)->tv_nsec - (val)->tv_nsec; \ - if ((dst)->tv_nsec < 0) { \ - (dst)->tv_sec--; \ - (dst)->tv_nsec += 1000000000; \ - } \ - } while (0) - - int _sem_timedwait(sem_t * __restrict sem, const struct timespec * __restrict abstime) @@ -438,10 +424,16 @@ _sem_wait(sem_t *sem) int _sem_post(sem_t *sem) { + unsigned int count; if (sem_check_validity(sem) != 0) return (-1); - atomic_add_rel_int(&sem->_kern._count, 1); - return usem_wake(&sem->_kern); + do { + count = sem->_kern._count; + if (count + 1 > SEM_VALUE_MAX) + return (EOVERFLOW); + } while(!atomic_cmpset_rel_int(&sem->_kern._count, count, count+1)); + (void)usem_wake(&sem->_kern); + return (0); } |