Date: Thu, 5 Apr 2012 03:05:02 +0000 (UTC) From: David Xu <davidxu@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r233913 - in head: lib/libc/gen sys/kern Message-ID: <201204050305.q35352O4037183@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201204050305.q35352O4037183>