Author: davidxu
Date: Thu Apr  5 03:05:02 2012
New Revision: 233913
URL: http://svn.freebsd.org/changeset/base/233913

Log:
  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.

Modified:
  head/lib/libc/gen/sem_new.c
  head/sys/kern/kern_umtx.c

Modified: head/lib/libc/gen/sem_new.c
==============================================================================
--- head/lib/libc/gen/sem_new.c Thu Apr  5 02:24:08 2012        (r233912)
+++ head/lib/libc/gen/sem_new.c Thu Apr  5 03:05:02 2012        (r233913)
@@ -332,9 +332,6 @@ _sem_getvalue(sem_t * __restrict sem, in
 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);
 }

Modified: head/sys/kern/kern_umtx.c
==============================================================================
--- head/sys/kern/kern_umtx.c   Thu Apr  5 02:24:08 2012        (r233912)
+++ head/sys/kern/kern_umtx.c   Thu Apr  5 03:05:02 2012        (r233913)
@@ -2840,9 +2840,7 @@ do_sem_wait(struct thread *td, struct _u
        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 _u
        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);
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to