Ryo ONODERA <r...@tetera.org> writes: > Hi, > > Andrew Doran <a...@netbsd.org> writes: > >> 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. > > I will enable LOCKDEBUG and DIAGNOSTIC soon.
Sadly DIAGNOSTIC and LOCKDEBUG with i915drmkms(4) makes my LCD black and I cannot see any messages. When i915drmkms is disabled, the kernel boots without freeze in DIAGNOSTIC and LOCKDEBUG case. However ioctl(2) to ims(4) causes kernel panic. I feel that this panic is not related to the boot freeze. See: $ crash -M netbsd.10.core -N netbsd.10 Crash version 9.99.39, image version 9.99.39. System panicked: kernel diagnostic assertion "ci->ci_mtx_count == -1" failed: file "/usr/src/sys/kern/kern_synch.c", line 676 mi_switch: cpu0: ci_mtx_count (-2) != -1 (block with spin-mutex held) Backtrace from time of crash is available. crash> bt _KERNEL_OPT_NARCNET() at 0 _KERNEL_OPT_ACPI_SCANPCI() at _KERNEL_OPT_ACPI_SCANPCI sys_reboot() at sys_reboot vpanic() at vpanic+0x181 kern_assert() at kern_assert+0x48 mi_switch() at mi_switch+0x9b8 sleepq_block() at sleepq_block+0x1cb turnstile_block() at turnstile_block+0x5bd mutex_enter() at mutex_enter+0x31d iic_acquire_bus() at iic_acquire_bus+0x2a ihidev_softintr() at ihidev_softintr+0x27 softint_dispatch() at softint_dispatch+0xdb DDB lost frame for Xsoftintr+0x4f, trying 0xffffda8138ef00f0 Xsoftintr() at Xsoftintr+0x4f --- interrupt --- 1c6f7f77b9463525: crash> >> - Do you have an ATI Radeon graphics chip? >> - Are you using ZFS? > > My GPU is in Intel CPU (KabyLake Refresh). > And I do not use ZFS at all. All partitions are FFSv2 with WAPBL. > >> 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 > > -- > Ryo ONODERA // r...@tetera.org > PGP fingerprint = 82A2 DC91 76E0 A10A 8ABB FD1B F404 27FA C7D1 15F3 -- Ryo ONODERA // r...@tetera.org PGP fingerprint = 82A2 DC91 76E0 A10A 8ABB FD1B F404 27FA C7D1 15F3