| SX(9) | Kernel Developer's Manual | SX(9) |
sx, sx_init,
sx_init_flags, sx_destroy,
sx_slock, sx_xlock,
sx_slock_sig, sx_xlock_sig,
sx_try_slock, sx_try_xlock,
sx_sunlock, sx_xunlock,
sx_unlock, sx_try_upgrade,
sx_downgrade, sx_sleep,
sx_xholder, sx_xlocked,
sx_assert, SX_SYSINIT,
SX_SYSINIT_FLAGS — kernel
shared/exclusive lock
#include
<sys/param.h>
#include <sys/lock.h>
#include <sys/sx.h>
void
sx_init(struct
sx *sx, const char
*description);
void
sx_init_flags(struct
sx *sx, const char
*description, int
opts);
void
sx_destroy(struct
sx *sx);
void
sx_slock(struct
sx *sx);
void
sx_xlock(struct
sx *sx);
int
sx_slock_sig(struct
sx *sx);
int
sx_xlock_sig(struct
sx *sx);
int
sx_try_slock(struct
sx *sx);
int
sx_try_xlock(struct
sx *sx);
void
sx_sunlock(struct
sx *sx);
void
sx_xunlock(struct
sx *sx);
void
sx_unlock(struct
sx *sx);
int
sx_try_upgrade(struct
sx *sx);
void
sx_downgrade(struct
sx *sx);
int
sx_sleep(void
*chan, struct sx
*sx, int priority,
const char *wmesg,
int timo);
struct thread *
sx_xholder(struct
sx *sx);
int
sx_xlocked(const
struct sx *sx);
options INVARIANTS
options INVARIANT_SUPPORT
void
sx_assert(const
struct sx *sx, int
what);
#include
<sys/kernel.h>
SX_SYSINIT(name,
struct sx *sx,
const char *desc);
SX_SYSINIT_FLAGS(name,
struct sx *sx,
const char *desc,
int flags);
Shared/exclusive locks are used to protect data that are read far more often than they are written. Shared/exclusive locks do not implement priority propagation like mutexes and reader/writer locks to prevent priority inversions, so shared/exclusive locks should be used prudently.
Shared/exclusive locks are created with either
sx_init()
or
sx_init_flags()
where sx is a pointer to space for a
struct sx, and description is a
pointer to a null-terminated character string that describes the
shared/exclusive lock. The opts argument to
sx_init_flags() specifies a set of optional flags to
alter the behavior of sx. It contains one or more of
the following flags:
SX_NOADAPTIVEoptions
NO_ADAPTIVE_SX.SX_DUPOKSX_NOWITNESSSX_NOPROFILESX_RECURSESX_QUIETSX_NEWoptions
INVARIANTS, sx_init() will assert that the
sx has not been initialized multiple times without
intervening calls to sx_destroy() unless this
option is specified.Shared/exclusive locks are destroyed with
sx_destroy().
The lock sx must not be locked by any thread when it
is destroyed.
Threads acquire and release a shared lock by calling
sx_slock(),
sx_slock_sig() or
sx_try_slock() and
sx_sunlock() or sx_unlock().
Threads acquire and release an exclusive lock by calling
sx_xlock(),
sx_xlock_sig() or
sx_try_xlock() and
sx_xunlock() or sx_unlock().
A thread can attempt to upgrade a currently held shared lock to an exclusive
lock by calling sx_try_upgrade(). A thread that has
an exclusive lock can downgrade it to a shared lock by calling
sx_downgrade().
sx_try_slock()
and
sx_try_xlock()
will return 0 if the shared/exclusive lock cannot be acquired immediately;
otherwise the shared/exclusive lock will be acquired and a non-zero value
will be returned.
sx_try_upgrade()
will return 0 if the shared lock cannot be upgraded to an exclusive lock
immediately; otherwise the exclusive lock will be acquired and a non-zero
value will be returned.
sx_slock_sig()
and
sx_xlock_sig()
do the same as their normal versions but performing an interruptible sleep.
They return a non-zero value if the sleep has been interrupted by a signal
or an interrupt, otherwise 0.
A thread can atomically release a shared/exclusive
lock while waiting for an event by calling
sx_sleep().
For more details on the parameters to this function, see
sleep(9).
When compiled with options
INVARIANTS and options INVARIANT_SUPPORT, the
sx_assert()
function tests sx for the assertions specified in
what, and panics if they are not met. One of the
following assertions must be specified:
SA_LOCKEDSA_SLOCKEDSA_XLOCKEDSA_UNLOCKEDIn addition, one of the following optional assertions may be
included with either an SA_LOCKED,
SA_SLOCKED, or SA_XLOCKED
assertion:
SA_RECURSEDSA_NOTRECURSEDsx_xholder()
will return a pointer to the thread which currently holds an exclusive lock
on sx. If no thread holds an exclusive lock on
sx, then NULL is returned
instead.
sx_xlocked()
will return non-zero if the current thread holds the exclusive lock;
otherwise, it will return zero.
For ease of programming,
sx_unlock()
is provided as a macro frontend to the respective functions,
sx_sunlock()
and
sx_xunlock().
Algorithms that are aware of what state the lock is in should use either of
the two specific functions for a minor performance benefit.
The
SX_SYSINIT()
macro is used to generate a call to the
sx_sysinit()
routine at system startup in order to initialize a given
sx lock. The parameters are the same as
sx_init() but with an additional argument,
name, that is used in generating unique variable names
for the related structures associated with the lock and the sysinit routine.
The
SX_SYSINIT_FLAGS()
macro can similarly be used to initialize a given sx
lock using sx_init_flags().
A thread may not hold both a shared lock and an exclusive lock on the same lock simultaneously; attempting to do so will result in deadlock.
A thread may hold a shared or exclusive lock on an
sx lock while sleeping. As a result, an
sx lock may not be acquired while holding a mutex.
Otherwise, if one thread slept while holding an sx
lock while another thread blocked on the same sx
lock after acquiring a mutex, then the second thread would effectively end
up sleeping while holding a mutex, which is not allowed.
A kernel without WITNESS cannot assert
whether the current thread does or does not hold a shared lock.
SA_LOCKED and SA_SLOCKED can
only assert that
any thread
holds a shared lock. They cannot ensure that the current thread holds a
shared lock. Further, SA_UNLOCKED can only assert
that the current thread does not hold an exclusive lock.
| November 11, 2017 | Debian |