Hi, This also happened the last time I touched rw_downgrade(), and I backed out the change then, but both times I don't see the bug. I have some questions:
- Are you running DIAGNOSTIC and/or LOCKDEBUG? I would be very interested to see what happens with a LOCKDEBUG kernel here. - Do you have an ATI Radeon graphics chip? - Are you using ZFS? Thanks, Andrew On Mon, Jan 20, 2020 at 12:41:37PM +0900, Ryo ONODERA wrote: > Hi, > > After this commit, the kernel stalls just before root file system > will be found on my NetBSD/amd64 laptop. > > Reverting > src/sys/kern/kern_rwlock.c to r1.60 > and > src/sys/sys/rwlock.h to r1.12 > in latest -current tree and I can get the kernel that works like > before. > > And on another laptop, the problematic kernel stalls before root file > system detection like my laptop. > > It may be universal problem. > > Could you take a look at this problem? > > Thank you. > > "Andrew Doran" <a...@netbsd.org> writes: > > > Module Name: src > > Committed By: ad > > Date: Sun Jan 19 18:34:24 UTC 2020 > > > > Modified Files: > > src/sys/kern: kern_rwlock.c > > src/sys/sys: rwlock.h > > > > Log Message: > > Tidy rwlocks a bit, no functional change intended. Mainly: > > > > - rw_downgrade(): do it in a for () loop like all the others. > > - Explicitly carry around RW_NODEBUG - don't be lazy. > > - Remove pointless macros. > > - Don't make assertions conditional on LOCKDEBUG, there's no reason. > > - Make space for a new flag bit (not added yet). > > > > > > To generate a diff of this commit: > > cvs rdiff -u -r1.60 -r1.61 src/sys/kern/kern_rwlock.c > > cvs rdiff -u -r1.12 -r1.13 src/sys/sys/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/kern/kern_rwlock.c > > diff -u src/sys/kern/kern_rwlock.c:1.60 src/sys/kern/kern_rwlock.c:1.61 > > --- src/sys/kern/kern_rwlock.c:1.60 Sun Jan 12 18:37:10 2020 > > +++ src/sys/kern/kern_rwlock.c Sun Jan 19 18:34:24 2020 > > @@ -1,4 +1,4 @@ > > -/* $NetBSD: kern_rwlock.c,v 1.60 2020/01/12 18:37:10 ad Exp $ */ > > +/* $NetBSD: kern_rwlock.c,v 1.61 2020/01/19 18:34:24 ad Exp $ */ > > > > /*- > > * Copyright (c) 2002, 2006, 2007, 2008, 2009, 2019, 2020 > > @@ -39,7 +39,9 @@ > > */ > > > > #include <sys/cdefs.h> > > -__KERNEL_RCSID(0, "$NetBSD: kern_rwlock.c,v 1.60 2020/01/12 18:37:10 ad > > Exp $"); > > +__KERNEL_RCSID(0, "$NetBSD: kern_rwlock.c,v 1.61 2020/01/19 18:34:24 ad > > Exp $"); > > + > > +#include "opt_lockdebug.h" > > > > #define __RWLOCK_PRIVATE > > > > @@ -63,58 +65,32 @@ __KERNEL_RCSID(0, "$NetBSD: kern_rwlock. > > * LOCKDEBUG > > */ > > > > -#if defined(LOCKDEBUG) > > - > > -#define RW_WANTLOCK(rw, op) > > \ > > - LOCKDEBUG_WANTLOCK(RW_DEBUG_P(rw), (rw), \ > > - (uintptr_t)__builtin_return_address(0), op == RW_READER); > > -#define RW_LOCKED(rw, op) > > \ > > - LOCKDEBUG_LOCKED(RW_DEBUG_P(rw), (rw), NULL, \ > > - (uintptr_t)__builtin_return_address(0), op == RW_READER); > > -#define RW_UNLOCKED(rw, op) > > \ > > - LOCKDEBUG_UNLOCKED(RW_DEBUG_P(rw), (rw), \ > > - (uintptr_t)__builtin_return_address(0), op == RW_READER); > > -#define RW_DASSERT(rw, cond) > > \ > > -do { > > \ > > - if (__predict_false(!(cond))) \ > > - rw_abort(__func__, __LINE__, rw, "assertion failed: " #cond);\ > > -} while (/* CONSTCOND */ 0); > > - > > -#else /* LOCKDEBUG */ > > - > > -#define RW_WANTLOCK(rw, op) /* nothing */ > > -#define RW_LOCKED(rw, op) /* nothing */ > > -#define RW_UNLOCKED(rw, op) /* nothing */ > > -#define RW_DASSERT(rw, cond) /* nothing */ > > +#define RW_DEBUG_P(rw) (((rw)->rw_owner & RW_NODEBUG) == 0) > > > > -#endif /* LOCKDEBUG */ > > +#define RW_WANTLOCK(rw, op) \ > > + LOCKDEBUG_WANTLOCK(RW_DEBUG_P(rw), (rw), \ > > + (uintptr_t)__builtin_return_address(0), op == RW_READER); > > +#define RW_LOCKED(rw, op) \ > > + LOCKDEBUG_LOCKED(RW_DEBUG_P(rw), (rw), NULL, \ > > + (uintptr_t)__builtin_return_address(0), op == RW_READER); > > +#define RW_UNLOCKED(rw, op) \ > > + LOCKDEBUG_UNLOCKED(RW_DEBUG_P(rw), (rw), \ > > + (uintptr_t)__builtin_return_address(0), op == RW_READER); > > > > /* > > * DIAGNOSTIC > > */ > > > > #if defined(DIAGNOSTIC) > > - > > -#define RW_ASSERT(rw, cond) > > \ > > -do { > > \ > > - if (__predict_false(!(cond))) \ > > +#define RW_ASSERT(rw, cond) \ > > +do { \ > > + if (__predict_false(!(cond))) \ > > rw_abort(__func__, __LINE__, rw, "assertion failed: " #cond);\ > > } while (/* CONSTCOND */ 0) > > - > > #else > > - > > #define RW_ASSERT(rw, cond) /* nothing */ > > - > > #endif /* DIAGNOSTIC */ > > > > -#define RW_SETDEBUG(rw, on) ((rw)->rw_owner |= (on) ? 0 : > > RW_NODEBUG) > > -#define RW_DEBUG_P(rw) (((rw)->rw_owner & RW_NODEBUG) > > == 0) > > -#if defined(LOCKDEBUG) > > -#define RW_INHERITDEBUG(n, o) (n) |= (o) & RW_NODEBUG > > -#else /* defined(LOCKDEBUG) */ > > -#define RW_INHERITDEBUG(n, o) /* nothing */ > > -#endif /* defined(LOCKDEBUG) */ > > - > > /* > > * Memory barriers. > > */ > > @@ -128,29 +104,6 @@ do { > > \ > > #define RW_MEMBAR_PRODUCER() membar_producer() > > #endif > > > > -static void rw_abort(const char *, size_t, krwlock_t *, const char > > *); > > -static void rw_dump(const volatile void *, lockop_printer_t); > > -static lwp_t *rw_owner(wchan_t); > > - > > -static inline uintptr_t > > -rw_cas(krwlock_t *rw, uintptr_t o, uintptr_t n) > > -{ > > - > > - RW_INHERITDEBUG(n, o); > > - return (uintptr_t)atomic_cas_ptr((volatile void *)&rw->rw_owner, > > - (void *)o, (void *)n); > > -} > > - > > -static inline void > > -rw_swap(krwlock_t *rw, uintptr_t o, uintptr_t n) > > -{ > > - > > - RW_INHERITDEBUG(n, o); > > - n = (uintptr_t)atomic_swap_ptr((volatile void *)&rw->rw_owner, > > - (void *)n); > > - RW_DASSERT(rw, n == o); > > -} > > - > > /* > > * For platforms that do not provide stubs, or for the LOCKDEBUG case. > > */ > > @@ -164,6 +117,10 @@ __strong_alias(rw_exit,rw_vector_exit); > > __strong_alias(rw_tryenter,rw_vector_tryenter); > > #endif > > > > +static void rw_abort(const char *, size_t, krwlock_t *, const char > > *); > > +static void rw_dump(const volatile void *, lockop_printer_t); > > +static lwp_t *rw_owner(wchan_t); > > + > > lockops_t rwlock_lockops = { > > .lo_name = "Reader / writer lock", > > .lo_type = LOCKOPS_SLEEP, > > @@ -179,6 +136,37 @@ syncobj_t rw_syncobj = { > > }; > > > > /* > > + * rw_cas: > > + * > > + * Do an atomic compare-and-swap on the lock word. > > + */ > > +static inline uintptr_t > > +rw_cas(krwlock_t *rw, uintptr_t o, uintptr_t n) > > +{ > > + > > + return (uintptr_t)atomic_cas_ptr((volatile void *)&rw->rw_owner, > > + (void *)o, (void *)n); > > +} > > + > > +/* > > + * rw_swap: > > + * > > + * Do an atomic swap of the lock word. This is used only when it's > > + * known that the lock word is set up such that it can't be changed > > + * behind us (assert this), so there's no point considering the result. > > + */ > > +static inline void > > +rw_swap(krwlock_t *rw, uintptr_t o, uintptr_t n) > > +{ > > + > > + n = (uintptr_t)atomic_swap_ptr((volatile void *)&rw->rw_owner, > > + (void *)n); > > + > > + RW_ASSERT(rw, n == o); > > + RW_ASSERT(rw, (o & RW_HAS_WAITERS) != 0); > > +} > > + > > +/* > > * rw_dump: > > * > > * Dump the contents of a rwlock structure. > > @@ -214,16 +202,14 @@ rw_abort(const char *func, size_t line, > > * > > * Initialize a rwlock for use. > > */ > > -void _rw_init(krwlock_t *, uintptr_t); > > void > > _rw_init(krwlock_t *rw, uintptr_t return_address) > > { > > - bool dodebug; > > > > - memset(rw, 0, sizeof(*rw)); > > - > > - dodebug = LOCKDEBUG_ALLOC(rw, &rwlock_lockops, return_address); > > - RW_SETDEBUG(rw, dodebug); > > + if (LOCKDEBUG_ALLOC(rw, &rwlock_lockops, return_address)) > > + rw->rw_owner = 0; > > + else > > + rw->rw_owner = RW_NODEBUG; > > } > > > > void > > @@ -243,7 +229,7 @@ rw_destroy(krwlock_t *rw) > > { > > > > RW_ASSERT(rw, (rw->rw_owner & ~RW_NODEBUG) == 0); > > - LOCKDEBUG_FREE(RW_DEBUG_P(rw), rw); > > + LOCKDEBUG_FREE((rw->rw_owner & RW_NODEBUG) == 0, rw); > > } > > > > /* > > @@ -327,7 +313,7 @@ rw_vector_enter(krwlock_t *rw, const krw > > need_wait = RW_WRITE_LOCKED | RW_WRITE_WANTED; > > queue = TS_READER_Q; > > } else { > > - RW_DASSERT(rw, op == RW_WRITER); > > + RW_ASSERT(rw, op == RW_WRITER); > > incr = curthread | RW_WRITE_LOCKED; > > set_wait = RW_HAS_WAITERS | RW_WRITE_WANTED; > > need_wait = RW_WRITE_LOCKED | RW_THREAD; > > @@ -430,7 +416,7 @@ rw_vector_enter(krwlock_t *rw, const krw > > (uintptr_t)__builtin_return_address(0))); > > LOCKSTAT_EXIT(lsflag); > > > > - RW_DASSERT(rw, (op != RW_READER && RW_OWNER(rw) == curthread) || > > + RW_ASSERT(rw, (op != RW_READER && RW_OWNER(rw) == curthread) || > > (op == RW_READER && RW_COUNT(rw) != 0)); > > RW_LOCKED(rw, op); > > } > > @@ -448,7 +434,8 @@ rw_vector_exit(krwlock_t *rw) > > int rcnt, wcnt; > > lwp_t *l; > > > > - curthread = (uintptr_t)curlwp; > > + l = curlwp; > > + curthread = (uintptr_t)l; > > RW_ASSERT(rw, curthread != 0); > > > > /* > > @@ -491,8 +478,8 @@ rw_vector_exit(krwlock_t *rw) > > */ > > ts = turnstile_lookup(rw); > > owner = rw->rw_owner; > > - RW_DASSERT(rw, ts != NULL); > > - RW_DASSERT(rw, (owner & RW_HAS_WAITERS) != 0); > > + RW_ASSERT(rw, ts != NULL); > > + RW_ASSERT(rw, (owner & RW_HAS_WAITERS) != 0); > > > > wcnt = TS_WAITERS(ts, TS_WRITER_Q); > > rcnt = TS_WAITERS(ts, TS_READER_Q); > > @@ -509,31 +496,35 @@ rw_vector_exit(krwlock_t *rw) > > * do the work of acquiring the lock in rw_vector_enter(). > > */ > > if (rcnt == 0 || decr == RW_READ_INCR) { > > - RW_DASSERT(rw, wcnt != 0); > > - RW_DASSERT(rw, (owner & RW_WRITE_WANTED) != 0); > > + RW_ASSERT(rw, wcnt != 0); > > + RW_ASSERT(rw, (owner & RW_WRITE_WANTED) != 0); > > > > if (rcnt != 0) { > > /* Give the lock to the longest waiting writer. */ > > l = TS_FIRST(ts, TS_WRITER_Q); > > - newown = (uintptr_t)l | RW_WRITE_LOCKED | > > RW_HAS_WAITERS; > > + newown = (uintptr_t)l | (owner & RW_NODEBUG); > > + newown |= RW_WRITE_LOCKED | RW_HAS_WAITERS; > > if (wcnt > 1) > > newown |= RW_WRITE_WANTED; > > rw_swap(rw, owner, newown); > > turnstile_wakeup(ts, TS_WRITER_Q, 1, l); > > } else { > > /* Wake all writers and let them fight it out. */ > > - rw_swap(rw, owner, RW_WRITE_WANTED); > > + newown = owner & RW_NODEBUG; > > + newown |= RW_WRITE_WANTED; > > + rw_swap(rw, owner, newown); > > turnstile_wakeup(ts, TS_WRITER_Q, wcnt, NULL); > > } > > } else { > > - RW_DASSERT(rw, rcnt != 0); > > + RW_ASSERT(rw, rcnt != 0); > > > > /* > > * Give the lock to all blocked readers. If there > > * is a writer waiting, new readers that arrive > > * after the release will be blocked out. > > */ > > - newown = rcnt << RW_READ_COUNT_SHIFT; > > + newown = owner & RW_NODEBUG; > > + newown += rcnt << RW_READ_COUNT_SHIFT; > > if (wcnt != 0) > > newown |= RW_HAS_WAITERS | RW_WRITE_WANTED; > > > > @@ -552,8 +543,10 @@ int > > rw_vector_tryenter(krwlock_t *rw, const krw_t op) > > { > > uintptr_t curthread, owner, incr, need_wait, next; > > + lwp_t *l; > > > > - curthread = (uintptr_t)curlwp; > > + l = curlwp; > > + curthread = (uintptr_t)l; > > > > RW_ASSERT(rw, curthread != 0); > > > > @@ -561,7 +554,7 @@ rw_vector_tryenter(krwlock_t *rw, const > > incr = RW_READ_INCR; > > need_wait = RW_WRITE_LOCKED | RW_WRITE_WANTED; > > } else { > > - RW_DASSERT(rw, op == RW_WRITER); > > + RW_ASSERT(rw, op == RW_WRITER); > > incr = curthread | RW_WRITE_LOCKED; > > need_wait = RW_WRITE_LOCKED | RW_THREAD; > > } > > @@ -572,24 +565,23 @@ rw_vector_tryenter(krwlock_t *rw, const > > next = rw_cas(rw, owner, owner + incr); > > if (__predict_true(next == owner)) { > > /* Got it! */ > > - RW_MEMBAR_ENTER(); > > break; > > } > > } > > > > RW_WANTLOCK(rw, op); > > RW_LOCKED(rw, op); > > - RW_DASSERT(rw, (op != RW_READER && RW_OWNER(rw) == curthread) || > > + RW_ASSERT(rw, (op != RW_READER && RW_OWNER(rw) == curthread) || > > (op == RW_READER && RW_COUNT(rw) != 0)); > > > > + RW_MEMBAR_ENTER(); > > return 1; > > } > > > > /* > > * rw_downgrade: > > * > > - * Downgrade a write lock to a read lock. Optimise memory accesses for > > - * the uncontended case. > > + * Downgrade a write lock to a read lock. > > */ > > void > > rw_downgrade(krwlock_t *rw) > > @@ -597,55 +589,64 @@ rw_downgrade(krwlock_t *rw) > > uintptr_t owner, curthread, newown, next; > > turnstile_t *ts; > > int rcnt, wcnt; > > + lwp_t *l; > > > > - curthread = (uintptr_t)curlwp; > > + l = curlwp; > > + curthread = (uintptr_t)l; > > RW_ASSERT(rw, curthread != 0); > > - RW_DASSERT(rw, (rw->rw_owner & RW_WRITE_LOCKED) != 0); > > + RW_ASSERT(rw, (rw->rw_owner & RW_WRITE_LOCKED) != 0); > > RW_ASSERT(rw, RW_OWNER(rw) == curthread); > > RW_UNLOCKED(rw, RW_WRITER); > > #if !defined(DIAGNOSTIC) > > __USE(curthread); > > #endif > > > > - /* > > - * If there are no waiters, so we can do this the easy way. > > - * Try swapping us down to one read hold. If it fails, the > > - * lock condition has changed and we most likely now have > > - * waiters. > > - */ > > RW_MEMBAR_PRODUCER(); > > - owner = curthread | RW_WRITE_LOCKED; > > - next = rw_cas(rw, owner, RW_READ_INCR); > > - if (__predict_true(next == owner)) { > > - RW_LOCKED(rw, RW_READER); > > - RW_DASSERT(rw, (rw->rw_owner & RW_WRITE_LOCKED) == 0); > > - RW_DASSERT(rw, RW_COUNT(rw) != 0); > > - return; > > - } > > > > - /* > > - * Grab the turnstile chain lock. This gets the interlock > > - * on the sleep queue. Once we have that, we can adjust the > > - * waiter bits. > > - */ > > - for (;;) { > > - owner = next; > > + for (owner = rw->rw_owner;; owner = next) { > > + /* > > + * If there are no waiters we can do this the easy way. Try > > + * swapping us down to one read hold. If it fails, the lock > > + * condition has changed and we most likely now have > > + * waiters. > > + */ > > + if ((owner & RW_HAS_WAITERS) == 0) { > > + newown = (owner & RW_NODEBUG); > > + next = rw_cas(rw, owner, newown + RW_READ_INCR); > > + if (__predict_true(next == owner)) { > > + RW_LOCKED(rw, RW_READER); > > + RW_ASSERT(rw, > > + (rw->rw_owner & RW_WRITE_LOCKED) == 0); > > + RW_ASSERT(rw, RW_COUNT(rw) != 0); > > + return; > > + } > > + continue; > > + } > > + > > + /* > > + * Grab the turnstile chain lock. This gets the interlock > > + * on the sleep queue. Once we have that, we can adjust the > > + * waiter bits. > > + */ > > ts = turnstile_lookup(rw); > > - RW_DASSERT(rw, ts != NULL); > > + RW_ASSERT(rw, ts != NULL); > > > > rcnt = TS_WAITERS(ts, TS_READER_Q); > > wcnt = TS_WAITERS(ts, TS_WRITER_Q); > > > > - /* > > - * If there are no readers, just preserve the waiters > > - * bits, swap us down to one read hold and return. > > - */ > > if (rcnt == 0) { > > - RW_DASSERT(rw, wcnt != 0); > > - RW_DASSERT(rw, (rw->rw_owner & RW_WRITE_WANTED) != 0); > > - RW_DASSERT(rw, (rw->rw_owner & RW_HAS_WAITERS) != 0); > > - > > - newown = RW_READ_INCR | RW_HAS_WAITERS | > > RW_WRITE_WANTED; > > + /* > > + * If there are no readers, just preserve the > > + * waiters bits, swap us down to one read hold and > > + * return. > > + */ > > + RW_ASSERT(rw, wcnt != 0); > > + RW_ASSERT(rw, (rw->rw_owner & RW_WRITE_WANTED) != 0); > > + RW_ASSERT(rw, (rw->rw_owner & RW_HAS_WAITERS) != 0); > > + > > + newown = owner & RW_NODEBUG; > > + newown = RW_READ_INCR | RW_HAS_WAITERS | > > + RW_WRITE_WANTED; > > next = rw_cas(rw, owner, newown); > > turnstile_exit(rw); > > if (__predict_true(next == owner)) > > @@ -653,11 +654,12 @@ rw_downgrade(krwlock_t *rw) > > } else { > > /* > > * Give the lock to all blocked readers. We may > > - * retain one read hold if downgrading. If there > > - * is a writer waiting, new readers will be blocked > > + * retain one read hold if downgrading. If there is > > + * a writer waiting, new readers will be blocked > > * out. > > */ > > - newown = (rcnt << RW_READ_COUNT_SHIFT) + RW_READ_INCR; > > + newown = owner & RW_NODEBUG; > > + newown += (rcnt << RW_READ_COUNT_SHIFT) + RW_READ_INCR; > > if (wcnt != 0) > > newown |= RW_HAS_WAITERS | RW_WRITE_WANTED; > > > > @@ -673,22 +675,24 @@ rw_downgrade(krwlock_t *rw) > > > > RW_WANTLOCK(rw, RW_READER); > > RW_LOCKED(rw, RW_READER); > > - RW_DASSERT(rw, (rw->rw_owner & RW_WRITE_LOCKED) == 0); > > - RW_DASSERT(rw, RW_COUNT(rw) != 0); > > + RW_ASSERT(rw, (rw->rw_owner & RW_WRITE_LOCKED) == 0); > > + RW_ASSERT(rw, RW_COUNT(rw) != 0); > > } > > > > /* > > * rw_tryupgrade: > > * > > * Try to upgrade a read lock to a write lock. We must be the only > > - * reader. Optimise memory accesses for the uncontended case. > > + * reader. > > */ > > int > > rw_tryupgrade(krwlock_t *rw) > > { > > uintptr_t owner, curthread, newown, next; > > + struct lwp *l; > > > > - curthread = (uintptr_t)curlwp; > > + l = curlwp; > > + curthread = (uintptr_t)l; > > RW_ASSERT(rw, curthread != 0); > > RW_ASSERT(rw, rw_read_held(rw)); > > > > @@ -709,8 +713,8 @@ rw_tryupgrade(krwlock_t *rw) > > RW_UNLOCKED(rw, RW_READER); > > RW_WANTLOCK(rw, RW_WRITER); > > RW_LOCKED(rw, RW_WRITER); > > - RW_DASSERT(rw, rw->rw_owner & RW_WRITE_LOCKED); > > - RW_DASSERT(rw, RW_OWNER(rw) == curthread); > > + RW_ASSERT(rw, rw->rw_owner & RW_WRITE_LOCKED); > > + RW_ASSERT(rw, RW_OWNER(rw) == curthread); > > > > return 1; > > } > > > > Index: src/sys/sys/rwlock.h > > diff -u src/sys/sys/rwlock.h:1.12 src/sys/sys/rwlock.h:1.13 > > --- src/sys/sys/rwlock.h:1.12 Wed Jan 1 21:34:39 2020 > > +++ src/sys/sys/rwlock.h Sun Jan 19 18:34:24 2020 > > @@ -1,7 +1,7 @@ > > -/* $NetBSD: rwlock.h,v 1.12 2020/01/01 21:34:39 ad Exp $ */ > > +/* $NetBSD: rwlock.h,v 1.13 2020/01/19 18:34:24 ad Exp $ */ > > > > /*- > > - * Copyright (c) 2002, 2006, 2007, 2008, 2019 The NetBSD Foundation, Inc. > > + * Copyright (c) 2002, 2006, 2007, 2008, 2019, 2020 The NetBSD Foundation, > > Inc. > > * All rights reserved. > > * > > * This code is derived from software contributed to The NetBSD Foundation > > @@ -45,10 +45,6 @@ > > * rw_tryenter() > > */ > > > > -#if defined(_KERNEL_OPT) > > -#include "opt_lockdebug.h" > > -#endif > > - > > #if !defined(_KERNEL) > > #include <sys/types.h> > > #include <sys/inttypes.h> > > @@ -75,13 +71,9 @@ typedef struct krwlock krwlock_t; > > #define RW_HAS_WAITERS 0x01UL /* lock has waiters */ > > #define RW_WRITE_WANTED 0x02UL /* >= 1 waiter is a writer */ > > #define RW_WRITE_LOCKED 0x04UL /* lock is currently write > > locked */ > > -#if defined(LOCKDEBUG) > > -#define RW_NODEBUG 0x08UL /* LOCKDEBUG disabled */ > > -#else > > -#define RW_NODEBUG 0x00UL /* do nothing */ > > -#endif /* LOCKDEBUG */ > > +#define RW_NODEBUG 0x10UL /* LOCKDEBUG disabled */ > > > > -#define RW_READ_COUNT_SHIFT 4 > > +#define RW_READ_COUNT_SHIFT 5 > > #define RW_READ_INCR (1UL << RW_READ_COUNT_SHIFT) > > #define RW_THREAD ((uintptr_t)-RW_READ_INCR) > > #define RW_OWNER(rw) ((rw)->rw_owner & RW_THREAD) > > @@ -91,6 +83,7 @@ typedef struct krwlock krwlock_t; > > void rw_vector_enter(krwlock_t *, const krw_t); > > void rw_vector_exit(krwlock_t *); > > int rw_vector_tryenter(krwlock_t *, const krw_t); > > +void _rw_init(krwlock_t *, uintptr_t); > > #endif /* __RWLOCK_PRIVATE */ > > > > struct krwlock { > > > > -- > Ryo ONODERA // r...@tetera.org > PGP fingerprint = 82A2 DC91 76E0 A10A 8ABB FD1B F404 27FA C7D1 15F3