Index: sys/kern/subr_lock.c =================================================================== --- sys/kern/subr_lock.c +++ sys/kern/subr_lock.c @@ -50,6 +50,7 @@ #include #include #include +#include #ifdef DDB #include @@ -93,6 +94,7 @@ /* Initialize the lock object. */ lock->lo_name = name; lock->lo_flags |= flags | LO_INITIALIZED; + lock->lo_refcount = 0; LOCK_LOG_INIT(lock, 0); WITNESS_INIT(lock, (type != NULL) ? type : name); } @@ -102,11 +104,58 @@ { KASSERT(lock_initialized(lock), ("lock %p is not initialized", lock)); + KASSERT(lock->lo_refcount == 0, ("lock %p refcount is not zero", lock)); WITNESS_DESTROY(lock); LOCK_LOG_DESTROY(lock, 0); lock->lo_flags &= ~LO_INITIALIZED; } +void +lock_ref(struct lock_object *lock) +{ + + atomic_add_32(&lock->lo_refcount, 1); +} + +void +lock_unref(struct lock_object *lock) +{ + volatile u_int *pref = &lock->lo_refcount; + struct turnstile *ts; + + MPASS(*pref != 0); + + if (atomic_fetchadd_32(pref, -1U) != 1) + return; + turnstile_chain_lock(lock); + ts = turnstile_lookup(lock); + MPASS(ts != NULL); + turnstile_broadcast(ts, TS_EXCLUSIVE_QUEUE); + turnstile_unpend(ts); + turnstile_chain_unlock(lock); +} + +void +lock_unref_and_wait(struct lock_object *lock) +{ + volatile u_int *pref = &lock->lo_refcount; + struct turnstile *ts; + + MPASS(*pref != 0); + + if (atomic_fetchadd_32(pref, -1U) == 1) + return; + + while (1) { + ts = turnstile_trywait(lock); + if (*pref == 0) { + turnstile_cancel(ts); + break; + } + turnstile_wait(ts, NULL, TS_EXCLUSIVE_QUEUE); + } +} + static SYSCTL_NODE(_debug, OID_AUTO, lock, CTLFLAG_RD, NULL, "lock debugging"); static SYSCTL_NODE(_debug_lock, OID_AUTO, delay, CTLFLAG_RD, NULL, "lock delay"); Index: sys/sys/_lock.h =================================================================== --- sys/sys/_lock.h +++ sys/sys/_lock.h @@ -38,6 +38,7 @@ u_int lo_flags; u_int lo_data; /* General class specific data. */ struct witness *lo_witness; /* Data for witness. */ + u_int lo_refcount; /* Lock refcount */ }; #ifdef _KERNEL Index: sys/sys/lock.h =================================================================== --- sys/sys/lock.h +++ sys/sys/lock.h @@ -219,6 +219,9 @@ void lock_destroy(struct lock_object *); void lock_delay(struct lock_delay_arg *); void lock_delay_default_init(struct lock_delay_config *); +void lock_ref(struct lock_object *); +void lock_unref(struct lock_object *); +void lock_unref_and_wait(struct lock_object *); void spinlock_enter(void); void spinlock_exit(void); void witness_init(struct lock_object *, const char *);