Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 21 Mar 2012 07:12:52 +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: r233262 - head/lib/libc/gen
Message-ID:  <201203210712.q2L7Cqs1059189@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: davidxu
Date: Wed Mar 21 07:12:52 2012
New Revision: 233262
URL: http://svn.freebsd.org/changeset/base/233262

Log:
  Use version 2 of semaphore provided by kernel umtx code, now if there is
  no waiters, we still increase and decrease count in user mode without
  entering kernel, once there is a waiter, sem_post will enter kernel to
  increase count and wake thread up, this is atomicy and allow us to
  gracefully destroy semaphore after sem_wait returned.

Modified:
  head/lib/libc/gen/sem_new.c

Modified: head/lib/libc/gen/sem_new.c
==============================================================================
--- head/lib/libc/gen/sem_new.c	Wed Mar 21 07:07:43 2012	(r233261)
+++ head/lib/libc/gen/sem_new.c	Wed Mar 21 07:12:52 2012	(r233262)
@@ -61,7 +61,8 @@ __weak_reference(_sem_unlink, sem_unlink
 __weak_reference(_sem_wait, sem_wait);
 
 #define SEM_PREFIX	"/tmp/SEMD"
-#define SEM_MAGIC	((u_int32_t)0x73656d31)
+#define SEM_MAGIC1	((u_int32_t)0x73656d31)
+#define SEM_MAGIC	((u_int32_t)0x73656d32)
 
 struct sem_nameinfo {
 	int open_count;
@@ -109,7 +110,7 @@ static inline int
 sem_check_validity(sem_t *sem)
 {
 
-	if (sem->_magic == SEM_MAGIC)
+	if (sem->_magic == SEM_MAGIC || sem->_magic == SEM_MAGIC1)
 		return (0);
 	else {
 		errno = EINVAL;
@@ -130,7 +131,7 @@ _sem_init(sem_t *sem, int pshared, unsig
 	sem->_magic = SEM_MAGIC;
 	sem->_kern._count = (u_int32_t)value;
 	sem->_kern._has_waiters = 0;
-	sem->_kern._flags = pshared ? USYNC_PROCESS_SHARED : 0;
+	sem->_kern._flags = (pshared ? USYNC_PROCESS_SHARED : 0) | SEM_VER2;
 	return (0);
 }
 
@@ -207,7 +208,7 @@ _sem_open(const char *name, int flags, .
 		tmp._magic = SEM_MAGIC;
 		tmp._kern._has_waiters = 0;
 		tmp._kern._count = value;
-		tmp._kern._flags = USYNC_PROCESS_SHARED | SEM_NAMED;
+		tmp._kern._flags = USYNC_PROCESS_SHARED | SEM_NAMED | SEM_VER2;
 		if (_write(fd, &tmp, sizeof(tmp)) != sizeof(tmp)) {
 			flock(fd, LOCK_UN);
 			goto error;
@@ -325,20 +326,11 @@ _sem_getvalue(sem_t * __restrict sem, in
 	if (sem_check_validity(sem) != 0)
 		return (-1);
 
-	*sval = (int)sem->_kern._count;
+	*sval = (int)sem->_kern._count & ~SEM_WAITERS;
 	return (0);
 }
 
 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);
-}
-
-static __inline int
 usem_wait(struct _usem *sem, const struct timespec *abstime)
 {
 	struct _umtx_time *tm_p, timeout;
@@ -358,48 +350,51 @@ usem_wait(struct _usem *sem, const struc
 		    (void *)tm_size, __DECONST(void*, tm_p));
 }
 
+static inline int
+_trywait(sem_t *sem)
+{
+	int count;
+
+	if ((sem->_kern._flags & SEM_VER2) != 0) {
+		while (((count = sem->_kern._count) & ~SEM_WAITERS) > 0) {
+			if (atomic_cmpset_acq_int(&sem->_kern._count, count, count - 1))
+				return (0);
+		}
+	} else {
+		while ((count = sem->_kern._count) > 0) {
+			if (atomic_cmpset_acq_int(&sem->_kern._count, count, count - 1))
+				return (0);
+		}
+	}
+	return (EAGAIN);
+}
+
 int
 _sem_trywait(sem_t *sem)
 {
-	int val;
+	int status;
 
 	if (sem_check_validity(sem) != 0)
 		return (-1);
-
-	while ((val = sem->_kern._count) > 0) {
-		if (atomic_cmpset_acq_int(&sem->_kern._count, val, val - 1))
-			return (0);
-	}
-	errno = EAGAIN;
+	if ((status = _trywait(sem)) == 0)
+		return (0);
+	errno = status;
 	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)
 {
-	int val, retval;
+	int retval;
 
 	if (sem_check_validity(sem) != 0)
 		return (-1);
 
 	retval = 0;
 	for (;;) {
-		while ((val = sem->_kern._count) > 0) {
-			if (atomic_cmpset_acq_int(&sem->_kern._count, val, val - 1))
-				return (0);
-		}
+		if (_trywait(sem) == 0)
+			return (0);
 
 		if (retval) {
 			_pthread_testcancel();
@@ -438,10 +433,36 @@ _sem_wait(sem_t *sem)
 int
 _sem_post(sem_t *sem)
 {
+	int count;
 
 	if (sem_check_validity(sem) != 0)
 		return (-1);
 
-	atomic_add_rel_int(&sem->_kern._count, 1);
-	return usem_wake(&sem->_kern);
+	if ((sem->_kern._flags & SEM_VER2) != 0) {
+		for (;;) {
+			count = sem->_kern._count;
+			if ((count & SEM_WAITERS) == 0) {
+				if (__predict_false(count == SEM_VALUE_MAX)) {
+					errno = ERANGE;
+					return (-1);
+				}
+				if (atomic_cmpset_rel_int(&sem->_kern._count, count, count+1))
+					return (0);
+			} else {
+				return _umtx_op(&sem->_kern, UMTX_OP_SEM_WAKE, 0, NULL, NULL);
+			}
+		}
+	} else {
+		do {
+			count = sem->_kern._count;
+			if (__predict_false(count == SEM_VALUE_MAX)) {
+				errno = ERANGE;
+				return (-1);
+			}
+		} while (!atomic_cmpset_rel_int(&sem->_kern._count, count, count+1));
+		rmb();
+		if (!sem->_kern._has_waiters)
+			return (0);
+		return _umtx_op(&sem->_kern, UMTX_OP_SEM_WAKE, 0, NULL, NULL);
+	}
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201203210712.q2L7Cqs1059189>