Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 16 Aug 2010 05:15:21 +0200
From:      Max Laier <max@love2party.net>
To:        freebsd-arch@freebsd.org
Cc:        ups@freebsd.org
Subject:   rmlock(9) two additions
Message-ID:  <201008160515.21412.max@love2party.net>

next in thread | raw e-mail | index | archive | help
--Boundary-00=_J1KaMsyD3+FF4Et
Content-Type: Text/Plain;
  charset="us-ascii"
Content-Transfer-Encoding: 7bit

Hi,

I'd like to run two additions to rmlock(9) by you:

1) See the attached patch.  It adds rm_try_rlock() which avoids taking the 
mutex if the lock is currently in a write episode.  The only overhead to the 
hot path is an additional argument and a return value for _rm_rlock*.  If you 
are worried about that, it can obviously be done in a separate code path, but 
I reckon it not worth the code crunch.  Finally, there is one additional 
branch to check the "trylock" argument, but that's well past the hot path.

2) No code for this yet - testing the waters first.  I'd like to add the 
ability to replace the mutex for writer synchronization with a general lock - 
especially to be able to use a sx(9) lock here.

The reason for #2 is the following use case in a debugging facility:

	"reader":
		if (rm_try_rlock()) {
			grab_per_cpu_buffer();
			fill_per_cpu_buffer();
			rm_runlock();
		}

	"writer" - better exclusive access thread:
		rm_wlock();
		collect_buffers_and_copy_out_to_userspace();
		rm_wunlock();

This is much cleaner and possibly cheaper than the various hand rolled 
versions I've come across, that try to get the same synchronization with 
atomic operations.  If we could sleep with the wlock held, we can also avoid 
copying the buffer contents, or swapping buffers.

Is there any concern about either of this?  Any objection?  Input?

Thanks,
  Max Laier

--Boundary-00=_J1KaMsyD3+FF4Et
Content-Type: text/x-patch; charset="ISO-8859-1"; name="rm_try_rlock.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="rm_try_rlock.diff"

diff --git a/sys/kern/kern_rmlock.c b/sys/kern/kern_rmlock.c
index a6a622e..9b91fb1 100644
--- a/sys/kern/kern_rmlock.c
+++ b/sys/kern/kern_rmlock.c
@@ -241,8 +241,8 @@ rm_sysinit_flags(void *arg)
 	rm_init_flags(args->ra_rm, args->ra_desc, args->ra_opts);
 }
 
-static void
-_rm_rlock_hard(struct rmlock *rm, struct rm_priotracker *tracker)
+static int
+_rm_rlock_hard(struct rmlock *rm, struct rm_priotracker *tracker, int trylock)
 {
 	struct pcpu *pc;
 	struct rm_queue *queue;
@@ -254,7 +254,7 @@ _rm_rlock_hard(struct rmlock *rm, struct rm_priotracker *tracker)
 	/* Check if we just need to do a proper critical_exit. */
 	if (0 == rm->rm_noreadtoken) {
 		critical_exit();
-		return;
+		return (1);
 	}
 
 	/* Remove our tracker from the per-cpu list. */
@@ -265,7 +265,7 @@ _rm_rlock_hard(struct rmlock *rm, struct rm_priotracker *tracker)
 		/* Just add back tracker - we hold the lock. */
 		rm_tracker_add(pc, tracker);
 		critical_exit();
-		return;
+		return (1);
 	}
 
 	/*
@@ -289,7 +289,7 @@ _rm_rlock_hard(struct rmlock *rm, struct rm_priotracker *tracker)
 				mtx_unlock_spin(&rm_spinlock);
 				rm_tracker_add(pc, tracker);
 				critical_exit();
-				return;
+				return (1);
 			}
 		}
 	}
@@ -297,6 +297,9 @@ _rm_rlock_hard(struct rmlock *rm, struct rm_priotracker *tracker)
 	sched_unpin();
 	critical_exit();
 
+	if (trylock)
+		return (0);
+
 	mtx_lock(&rm->rm_lock);
 	rm->rm_noreadtoken = 0;
 	critical_enter();
@@ -307,10 +310,12 @@ _rm_rlock_hard(struct rmlock *rm, struct rm_priotracker *tracker)
 	critical_exit();
 
 	mtx_unlock(&rm->rm_lock);
+
+	return (1);
 }
 
-void
-_rm_rlock(struct rmlock *rm, struct rm_priotracker *tracker)
+int
+_rm_rlock(struct rmlock *rm, struct rm_priotracker *tracker, int trylock)
 {
 	struct thread *td = curthread;
 	struct pcpu *pc;
@@ -338,10 +343,10 @@ _rm_rlock(struct rmlock *rm, struct rm_priotracker *tracker)
 	 * conditional jump.
 	 */
 	if (0 == (td->td_owepreempt | rm->rm_noreadtoken))
-		return;
+		return (1);
 
 	/* We do not have a read token and need to acquire one. */
