#include "opt_lint.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/lock.h>
#include <sys/sysctl.h>
#include <sys/spinlock.h>
#include <sys/spinlock2.h>
#include <sys/indefinite2.h>
static void undo_shreq(struct lock *lkp);
static int undo_upreq(struct lock *lkp);
static int undo_exreq(struct lock *lkp);
#ifdef DEBUG_CANCEL_LOCKS
static int sysctl_cancel_lock(SYSCTL_HANDLER_ARGS);
static int sysctl_cancel_test(SYSCTL_HANDLER_ARGS);
static struct lock cancel_lk;
LOCK_SYSINIT(cancellk, &cancel_lk, "cancel", 0);
SYSCTL_PROC(_kern, OID_AUTO, cancel_lock, CTLTYPE_INT|CTLFLAG_RW, 0, 0,
sysctl_cancel_lock, "I", "test cancelable locks");
SYSCTL_PROC(_kern, OID_AUTO, cancel_test, CTLTYPE_INT|CTLFLAG_RW, 0, 0,
sysctl_cancel_test, "I", "test cancelable locks");
#endif
__read_frequently int lock_test_mode;
SYSCTL_INT(_debug, OID_AUTO, lock_test_mode, CTLFLAG_RW,
&lock_test_mode, 0, "");
#ifdef DEBUG_LOCKS
#define COUNT(td, x) (td)->td_locks += (x)
#else
#define COUNT(td, x) do { } while (0)
#endif
static __inline void
_lockmgr_assert(struct lock *lkp, u_int flags)
{
if (mycpu->gd_intr_nesting_level &&
(flags & LK_NOWAIT) == 0 &&
(flags & LK_TYPE_MASK) != LK_RELEASE &&
panic_cpu_gd != mycpu
) {
panic("lockmgr %s from %p: called from interrupt, ipi, "
"or hard code section",
lkp->lk_wmesg, ((int **)&lkp)[-1]);
}
}
int
lockmgr_shared(struct lock *lkp, u_int flags)
{
uint32_t extflags;
thread_t td;
uint64_t count;
int error;
int pflags;
int timo;
int didloop;
_lockmgr_assert(lkp, flags);
extflags = (flags | lkp->lk_flags) & LK_EXTFLG_MASK;
td = curthread;
count = lkp->lk_count;
cpu_ccfence();
if ((count & LKC_XMASK) && lkp->lk_lockholder == td) {
KKASSERT(lkp->lk_count & LKC_XMASK);
if ((extflags & LK_CANRECURSE) == 0) {
if (extflags & LK_NOWAIT)
return EBUSY;
panic("lockmgr: locking against myself");
}
atomic_add_64(&lkp->lk_count, 1);
COUNT(td, 1);
return 0;
}
if ((td->td_flags & TDF_DEADLKTREAT) == 0) {
while ((count & LKC_SHARED) &&
(count & (LKC_EXREQ | LKC_UPREQ))) {
if (extflags & LK_CANCELABLE) {
if (count & LKC_CANCEL)
return ENOLCK;
}
if (extflags & LK_NOWAIT)
return EBUSY;
pflags = (extflags & LK_PCATCH) ? PCATCH : 0;
timo = (extflags & LK_TIMELOCK) ? lkp->lk_timo : 0;
tsleep_interlock(lkp, pflags);
count = atomic_fetchadd_long(&lkp->lk_count, 0);
if ((count & LKC_SHARED) &&
(count & (LKC_EXREQ | LKC_UPREQ))) {
error = tsleep(lkp, pflags | PINTERLOCKED,
lkp->lk_wmesg, timo);
if (error)
return error;
count = lkp->lk_count;
cpu_ccfence();
continue;
}
break;
}
}
count = atomic_fetchadd_64(&lkp->lk_count, LKC_SCOUNT) + LKC_SCOUNT;
error = 0;
didloop = 0;
for (;;) {
if ((count & (LKC_XMASK | LKC_EXREQ |
LKC_UPREQ | LKC_SHARED)) == 0) {
if (atomic_fcmpset_64(&lkp->lk_count,
&count, count | LKC_SHARED)) {
break;
}
continue;
}
if ((td->td_flags & TDF_DEADLKTREAT) &&
(count & (LKC_XMASK | LKC_SHARED)) == 0) {
if (atomic_fcmpset_64(&lkp->lk_count,
&count, count | LKC_SHARED)) {
break;
}
continue;
}
if (count & LKC_SHARED)
break;
pflags = (extflags & LK_PCATCH) ? PCATCH : 0;
timo = (extflags & LK_TIMELOCK) ? lkp->lk_timo : 0;
if (extflags & LK_CANCELABLE) {
if (count & LKC_CANCEL) {
undo_shreq(lkp);
error = ENOLCK;
break;
}
}
if (extflags & LK_NOWAIT) {
undo_shreq(lkp);
error = EBUSY;
break;
}
if (didloop) {
error = tsleep(lkp, pflags | PINTERLOCKED,
lkp->lk_wmesg, timo);
if (extflags & LK_SLEEPFAIL) {
undo_shreq(lkp);
error = ENOLCK;
break;
}
if (error) {
undo_shreq(lkp);
break;
}
}
didloop = 1;
count = lkp->lk_count;
if (count & LKC_SHARED)
break;
tsleep_interlock(lkp, pflags);
count = atomic_fetchadd_64(&lkp->lk_count, 0);
}
if (error == 0)
COUNT(td, 1);
return error;
}
int
lockmgr_exclusive(struct lock *lkp, u_int flags)
{
uint64_t count;
uint64_t ncount;
uint32_t extflags;
thread_t td;
int error;
int pflags;
int timo;
_lockmgr_assert(lkp, flags);
extflags = (flags | lkp->lk_flags) & LK_EXTFLG_MASK;
td = curthread;
error = 0;
count = lkp->lk_count;
cpu_ccfence();
if ((count & LKC_XMASK) && lkp->lk_lockholder == td) {
if ((extflags & LK_CANRECURSE) == 0) {
if (extflags & LK_NOWAIT)
return EBUSY;
panic("lockmgr: locking against myself");
}
count = atomic_fetchadd_64(&lkp->lk_count, 1) + 1;
KKASSERT((count & LKC_XMASK) > 1);
COUNT(td, 1);
return 0;
}
for (;;) {
if ((count & (LKC_UPREQ | LKC_EXREQ |
LKC_XMASK)) == 0 &&
((count & LKC_SHARED) == 0 ||
(count & LKC_SMASK) == 0)) {
ncount = (count + 1) & ~LKC_SHARED;
if (atomic_fcmpset_64(&lkp->lk_count,
&count, ncount)) {
lkp->lk_lockholder = td;
COUNT(td, 1);
return 0;
}
continue;
}
if (extflags & LK_CANCELABLE) {
if (count & LKC_CANCEL)
return ENOLCK;
}
if (extflags & LK_NOWAIT)
return EBUSY;
pflags = (extflags & LK_PCATCH) ? PCATCH : 0;
timo = (extflags & LK_TIMELOCK) ? lkp->lk_timo : 0;
if (count & (LKC_EXREQ | LKC_XMASK))
ncount = count | LKC_EXREQ2;
else
ncount = count | LKC_EXREQ;
tsleep_interlock(lkp, pflags);
if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) {
if ((count & (LKC_EXREQ | LKC_XMASK)) == 0) {
count = ncount;
break;
}
error = tsleep(lkp, pflags | PINTERLOCKED,
lkp->lk_wmesg, timo);
count = lkp->lk_count;
cpu_ccfence();
}
#ifdef INVARIANTS
if (lock_test_mode > 0) {
--lock_test_mode;
print_backtrace(8);
}
#endif
if (error)
return error;
if (extflags & LK_SLEEPFAIL)
return ENOLCK;
}
for (;;) {
if ((count & LKC_EXREQ) == 0) {
KKASSERT(count & LKC_XMASK);
lkp->lk_lockholder = td;
COUNT(td, 1);
break;
}
if (extflags & LK_CANCELABLE) {
if (count & LKC_CANCEL) {
if (undo_exreq(lkp) == 0) {
lkp->lk_lockholder = LK_KERNTHREAD;
lockmgr_release(lkp, 0);
}
error = ENOLCK;
break;
}
}
pflags = (extflags & LK_PCATCH) ? PCATCH : 0;
timo = (extflags & LK_TIMELOCK) ? lkp->lk_timo : 0;
error = tsleep(lkp, pflags | PINTERLOCKED, lkp->lk_wmesg, timo);
#ifdef INVARIANTS
if (lock_test_mode > 0) {
--lock_test_mode;
print_backtrace(8);
}
#endif
if (extflags & LK_SLEEPFAIL) {
if (undo_exreq(lkp) == 0) {
lkp->lk_lockholder = LK_KERNTHREAD;
lockmgr_release(lkp, 0);
}
if (error == 0)
error = ENOLCK;
break;
}
if (error) {
if (undo_exreq(lkp))
break;
lkp->lk_lockholder = td;
COUNT(td, 1);
error = 0;
break;
}
count = lkp->lk_count;
cpu_ccfence();
if ((count & LKC_EXREQ) == 0) {
KKASSERT(count & LKC_XMASK);
lkp->lk_lockholder = td;
COUNT(td, 1);
break;
}
tsleep_interlock(lkp, pflags);
count = atomic_fetchadd_64(&lkp->lk_count, 0);
}
return error;
}
int
lockmgr_downgrade(struct lock *lkp, u_int flags)
{
uint64_t count;
uint64_t ncount;
uint32_t extflags;
thread_t otd;
thread_t td;
extflags = (flags | lkp->lk_flags) & LK_EXTFLG_MASK;
td = curthread;
count = lkp->lk_count;
for (;;) {
cpu_ccfence();
if (lkp->lk_lockholder != td || (count & LKC_XMASK) != 1) {
panic("lockmgr: not holding exclusive lock: "
"%p/%p %016jx", lkp->lk_lockholder, td, count);
}
otd = lkp->lk_lockholder;
lkp->lk_lockholder = NULL;
ncount = (count & ~(LKC_XMASK | LKC_EXREQ2)) +
((count & LKC_XMASK) << LKC_SSHIFT);
ncount |= LKC_SHARED;
if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) {
if (count & (LKC_SMASK | LKC_EXREQ2))
wakeup(lkp);
break;
}
lkp->lk_lockholder = otd;
}
return 0;
}
int
lockmgr_upgrade(struct lock *lkp, u_int flags)
{
uint64_t count;
uint64_t ncount;
uint32_t extflags;
thread_t td;
int error;
int pflags;
int timo;
_lockmgr_assert(lkp, flags);
extflags = (flags | lkp->lk_flags) & LK_EXTFLG_MASK;
td = curthread;
error = 0;
count = lkp->lk_count;
cpu_ccfence();
if (count & LKC_XMASK) {
if (lkp->lk_lockholder == td)
return 0;
panic("lockmgr: upgrade unowned lock");
}
if ((count & LKC_SMASK) == 0)
panic("lockmgr: upgrade unowned lock");
for (;;) {
if (count & LKC_UPREQ) {
lockmgr_release(lkp, 0);
if ((flags & LK_TYPE_MASK) == LK_EXCLUPGRADE)
error = EBUSY;
else if (extflags & LK_NOWAIT)
error = EBUSY;
else
error = lockmgr_exclusive(lkp, flags);
return error;
}
if ((count & LKC_SMASK) == LKC_SCOUNT) {
ncount = (count - LKC_SCOUNT + 1) & ~LKC_SHARED;
if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) {
lkp->lk_lockholder = td;
return 0;
}
} else if (extflags & LK_NOWAIT) {
lockmgr_release(lkp, 0);
return EBUSY;
} else {
pflags = (extflags & LK_PCATCH) ? PCATCH : 0;
tsleep_interlock(lkp, pflags);
ncount = (count - LKC_SCOUNT) | LKC_UPREQ;
if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) {
count = ncount;
break;
}
}
}
for (;;) {
cpu_ccfence();
if ((count & LKC_UPREQ) == 0) {
KKASSERT((count & LKC_XMASK) == 1);
lkp->lk_lockholder = td;
break;
}
if (extflags & LK_CANCELABLE) {
if (count & LKC_CANCEL) {
if (undo_upreq(lkp) == 0) {
lkp->lk_lockholder = LK_KERNTHREAD;
lockmgr_release(lkp, 0);
}
error = ENOLCK;
break;
}
}
pflags = (extflags & LK_PCATCH) ? PCATCH : 0;
timo = (extflags & LK_TIMELOCK) ? lkp->lk_timo : 0;
error = tsleep(lkp, pflags | PINTERLOCKED, lkp->lk_wmesg, timo);
if (extflags & LK_SLEEPFAIL) {
if (undo_upreq(lkp) == 0) {
lkp->lk_lockholder = LK_KERNTHREAD;
lockmgr_release(lkp, 0);
}
if (error == 0)
error = ENOLCK;
break;
}
if (error) {
if (undo_upreq(lkp))
break;
error = 0;
}
count = lkp->lk_count;
if ((count & LKC_UPREQ) == 0) {
KKASSERT((count & LKC_XMASK) == 1);
lkp->lk_lockholder = td;
break;
}
tsleep_interlock(lkp, pflags);
count = atomic_fetchadd_64(&lkp->lk_count, 0);
}
return error;
}
int
lockmgr_release(struct lock *lkp, u_int flags)
{
uint64_t count;
uint64_t ncount;
uint32_t extflags;
thread_t otd;
thread_t td;
extflags = (flags | lkp->lk_flags) & LK_EXTFLG_MASK;
td = curthread;
count = lkp->lk_count;
cpu_ccfence();
for (;;) {
if ((count & (LKC_SMASK | LKC_XMASK)) == 0)
panic("lockmgr: LK_RELEASE: no lock held");
if (count & LKC_XMASK) {
if (lkp->lk_lockholder != LK_KERNTHREAD &&
lkp->lk_lockholder != td) {
panic("lockmgr: pid %d, not exclusive "
"lock holder thr %p/%p unlocking",
(td->td_proc ? td->td_proc->p_pid : -1),
td, lkp->lk_lockholder);
}
if ((count & (LKC_UPREQ | LKC_EXREQ |
LKC_XMASK)) == 1) {
otd = lkp->lk_lockholder;
lkp->lk_lockholder = NULL;
ncount = (count - 1);
ncount &= ~(LKC_CANCEL | LKC_EXREQ2);
ncount |= LKC_SHARED;
if (atomic_fcmpset_64(&lkp->lk_count,
&count, ncount)) {
if (count & (LKC_SMASK | LKC_EXREQ2))
wakeup(lkp);
if (otd != LK_KERNTHREAD)
COUNT(td, -1);
break;
}
lkp->lk_lockholder = otd;
} else if ((count & (LKC_UPREQ | LKC_XMASK)) ==
(LKC_UPREQ | 1)) {
otd = lkp->lk_lockholder;
lkp->lk_lockholder = NULL;
ncount = count & ~LKC_UPREQ;
if (atomic_fcmpset_64(&lkp->lk_count,
&count, ncount)) {
wakeup(lkp);
if (otd != LK_KERNTHREAD)
COUNT(td, -1);
break;
}
lkp->lk_lockholder = otd;
} else if ((count & (LKC_EXREQ | LKC_XMASK)) ==
(LKC_EXREQ | 1)) {
otd = lkp->lk_lockholder;
lkp->lk_lockholder = NULL;
ncount = count & ~LKC_EXREQ;
if (atomic_fcmpset_64(&lkp->lk_count,
&count, ncount)) {
wakeup(lkp);
if (otd != LK_KERNTHREAD)
COUNT(td, -1);
break;
}
lkp->lk_lockholder = otd;
} else {
count =
atomic_fetchadd_long(&lkp->lk_count, -1);
if (lkp->lk_lockholder != LK_KERNTHREAD)
COUNT(td, -1);
break;
}
} else {
KKASSERT((count & LKC_SHARED) && (count & LKC_SMASK));
if ((count & (LKC_EXREQ | LKC_UPREQ | LKC_SMASK)) ==
LKC_SCOUNT) {
ncount = (count - LKC_SCOUNT) & ~LKC_CANCEL;
if (atomic_fcmpset_64(&lkp->lk_count,
&count, ncount)) {
COUNT(td, -1);
break;
}
} else if ((count & (LKC_UPREQ | LKC_SMASK)) ==
(LKC_UPREQ | LKC_SCOUNT)) {
ncount = (count - LKC_SCOUNT + 1) &
~(LKC_UPREQ | LKC_CANCEL | LKC_SHARED);
if (atomic_fcmpset_64(&lkp->lk_count,
&count, ncount)) {
wakeup(lkp);
COUNT(td, -1);
break;
}
} else if ((count & (LKC_EXREQ | LKC_SMASK)) ==
(LKC_EXREQ | LKC_SCOUNT)) {
ncount = (count - LKC_SCOUNT + 1) &
~(LKC_EXREQ | LKC_EXREQ2 |
LKC_CANCEL | LKC_SHARED);
if (atomic_fcmpset_64(&lkp->lk_count,
&count, ncount)) {
wakeup(lkp);
COUNT(td, -1);
break;
}
} else {
undo_shreq(lkp);
COUNT(td, -1);
break;
}
}
}
return 0;
}
int
lockmgr_cancel_beg(struct lock *lkp, u_int flags)
{
uint64_t count;
count = lkp->lk_count;
for (;;) {
cpu_ccfence();
KKASSERT((count & LKC_CANCEL) == 0);
KKASSERT((count & (LKC_XMASK | LKC_SMASK)) != 0);
if (!atomic_fcmpset_64(&lkp->lk_count,
&count, count | LKC_CANCEL)) {
continue;
}
if (count & (LKC_EXREQ | LKC_EXREQ2 | LKC_SMASK | LKC_UPREQ)) {
wakeup(lkp);
}
break;
}
return 0;
}
int
lockmgr_cancel_end(struct lock *lkp, u_int flags)
{
atomic_clear_long(&lkp->lk_count, LKC_CANCEL);
return 0;
}
static void
undo_shreq(struct lock *lkp)
{
uint64_t count;
uint64_t ncount;
count = atomic_fetchadd_64(&lkp->lk_count, -LKC_SCOUNT) - LKC_SCOUNT;
while ((count & (LKC_EXREQ | LKC_UPREQ | LKC_CANCEL)) &&
(count & (LKC_SMASK | LKC_XMASK)) == 0) {
if (count & LKC_UPREQ) {
ncount = (count + 1) & ~(LKC_UPREQ | LKC_CANCEL |
LKC_SHARED);
if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) {
wakeup(lkp);
break;
}
wakeup(lkp);
continue;
}
if (count & LKC_EXREQ) {
ncount = (count + 1) & ~(LKC_EXREQ | LKC_EXREQ2 |
LKC_CANCEL | LKC_SHARED);
if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) {
wakeup(lkp);
break;
}
wakeup(lkp);
continue;
}
if (count & LKC_CANCEL) {
ncount = count & ~LKC_CANCEL;
if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) {
wakeup(lkp);
break;
}
}
}
}
static
int
undo_exreq(struct lock *lkp)
{
uint64_t count;
uint64_t ncount;
int error;
count = lkp->lk_count;
error = 0;
for (;;) {
cpu_ccfence();
if ((count & LKC_EXREQ) == 0) {
break;
}
if (count & LKC_XMASK) {
ncount = count & ~(LKC_EXREQ | LKC_EXREQ2);
if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) {
if ((count & (LKC_EXREQ2 | LKC_UPREQ)) ==
LKC_EXREQ2) {
wakeup(lkp);
}
error = EBUSY;
break;
}
} else if (count & LKC_UPREQ) {
ncount = count & ~(LKC_EXREQ | LKC_EXREQ2);
if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) {
error = EBUSY;
break;
}
} else if ((count & LKC_SHARED) && (count & LKC_SMASK)) {
ncount = count & ~(LKC_EXREQ | LKC_EXREQ2);
if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) {
wakeup(lkp);
error = EBUSY;
break;
}
} else {
ncount = (count + 1) & ~(LKC_EXREQ | LKC_EXREQ2);
if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) {
if (count & (LKC_EXREQ2 | LKC_SHARED))
wakeup(lkp);
break;
}
}
}
return error;
}
static
int
undo_upreq(struct lock *lkp)
{
uint64_t count;
uint64_t ncount;
int error;
count = lkp->lk_count;
error = 0;
for (;;) {
cpu_ccfence();
if ((count & LKC_UPREQ) == 0) {
break;
}
if (count & LKC_XMASK) {
if (atomic_fcmpset_64(&lkp->lk_count, &count,
count & ~LKC_UPREQ)) {
error = EBUSY;
break;
}
} else if (count & LKC_EXREQ) {
ncount = (count + 1);
ncount &= ~(LKC_EXREQ | LKC_EXREQ2 | LKC_UPREQ);
if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) {
wakeup(lkp);
error = EBUSY;
break;
}
} else {
ncount = count & ~LKC_UPREQ;
if (count & LKC_SMASK)
ncount |= LKC_SHARED;
if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) {
if ((count & LKC_SHARED) ||
(ncount & LKC_SHARED)) {
wakeup(lkp);
}
error = EBUSY;
break;
}
}
}
return error;
}
void
lockmgr_kernproc(struct lock *lp)
{
struct thread *td __debugvar = curthread;
if (lp->lk_lockholder != LK_KERNTHREAD) {
KASSERT(lp->lk_lockholder == td,
("lockmgr_kernproc: lock not owned by curthread %p: %p",
td, lp->lk_lockholder));
lp->lk_lockholder = LK_KERNTHREAD;
COUNT(td, -1);
}
}
void
lockinit(struct lock *lkp, const char *wmesg, int timo, int flags)
{
lkp->lk_flags = (flags & LK_EXTFLG_MASK);
lkp->lk_count = 0;
lkp->lk_wmesg = wmesg;
lkp->lk_timo = timo;
lkp->lk_lockholder = NULL;
}
void
lockreinit(struct lock *lkp, const char *wmesg, int timo, int flags)
{
lkp->lk_wmesg = wmesg;
lkp->lk_timo = timo;
}
void
lockuninit(struct lock *lkp)
{
uint64_t count __unused;
count = lkp->lk_count;
cpu_ccfence();
KKASSERT((count & (LKC_EXREQ | LKC_UPREQ)) == 0 &&
((count & LKC_SHARED) || (count & LKC_SMASK) == 0));
}
int
lockstatus(struct lock *lkp, struct thread *td)
{
int lock_type = 0;
uint64_t count;
count = lkp->lk_count;
cpu_ccfence();
if (count & (LKC_XMASK | LKC_SMASK | LKC_EXREQ | LKC_UPREQ)) {
if (count & LKC_XMASK) {
if (td == NULL || lkp->lk_lockholder == td)
lock_type = LK_EXCLUSIVE;
else
lock_type = LK_EXCLOTHER;
} else if ((count & LKC_SMASK) && (count & LKC_SHARED)) {
lock_type = LK_SHARED;
}
}
return (lock_type);
}
int
lockowned(struct lock *lkp)
{
thread_t td = curthread;
uint64_t count;
count = lkp->lk_count;
cpu_ccfence();
if (count & LKC_XMASK)
return(lkp->lk_lockholder == td);
else
return((count & LKC_SMASK) != 0);
}
#if 0
int
lockcount(struct lock *lkp)
{
panic("lockcount cannot be used");
}
int
lockcountnb(struct lock *lkp)
{
panic("lockcount cannot be used");
}
#endif
void
lockmgr_printinfo(struct lock *lkp)
{
struct thread *td = lkp->lk_lockholder;
struct proc *p;
uint64_t count;
count = lkp->lk_count;
cpu_ccfence();
if (td && td != LK_KERNTHREAD)
p = td->td_proc;
else
p = NULL;
if (count & LKC_XMASK) {
kprintf(" lock type %s: EXCLUS (count %016jx) by td %p pid %d",
lkp->lk_wmesg, (intmax_t)count, td,
p ? p->p_pid : -99);
} else if ((count & LKC_SMASK) && (count & LKC_SHARED)) {
kprintf(" lock type %s: SHARED (count %016jx)",
lkp->lk_wmesg, (intmax_t)count);
} else {
kprintf(" lock type %s: NOTHELD", lkp->lk_wmesg);
}
if ((count & (LKC_EXREQ | LKC_UPREQ)) ||
((count & LKC_XMASK) && (count & LKC_SMASK)))
kprintf(" with waiters\n");
else
kprintf("\n");
}
void
lock_sysinit(struct lock_args *arg)
{
lockinit(arg->la_lock, arg->la_desc, 0, arg->la_flags);
}
#ifdef DEBUG_CANCEL_LOCKS
static
int
sysctl_cancel_lock(SYSCTL_HANDLER_ARGS)
{
int error;
if (req->newptr) {
SYSCTL_XUNLOCK();
lockmgr(&cancel_lk, LK_EXCLUSIVE);
error = tsleep(&error, PCATCH, "canmas", hz * 5);
lockmgr(&cancel_lk, LK_CANCEL_BEG);
error = tsleep(&error, PCATCH, "canmas", hz * 5);
lockmgr(&cancel_lk, LK_RELEASE);
SYSCTL_XLOCK();
SYSCTL_OUT(req, &error, sizeof(error));
}
error = 0;
return error;
}
static
int
sysctl_cancel_test(SYSCTL_HANDLER_ARGS)
{
int error;
if (req->newptr) {
error = lockmgr(&cancel_lk, LK_EXCLUSIVE|LK_CANCELABLE);
if (error == 0)
lockmgr(&cancel_lk, LK_RELEASE);
SYSCTL_OUT(req, &error, sizeof(error));
kprintf("test %d\n", error);
}
return 0;
}
#endif