summaryrefslogtreecommitdiffstats
path: root/lib/libc
diff options
context:
space:
mode:
authordavidxu <davidxu@FreeBSD.org>2012-04-05 03:05:02 +0000
committerdavidxu <davidxu@FreeBSD.org>2012-04-05 03:05:02 +0000
commitcc55f4943b841b3772901d62a327ad4f9edb2c95 (patch)
treec3b9f33711c130d7a58e15afe974452d99fe010a /lib/libc
parent8c31e244f2179705d23a9bc680f47ba978ff9bcb (diff)
downloadFreeBSD-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.c24
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);
}
OpenPOWER on IntegriCloud