take 42. http://marc.info/?l=openbsd-tech&m=130999022613838&w=2
Updated diff follows below. Add rrwlocks. Make lockmgr a wrapper shim. Tests, oks, the whole nine yards, please. And maybe if I get lucky this can get committed before it's two years old... Index: kern/kern_lock.c =================================================================== RCS file: /cvs/src/sys/kern/kern_lock.c,v retrieving revision 1.39 diff -u -p -r1.39 kern_lock.c --- kern/kern_lock.c 28 Mar 2013 16:55:25 -0000 1.39 +++ kern/kern_lock.c 5 Apr 2013 05:57:38 -0000 @@ -41,39 +41,10 @@ #include <sys/systm.h> #include <sys/sched.h> - -/* - * Locking primitives implementation. - * Locks provide shared/exclusive synchronization. - */ - -/* - * Acquire a resource. We sleep on the address of the lk_sharecount - * member normally; if waiting for it to drain we sleep on the address - * of the lk_waitcount member instead. - */ -#define ACQUIRE(lkp, error, extflags, drain, wanted) \ -do { \ - for (error = 0; wanted; ) { \ - if ((drain)) \ - (lkp)->lk_flags |= LK_WAITDRAIN; \ - else \ - (lkp)->lk_waitcount++; \ - error = tsleep((drain) ? \ - &(lkp)->lk_waitcount : &(lkp)->lk_sharecount, \ - (lkp)->lk_prio, (lkp)->lk_wmesg, (lkp)->lk_timo); \ - if ((drain) == 0) \ - (lkp)->lk_waitcount--; \ - if (error) \ - break; \ - } \ -} while (0) - -#define SETHOLDER(lkp, pid, cpu_id) \ - (lkp)->lk_lockholder = (pid) - -#define WEHOLDIT(lkp, pid, cpu_id) \ - ((lkp)->lk_lockholder == (pid)) +#ifdef MP_LOCKDEBUG +/* CPU-dependent timing, needs this to be settable from ddb. */ +int __mp_lock_spinout = 200000000; +#endif /* * Initialize a lock; required before use. @@ -81,261 +52,46 @@ do { \ void lockinit(struct lock *lkp, int prio, char *wmesg, int timo, int flags) { + KASSERT(flags == 0); bzero(lkp, sizeof(struct lock)); - lkp->lk_flags = flags & LK_EXTFLG_MASK; - lkp->lk_lockholder = LK_NOPROC; - lkp->lk_prio = prio; - lkp->lk_timo = timo; - lkp->lk_wmesg = wmesg; /* just a name for spin locks */ + rrw_init(&lkp->lk_lck, wmesg); } -/* - * Determine the status of a lock. - */ int lockstatus(struct lock *lkp) { - int lock_type = 0; - - if (lkp->lk_exclusivecount != 0) - lock_type = LK_EXCLUSIVE; - else if (lkp->lk_sharecount != 0) - lock_type = LK_SHARED; - return (lock_type); + return (rrw_status(&lkp->lk_lck)); } -/* - * Set, change, or release a lock. - * - * Shared requests increment the shared count. Exclusive requests set the - * LK_WANT_EXCL flag (preventing further shared locks), and wait for already - * accepted shared locks and shared-to-exclusive upgrades to go away. - */ int -lockmgr(__volatile struct lock *lkp, u_int flags, void *notused) +lockmgr(struct lock *lkp, u_int flags, void *notused) { - int error; - pid_t pid; - int extflags; - cpuid_t cpu_id; - struct proc *p = curproc; - - error = 0; - extflags = (flags | lkp->lk_flags) & LK_EXTFLG_MASK; - -#ifdef DIAGNOSTIC - if (p == NULL) - panic("lockmgr: process context required"); -#endif - /* Process context required. */ - pid = p->p_pid; - cpu_id = cpu_number(); - - /* - * Once a lock has drained, the LK_DRAINING flag is set and an - * exclusive lock is returned. The only valid operation thereafter - * is a single release of that exclusive lock. This final release - * clears the LK_DRAINING flag and sets the LK_DRAINED flag. Any - * further requests of any sort will result in a panic. The bits - * selected for these two flags are chosen so that they will be set - * in memory that is freed (freed memory is filled with 0xdeadbeef). - */ - if (lkp->lk_flags & (LK_DRAINING|LK_DRAINED)) { -#ifdef DIAGNOSTIC - if (lkp->lk_flags & LK_DRAINED) - panic("lockmgr: using decommissioned lock"); - if ((flags & LK_TYPE_MASK) != LK_RELEASE || - WEHOLDIT(lkp, pid, cpu_id) == 0) - panic("lockmgr: non-release on draining lock: %d", - flags & LK_TYPE_MASK); -#endif /* DIAGNOSTIC */ - lkp->lk_flags &= ~LK_DRAINING; - lkp->lk_flags |= LK_DRAINED; - } + int rwflags = 0; - /* - * Check if the caller is asking us to be schizophrenic. - */ - if ((lkp->lk_flags & (LK_CANRECURSE|LK_RECURSEFAIL)) == - (LK_CANRECURSE|LK_RECURSEFAIL)) - panic("lockmgr: make up your mind"); - - switch (flags & LK_TYPE_MASK) { - - case LK_SHARED: - if (WEHOLDIT(lkp, pid, cpu_id) == 0) { - /* - * If just polling, check to see if we will block. - */ - if ((extflags & LK_NOWAIT) && (lkp->lk_flags & - (LK_HAVE_EXCL | LK_WANT_EXCL))) { - error = EBUSY; - break; - } - /* - * Wait for exclusive locks and upgrades to clear. - */ - ACQUIRE(lkp, error, extflags, 0, lkp->lk_flags & - (LK_HAVE_EXCL | LK_WANT_EXCL)); - if (error) - break; - lkp->lk_sharecount++; - break; - } - /* - * We hold an exclusive lock, so downgrade it to shared. - * An alternative would be to fail with EDEADLK. - */ - lkp->lk_sharecount++; - - if (WEHOLDIT(lkp, pid, cpu_id) == 0 || - lkp->lk_exclusivecount == 0) - panic("lockmgr: not holding exclusive lock"); - lkp->lk_sharecount += lkp->lk_exclusivecount; - lkp->lk_exclusivecount = 0; - lkp->lk_flags &= ~LK_HAVE_EXCL; - SETHOLDER(lkp, LK_NOPROC, LK_NOCPU); - if (lkp->lk_waitcount) - wakeup(&lkp->lk_sharecount); - break; - - case LK_EXCLUSIVE: - if (WEHOLDIT(lkp, pid, cpu_id)) { - /* - * Recursive lock. - */ - if ((extflags & LK_CANRECURSE) == 0) { - if (extflags & LK_RECURSEFAIL) { - error = EDEADLK; - break; - } else - panic("lockmgr: locking against myself"); - } - lkp->lk_exclusivecount++; - break; - } - /* - * If we are just polling, check to see if we will sleep. - */ - if ((extflags & LK_NOWAIT) && ((lkp->lk_flags & - (LK_HAVE_EXCL | LK_WANT_EXCL)) || - lkp->lk_sharecount != 0)) { - error = EBUSY; - break; - } - /* - * Try to acquire the want_exclusive flag. - */ - ACQUIRE(lkp, error, extflags, 0, lkp->lk_flags & - (LK_HAVE_EXCL | LK_WANT_EXCL)); - if (error) - break; - lkp->lk_flags |= LK_WANT_EXCL; - /* - * Wait for shared locks and upgrades to finish. - */ - ACQUIRE(lkp, error, extflags, 0, lkp->lk_sharecount != 0); - lkp->lk_flags &= ~LK_WANT_EXCL; - if (error) - break; - lkp->lk_flags |= LK_HAVE_EXCL; - SETHOLDER(lkp, pid, cpu_id); - if (lkp->lk_exclusivecount != 0) - panic("lockmgr: non-zero exclusive count"); - lkp->lk_exclusivecount = 1; - break; - - case LK_RELEASE: - if (lkp->lk_exclusivecount != 0) { - if (WEHOLDIT(lkp, pid, cpu_id) == 0) { - panic("lockmgr: pid %d, not exclusive lock " - "holder %d unlocking", - pid, lkp->lk_lockholder); - } - lkp->lk_exclusivecount--; - if (lkp->lk_exclusivecount == 0) { - lkp->lk_flags &= ~LK_HAVE_EXCL; - SETHOLDER(lkp, LK_NOPROC, LK_NOCPU); - } - } else if (lkp->lk_sharecount != 0) { - lkp->lk_sharecount--; - } -#ifdef DIAGNOSTIC - else - panic("lockmgr: release of unlocked lock!"); -#endif - if (lkp->lk_waitcount) - wakeup(&lkp->lk_sharecount); - break; - - case LK_DRAIN: - /* - * Check that we do not already hold the lock, as it can - * never drain if we do. Unfortunately, we have no way to - * check for holding a shared lock, but at least we can - * check for an exclusive one. - */ - if (WEHOLDIT(lkp, pid, cpu_id)) - panic("lockmgr: draining against myself"); - /* - * If we are just polling, check to see if we will sleep. - */ - if ((extflags & LK_NOWAIT) && ((lkp->lk_flags & - (LK_HAVE_EXCL | LK_WANT_EXCL)) || - lkp->lk_sharecount != 0 || lkp->lk_waitcount != 0)) { - error = EBUSY; - break; - } - ACQUIRE(lkp, error, extflags, 1, - ((lkp->lk_flags & - (LK_HAVE_EXCL | LK_WANT_EXCL)) || - lkp->lk_sharecount != 0 || - lkp->lk_waitcount != 0)); - if (error) - break; - lkp->lk_flags |= LK_DRAINING | LK_HAVE_EXCL; - SETHOLDER(lkp, pid, cpu_id); - lkp->lk_exclusivecount = 1; - break; - - default: - panic("lockmgr: unknown locktype request %d", - flags & LK_TYPE_MASK); - /* NOTREACHED */ - } - if ((lkp->lk_flags & LK_WAITDRAIN) != 0 && - ((lkp->lk_flags & - (LK_HAVE_EXCL | LK_WANT_EXCL)) == 0 && - lkp->lk_sharecount == 0 && lkp->lk_waitcount == 0)) { - lkp->lk_flags &= ~LK_WAITDRAIN; - wakeup(&lkp->lk_waitcount); + KASSERT(!((flags & (LK_SHARED|LK_EXCLUSIVE)) == + (LK_SHARED|LK_EXCLUSIVE))); + KASSERT(!((flags & (LK_CANRECURSE|LK_RECURSEFAIL)) == + (LK_CANRECURSE|LK_RECURSEFAIL))); + KASSERT((flags & LK_RELEASE) || + (flags & (LK_SHARED|LK_EXCLUSIVE|LK_DRAIN))); + + if (flags & LK_RELEASE) { + rrw_exit(&lkp->lk_lck); + return (0); } - return (error); -} + if (flags & LK_SHARED) + rwflags |= RW_READ; + if (flags & (LK_EXCLUSIVE|LK_DRAIN)) + rwflags |= RW_WRITE; + if (flags & LK_RECURSEFAIL) + rwflags |= RW_RECURSEFAIL; + if (flags & LK_NOWAIT) + rwflags |= RW_NOSLEEP; -#ifdef DIAGNOSTIC -/* - * Print out information about state of a lock. Used by VOP_PRINT - * routines to display status about contained locks. - */ -void -lockmgr_printinfo(__volatile struct lock *lkp) -{ + return (rrw_enter(&lkp->lk_lck, rwflags)); - if (lkp->lk_sharecount) - printf(" lock type %s: SHARED (count %d)", lkp->lk_wmesg, - lkp->lk_sharecount); - else if (lkp->lk_flags & LK_HAVE_EXCL) { - printf(" lock type %s: EXCL (count %d) by ", - lkp->lk_wmesg, lkp->lk_exclusivecount); - printf("pid %d", lkp->lk_lockholder); - } else - printf(" not locked"); - if (lkp->lk_waitcount > 0) - printf(" with %d pending", lkp->lk_waitcount); } -#endif /* DIAGNOSTIC */ #if defined(MULTIPROCESSOR) /* @@ -343,7 +99,7 @@ lockmgr_printinfo(__volatile struct lock * so that they show up in profiles. */ -struct __mp_lock kernel_lock; +struct __mp_lock kernel_lock; void _kernel_lock_init(void) @@ -368,10 +124,4 @@ _kernel_unlock(void) { __mp_unlock(&kernel_lock); } - -#ifdef MP_LOCKDEBUG -/* CPU-dependent timing, needs this to be settable from ddb. */ -int __mp_lock_spinout = 200000000; -#endif - #endif /* MULTIPROCESSOR */ Index: kern/kern_rwlock.c =================================================================== RCS file: /cvs/src/sys/kern/kern_rwlock.c,v retrieving revision 1.17 diff -u -p -r1.17 kern_rwlock.c --- kern/kern_rwlock.c 5 Jul 2011 03:58:22 -0000 1.17 +++ kern/kern_rwlock.c 5 Apr 2013 05:57:38 -0000 @@ -2,27 +2,19 @@ /* * Copyright (c) 2002, 2003 Artur Grabowski <a...@openbsd.org> - * All rights reserved. + * Copyright (c) 2011 Thordur Bjornsson <h...@secnorth.net> * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED ``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. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <sys/param.h> @@ -69,6 +61,9 @@ static const struct rwlock_op { 0, PLOCK }, + { /* Sparse Entry. */ + 0, + }, { /* RW_DOWNGRADE */ RWLOCK_READ_INCR - RWLOCK_WRLOCK, 0, @@ -191,7 +186,7 @@ rw_enter(struct rwlock *rwl, int flags) unsigned long inc, o; int error; - op = &rw_ops[flags & RW_OPMASK]; + op = &rw_ops[(flags & RW_OPMASK) - 1]; inc = op->inc + RW_PROC(curproc) * op->proc_mult; retry: @@ -258,6 +253,13 @@ rw_exit(struct rwlock *rwl) wakeup(rwl); } +int +rw_status(struct rwlock *rwl) +{ + + return (rwl->rwl_owner != 0L); +} + #ifdef DIAGNOSTIC void rw_assert_wrlock(struct rwlock *rwl) @@ -283,3 +285,55 @@ rw_assert_unlocked(struct rwlock *rwl) panic("%s: lock held", rwl->rwl_name); } #endif + +/* recursive rwlocks; */ +void +rrw_init(struct rrwlock *rrwl, char *name) +{ + bzero(rrwl, sizeof(struct rrwlock)); + rw_init(&rrwl->rrwl_lock, name); +} + +int +rrw_enter(struct rrwlock *rrwl, int flags) +{ + int rv; + + if (RWLOCK_OWNER(&rrwl->rrwl_lock) == + (struct proc *)RW_PROC(curproc)) { + if (flags & RW_RECURSEFAIL) + return (EDEADLK); + else { + rrwl->rrwl_wcnt++; + return (0); + } + } + + rv = rw_enter(&rrwl->rrwl_lock, flags); + if (rv == 0) + rrwl->rrwl_wcnt = 1; + + return (rv); +} + +void +rrw_exit(struct rrwlock *rrwl) +{ + + if (RWLOCK_OWNER(&rrwl->rrwl_lock) == + (struct proc *)RW_PROC(curproc)) { + KASSERT(rrwl->rrwl_wcnt > 0); + rrwl->rrwl_wcnt--; + if (rrwl->rrwl_wcnt != 0) + return; + } + + rw_exit(&rrwl->rrwl_lock); +} + +int +rrw_status(struct rrwlock *rrwl) +{ + + return (rw_status(&rrwl->rrwl_lock)); +} Index: sys/lock.h =================================================================== RCS file: /cvs/src/sys/sys/lock.h,v retrieving revision 1.21 diff -u -p -r1.21 lock.h --- sys/lock.h 26 Apr 2010 05:48:19 -0000 1.21 +++ sys/lock.h 5 Apr 2013 05:57:38 -0000 @@ -42,6 +42,8 @@ #include <machine/lock.h> #endif +#include <sys/rwlock.h> + struct simplelock { }; @@ -53,123 +55,27 @@ typedef struct simplelock *simple_ #define simple_lock_try(lkp) (1) /* always succeeds */ #define simple_unlock(lkp) #define simple_lock_assert(lkp) - -static __inline void simple_lock_init(struct simplelock *lkp) -{ -} - +#define simple_lock_init(lkp) #endif /* _KERNEL */ -typedef struct lock lock_data_t; -typedef struct lock *lock_t; - -/* - * The general lock structure. Provides for multiple shared locks, - * upgrading from shared to exclusive, and sleeping until the lock - * can be gained. The simple locks are defined in <machine/param.h>. - */ struct lock { - u_int lk_flags; /* see below */ - int lk_sharecount; /* # of accepted shared locks */ - int lk_waitcount; /* # of processes sleeping for lock */ - int lk_exclusivecount; /* # of recursive exclusive locks */ - - /* - * This is the sleep message for sleep locks, and a simple name - * for spin locks. - */ - char *lk_wmesg; /* resource sleeping (for tsleep) */ - - /* pid of exclusive lock holder */ - pid_t lk_lockholder; - - /* priority at which to sleep */ - int lk_prio; - - /* maximum sleep time (for tsleep) */ - int lk_timo; + struct rrwlock lk_lck; }; -/* - * Lock request types: - * LK_SHARED - get one of many possible shared locks. If a process - * holding an exclusive lock requests a shared lock, the exclusive - * lock(s) will be downgraded to shared locks. - * LK_EXCLUSIVE - stop further shared locks, when they are cleared, - * grant a pending upgrade if it exists, then grant an exclusive - * lock. Only one exclusive lock may exist at a time, except that - * a process holding an exclusive lock may get additional exclusive - * locks if it explicitly sets the LK_CANRECURSE flag in the lock - * request, or if the LK_CANRECUSE flag was set when the lock was - * initialized. - * LK_RELEASE - release one instance of a lock. - * LK_DRAIN - wait for all activity on the lock to end, then mark it - * decommissioned. This feature is used before freeing a lock that - * is part of a piece of memory that is about to be freed. - * - * These are flags that are passed to the lockmgr routine. - */ -#define LK_TYPE_MASK 0x0000000f /* type of lock sought */ -#define LK_SHARED 0x00000001 /* shared lock */ -#define LK_EXCLUSIVE 0x00000002 /* exclusive lock */ -#define LK_RELEASE 0x00000006 /* release any type of lock */ -#define LK_DRAIN 0x00000007 /* wait for all lock activity to end */ -/* - * External lock flags. - * - * The first three flags may be set in lock_init to set their mode permanently, - * or passed in as arguments to the lock manager. - */ -#define LK_EXTFLG_MASK 0x00200070 /* mask of external flags */ -#define LK_NOWAIT 0x00000010 /* do not sleep to await lock */ -#define LK_CANRECURSE 0x00000040 /* allow recursive exclusive lock */ -#define LK_RECURSEFAIL 0x00200000 /* fail if recursive exclusive lock */ -/* - * Internal lock flags. - * - * These flags are used internally to the lock manager. - */ -#define LK_WANT_EXCL 0x00002000 /* exclusive lock sought */ -#define LK_HAVE_EXCL 0x00004000 /* exclusive lock obtained */ -#define LK_WAITDRAIN 0x00008000 /* process waiting for lock to drain */ -#define LK_DRAINING 0x00040000 /* lock is being drained */ -#define LK_DRAINED 0x00080000 /* lock has been decommissioned */ -/* - * Control flags - * - * Non-persistent external flags. - */ -#define LK_RETRY 0x00020000 /* vn_lock: retry until locked */ - -/* - * Lock return status. - * - * Successfully obtained locks return 0. Locks will always succeed - * unless one of the following is true: - * LK_NOWAIT is set and a sleep would be required (returns EBUSY). - * PCATCH is set in lock priority and a signal arrives (returns - * either EINTR or ERESTART if system calls is to be restarted). - * Non-null lock timeout and timeout expires (returns EWOULDBLOCK). - * A failed lock attempt always returns a non-zero error value. No lock - * is held after an error return. - */ - -/* - * Indicator that no process holds exclusive lock - */ -#define LK_KERNPROC ((pid_t) -2) -#define LK_NOPROC ((pid_t) -1) -#define LK_NOCPU ((cpuid_t) -1) - -void lockinit(struct lock *, int prio, char *wmesg, int timo, - int flags); -int lockmgr(__volatile struct lock *, u_int flags, void *); -void lockmgr_printinfo(__volatile struct lock *); -int lockstatus(struct lock *); +#define LK_SHARED 0x01 /* shared lock */ +#define LK_EXCLUSIVE 0x02 /* exclusive lock */ +#define LK_TYPE_MASK 0x03 /* type of lock sought */ +#define LK_DRAIN 0x04 /* wait for all lock activity to end */ +#define LK_RELEASE 0x08 /* release any type of lock */ +#define LK_NOWAIT 0x10 /* do not sleep to await lock */ +#define LK_CANRECURSE 0x20 /* allow recursive exclusive lock */ +#define LK_RECURSEFAIL 0x40 /* fail if recursive exclusive lock */ +#define LK_RETRY 0x80 /* vn_lock: retry until locked */ -int spinlock_release_all(__volatile struct lock *); -void spinlock_acquire_count(__volatile struct lock *, int); +void lockinit(struct lock *, int, char *, int, int); +int lockmgr(struct lock *, u_int flags, void *); +int lockstatus(struct lock *); -#define LOCK_ASSERT(x) /* nothing */ +#define lockmgr_printinfo(lkp) #endif /* !_LOCK_H_ */ Index: sys/rwlock.h =================================================================== RCS file: /cvs/src/sys/sys/rwlock.h,v retrieving revision 1.13 diff -u -p -r1.13 rwlock.h --- sys/rwlock.h 24 Sep 2010 13:21:30 -0000 1.13 +++ sys/rwlock.h 5 Apr 2013 05:57:38 -0000 @@ -1,27 +1,18 @@ /* $OpenBSD: rwlock.h,v 1.13 2010/09/24 13:21:30 matthew Exp $ */ /* * Copyright (c) 2002 Artur Grabowski <a...@openbsd.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, this list of conditions and the following disclaimer. - * 2. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED ``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. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* @@ -43,7 +34,7 @@ * optimized by machine dependent code when __HAVE_MD_RWLOCK is defined. * * MD code that defines __HAVE_MD_RWLOCK and implement four functions: - * + * * void rw_enter_read(struct rwlock *) * atomically test for RWLOCK_WRLOCK and if not set, increment the lock * by RWLOCK_READ_INCR. While RWLOCK_WRLOCK is set, loop into rw_enter_wait. @@ -68,7 +59,6 @@ #ifndef SYS_RWLOCK_H #define SYS_RWLOCK_H - struct proc; struct rwlock { @@ -107,17 +97,31 @@ void rw_assert_unlocked(struct rwlock *) int rw_enter(struct rwlock *, int); void rw_exit(struct rwlock *); -#define RW_WRITE 0x00UL /* exclusive lock */ -#define RW_READ 0x01UL /* shared lock */ -#define RW_DOWNGRADE 0x02UL /* downgrade exclusive to shared */ -#define RW_OPMASK 0x03UL - -#define RW_INTR 0x10UL /* interruptible sleep */ -#define RW_SLEEPFAIL 0x20UL /* fail if we slept for the lock */ -#define RW_NOSLEEP 0x40UL /* don't wait for the lock */ +int rw_status(struct rwlock *); + +#define RW_WRITE 0x0001UL /* exclusive lock */ +#define RW_READ 0x0002UL /* shared lock */ +#define RW_DOWNGRADE 0x0004UL /* downgrade exclusive to shared */ +#define RW_OPMASK 0x0007UL + +#define RW_INTR 0x0010UL /* interruptible sleep */ +#define RW_SLEEPFAIL 0x0020UL /* fail if we slept for the lock */ +#define RW_NOSLEEP 0x0040UL /* don't wait for the lock */ +#define RW_RECURSEFAIL 0x0080UL /* Fail on recursion for RRW locks. */ #ifndef rw_cas int rw_cas(volatile unsigned long *, unsigned long, unsigned long); #endif + +/* recursive rwlocks; */ +struct rrwlock { + struct rwlock rrwl_lock; + uint32_t rrwl_wcnt; /* # writers. */ +}; + +void rrw_init(struct rrwlock *, char *); +int rrw_enter(struct rrwlock *, int); +void rrw_exit(struct rrwlock *); +int rrw_status(struct rrwlock *); #endif