#ifndef _SYS_RWLOCK_H
#define _SYS_RWLOCK_H
#include <sys/_lock.h>
struct proc;
struct rwlock {
volatile unsigned long rwl_owner;
volatile unsigned int rwl_waiters;
volatile unsigned int rwl_readers;
const char *rwl_name;
#ifdef WITNESS
struct lock_object rwl_lock_obj;
#endif
int rwl_traceidx;
};
#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, 0, 0, name, .rwl_lock_obj = RWLOCK_LO_INITIALIZER(name, 0), 0 }
#define RWLOCK_INITIALIZER_TRACE(name, trace) \
{ 0, 0, 0, name, .rwl_lock_obj = RWLOCK_LO_INITIALIZER(name, 0), trace }
#else
#define RWLOCK_INITIALIZER(name) \
{ 0, 0, 0, name, 0 }
#define RWLOCK_INITIALIZER_TRACE(name, trace) \
{ 0, 0, 0, name, trace }
#endif
#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
#define RW_READ 0x0002UL
#define RW_DOWNGRADE 0x0004UL
#define RW_UPGRADE 0x0005UL
#define RW_OPMASK 0x0007UL
#define RW_INTR 0x0010UL
#define RW_NOSLEEP 0x0040UL
#define RW_RECURSEFAIL 0x0080UL
#define RW_DUPOK 0x0100UL
#define RW_WRITE_OTHER 0x0100UL
struct rrwlock {
struct rwlock rrwl_lock;
uint32_t rrwl_wcnt;
};
#ifdef _KERNEL
void _rw_init_flags(struct rwlock *, const char *, int,
const struct lock_type *, int);
#ifdef WITNESS
#define rw_init_flags_trace(rwl, name, flags, trace) do { \
static const struct lock_type __lock_type = { .lt_name = #rwl };\
_rw_init_flags(rwl, name, flags, &__lock_type, trace); \
} while (0)
#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, 0); \
} while (0)
#define rw_init(rwl, name) rw_init_flags(rwl, name, 0)
#else
#define rw_init_flags_trace(rwl, name, flags, trace) \
_rw_init_flags(rwl, name, flags, NULL, trace)
#define rw_init_flags(rwl, name, flags) \
_rw_init_flags(rwl, name, flags, NULL, 0)
#define rw_init(rwl, name) _rw_init_flags(rwl, name, 0, NULL, 0)
#endif
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 *);
static inline int
rw_read_held(struct rwlock *rwl)
{
return (rw_status(rwl) == RW_READ);
}
static inline int
rw_write_held(struct rwlock *rwl)
{
return (rw_status(rwl) == RW_WRITE);
}
static inline int
rw_lock_held(struct rwlock *rwl)
{
int status;
status = rw_status(rwl);
return (status == RW_READ || status == RW_WRITE);
}
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
#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
#ifdef WITNESS
#define rw_obj_alloc_flags(rwl, name, flags) do { \
static struct lock_type __lock_type = { .lt_name = #rwl }; \
_rw_obj_alloc_flags(rwl, name, flags, &__lock_type); \
} while (0)
#else
#define rw_obj_alloc_flags(rwl, name, flags) \
_rw_obj_alloc_flags(rwl, name, flags, NULL)
#endif
#define rw_obj_alloc(rwl, name) rw_obj_alloc_flags(rwl, name, 0)
void rw_obj_init(void);
void _rw_obj_alloc_flags(struct rwlock **, const char *, int,
struct lock_type *);
void rw_obj_hold(struct rwlock *);
int rw_obj_free(struct rwlock *);
#define DT_RWLOCK_IDX_NETLOCK 1
#define DT_RWLOCK_IDX_SOLOCK 2
#endif
#endif