summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_umtx.c
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 /sys/kern/kern_umtx.c
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 'sys/kern/kern_umtx.c')
-rw-r--r--sys/kern/kern_umtx.c23
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);
OpenPOWER on IntegriCloud