Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 4 Jan 2010 05:27:50 +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: r201472 - in head/sys: kern sys
Message-ID:  <201001040527.o045RoNN062634@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: davidxu
Date: Mon Jan  4 05:27:49 2010
New Revision: 201472
URL: http://svn.freebsd.org/changeset/base/201472

Log:
  Add user-level semaphore synchronous type, this change allows multiple
  processes to share semaphore by using shared memory area, in simplest case,
  only one atomic operation is needed in userland, waiter flag is maintained by
  kernel and userland only checks the flag, if the flag is set, user code enters
  kernel and does a wakeup() call.
  Move type definitions into file _umtx.h to minimize compiling time.
  Also type names need to be prefixed with underline character, this would reduce
  name conflict (still in progress).

Added:
  head/sys/sys/_umtx.h   (contents, props changed)
Modified:
  head/sys/kern/kern_umtx.c
  head/sys/sys/umtx.h

Modified: head/sys/kern/kern_umtx.c
==============================================================================
--- head/sys/kern/kern_umtx.c	Mon Jan  4 04:29:01 2010	(r201471)
+++ head/sys/kern/kern_umtx.c	Mon Jan  4 05:27:49 2010	(r201472)
@@ -2759,6 +2759,110 @@ out:
 	return (error);
 }
 
+static int
+do_sem_wait(struct thread *td, struct _usem *sem, struct timespec *timeout)
+{
+	struct umtx_q *uq;
+	struct timeval tv;
+	struct timespec cts, ets, tts;
+	uint32_t flags, count;
+	int error;
+
+	uq = td->td_umtxq;
+	flags = fuword32(&sem->_flags);
+	error = umtx_key_get(sem, TYPE_CV, GET_SHARE(flags), &uq->uq_key);
+	if (error != 0)
+		return (error);
+	umtxq_lock(&uq->uq_key);
+	umtxq_busy(&uq->uq_key);
+	umtxq_insert(uq);
+	umtxq_unlock(&uq->uq_key);
+
+	count = fuword32(__DEVOLATILE(uint32_t *, &sem->_count));
+	if (count != 0) {
+		umtxq_lock(&uq->uq_key);
+		umtxq_unbusy(&uq->uq_key);
+		umtxq_remove(uq);
+		umtxq_unlock(&uq->uq_key);
+		umtx_key_release(&uq->uq_key);
+		return (0);
+	}
+
+	/*
+	 * The magic thing is we should set c_has_waiters to 1 before
+	 * releasing user mutex.
+	 */
+	suword32(__DEVOLATILE(uint32_t *, &sem->_has_waiters), 1);
+
+	umtxq_lock(&uq->uq_key);
+	umtxq_unbusy(&uq->uq_key);
+	umtxq_unlock(&uq->uq_key);
+
+	umtxq_lock(&uq->uq_key);
+	if (timeout == NULL) {
+		error = umtxq_sleep(uq, "usem", 0);
+	} else {
+		getnanouptime(&ets);
+		timespecadd(&ets, timeout);
+		TIMESPEC_TO_TIMEVAL(&tv, timeout);
+		for (;;) {
+			error = umtxq_sleep(uq, "usem", tvtohz(&tv));
+			if (error != ETIMEDOUT)
+				break;
+			getnanouptime(&cts);
+			if (timespeccmp(&cts, &ets, >=)) {
+				error = ETIMEDOUT;
+				break;
+			}
+			tts = ets;
+			timespecsub(&tts, &cts);
+			TIMESPEC_TO_TIMEVAL(&tv, &tts);
+		}
+	}
+
+	if (error != 0) {
+		if ((uq->uq_flags & UQF_UMTXQ) == 0) {
+			if (!umtxq_signal(&uq->uq_key, 1))
+				error = 0;
+		}
+		if (error == ERESTART)
+			error = EINTR;
+	}
+	umtxq_remove(uq);
+	umtxq_unlock(&uq->uq_key);
+	umtx_key_release(&uq->uq_key);
+	return (error);
+}
+
+/*
+ * Signal a userland condition variable.
+ */
+static int
+do_sem_wake(struct thread *td, struct _usem *sem)
+{
+	struct umtx_key key;
+	int error, cnt, nwake;
+	uint32_t flags;
+
+	flags = fuword32(&sem->_flags);
+	if ((error = umtx_key_get(sem, TYPE_CV, GET_SHARE(flags), &key)) != 0)
+		return (error);	
+	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);
+	}
+	umtxq_unbusy(&key);
+	umtxq_unlock(&key);
+	umtx_key_release(&key);
+	return (error);
+}
+
 int
 _umtx_lock(struct thread *td, struct _umtx_lock_args *uap)
     /* struct umtx *umtx */
