mirror of
https://git.rtems.org/rtems-libbsd/
synced 2025-07-24 02:12:08 +08:00
LOCKING(9): Update to current FreeBSD version
This commit is contained in:
parent
b03a1c0b59
commit
9c1490aac3
@ -25,7 +25,7 @@
|
|||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* from BSDI $Id: mutex.h,v 2.7.2.35 2000/04/27 03:10:26 cp Exp $
|
* from BSDI Id: mutex.h,v 2.7.2.35 2000/04/27 03:10:26 cp
|
||||||
* $FreeBSD$
|
* $FreeBSD$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
#include <sys/_lock.h>
|
#include <sys/_lock.h>
|
||||||
|
#include <sys/ktr_class.h>
|
||||||
|
|
||||||
struct lock_list_entry;
|
struct lock_list_entry;
|
||||||
struct thread;
|
struct thread;
|
||||||
@ -56,13 +57,14 @@ struct thread;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct lock_class {
|
struct lock_class {
|
||||||
const char *lc_name;
|
const char *lc_name;
|
||||||
unsigned int lc_flags;
|
unsigned int lc_flags;
|
||||||
void (*lc_assert)(struct lock_object *lock, int what);
|
void (*lc_assert)(const struct lock_object *lock, int what);
|
||||||
void (*lc_ddb_show)(struct lock_object *lock);
|
void (*lc_ddb_show)(const struct lock_object *lock);
|
||||||
void (*lc_lock)(struct lock_object *lock, int how);
|
void (*lc_lock)(struct lock_object *lock, __uintptr_t how);
|
||||||
int (*lc_owner)(struct lock_object *lock, struct thread **owner);
|
int (*lc_owner)(const struct lock_object *lock,
|
||||||
int (*lc_unlock)(struct lock_object *lock);
|
struct thread **owner);
|
||||||
|
__uintptr_t (*lc_unlock)(struct lock_object *lock);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define LC_SLEEPLOCK 0x00000001 /* Sleep lock. */
|
#define LC_SLEEPLOCK 0x00000001 /* Sleep lock. */
|
||||||
@ -79,8 +81,10 @@ struct lock_class {
|
|||||||
#define LO_SLEEPABLE 0x00100000 /* Lock may be held while sleeping. */
|
#define LO_SLEEPABLE 0x00100000 /* Lock may be held while sleeping. */
|
||||||
#define LO_UPGRADABLE 0x00200000 /* Lock may be upgraded/downgraded. */
|
#define LO_UPGRADABLE 0x00200000 /* Lock may be upgraded/downgraded. */
|
||||||
#define LO_DUPOK 0x00400000 /* Don't check for duplicate acquires */
|
#define LO_DUPOK 0x00400000 /* Don't check for duplicate acquires */
|
||||||
|
#define LO_IS_VNODE 0x00800000 /* Tell WITNESS about a VNODE lock */
|
||||||
#define LO_CLASSMASK 0x0f000000 /* Class index bitmask. */
|
#define LO_CLASSMASK 0x0f000000 /* Class index bitmask. */
|
||||||
#define LO_NOPROFILE 0x10000000 /* Don't profile this lock */
|
#define LO_NOPROFILE 0x10000000 /* Don't profile this lock */
|
||||||
|
#define LO_NEW 0x20000000 /* Don't check for double-init */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lock classes are statically assigned an index into the gobal lock_classes
|
* Lock classes are statically assigned an index into the gobal lock_classes
|
||||||
@ -121,7 +125,8 @@ struct lock_class {
|
|||||||
* calling conventions for this debugging code in modules so that modules can
|
* calling conventions for this debugging code in modules so that modules can
|
||||||
* work with both debug and non-debug kernels.
|
* work with both debug and non-debug kernels.
|
||||||
*/
|
*/
|
||||||
#if defined(KLD_MODULE) || defined(WITNESS) || defined(INVARIANTS) || defined(INVARIANT_SUPPORT) || defined(KTR) || defined(LOCK_PROFILING)
|
#if defined(KLD_MODULE) || defined(WITNESS) || defined(INVARIANTS) || \
|
||||||
|
defined(LOCK_PROFILING) || defined(KTR)
|
||||||
#define LOCK_DEBUG 1
|
#define LOCK_DEBUG 1
|
||||||
#else
|
#else
|
||||||
#define LOCK_DEBUG 0
|
#define LOCK_DEBUG 0
|
||||||
@ -150,21 +155,26 @@ struct lock_class {
|
|||||||
* file - file name
|
* file - file name
|
||||||
* line - line number
|
* line - line number
|
||||||
*/
|
*/
|
||||||
|
#if LOCK_DEBUG > 0
|
||||||
#define LOCK_LOG_TEST(lo, flags) \
|
#define LOCK_LOG_TEST(lo, flags) \
|
||||||
(((flags) & LOP_QUIET) == 0 && ((lo)->lo_flags & LO_QUIET) == 0)
|
(((flags) & LOP_QUIET) == 0 && ((lo)->lo_flags & LO_QUIET) == 0)
|
||||||
|
#else
|
||||||
|
#define LOCK_LOG_TEST(lo, flags) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define LOCK_LOG_LOCK(opname, lo, flags, recurse, file, line) do { \
|
#define LOCK_LOG_LOCK(opname, lo, flags, recurse, file, line) do { \
|
||||||
if (LOCK_LOG_TEST((lo), (flags))) \
|
if (LOCK_LOG_TEST((lo), (flags))) \
|
||||||
CTR6(KTR_LOCK, opname " (%s) %s %p r = %d at %s:%d", \
|
CTR6(KTR_LOCK, opname " (%s) %s %p r = %d at %s:%d", \
|
||||||
LOCK_CLASS(lo)->lc_name, (lo)->lo_name, \
|
LOCK_CLASS(lo)->lc_name, (lo)->lo_name, \
|
||||||
(lo), (u_int)(recurse), (file), (line)); \
|
(lo), (unsigned int)(recurse), (file), (line)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define LOCK_LOG_TRY(opname, lo, flags, result, file, line) do { \
|
#define LOCK_LOG_TRY(opname, lo, flags, result, file, line) do { \
|
||||||
if (LOCK_LOG_TEST((lo), (flags))) \
|
if (LOCK_LOG_TEST((lo), (flags))) \
|
||||||
CTR6(KTR_LOCK, "TRY_" opname " (%s) %s %p result=%d at %s:%d",\
|
CTR6(KTR_LOCK, "TRY_" opname " (%s) %s %p result=%d at %s:%d",\
|
||||||
LOCK_CLASS(lo)->lc_name, (lo)->lo_name, \
|
LOCK_CLASS(lo)->lc_name, (lo)->lo_name, \
|
||||||
(lo), (u_int)(result), (file), (line)); \
|
(lo), (unsigned int)(result), (file), (line)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define LOCK_LOG_INIT(lo, flags) do { \
|
#define LOCK_LOG_INIT(lo, flags) do { \
|
||||||
@ -192,13 +202,42 @@ extern struct lock_class lock_class_mtx_spin;
|
|||||||
extern struct lock_class lock_class_sx;
|
extern struct lock_class lock_class_sx;
|
||||||
extern struct lock_class lock_class_rw;
|
extern struct lock_class lock_class_rw;
|
||||||
extern struct lock_class lock_class_rm;
|
extern struct lock_class lock_class_rm;
|
||||||
|
extern struct lock_class lock_class_rm_sleepable;
|
||||||
extern struct lock_class lock_class_lockmgr;
|
extern struct lock_class lock_class_lockmgr;
|
||||||
|
|
||||||
extern struct lock_class *lock_classes[];
|
extern struct lock_class *lock_classes[];
|
||||||
|
|
||||||
|
struct lock_delay_config {
|
||||||
|
unsigned int base;
|
||||||
|
unsigned int max;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lock_delay_arg {
|
||||||
|
struct lock_delay_config *config;
|
||||||
|
unsigned int delay;
|
||||||
|
unsigned int spin_cnt;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
lock_delay_arg_init(struct lock_delay_arg *la, struct lock_delay_config *lc)
|
||||||
|
{
|
||||||
|
la->config = lc;
|
||||||
|
la->delay = lc->base;
|
||||||
|
la->spin_cnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LOCK_DELAY_SYSINIT(func) \
|
||||||
|
SYSINIT(func##_ld, SI_SUB_LOCK, SI_ORDER_ANY, func, NULL)
|
||||||
|
|
||||||
|
#define LOCK_DELAY_SYSINIT_DEFAULT(lc) \
|
||||||
|
SYSINIT(lock_delay_##lc##_ld, SI_SUB_LOCK, SI_ORDER_ANY, \
|
||||||
|
lock_delay_default_init, &lc)
|
||||||
|
|
||||||
void lock_init(struct lock_object *, struct lock_class *,
|
void lock_init(struct lock_object *, struct lock_class *,
|
||||||
const char *, const char *, int);
|
const char *, const char *, int);
|
||||||
void lock_destroy(struct lock_object *);
|
void lock_destroy(struct lock_object *);
|
||||||
|
void lock_delay(struct lock_delay_arg *);
|
||||||
|
void lock_delay_default_init(struct lock_delay_config *);
|
||||||
void spinlock_enter(void);
|
void spinlock_enter(void);
|
||||||
void spinlock_exit(void);
|
void spinlock_exit(void);
|
||||||
void witness_init(struct lock_object *, const char *);
|
void witness_init(struct lock_object *, const char *);
|
||||||
@ -215,7 +254,7 @@ void witness_restore(struct lock_object *, const char *, int);
|
|||||||
int witness_list_locks(struct lock_list_entry **,
|
int witness_list_locks(struct lock_list_entry **,
|
||||||
int (*)(const char *, ...));
|
int (*)(const char *, ...));
|
||||||
int witness_warn(int, struct lock_object *, const char *, ...);
|
int witness_warn(int, struct lock_object *, const char *, ...);
|
||||||
void witness_assert(struct lock_object *, int, const char *, int);
|
void witness_assert(const struct lock_object *, int, const char *, int);
|
||||||
void witness_display_spinlock(struct lock_object *, struct thread *,
|
void witness_display_spinlock(struct lock_object *, struct thread *,
|
||||||
int (*)(const char *, ...));
|
int (*)(const char *, ...));
|
||||||
int witness_line(struct lock_object *);
|
int witness_line(struct lock_object *);
|
||||||
@ -304,16 +343,5 @@ void witness_thread_exit(struct thread *);
|
|||||||
#define WITNESS_LINE(lock) (0)
|
#define WITNESS_LINE(lock) (0)
|
||||||
#endif /* WITNESS */
|
#endif /* WITNESS */
|
||||||
|
|
||||||
/*
|
|
||||||
* Helper macros to allow developers to add explicit lock order checks
|
|
||||||
* wherever they please without having to actually grab a lock to do so.
|
|
||||||
*/
|
|
||||||
#define witness_check(l) \
|
|
||||||
WITNESS_CHECKORDER(&(l)->lock_object, LOP_EXCLUSIVE, LOCK_FILE, \
|
|
||||||
LOCK_LINE, NULL)
|
|
||||||
|
|
||||||
#define witness_check_shared(l) \
|
|
||||||
WITNESS_CHECKORDER(&(l)->lock_object, 0, LOCK_FILE, LOCK_LINE, NULL)
|
|
||||||
|
|
||||||
#endif /* _KERNEL */
|
#endif /* _KERNEL */
|
||||||
#endif /* _MACHINE__KERNEL_LOCK_H_ */
|
#endif /* _MACHINE__KERNEL_LOCK_H_ */
|
||||||
|
@ -48,67 +48,69 @@
|
|||||||
#include <sys/proc.h>
|
#include <sys/proc.h>
|
||||||
#include <sys/conf.h>
|
#include <sys/conf.h>
|
||||||
|
|
||||||
static void assert_mtx(struct lock_object *lock, int what);
|
static void assert_mtx(const struct lock_object *lock, int what);
|
||||||
static void lock_mtx(struct lock_object *lock, int how);
|
static void lock_mtx(struct lock_object *lock, uintptr_t how);
|
||||||
#ifdef KDTRACE_HOOKS
|
#ifdef KDTRACE_HOOKS
|
||||||
static int owner_mtx(struct lock_object *lock, struct thread **owner);
|
static int owner_mtx(const struct lock_object *lock,
|
||||||
|
struct thread **owner);
|
||||||
#endif
|
#endif
|
||||||
static int unlock_mtx(struct lock_object *lock);
|
static uintptr_t unlock_mtx(struct lock_object *lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lock classes for sleep and spin mutexes.
|
* Lock classes for sleep and spin mutexes.
|
||||||
*/
|
*/
|
||||||
struct lock_class lock_class_mtx_sleep = {
|
struct lock_class lock_class_mtx_sleep = {
|
||||||
.lc_name = "sleep mutex",
|
.lc_name = "sleep mutex",
|
||||||
.lc_flags = LC_SLEEPLOCK | LC_RECURSABLE,
|
.lc_flags = LC_SLEEPLOCK | LC_RECURSABLE,
|
||||||
.lc_assert = assert_mtx,
|
.lc_assert = assert_mtx,
|
||||||
#ifdef DDB
|
#ifdef DDB
|
||||||
.lc_ddb_show = db_show_mtx,
|
.lc_ddb_show = db_show_mtx,
|
||||||
#endif
|
#endif
|
||||||
.lc_lock = lock_mtx,
|
.lc_lock = lock_mtx,
|
||||||
.lc_unlock = unlock_mtx,
|
.lc_unlock = unlock_mtx,
|
||||||
#ifdef KDTRACE_HOOKS
|
#ifdef KDTRACE_HOOKS
|
||||||
.lc_owner = owner_mtx,
|
.lc_owner = owner_mtx,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lock_class lock_class_mtx_spin = {
|
struct lock_class lock_class_mtx_spin = {
|
||||||
.lc_name = "spin mutex",
|
.lc_name = "spin mutex",
|
||||||
.lc_flags = LC_SPINLOCK | LC_RECURSABLE,
|
.lc_flags = LC_SPINLOCK | LC_RECURSABLE,
|
||||||
.lc_assert = assert_mtx,
|
.lc_assert = assert_mtx,
|
||||||
#ifdef DDB
|
#ifdef DDB
|
||||||
.lc_ddb_show = db_show_mtx,
|
.lc_ddb_show = db_show_mtx,
|
||||||
#endif
|
#endif
|
||||||
.lc_lock = lock_mtx,
|
.lc_lock = lock_mtx,
|
||||||
.lc_unlock = unlock_mtx,
|
.lc_unlock = unlock_mtx,
|
||||||
#ifdef KDTRACE_HOOKS
|
#ifdef KDTRACE_HOOKS
|
||||||
.lc_owner = owner_mtx,
|
.lc_owner = owner_mtx,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mtx Giant;
|
struct mtx Giant;
|
||||||
|
|
||||||
void
|
void
|
||||||
assert_mtx(struct lock_object *lock, int what)
|
assert_mtx(const struct lock_object *lock, int what)
|
||||||
{
|
{
|
||||||
mtx_assert((struct mtx *)lock, what);
|
|
||||||
|
mtx_assert((const struct mtx *)lock, what);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
lock_mtx(struct lock_object *lock, int how)
|
lock_mtx(struct lock_object *lock, uintptr_t how)
|
||||||
{
|
{
|
||||||
|
|
||||||
mtx_lock((struct mtx *)lock);
|
mtx_lock((struct mtx *)lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
uintptr_t
|
||||||
unlock_mtx(struct lock_object *lock)
|
unlock_mtx(struct lock_object *lock)
|
||||||
{
|
{
|
||||||
mtx_unlock((struct mtx *)lock);
|
|
||||||
|
|
||||||
|
mtx_unlock((struct mtx *)lock);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef KDTRACE_HOOKS
|
#ifdef KDTRACE_HOOKS
|
||||||
int
|
int
|
||||||
owner_mtx(struct lock_object *lock, struct thread **owner)
|
owner_mtx(struct lock_object *lock, struct thread **owner)
|
||||||
|
@ -58,24 +58,24 @@
|
|||||||
#define _rw_assert(rw, what, file, line)
|
#define _rw_assert(rw, what, file, line)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void assert_rw(struct lock_object *lock, int what);
|
static void assert_rw(const struct lock_object *lock, int what);
|
||||||
static void lock_rw(struct lock_object *lock, int how);
|
static void lock_rw(struct lock_object *lock, uintptr_t how);
|
||||||
#ifdef KDTRACE_HOOKS
|
#ifdef KDTRACE_HOOKS
|
||||||
static int owner_rw(struct lock_object *lock, struct thread **owner);
|
static int owner_rw(const struct lock_object *lock, struct thread **owner);
|
||||||
#endif
|
#endif
|
||||||
static int unlock_rw(struct lock_object *lock);
|
static uintptr_t unlock_rw(struct lock_object *lock);
|
||||||
|
|
||||||
struct lock_class lock_class_rw = {
|
struct lock_class lock_class_rw = {
|
||||||
.lc_name = "rw",
|
.lc_name = "rw",
|
||||||
.lc_flags = LC_SLEEPLOCK | LC_RECURSABLE | LC_UPGRADABLE,
|
.lc_flags = LC_SLEEPLOCK | LC_RECURSABLE | LC_UPGRADABLE,
|
||||||
.lc_assert = assert_rw,
|
.lc_assert = assert_rw,
|
||||||
#ifdef DDB
|
#ifdef DDB
|
||||||
.lc_ddb_show = db_show_rwlock,
|
.lc_ddb_show = db_show_rwlock,
|
||||||
#endif
|
#endif
|
||||||
.lc_lock = lock_rw,
|
.lc_lock = lock_rw,
|
||||||
.lc_unlock = unlock_rw,
|
.lc_unlock = unlock_rw,
|
||||||
#ifdef KDTRACE_HOOKS
|
#ifdef KDTRACE_HOOKS
|
||||||
.lc_owner = owner_rw,
|
.lc_owner = owner_rw,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -84,23 +84,25 @@ struct lock_class lock_class_rw = {
|
|||||||
#define rw_recursed(rw) rtems_bsd_mutex_recursed(&(rw)->mutex)
|
#define rw_recursed(rw) rtems_bsd_mutex_recursed(&(rw)->mutex)
|
||||||
|
|
||||||
void
|
void
|
||||||
assert_rw(struct lock_object *lock, int what)
|
assert_rw(const struct lock_object *lock, int what)
|
||||||
{
|
{
|
||||||
rw_assert((struct rwlock *)lock, what);
|
|
||||||
|
rw_assert((const struct rwlock *)lock, what);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
lock_rw(struct lock_object *lock, int how)
|
lock_rw(struct lock_object *lock, uintptr_t how)
|
||||||
{
|
{
|
||||||
rw_wlock((struct rwlock *)lock);
|
|
||||||
|
rw_wlock((struct rwlock *)lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
uintptr_t
|
||||||
unlock_rw(struct lock_object *lock)
|
unlock_rw(struct lock_object *lock)
|
||||||
{
|
{
|
||||||
rw_unlock((struct rwlock *)lock);
|
|
||||||
|
|
||||||
return (0);
|
rw_unlock((struct rwlock *)lock);
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef KDTRACE_HOOKS
|
#ifdef KDTRACE_HOOKS
|
||||||
|
@ -47,24 +47,24 @@
|
|||||||
#include <sys/lock.h>
|
#include <sys/lock.h>
|
||||||
#include <sys/sx.h>
|
#include <sys/sx.h>
|
||||||
|
|
||||||
static void assert_sx(struct lock_object *lock, int what);
|
static void assert_sx(const struct lock_object *lock, int what);
|
||||||
static void lock_sx(struct lock_object *lock, int how);
|
static void lock_sx(struct lock_object *lock, uintptr_t how);
|
||||||
#ifdef KDTRACE_HOOKS
|
#ifdef KDTRACE_HOOKS
|
||||||
static int owner_sx(struct lock_object *lock, struct thread **owner);
|
static int owner_sx(const struct lock_object *lock, struct thread **owner);
|
||||||
#endif
|
#endif
|
||||||
static int unlock_sx(struct lock_object *lock);
|
static uintptr_t unlock_sx(struct lock_object *lock);
|
||||||
|
|
||||||
struct lock_class lock_class_sx = {
|
struct lock_class lock_class_sx = {
|
||||||
.lc_name = "sx",
|
.lc_name = "sx",
|
||||||
.lc_flags = LC_SLEEPLOCK | LC_SLEEPABLE | LC_RECURSABLE | LC_UPGRADABLE,
|
.lc_flags = LC_SLEEPLOCK | LC_SLEEPABLE | LC_RECURSABLE | LC_UPGRADABLE,
|
||||||
.lc_assert = assert_sx,
|
.lc_assert = assert_sx,
|
||||||
#ifdef DDB
|
#ifdef DDB
|
||||||
.lc_ddb_show = db_show_sx,
|
.lc_ddb_show = db_show_sx,
|
||||||
#endif
|
#endif
|
||||||
.lc_lock = lock_sx,
|
.lc_lock = lock_sx,
|
||||||
.lc_unlock = unlock_sx,
|
.lc_unlock = unlock_sx,
|
||||||
#ifdef KDTRACE_HOOKS
|
#ifdef KDTRACE_HOOKS
|
||||||
.lc_owner = owner_sx,
|
.lc_owner = owner_sx,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -73,22 +73,24 @@ struct lock_class lock_class_sx = {
|
|||||||
#define sx_recursed(sx) rtems_bsd_mutex_recursed(&(sx)->mutex)
|
#define sx_recursed(sx) rtems_bsd_mutex_recursed(&(sx)->mutex)
|
||||||
|
|
||||||
void
|
void
|
||||||
assert_sx(struct lock_object *lock, int what)
|
assert_sx(const struct lock_object *lock, int what)
|
||||||
{
|
{
|
||||||
sx_assert((struct sx *)lock, what);
|
|
||||||
|
sx_assert((const struct sx *)lock, what);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
lock_sx(struct lock_object *lock, int how)
|
lock_sx(struct lock_object *lock, uintptr_t how)
|
||||||
{
|
{
|
||||||
|
|
||||||
sx_xlock((struct sx *)lock);
|
sx_xlock((struct sx *)lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
uintptr_t
|
||||||
unlock_sx(struct lock_object *lock)
|
unlock_sx(struct lock_object *lock)
|
||||||
{
|
{
|
||||||
sx_xunlock((struct sx *)lock);
|
|
||||||
|
|
||||||
|
sx_xunlock((struct sx *)lock);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user