Module Name: src
Committed By: thorpej
Date: Sun Jul 11 01:58:41 UTC 2021
Modified Files:
src/sys/arch/alpha/alpha: genassym.cf lock_stubs.s machdep.c
src/sys/arch/alpha/include: rwlock.h
Log Message:
Optimized fast-paths for rw_enter() / rw_tryenter() / rw_exit().
To generate a diff of this commit:
cvs rdiff -u -r1.28 -r1.29 src/sys/arch/alpha/alpha/genassym.cf
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/alpha/alpha/lock_stubs.s
cvs rdiff -u -r1.373 -r1.374 src/sys/arch/alpha/alpha/machdep.c
cvs rdiff -u -r1.5 -r1.6 src/sys/arch/alpha/include/rwlock.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/alpha/alpha/genassym.cf
diff -u src/sys/arch/alpha/alpha/genassym.cf:1.28 src/sys/arch/alpha/alpha/genassym.cf:1.29
--- src/sys/arch/alpha/alpha/genassym.cf:1.28 Sun Jul 11 01:54:42 2021
+++ src/sys/arch/alpha/alpha/genassym.cf Sun Jul 11 01:58:41 2021
@@ -1,4 +1,4 @@
-# $NetBSD: genassym.cf,v 1.28 2021/07/11 01:54:42 thorpej Exp $
+# $NetBSD: genassym.cf,v 1.29 2021/07/11 01:58:41 thorpej Exp $
#
# Copyright (c) 1982, 1990, 1993
@@ -66,12 +66,15 @@
# from: @(#)genassym.c 8.3 (Berkeley) 1/4/94
#
+quote #define __RWLOCK_PRIVATE
+
include <sys/param.h>
include <sys/buf.h>
include <sys/proc.h>
include <sys/sched.h>
include <sys/mbuf.h>
include <sys/msgbuf.h>
+include <sys/rwlock.h>
include <sys/syscall.h>
include <machine/cpu.h>
@@ -196,3 +199,9 @@ define CPU_INFO_IDLE_LWP offsetof(struct
define CPU_INFO_SSIR offsetof(struct cpu_info, ci_ssir)
define CPU_INFO_MTX_COUNT offsetof(struct cpu_info, ci_mtx_count)
define CPU_INFO_SIZEOF sizeof(struct cpu_info)
+
+# Bits in lock fields
+define RW_WRITE_WANTED RW_WRITE_WANTED
+define RW_WRITE_LOCKED RW_WRITE_LOCKED
+define RW_READ_INCR RW_READ_INCR
+define RW_READ_COUNT_SHIFT RW_READ_COUNT_SHIFT
Index: src/sys/arch/alpha/alpha/lock_stubs.s
diff -u src/sys/arch/alpha/alpha/lock_stubs.s:1.4 src/sys/arch/alpha/alpha/lock_stubs.s:1.5
--- src/sys/arch/alpha/alpha/lock_stubs.s:1.4 Fri Sep 4 02:54:56 2020
+++ src/sys/arch/alpha/alpha/lock_stubs.s Sun Jul 11 01:58:41 2021
@@ -1,11 +1,11 @@
-/* $NetBSD: lock_stubs.s,v 1.4 2020/09/04 02:54:56 thorpej Exp $ */
+/* $NetBSD: lock_stubs.s,v 1.5 2021/07/11 01:58:41 thorpej Exp $ */
/*-
- * Copyright (c) 2007 The NetBSD Foundation, Inc.
+ * Copyright (c) 2007, 2021 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Andrew Doran.
+ * by Andrew Doran, and by Jason R. Thorpe.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -34,7 +34,7 @@
#include <machine/asm.h>
-__KERNEL_RCSID(0, "$NetBSD: lock_stubs.s,v 1.4 2020/09/04 02:54:56 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: lock_stubs.s,v 1.5 2021/07/11 01:58:41 thorpej Exp $");
#include "assym.h"
@@ -63,7 +63,7 @@ LEAF(_lock_cas, 3)
RET
3:
br 1b
-END(_lock_cas)
+ END(_lock_cas)
#if !defined(LOCKDEBUG)
@@ -72,7 +72,7 @@ END(_lock_cas)
*/
LEAF(mutex_enter, 1)
LDGP(pv)
- GET_CURLWP
+ GET_CURLWP /* Note: GET_CURLWP clobbers v0, t0, t8...t11. */
1:
mov v0, t1
ldq_l t2, 0(a0)
@@ -86,7 +86,7 @@ LEAF(mutex_enter, 1)
jmp (t12)
3:
br 1b
-END(mutex_enter)
+ END(mutex_enter)
/*
* void mutex_exit(kmutex_t *mtx);
@@ -94,7 +94,7 @@ END(mutex_enter)
LEAF(mutex_exit, 1)
LDGP(pv)
MB
- GET_CURLWP
+ GET_CURLWP /* Note: GET_CURLWP clobbers v0, t0, t8...t11. */
mov zero, t3
1:
ldq_l t2, 0(a0)
@@ -108,6 +108,162 @@ LEAF(mutex_exit, 1)
jmp (t12)
3:
br 1b
-END(mutex_exit)
+ END(mutex_exit)
+
+/*
+ * void rw_enter(krwlock_t *rwl, krw_t op);
+ *
+ * Acquire one hold on a RW lock.
+ */
+LEAF(rw_enter, 2)
+ LDGP(pv)
+
+ /*
+ * RW_READER == 0 (we have a compile-time assert in machdep.c
+ * to ensure this).
+ *
+ * Acquire for read is the most common case.
+ */
+ bne a1, 3f
+
+ /* Acquiring for read. */
+1: ldq_l t0, 0(a0)
+ and t0, (RW_WRITE_LOCKED|RW_WRITE_WANTED), t1
+ addq t0, RW_READ_INCR, t2
+ bne t1, 4f /* contended */
+ stq_c t2, 0(a0)
+ beq t2, 2f /* STQ_C failed; retry */
+ MB
+ RET
+
+2: br 1b
+
+3: /* Acquiring for write. */
+ GET_CURLWP /* Note: GET_CURLWP clobbers v0, t0, t8...t11. */
+ ldq_l t0, 0(a0)
+ or v0, RW_WRITE_LOCKED, t2
+ bne t0, 4f /* contended */
+ stq_c t2, 0(a0)
+ beq t2, 4f /* STQ_C failed; consider it contended */
+ MB
+ RET
+
+4: lda pv, rw_vector_enter
+ jmp (pv)
+ END(rw_enter)
+
+/*
+ * int rw_tryenter(krwlock_t *rwl, krw_t op);
+ *
+ * Try to acquire one hold on a RW lock.
+ */
+LEAF(rw_tryenter, 2)
+ LDGP(pv)
+
+ /* See above. */
+ bne a1, 3f
+
+ /* Acquiring for read. */
+1: ldq_l t0, 0(a0)
+ and t0, (RW_WRITE_LOCKED|RW_WRITE_WANTED), t1
+ addq t0, RW_READ_INCR, v0
+ bne t1, 4f /* contended */
+ stq_c v0, 0(a0)
+ beq v0, 2f /* STQ_C failed; retry */
+ MB
+ RET /* v0 contains non-zero LOCK_FLAG from STQ_C */
+
+2: br 1b
+
+ /* Acquiring for write. */
+3: GET_CURLWP /* Note: GET_CURLWP clobbers v0, t0, t8...t11. */
+ ldq_l t0, 0(a0)
+ or v0, RW_WRITE_LOCKED, v0
+ bne t0, 4f /* contended */
+ stq_c v0, 0(a0)
+ /*
+ * v0 now contains the LOCK_FLAG value from STQ_C, which is either
+ * 0 for failure, or non-zero for success. In either case, v0's
+ * value is correct. Go ahead and perform the memory barrier even
+ * in the failure case because we expect it to be rare and it saves
+ * a branch-not-taken instruction in the success case.
+ */
+ MB
+ RET
+
+4: mov zero, v0 /* return 0 (failure) */
+ RET
+ END(rw_tryenter)
+
+/*
+ * void rw_exit(krwlock_t *rwl);
+ *
+ * Release one hold on a RW lock.
+ */
+LEAF(rw_exit, 1)
+ LDGP(pv)
+ MB
+
+ /*
+ * Check for write-lock release, and get the owner/count field
+ * on its own for sanity-checking against expected values.
+ */
+ ldq a1, 0(a0)
+ and a1, RW_WRITE_LOCKED, t1
+ srl a1, RW_READ_COUNT_SHIFT, a2
+ bne t1, 3f
+
+ /*
+ * Releasing a read-lock. Make sure the count is non-zero.
+ * If it is zero, take the slow path where the juicy diagnostic
+ * checks are located.
+ */
+ beq a2, 4f
+
+ /*
+ * We do the following trick to check to see if we're releasing
+ * the last read-count and there are waiters:
+ *
+ * 1. Set v0 to 1.
+ * 2. Shift the new read count into t1.
+ * 3. Conditally move t1 to v0 based on low-bit-set of t0
+ * (RW_HAS_WAITERS). If RW_HAS_WAITERS is not set, then
+ * the move will not take place, and v0 will remain 1.
+ * Otherwise, v0 will contain the updated read count.
+ * 4. Jump to slow path if v0 == 0.
+ */
+1: ldq_l t0, 0(a0)
+ ldiq v0, 1
+ subq t0, RW_READ_INCR, t2
+ srl t2, RW_READ_COUNT_SHIFT, t1
+ cmovlbs t0, t1, v0
+ beq v0, 4f
+ stq_c t2, 0(a0)
+ beq t2, 2f /* STQ_C failed; try again */
+ RET
+
+2: br 1b
+
+ /*
+ * Releasing a write-lock. Make sure the owner field points
+ * to our LWP. If it does not, take the slow path where the
+ * juicy diagnostic checks are located. a2 contains the owner
+ * field shifted down. Shift it back up to compare to curlwp;
+ * this conveniently discards the bits we don't want to compare.
+ */
+3: GET_CURLWP /* Note: GET_CURLWP clobbers v0, t0, t8...t11. */
+ sll a2, RW_READ_COUNT_SHIFT, a2
+ mov zero, t2 /* fast-path write-unlock stores NULL */
+ cmpeq v0, a2, v0 /* v0 = (owner == curlwp) */
+ ldq_l t0, 0(a0)
+ beq v0, 4f /* owner field mismatch; need slow path */
+ blbs t0, 4f /* RW_HAS_WAITERS set; need slow-path */
+ stq_c t2, 0(a0)
+ beq t2, 4f /* STQ_C failed; need slow-path */
+ RET
+
+4: lda pv, rw_vector_exit
+ jmp (pv)
+ END(rw_exit)
#endif /* !LOCKDEBUG */
Index: src/sys/arch/alpha/alpha/machdep.c
diff -u src/sys/arch/alpha/alpha/machdep.c:1.373 src/sys/arch/alpha/alpha/machdep.c:1.374
--- src/sys/arch/alpha/alpha/machdep.c:1.373 Sun Jul 4 22:42:35 2021
+++ src/sys/arch/alpha/alpha/machdep.c Sun Jul 11 01:58:41 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: machdep.c,v 1.373 2021/07/04 22:42:35 thorpej Exp $ */
+/* $NetBSD: machdep.c,v 1.374 2021/07/11 01:58:41 thorpej Exp $ */
/*-
* Copyright (c) 1998, 1999, 2000, 2019, 2020 The NetBSD Foundation, Inc.
@@ -65,9 +65,11 @@
#include "opt_dec_3000_500.h"
#include "opt_execfmt.h"
+#define __RWLOCK_PRIVATE
+
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
-__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.373 2021/07/04 22:42:35 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.374 2021/07/11 01:58:41 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -95,6 +97,7 @@ __KERNEL_RCSID(0, "$NetBSD: machdep.c,v
#include <sys/kauth.h>
#include <sys/atomic.h>
#include <sys/cpu.h>
+#include <sys/rwlock.h>
#include <machine/kcore.h>
#include <machine/fpu.h>
@@ -133,6 +136,10 @@ int sigdebug = 0x0;
int sigpid = 0;
#endif
+/* Assert some assumptions made in lock_stubs.s */
+__CTASSERT(RW_READER == 0);
+__CTASSERT(RW_HAS_WAITERS == 1);
+
#include <machine/alpha.h>
#include "ksyms.h"
Index: src/sys/arch/alpha/include/rwlock.h
diff -u src/sys/arch/alpha/include/rwlock.h:1.5 src/sys/arch/alpha/include/rwlock.h:1.6
--- src/sys/arch/alpha/include/rwlock.h:1.5 Fri Nov 29 20:04:52 2019
+++ src/sys/arch/alpha/include/rwlock.h Sun Jul 11 01:58:41 2021
@@ -1 +1,37 @@
-/* $NetBSD: rwlock.h,v 1.5 2019/11/29 20:04:52 riastradh Exp $ */
+/* $NetBSD: rwlock.h,v 1.6 2021/07/11 01:58:41 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 2002, 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe and Andrew Doran.
+ *
+ * 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, 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+#ifndef _ALPHA_RWLOCK_H_
+#define _ALPHA_RWLOCK_H_
+
+#define __HAVE_RW_STUBS 1
+
+#endif /* _ALPHA_RWLOCK_H_ */