Implement mtx_trylock_spin(9).
Discussed with: bde Reviewed by: jhb Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D7192
This commit is contained in:
parent
a5ab035dd7
commit
90b581f2cc
@ -1181,6 +1181,8 @@ MLINKS+=mutex.9 mtx_assert.9 \
|
||||
mutex.9 MTX_SYSINIT.9 \
|
||||
mutex.9 mtx_trylock.9 \
|
||||
mutex.9 mtx_trylock_flags.9 \
|
||||
mutex.9 mtx_trylock_spin.9 \
|
||||
mutex.9 mtx_trylock_spin_flags.9 \
|
||||
mutex.9 mtx_unlock.9 \
|
||||
mutex.9 mtx_unlock_flags.9 \
|
||||
mutex.9 mtx_unlock_spin.9 \
|
||||
|
@ -28,7 +28,7 @@
|
||||
.\" from BSDI $Id: mutex.4,v 1.1.2.3 1998/04/27 22:53:13 ewv Exp $
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd December 13, 2014
|
||||
.Dd July 18, 2016
|
||||
.Dt MUTEX 9
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -41,6 +41,8 @@
|
||||
.Nm mtx_lock_spin_flags ,
|
||||
.Nm mtx_trylock ,
|
||||
.Nm mtx_trylock_flags ,
|
||||
.Nm mtx_trylock_spin ,
|
||||
.Nm mtx_trylock_spin_flags ,
|
||||
.Nm mtx_unlock ,
|
||||
.Nm mtx_unlock_spin ,
|
||||
.Nm mtx_unlock_flags ,
|
||||
@ -73,6 +75,10 @@
|
||||
.Ft int
|
||||
.Fn mtx_trylock_flags "struct mtx *mutex" "int flags"
|
||||
.Ft void
|
||||
.Fn mtx_trylock_spin "struct mtx *mutex"
|
||||
.Ft int
|
||||
.Fn mtx_trylock_spin_flags "struct mtx *mutex" "int flags"
|
||||
.Ft void
|
||||
.Fn mtx_unlock "struct mtx *mutex"
|
||||
.Ft void
|
||||
.Fn mtx_unlock_spin "struct mtx *mutex"
|
||||
@ -249,26 +255,33 @@ argument, then the mutex can be acquired recursively.
|
||||
.Pp
|
||||
The
|
||||
.Fn mtx_trylock
|
||||
attempts to acquire the
|
||||
and
|
||||
.Fn mtx_trylock_spin
|
||||
functions attempt to acquire a
|
||||
.Dv MTX_DEF
|
||||
mutex pointed to by
|
||||
or
|
||||
.Dv MTX_SPIN
|
||||
mutex, respectively, pointed to by
|
||||
.Fa mutex .
|
||||
If the mutex cannot be immediately acquired
|
||||
.Fn mtx_trylock
|
||||
will return 0,
|
||||
otherwise the mutex will be acquired
|
||||
and a non-zero value will be returned.
|
||||
If the mutex cannot be immediately acquired, the functions will return 0,
|
||||
otherwise the mutex will be acquired and a non-zero value will be returned.
|
||||
.Pp
|
||||
The
|
||||
.Fn mtx_trylock_flags
|
||||
function has the same behavior as
|
||||
and
|
||||
.Fn mtx_trylock_spin_flags
|
||||
functions have the same behavior as
|
||||
.Fn mtx_trylock
|
||||
but should be used when the caller desires to pass in a
|
||||
and
|
||||
.Fn mtx_trylock_spin
|
||||
respectively, but should be used when the caller desires to pass in a
|
||||
.Fa flags
|
||||
value.
|
||||
Presently, the only valid value in the
|
||||
.Fn mtx_trylock
|
||||
case is
|
||||
and
|
||||
.Fn mtx_trylock_spin
|
||||
cases is
|
||||
.Dv MTX_QUIET ,
|
||||
and its effects are identical to those described for
|
||||
.Fn mtx_lock
|
||||
@ -447,6 +460,13 @@ while any spin lock is held.
|
||||
.It Dv MTX_RECURSE
|
||||
Specifies that the initialized mutex is allowed to recurse.
|
||||
This bit must be present if the mutex is permitted to recurse.
|
||||
.Pp
|
||||
Note that neither
|
||||
.Fn mtx_trylock
|
||||
nor
|
||||
.Fn mtx_trylock_spin
|
||||
support recursion;
|
||||
that is, attempting to acquire an already-owned mutex fails.
|
||||
.It Dv MTX_QUIET
|
||||
Do not log any mutex operations for this lock.
|
||||
.It Dv MTX_NOWITNESS
|
||||
@ -534,3 +554,7 @@ functions appeared in
|
||||
.Bsx 4.1
|
||||
and
|
||||
.Fx 5.0 .
|
||||
The
|
||||
.Fn mtx_trylock_spin
|
||||
function was added in
|
||||
.Fx 12.0 .
|
||||
|
@ -281,6 +281,34 @@ __mtx_lock_spin_flags(volatile uintptr_t *c, int opts, const char *file,
|
||||
WITNESS_LOCK(&m->lock_object, opts | LOP_EXCLUSIVE, file, line);
|
||||
}
|
||||
|
||||
int
|
||||
__mtx_trylock_spin_flags(volatile uintptr_t *c, int opts, const char *file,
|
||||
int line)
|
||||
{
|
||||
struct mtx *m;
|
||||
|
||||
if (SCHEDULER_STOPPED())
|
||||
return (1);
|
||||
|
||||
m = mtxlock2mtx(c);
|
||||
|
||||
KASSERT(m->mtx_lock != MTX_DESTROYED,
|
||||
("mtx_trylock_spin() of destroyed mutex @ %s:%d", file, line));
|
||||
KASSERT(LOCK_CLASS(&m->lock_object) == &lock_class_mtx_spin,
|
||||
("mtx_trylock_spin() of sleep mutex %s @ %s:%d",
|
||||
m->lock_object.lo_name, file, line));
|
||||
KASSERT((opts & MTX_RECURSE) == 0,
|
||||
("mtx_trylock_spin: unsupp. opt MTX_RECURSE on mutex %s @ %s:%d\n",
|
||||
m->lock_object.lo_name, file, line));
|
||||
if (__mtx_trylock_spin(m, curthread, opts, file, line)) {
|
||||
LOCK_LOG_TRY("LOCK", &m->lock_object, opts, 1, file, line);
|
||||
WITNESS_LOCK(&m->lock_object, opts | LOP_EXCLUSIVE, file, line);
|
||||
return (1);
|
||||
}
|
||||
LOCK_LOG_TRY("LOCK", &m->lock_object, opts, 0, file, line);
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
__mtx_unlock_spin_flags(volatile uintptr_t *c, int opts, const char *file,
|
||||
int line)
|
||||
|
@ -112,6 +112,8 @@ void __mtx_unlock_flags(volatile uintptr_t *c, int opts, const char *file,
|
||||
int line);
|
||||
void __mtx_lock_spin_flags(volatile uintptr_t *c, int opts, const char *file,
|
||||
int line);
|
||||
int __mtx_trylock_spin_flags(volatile uintptr_t *c, int opts,
|
||||
const char *file, int line);
|
||||
void __mtx_unlock_spin_flags(volatile uintptr_t *c, int opts,
|
||||
const char *file, int line);
|
||||
#if defined(INVARIANTS) || defined(INVARIANT_SUPPORT)
|
||||
@ -152,6 +154,8 @@ void thread_lock_flags_(struct thread *, int, const char *, int);
|
||||
__mtx_unlock_flags(&(m)->mtx_lock, o, f, l)
|
||||
#define _mtx_lock_spin_flags(m, o, f, l) \
|
||||
__mtx_lock_spin_flags(&(m)->mtx_lock, o, f, l)
|
||||
#define _mtx_trylock_spin_flags(m, o, f, l) \
|
||||
__mtx_trylock_spin_flags(&(m)->mtx_lock, o, f, l)
|
||||
#define _mtx_unlock_spin_flags(m, o, f, l) \
|
||||
__mtx_unlock_spin_flags(&(m)->mtx_lock, o, f, l)
|
||||
#if defined(INVARIANTS) || defined(INVARIANT_SUPPORT)
|
||||
@ -212,6 +216,21 @@ void thread_lock_flags_(struct thread *, int, const char *, int);
|
||||
LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(spin__acquire, \
|
||||
mp, 0, 0, file, line); \
|
||||
} while (0)
|
||||
#define __mtx_trylock_spin(mp, tid, opts, file, line) __extension__ ({ \
|
||||
uintptr_t _tid = (uintptr_t)(tid); \
|
||||
int _ret; \
|
||||
\
|
||||
spinlock_enter(); \
|
||||
if (((mp)->mtx_lock != MTX_UNOWNED || !_mtx_obtain_lock((mp), _tid))) {\
|
||||
spinlock_exit(); \
|
||||
_ret = 0; \
|
||||
} else { \
|
||||
LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(spin__acquire, \
|
||||
mp, 0, 0, file, line); \
|
||||
_ret = 1; \
|
||||
} \
|
||||
_ret; \
|
||||
})
|
||||
#else /* SMP */
|
||||
#define __mtx_lock_spin(mp, tid, opts, file, line) do { \
|
||||
uintptr_t _tid = (uintptr_t)(tid); \
|
||||
@ -224,6 +243,20 @@ void thread_lock_flags_(struct thread *, int, const char *, int);
|
||||
(mp)->mtx_lock = _tid; \
|
||||
} \
|
||||
} while (0)
|
||||
#define __mtx_trylock_spin(mp, tid, opts, file, line) __extension__ ({ \
|
||||
uintptr_t _tid = (uintptr_t)(tid); \
|
||||
int _ret; \
|
||||
\
|
||||
spinlock_enter(); \
|
||||
if ((mp)->mtx_lock != MTX_UNOWNED) { \
|
||||
spinlock_exit(); \
|
||||
_ret = 0; \
|
||||
} else { \
|
||||
(mp)->mtx_lock = _tid; \
|
||||
_ret = 1; \
|
||||
} \
|
||||
_ret; \
|
||||
})
|
||||
#endif /* SMP */
|
||||
|
||||
/* Unlock a normal mutex. */
|
||||
@ -293,6 +326,10 @@ void thread_lock_flags_(struct thread *, int, const char *, int);
|
||||
* mtx_trylock_flags(m, opts) is used the same way as mtx_trylock() but accepts
|
||||
* relevant option flags `opts.'
|
||||
*
|
||||
* mtx_trylock_spin(m) attempts to acquire MTX_SPIN mutex `m' but doesn't
|
||||
* spin if it cannot. Rather, it returns 0 on failure and non-zero on
|
||||
* success. It always returns failure for recursed lock attempts.
|
||||
*
|
||||
* mtx_initialized(m) returns non-zero if the lock `m' has been initialized.
|
||||
*
|
||||
* mtx_owned(m) returns non-zero if the current thread owns the lock `m'
|
||||
@ -302,6 +339,7 @@ void thread_lock_flags_(struct thread *, int, const char *, int);
|
||||
#define mtx_lock(m) mtx_lock_flags((m), 0)
|
||||
#define mtx_lock_spin(m) mtx_lock_spin_flags((m), 0)
|
||||
#define mtx_trylock(m) mtx_trylock_flags((m), 0)
|
||||
#define mtx_trylock_spin(m) mtx_trylock_spin_flags((m), 0)
|
||||
#define mtx_unlock(m) mtx_unlock_flags((m), 0)
|
||||
#define mtx_unlock_spin(m) mtx_unlock_spin_flags((m), 0)
|
||||
|
||||
@ -335,6 +373,8 @@ extern struct mtx_pool *mtxpool_sleep;
|
||||
_mtx_unlock_flags((m), (opts), (file), (line))
|
||||
#define mtx_lock_spin_flags_(m, opts, file, line) \
|
||||
_mtx_lock_spin_flags((m), (opts), (file), (line))
|
||||
#define mtx_trylock_spin_flags_(m, opts, file, line) \
|
||||
_mtx_trylock_spin_flags((m), (opts), (file), (line))
|
||||
#define mtx_unlock_spin_flags_(m, opts, file, line) \
|
||||
_mtx_unlock_spin_flags((m), (opts), (file), (line))
|
||||
#else /* LOCK_DEBUG == 0 && !MUTEX_NOINLINE */
|
||||
@ -344,6 +384,8 @@ extern struct mtx_pool *mtxpool_sleep;
|
||||
__mtx_unlock((m), curthread, (opts), (file), (line))
|
||||
#define mtx_lock_spin_flags_(m, opts, file, line) \
|
||||
__mtx_lock_spin((m), curthread, (opts), (file), (line))
|
||||
#define mtx_trylock_spin_flags_(m, opts, file, line) \
|
||||
__mtx_trylock_spin((m), curthread, (opts), (file), (line))
|
||||
#define mtx_unlock_spin_flags_(m, opts, file, line) \
|
||||
__mtx_unlock_spin((m))
|
||||
#endif /* LOCK_DEBUG > 0 || MUTEX_NOINLINE */
|
||||
@ -369,6 +411,8 @@ extern struct mtx_pool *mtxpool_sleep;
|
||||
mtx_unlock_spin_flags_((m), (opts), LOCK_FILE, LOCK_LINE)
|
||||
#define mtx_trylock_flags(m, opts) \
|
||||
mtx_trylock_flags_((m), (opts), LOCK_FILE, LOCK_LINE)
|
||||
#define mtx_trylock_spin_flags(m, opts) \
|
||||
mtx_trylock_spin_flags_((m), (opts), LOCK_FILE, LOCK_LINE)
|
||||
#define mtx_assert(m, what) \
|
||||
mtx_assert_((m), (what), __FILE__, __LINE__)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user