From e2abcdca396661cbe0ae2ddb13d5c2b85682c13a Mon Sep 17 00:00:00 2001 From: Cem Keylan Date: Fri, 16 Oct 2020 17:41:25 +0300 Subject: initial commit --- sys/sys/rwlock.h | 191 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 sys/sys/rwlock.h (limited to 'sys/sys/rwlock.h') diff --git a/sys/sys/rwlock.h b/sys/sys/rwlock.h new file mode 100644 index 0000000..4b32e38 --- /dev/null +++ b/sys/sys/rwlock.h @@ -0,0 +1,191 @@ +/* $OpenBSD: rwlock.h,v 1.26 2019/07/16 01:40:49 jsg Exp $ */ +/* + * Copyright (c) 2002 Artur Grabowski + * + * 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. + */ + +/* + * Multiple readers, single writer lock. + * + * Simplistic implementation modelled after rw locks in Solaris. + * + * The rwl_owner has the following layout: + * [ owner or count of readers | wrlock | wrwant | wait ] + * + * When the WAIT bit is set (bit 0), the lock has waiters sleeping on it. + * When the WRWANT bit is set (bit 1), at least one waiter wants a write lock. + * When the WRLOCK bit is set (bit 2) the lock is currently write-locked. + * + * When write locked, the upper bits contain the struct proc * pointer to + * the writer, otherwise they count the number of readers. + * + * We provide a simple machine independent implementation: + * + * 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. + * + * void rw_enter_write(struct rwlock *); + * atomically test for the lock being 0 (it's not possible to have + * owner/read count unset and waiter bits set) and if 0 set the owner to + * the proc and RWLOCK_WRLOCK. While not zero, loop into rw_enter_wait. + * + * void rw_exit_read(struct rwlock *); + * atomically decrement lock by RWLOCK_READ_INCR and unset RWLOCK_WAIT and + * RWLOCK_WRWANT remembering the old value of lock and if RWLOCK_WAIT was set, + * call rw_exit_waiters with the old contents of the lock. + * + * void rw_exit_write(struct rwlock *); + * atomically swap the contents of the lock with 0 and if RWLOCK_WAIT was + * set, call rw_exit_waiters with the old contents of the lock. + */ + +#ifndef _SYS_RWLOCK_H +#define _SYS_RWLOCK_H + +#include + +struct proc; + +struct rwlock { + volatile unsigned long rwl_owner; + const char *rwl_name; +#ifdef WITNESS + struct lock_object rwl_lock_obj; +#endif +}; + +#define RWLOCK_LO_FLAGS(flags) \ + ((ISSET(flags, RWL_DUPOK) ? LO_DUPOK : 0) | \ + (ISSET(flags, RWL_NOWITNESS) ? 0 : LO_WITNESS) | \ + (ISSET(flags, RWL_IS_VNODE) ? LO_IS_VNODE : 0) | \ + LO_INITIALIZED | LO_SLEEPABLE | LO_UPGRADABLE | \ + (LO_CLASS_RWLOCK << LO_CLASSSHIFT)) + +#define RRWLOCK_LO_FLAGS(flags) \ + ((ISSET(flags, RWL_DUPOK) ? LO_DUPOK : 0) | \ + (ISSET(flags, RWL_NOWITNESS) ? 0 : LO_WITNESS) | \ + (ISSET(flags, RWL_IS_VNODE) ? LO_IS_VNODE : 0) | \ + LO_INITIALIZED | LO_RECURSABLE | LO_SLEEPABLE | LO_UPGRADABLE | \ + (LO_CLASS_RRWLOCK << LO_CLASSSHIFT)) + +#define RWLOCK_LO_INITIALIZER(name, flags) \ + { .lo_type = &(const struct lock_type){ .lt_name = name }, \ + .lo_name = (name), \ + .lo_flags = RWLOCK_LO_FLAGS(flags) } + +#define RWL_DUPOK 0x01 +#define RWL_NOWITNESS 0x02 +#define RWL_IS_VNODE 0x04 + +#ifdef WITNESS +#define RWLOCK_INITIALIZER(name) \ + { 0, name, .rwl_lock_obj = RWLOCK_LO_INITIALIZER(name, 0) } +#else +#define RWLOCK_INITIALIZER(name) \ + { 0, name } +#endif + +#define RWLOCK_WAIT 0x01UL +#define RWLOCK_WRWANT 0x02UL +#define RWLOCK_WRLOCK 0x04UL +#define RWLOCK_MASK 0x07UL + +#define RWLOCK_OWNER(rwl) ((struct proc *)((rwl)->rwl_owner & ~RWLOCK_MASK)) + +#define RWLOCK_READER_SHIFT 3UL +#define RWLOCK_READ_INCR (1UL << RWLOCK_READER_SHIFT) + +#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. */ +#define RW_DUPOK 0x0100UL /* Permit duplicate lock */ + +/* + * for rw_status() and rrw_status() only: exclusive lock held by + * some other thread + */ +#define RW_WRITE_OTHER 0x0100UL + +/* recursive rwlocks; */ +struct rrwlock { + struct rwlock rrwl_lock; + uint32_t rrwl_wcnt; /* # writers. */ +}; + +#ifdef _KERNEL + +void _rw_init_flags(struct rwlock *, const char *, int, + const struct lock_type *); + +#ifdef WITNESS +#define rw_init_flags(rwl, name, flags) do { \ + static const struct lock_type __lock_type = { .lt_name = #rwl };\ + _rw_init_flags(rwl, name, flags, &__lock_type); \ +} while (0) +#define rw_init(rwl, name) rw_init_flags(rwl, name, 0) +#else /* WITNESS */ +#define rw_init_flags(rwl, name, flags) \ + _rw_init_flags(rwl, name, flags, NULL) +#define rw_init(rwl, name) _rw_init_flags(rwl, name, 0, NULL) +#endif /* WITNESS */ + +void rw_enter_read(struct rwlock *); +void rw_enter_write(struct rwlock *); +void rw_exit_read(struct rwlock *); +void rw_exit_write(struct rwlock *); + +#ifdef DIAGNOSTIC +void rw_assert_wrlock(struct rwlock *); +void rw_assert_rdlock(struct rwlock *); +void rw_assert_anylock(struct rwlock *); +void rw_assert_unlocked(struct rwlock *); +#else +#define rw_assert_wrlock(rwl) ((void)0) +#define rw_assert_rdlock(rwl) ((void)0) +#define rw_assert_anylock(rwl) ((void)0) +#define rw_assert_unlocked(rwl) ((void)0) +#endif + +int rw_enter(struct rwlock *, int); +void rw_exit(struct rwlock *); +int rw_status(struct rwlock *); + +void _rrw_init_flags(struct rrwlock *, const char *, int, + const struct lock_type *); +int rrw_enter(struct rrwlock *, int); +void rrw_exit(struct rrwlock *); +int rrw_status(struct rrwlock *); + +#ifdef WITNESS +#define rrw_init_flags(rrwl, name, flags) do { \ + static const struct lock_type __lock_type = { .lt_name = #rrwl };\ + _rrw_init_flags(rrwl, name, flags, &__lock_type); \ +} while (0) +#define rrw_init(rrwl, name) rrw_init_flags(rrwl, name, 0) +#else /* WITNESS */ +#define rrw_init_flags(rrwl, name, flags) \ + _rrw_init_flags(rrwl, name, 0, NULL) +#define rrw_init(rrwl, name) _rrw_init_flags(rrwl, name, 0, NULL) +#endif /* WITNESS */ + +#endif /* _KERNEL */ + +#endif /* _SYS_RWLOCK_H */ -- cgit v1.2.3