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 /sys/kern/kern_umtx.c | |
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 'sys/kern/kern_umtx.c')
-rw-r--r-- | sys/kern/kern_umtx.c | 23 |
1 files changed, 14 insertions, 9 deletions
diff --git a/sys/kern/kern_umtx.c b/sys/kern/kern_umtx.c index 71b19e7..c2f5ca3 100644 --- a/sys/kern/kern_umtx.c +++ b/sys/kern/kern_umtx.c @@ -2840,9 +2840,7 @@ do_sem_wait(struct thread *td, struct _usem *sem, struct _umtx_time *timeout) umtxq_busy(&uq->uq_key); umtxq_insert(uq); umtxq_unlock(&uq->uq_key); - casuword32(__DEVOLATILE(uint32_t *, &sem->_has_waiters), 0, 1); - rmb(); count = fuword32(__DEVOLATILE(uint32_t *, &sem->_count)); if (count != 0) { umtxq_lock(&uq->uq_key); @@ -2876,7 +2874,7 @@ static int do_sem_wake(struct thread *td, struct _usem *sem) { struct umtx_key key; - int error, cnt, nwake; + int error, cnt; uint32_t flags; flags = fuword32(&sem->_flags); @@ -2885,12 +2883,19 @@ do_sem_wake(struct thread *td, struct _usem *sem) umtxq_lock(&key); umtxq_busy(&key); cnt = umtxq_count(&key); - nwake = umtxq_signal(&key, 1); - if (cnt <= nwake) { - umtxq_unlock(&key); - error = suword32( - __DEVOLATILE(uint32_t *, &sem->_has_waiters), 0); - umtxq_lock(&key); + if (cnt > 0) { + umtxq_signal(&key, 1); + /* + * Check if count is greater than 0, this means the memory is + * still being referenced by user code, so we can safely + * update _has_waiters flag. + */ + if (cnt == 1) { + umtxq_unlock(&key); + error = suword32( + __DEVOLATILE(uint32_t *, &sem->_has_waiters), 0); + umtxq_lock(&key); + } } umtxq_unbusy(&key); umtxq_unlock(&key); |