#include <sys/rwstlock.h>
#include <sys/errno.h>
#include <sys/debug.h>
#include <sys/lockstat.h>
#include <sys/sysmacros.h>
#include <sys/condvar_impl.h>
static int
rwst_enter_common(rwstlock_t *l, krw_t rw, int flags)
{
hrtime_t sleep_time;
int writer;
intptr_t readers;
mutex_enter(&l->rwst_lock);
if (rw == RW_READER || rw == RW_READER_STARVEWRITER) {
while (RWST_WRITE_HELD(l) ||
(rw != RW_READER_STARVEWRITER && RWST_WRITE_WANTED(l))) {
if (flags & RWST_TRYENTER) {
mutex_exit(&l->rwst_lock);
return (0);
}
if (panicstr)
return (0);
if (RWST_WRITE_HELD(l)) {
writer = 1;
readers = 0;
} else {
writer = 0;
readers = l->rwst_count;
}
sleep_time = -gethrtime();
if (!RWST_READ_WAIT(l, flags)) {
mutex_exit(&l->rwst_lock);
return (EINTR);
}
sleep_time += gethrtime();
LOCKSTAT_RECORD4(LS_RW_ENTER_BLOCK, l, sleep_time, rw,
writer, readers);
}
RWST_READ_ENTER(l);
LOCKSTAT_RECORD(LS_RW_ENTER_ACQUIRE, l, rw);
} else {
ASSERT(rw == RW_WRITER);
while (RWST_HELD(l)) {
if (flags & RWST_TRYENTER) {
mutex_exit(&l->rwst_lock);
return (0);
}
if (panicstr)
return (0);
if (RWST_WRITE_HELD(l)) {
writer = 1;
readers = 0;
} else {
writer = 0;
readers = l->rwst_count;
}
sleep_time = -gethrtime();
if (!RWST_WRITE_WAIT(l, flags)) {
if (!RWST_WRITE_HELD(l) &&
!RWST_WRITE_WANTED(l))
RWST_READ_WAKE_ALL(l);
mutex_exit(&l->rwst_lock);
return (EINTR);
}
sleep_time += gethrtime();
LOCKSTAT_RECORD4(LS_RW_ENTER_BLOCK, l, sleep_time, rw,
writer, readers);
}
RWST_WRITE_ENTER(l);
LOCKSTAT_RECORD(LS_RW_ENTER_ACQUIRE, l, rw);
}
mutex_exit(&l->rwst_lock);
return (flags & RWST_TRYENTER);
}
void
rwst_exit(rwstlock_t *l)
{
mutex_enter(&l->rwst_lock);
if (RWST_WRITE_HELD(l)) {
LOCKSTAT_RECORD(LS_RW_EXIT_RELEASE, l, RW_WRITER);
RWST_WRITE_EXIT(l);
} else {
ASSERT(RWST_READ_HELD(l));
LOCKSTAT_RECORD(LS_RW_EXIT_RELEASE, l, RW_READER);
RWST_READ_EXIT(l);
}
if (!RWST_WRITE_WANTED(l))
RWST_READ_WAKE_ALL(l);
else if (!RWST_HELD(l))
RWST_WRITE_WAKE_ONE(l);
mutex_exit(&l->rwst_lock);
}
void
rwst_enter(rwstlock_t *l, krw_t rw)
{
(void) rwst_enter_common(l, rw, 0);
}
int
rwst_enter_sig(rwstlock_t *l, krw_t rw)
{
return (rwst_enter_common(l, rw, RWST_SIG));
}
int
rwst_tryenter(rwstlock_t *l, krw_t rw)
{
return (rwst_enter_common(l, rw, RWST_TRYENTER));
}
int
rwst_lock_held(rwstlock_t *l, krw_t rw)
{
if (rw != RW_WRITER)
return (RWST_READ_HELD(l));
ASSERT(rw == RW_WRITER);
return (RWST_WRITE_OWNER(l));
}
void
rwst_init(rwstlock_t *l, char *name, krw_type_t krw_t, void *arg)
{
l->rwst_count = 0;
mutex_init(&l->rwst_lock, NULL, MUTEX_DEFAULT, NULL);
cv_init(&l->rwst_rcv, NULL, CV_DEFAULT, NULL);
cv_init(&l->rwst_wcv, NULL, CV_DEFAULT, NULL);
}
void
rwst_destroy(rwstlock_t *l)
{
ASSERT(l->rwst_count == 0);
mutex_destroy(&l->rwst_lock);
cv_destroy(&l->rwst_rcv);
cv_destroy(&l->rwst_wcv);
}
struct _kthread *
rwst_owner(rwstlock_t *l)
{
return (RWST_OWNER(l));
}