-	_rm_rlock_hard(rm, tracker);
+	return _rm_rlock_hard(rm, tracker, trylock);
 }
 
 static void
@@ -470,20 +475,23 @@ _rm_wunlock_debug(struct rmlock *rm, const char *file, int line)
 	_rm_wunlock(rm);
 }
 
-void
+int
 _rm_rlock_debug(struct rmlock *rm, struct rm_priotracker *tracker,
-    const char *file, int line)
+    int trylock, const char *file, int line)
 {
-
 	WITNESS_CHECKORDER(&rm->lock_object, LOP_NEWORDER, file, line, NULL);
 
-	_rm_rlock(rm, tracker);
+	if (_rm_rlock(rm, tracker, trylock)) {
+		LOCK_LOG_LOCK("RMRLOCK", &rm->lock_object, 0, 0, file, line);
 
-	LOCK_LOG_LOCK("RMRLOCK", &rm->lock_object, 0, 0, file, line);
+		WITNESS_LOCK(&rm->lock_object, 0, file, line);
 
-	WITNESS_LOCK(&rm->lock_object, 0, file, line);
+		curthread->td_locks++;
 
-	curthread->td_locks++;
+		return (1);
+	}
+
+	return (0);
 }
 
 void
@@ -517,12 +525,12 @@ _rm_wunlock_debug(struct rmlock *rm, const char *file, int line)
 	_rm_wunlock(rm);
 }
 
-void
+int
 _rm_rlock_debug(struct rmlock *rm, struct rm_priotracker *tracker,
-    const char *file, int line)
+    int trylock, const char *file, int line)
 {
 
-	_rm_rlock(rm, tracker);
+	return _rm_rlock(rm, tracker, trylock);
 }
 
 void
diff --git a/sys/sys/rmlock.h b/sys/sys/rmlock.h
index 9766f67..5261bcf 100644
--- a/sys/sys/rmlock.h
+++ b/sys/sys/rmlock.h
@@ -53,14 +53,15 @@ void	rm_sysinit_flags(void *arg);
 
 void	_rm_wlock_debug(struct rmlock *rm, const char *file, int line);
 void	_rm_wunlock_debug(struct rmlock *rm, const char *file, int line);
-void	_rm_rlock_debug(struct rmlock *rm, struct rm_priotracker *tracker,
-	    const char *file, int line);
+int	_rm_rlock_debug(struct rmlock *rm, struct rm_priotracker *tracker,
+	    int trylock, const char *file, int line);
 void	_rm_runlock_debug(struct rmlock *rm,  struct rm_priotracker *tracker,
 	    const char *file, int line);
 
 void	_rm_wlock(struct rmlock *rm);
 void	_rm_wunlock(struct rmlock *rm);
-void	_rm_rlock(struct rmlock *rm, struct rm_priotracker *tracker);
+int	_rm_rlock(struct rmlock *rm, struct rm_priotracker *tracker,
+	    int trylock);
 void	_rm_runlock(struct rmlock *rm,  struct rm_priotracker *tracker);
 
 /*
@@ -74,14 +75,17 @@ void	_rm_runlock(struct rmlock *rm,  struct rm_priotracker *tracker);
 #define	rm_wlock(rm)	_rm_wlock_debug((rm), LOCK_FILE, LOCK_LINE)
 #define	rm_wunlock(rm)	_rm_wunlock_debug((rm), LOCK_FILE, LOCK_LINE)
 #define	rm_rlock(rm,tracker)  \
-    _rm_rlock_debug((rm),(tracker), LOCK_FILE, LOCK_LINE )
+    ((void)_rm_rlock_debug((rm),(tracker), 0, LOCK_FILE, LOCK_LINE ))
+#define	rm_try_rlock(rm,tracker)  \
+    _rm_rlock_debug((rm),(tracker), 1, LOCK_FILE, LOCK_LINE )
 #define	rm_runlock(rm,tracker)	\
     _rm_runlock_debug((rm), (tracker), LOCK_FILE, LOCK_LINE )
 #else
-#define	rm_wlock(rm)		_rm_wlock((rm))
-#define	rm_wunlock(rm)		_rm_wunlock((rm))
-#define	rm_rlock(rm,tracker)   	_rm_rlock((rm),(tracker))
-#define	rm_runlock(rm,tracker)	_rm_runlock((rm), (tracker))
+#define	rm_wlock(rm)			_rm_wlock((rm))
+#define	rm_wunlock(rm)			_rm_wunlock((rm))
+#define	rm_rlock(rm,tracker)		((void)_rm_rlock((rm),(tracker), 0))
+#define	rm_try_rlock(rm,tracker)	_rm_rlock((rm),(tracker), 1)
+#define	rm_runlock(rm,tracker)		_rm_runlock((rm), (tracker))
 #endif
 
 struct rm_args {

--Boundary-00=_J1KaMsyD3+FF4Et--



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