Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 7 Mar 2011 17:15:10 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r219381 - in stable/8/sys: compat/linux sys
Message-ID:  <201103071715.p27HFAMT041828@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Mon Mar  7 17:15:10 2011
New Revision: 219381
URL: http://svn.freebsd.org/changeset/base/219381

Log:
  MFC 218970,219240:
  Use umtx_key objects to uniquely identify futexes.  Private futexes in
  different processes that happen to use the same user address in the
  separate processes will now be treated as distinct futexes rather than the
  same futex.  We can now honor shared futexes properly by mapping them to a
  AUTO_SHARED umtx_key.  Private futexes use THREAD_SHARED umtx_key objects.

Modified:
  stable/8/sys/compat/linux/linux_futex.c
  stable/8/sys/sys/umtx.h
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/sys/compat/linux/linux_futex.c
==============================================================================
--- stable/8/sys/compat/linux/linux_futex.c	Mon Mar  7 17:14:18 2011	(r219380)
+++ stable/8/sys/compat/linux/linux_futex.c	Mon Mar  7 17:15:10 2011	(r219381)
@@ -52,6 +52,7 @@ __KERNEL_RCSID(1, "$NetBSD: linux_futex.
 #include <sys/queue.h>
 #include <sys/sched.h>
 #include <sys/sx.h>
+#include <sys/umtx.h>
 
 #ifdef COMPAT_LINUX32
 #include <machine/../linux32/linux.h>
@@ -77,7 +78,8 @@ struct waiting_proc {
 
 struct futex {
 	struct sx	f_lck;
-	uint32_t	*f_uaddr;
+	uint32_t	*f_uaddr;	/* user-supplied value, for debug */
+	struct umtx_key	f_key;
 	uint32_t	f_refcount;
 	uint32_t	f_bitset;
 	LIST_ENTRY(futex) f_list;
@@ -100,6 +102,7 @@ struct mtx futex_mtx;			/* protects the 
 #define FUTEX_CREATE_WP		0x1	/* create waiting_proc */
 #define FUTEX_DONTCREATE	0x2	/* don't create futex if not exists */
 #define FUTEX_DONTEXISTS	0x4	/* return EINVAL if futex exists */
+#define	FUTEX_SHARED		0x8	/* shared futex */
 
 /* wp_flags */
 #define FUTEX_WP_REQUEUED	0x1	/* wp requeued - wp moved from wp_list
@@ -136,6 +139,7 @@ futex_put(struct futex *f, struct waitin
 
 		LINUX_CTR2(sys_futex, "futex_put destroy uaddr %p ref %d",
 		    f->f_uaddr, f->f_refcount);
+		umtx_key_release(&f->f_key);
 		FUTEX_DESTROY(f);
 		free(f, M_FUTEX);
 		return;
@@ -151,13 +155,19 @@ static int
 futex_get0(uint32_t *uaddr, struct futex **newf, uint32_t flags)
 {
 	struct futex *f, *tmpf;
+	struct umtx_key key;
+	int error;
 
 	*newf = tmpf = NULL;
 
+	error = umtx_key_get(uaddr, TYPE_FUTEX, (flags & FUTEX_SHARED) ?
+	    AUTO_SHARE : THREAD_SHARE, &key);
+	if (error)
+		return (error);
 retry:
 	FUTEXES_LOCK;
 	LIST_FOREACH(f, &futex_list, f_list) {
-		if (f->f_uaddr == uaddr) {
+		if (umtx_key_match(&f->f_key, &key)) {
 			if (tmpf != NULL) {
 				FUTEX_UNLOCK(tmpf);
 				FUTEX_DESTROY(tmpf);
@@ -165,6 +175,7 @@ retry:
 			}
 			if (flags & FUTEX_DONTEXISTS) {
 				FUTEXES_UNLOCK;
+				umtx_key_release(&key);
 				return (EINVAL);
 			}
 
@@ -174,6 +185,7 @@ retry:
 			 */
 			++f->f_refcount;
 			FUTEXES_UNLOCK;
+			umtx_key_release(&key);
 
 			FUTEX_LOCK(f);
 			*newf = f;
@@ -185,6 +197,7 @@ retry:
 
 	if (flags & FUTEX_DONTCREATE) {
 		FUTEXES_UNLOCK;
+		umtx_key_release(&key);
 		LINUX_CTR1(sys_futex, "futex_get uaddr %p null", uaddr);
 		return (0);
 	}
@@ -193,6 +206,7 @@ retry:
 		FUTEXES_UNLOCK;
 		tmpf = malloc(sizeof(*tmpf), M_FUTEX, M_WAITOK | M_ZERO);
 		tmpf->f_uaddr = uaddr;
+		tmpf->f_key = key;
 		tmpf->f_refcount = 1;
 		tmpf->f_bitset = FUTEX_BITSET_MATCH_ANY;
 		FUTEX_INIT(tmpf);
@@ -450,15 +464,13 @@ linux_sys_futex(struct thread *td, struc
 	struct waiting_proc *wp;
 	struct futex *f, *f2;
 	int error;
+	uint32_t flags;
 
-	/*
-	 * Our implementation provides only privates futexes. Most of the apps
-	 * should use private futexes but don't claim so. Therefore we treat
-	 * all futexes as private by clearing the FUTEX_PRIVATE_FLAG. It works
-	 * in most cases (ie. when futexes are not shared on file descriptor
-	 * or between different processes.).
-	 */
-	args->op = args->op & ~LINUX_FUTEX_PRIVATE_FLAG;
+	if (args->op & LINUX_FUTEX_PRIVATE_FLAG) {
+		flags = 0;
+		args->op &= ~LINUX_FUTEX_PRIVATE_FLAG;
+	} else
+		flags = FUTEX_SHARED;
 
 	/*
 	 * Currently support for switching between CLOCK_MONOTONIC and
@@ -490,7 +502,8 @@ linux_sys_futex(struct thread *td, struc
 			    "futex_wait uaddr %p val %d val3 %d"),
 			    args->uaddr, args->val, args->val3);
 #endif
-		error = futex_get(args->uaddr, &wp, &f, FUTEX_CREATE_WP);
+		error = futex_get(args->uaddr, &wp, &f,
+		    flags | FUTEX_CREATE_WP);
 		if (error)
 			return (error);
 		error = copyin(args->uaddr, &val, sizeof(val));
@@ -530,7 +543,8 @@ linux_sys_futex(struct thread *td, struc
 			printf(ARGS(sys_futex, "futex_wake uaddr %p val %d val3 %d"),
 			    args->uaddr, args->val, args->val3);
 #endif
-		error = futex_get(args->uaddr, NULL, &f, FUTEX_DONTCREATE);
+		error = futex_get(args->uaddr, NULL, &f,
+		    flags | FUTEX_DONTCREATE);
 		if (error)
 			return (error);
 		if (f == NULL) {
@@ -562,7 +576,7 @@ linux_sys_futex(struct thread *td, struc
 		 */
 		if (args->uaddr == args->uaddr2)
 			return (EINVAL);
-		error = futex_get0(args->uaddr, &f, 0);
+		error = futex_get(args->uaddr, NULL, &f, flags);
 		if (error)
 			return (error);
 
@@ -573,7 +587,8 @@ linux_sys_futex(struct thread *td, struc
 		 * Glibc fall back to FUTEX_WAKE in case of any error
 		 * returned by FUTEX_CMP_REQUEUE.
 		 */
-		error = futex_get0(args->uaddr2, &f2, FUTEX_DONTEXISTS);
+		error = futex_get(args->uaddr2, NULL, &f2,
+		    flags | FUTEX_DONTEXISTS);
 		if (error) {
 			futex_put(f, NULL);
 			return (error);
@@ -614,11 +629,11 @@ linux_sys_futex(struct thread *td, struc
 			    args->uaddr, args->op, args->val,
 			    args->uaddr2, args->val3);
 #endif
-		error = futex_get0(args->uaddr, &f, 0);
+		error = futex_get(args->uaddr, NULL, &f, flags);
 		if (error)
 			return (error);
 		if (args->uaddr != args->uaddr2)
-			error = futex_get0(args->uaddr2, &f2, 0);
+			error = futex_get(args->uaddr2, NULL, &f2, flags);
 		if (error) {
 			futex_put(f, NULL);
 			return (error);
@@ -812,7 +827,7 @@ retry:
 
 		if (!pi && (uval & FUTEX_WAITERS)) {
 			error = futex_get(uaddr, NULL, &f,
-			    FUTEX_DONTCREATE);
+			    FUTEX_DONTCREATE | FUTEX_SHARED);
 			if (error)
 				return (error);
 			if (f != NULL) {

Modified: stable/8/sys/sys/umtx.h
==============================================================================
--- stable/8/sys/sys/umtx.h	Mon Mar  7 17:14:18 2011	(r219380)
+++ stable/8/sys/sys/umtx.h	Mon Mar  7 17:15:10 2011	(r219381)
@@ -203,6 +203,7 @@ enum {
 	TYPE_PI_UMUTEX,
 	TYPE_PP_UMUTEX,
 	TYPE_RWLOCK,
+	TYPE_FUTEX
 };
 
 /* Key to represent a unique userland synchronous object */



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