@@ -3031,6 +3135,35 @@ __umtx_op_rw_unlock(struct thread *td, s
 	return do_rw_unlock(td, uap->obj);
 }
 
+static int
+__umtx_op_sem_wait(struct thread *td, struct _umtx_op_args *uap)
+{
+	struct timespec *ts, timeout;
+	int error;
+
+	/* Allow a null timespec (wait forever). */
+	if (uap->uaddr2 == NULL)
+		ts = NULL;
+	else {
+		error = copyin(uap->uaddr2, &timeout,
+		    sizeof(timeout));
+		if (error != 0)
+			return (error);
+		if (timeout.tv_nsec >= 1000000000 ||
+		    timeout.tv_nsec < 0) {
+			return (EINVAL);
+		}
+		ts = &timeout;
+	}
+	return (do_sem_wait(td, uap->obj, ts));
+}
+
+static int
+__umtx_op_sem_wake(struct thread *td, struct _umtx_op_args *uap)
+{
+	return do_sem_wake(td, uap->obj);
+}
+
 typedef int (*_umtx_op_func)(struct thread *td, struct _umtx_op_args *uap);
 
 static _umtx_op_func op_table[] = {
@@ -3052,7 +3185,9 @@ static _umtx_op_func op_table[] = {
 	__umtx_op_wait_uint_private,	/* UMTX_OP_WAIT_UINT_PRIVATE */
 	__umtx_op_wake_private,		/* UMTX_OP_WAKE_PRIVATE */
 	__umtx_op_wait_umutex,		/* UMTX_OP_UMUTEX_WAIT */
-	__umtx_op_wake_umutex		/* UMTX_OP_UMUTEX_WAKE */
+	__umtx_op_wake_umutex,		/* UMTX_OP_UMUTEX_WAKE */
+	__umtx_op_sem_wait,		/* UMTX_OP_SEM_WAIT */
+	__umtx_op_sem_wake		/* UMTX_OP_SEM_WAKE */
 };
 
 int
@@ -3274,6 +3409,27 @@ __umtx_op_wait_uint_private_compat32(str
 	return do_wait(td, uap->obj, uap->val, ts, 1, 1);
 }
 
+static int
+__umtx_op_sem_wait_compat32(struct thread *td, struct _umtx_op_args *uap)
+{
+	struct timespec *ts, timeout;
+	int error;
+
+	/* Allow a null timespec (wait forever). */
+	if (uap->uaddr2 == NULL)
+		ts = NULL;
+	else {
+		error = copyin_timeout32(uap->uaddr2, &timeout);
+		if (error != 0)
+			return (error);
+		if (timeout.tv_nsec >= 1000000000 ||
+		    timeout.tv_nsec < 0)
+			return (EINVAL);
+		ts = &timeout;
+	}
+	return (do_sem_wait(td, uap->obj, ts));
+}
+
 static _umtx_op_func op_table_compat32[] = {
 	__umtx_op_lock_umtx_compat32,	/* UMTX_OP_LOCK */
 	__umtx_op_unlock_umtx_compat32,	/* UMTX_OP_UNLOCK */
@@ -3293,7 +3449,9 @@ static _umtx_op_func op_table_compat32[]
 	__umtx_op_wait_uint_private_compat32,	/* UMTX_OP_WAIT_UINT_PRIVATE */
 	__umtx_op_wake_private,		/* UMTX_OP_WAKE_PRIVATE */
 	__umtx_op_wait_umutex_compat32, /* UMTX_OP_UMUTEX_WAIT */
-	__umtx_op_wake_umutex		/* UMTX_OP_UMUTEX_WAKE */
+	__umtx_op_wake_umutex,		/* UMTX_OP_UMUTEX_WAKE */
+	__umtx_op_sem_wait_compat32,	/* UMTX_OP_SEM_WAIT */
+	__umtx_op_sem_wake		/* UMTX_OP_SEM_WAKE */
 };
 
 int

Added: head/sys/sys/_umtx.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/sys/_umtx.h	Mon Jan  4 05:27:49 2010	(r201472)
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 2010, David Xu <davidxu@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#ifndef _SYS__UMTX_H_
+#define	_SYS__UMTX_H_
+
+#include <sys/_types.h>
+
+struct umtx {
+	volatile unsigned long	u_owner;	/* Owner of the mutex. */
+};
+
+struct umutex {
+	volatile __lwpid_t	m_owner;	/* Owner of the mutex */
+	__uint32_t		m_flags;	/* Flags of the mutex */
+	__uint32_t		m_ceilings[2];	/* Priority protect ceiling */
+	__uint32_t		m_spare[4];
+};
+
+struct ucond {
+	volatile __uint32_t	c_has_waiters;	/* Has waiters in kernel */
+	__uint32_t		c_flags;	/* Flags of the condition variable */
+	__uint32_t		c_spare[2];	/* Spare space */
+};
+
+struct urwlock {
+	volatile __int32_t	rw_state;
+	__uint32_t		rw_flags;
+	__uint32_t		rw_blocked_readers;
+	__uint32_t		rw_blocked_writers;
+	__uint32_t		rw_spare[4];
+};
+
+struct _usem {
+	volatile __uint32_t	_has_waiters;
+	volatile __uint32_t	_count;
+	__uint32_t		_flags;
+};
+
+#endif /* !_SYS__UMTX_H_ */

Modified: head/sys/sys/umtx.h
==============================================================================
--- head/sys/sys/umtx.h	Mon Jan  4 04:29:01 2010	(r201471)
+++ head/sys/sys/umtx.h	Mon Jan  4 05:27:49 2010	(r201472)
@@ -30,19 +30,11 @@
 #ifndef _SYS_UMTX_H_
 #define	_SYS_UMTX_H_
 
-#include <sys/_types.h>
+#include <sys/_umtx.h>
 #include <sys/limits.h>
 
-/* 
- * See pthread_*
- */
-
-#define	UMTX_UNOWNED	0x0
-#define	UMTX_CONTESTED	LONG_MIN
-
-struct umtx {
-	volatile u_long	u_owner;	/* Owner of the mutex. */
-};
+#define	UMTX_UNOWNED		0x0
+#define	UMTX_CONTESTED		LONG_MIN
 
 #define USYNC_PROCESS_SHARED	0x0001	/* Process shared sync objs */
 
@@ -53,27 +45,6 @@ struct umtx {
 #define	UMUTEX_PRIO_INHERIT	0x0004	/* Priority inherited mutex */
 #define	UMUTEX_PRIO_PROTECT	0x0008	/* Priority protect mutex */
 
-struct umutex {
-	volatile __lwpid_t	m_owner;	/* Owner of the mutex */
-	uint32_t		m_flags;	/* Flags of the mutex */
-	uint32_t		m_ceilings[2];	/* Priority protect ceiling */
-	uint32_t		m_spare[4];
-};
-
-struct ucond {
-	volatile uint32_t	c_has_waiters;	/* Has waiters in kernel */
-	uint32_t		c_flags;	/* Flags of the condition variable */
-	uint32_t		c_spare[2];	/* Spare space */
-};
-
-struct urwlock {
-	volatile int32_t	rw_state;
-	uint32_t		rw_flags;
-	uint32_t		rw_blocked_readers;
-	uint32_t		rw_blocked_writers;
-	uint32_t		rw_spare[4];
-};
-
 /* urwlock flags */
 #define URWLOCK_PREFER_READER	0x0002
 
@@ -83,6 +54,9 @@ struct urwlock {
 #define URWLOCK_MAX_READERS	0x1fffffffU
 #define URWLOCK_READER_COUNT(c)	((c) & URWLOCK_MAX_READERS)
 
+/* _usem flags */
+#define SEM_NAMED	0x0002
+
 /* op code for _umtx_op */
 #define	UMTX_OP_LOCK		0
 #define	UMTX_OP_UNLOCK		1
@@ -100,10 +74,12 @@ struct urwlock {
 #define	UMTX_OP_RW_WRLOCK	13
 #define	UMTX_OP_RW_UNLOCK	14
 #define	UMTX_OP_WAIT_UINT_PRIVATE	15
-#define	UMTX_OP_WAKE_PRIVATE		16
-#define	UMTX_OP_MUTEX_WAIT		17
-#define	UMTX_OP_MUTEX_WAKE		18
-#define	UMTX_OP_MAX		19
+#define	UMTX_OP_WAKE_PRIVATE	16
+#define	UMTX_OP_MUTEX_WAIT	17
+#define	UMTX_OP_MUTEX_WAKE	18
+#define	UMTX_OP_SEM_WAIT	19
+#define	UMTX_OP_SEM_WAKE	20
+#define	UMTX_OP_MAX		21
 
 /* flags for UMTX_OP_CV_WAIT */
 #define UMTX_CHECK_UNPARKING	0x01



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