20f16ca028
Approved by: re (bmah)
358 lines
11 KiB
Groff
358 lines
11 KiB
Groff
.\" Copyright (c) 2007 Julian Elischer (julian - freebsd org )
|
|
.\" All rights reserved.
|
|
.\"
|
|
.\" Redistribution and use in source and binary forms, with or without
|
|
.\" modification, are permitted provided that the following conditions
|
|
.\" are met:
|
|
.\" 1. Redistributions of source code must retain the above copyright
|
|
.\" notice, this list of conditions and the following disclaimer.
|
|
.\" 2. Redistributions in binary form must reproduce the above copyright
|
|
.\" notice, this list of conditions and the following disclaimer in the
|
|
.\" documentation and/or other materials provided with the distribution.
|
|
.\"
|
|
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
.\" SUCH DAMAGE.
|
|
.\"
|
|
.\" $FreeBSD$
|
|
.\"
|
|
.Dd March 14, 2007
|
|
.Dt LOCKING 9
|
|
.Os
|
|
.Sh NAME
|
|
.Nm locking
|
|
.Nd kernel synchronization primitives
|
|
.Sh SYNOPSIS
|
|
All sorts of stuff to go here.
|
|
.Pp
|
|
.Sh DESCRIPTION
|
|
The
|
|
.Em FreeBSD
|
|
kernel is written to run across multiple CPUs and as such requires
|
|
several different synchronization primitives to allow the developers
|
|
to safely access and manipulate the many data types required.
|
|
.Pp
|
|
These include:
|
|
.Bl -enum
|
|
.It
|
|
Spin Mutexes
|
|
.It
|
|
Sleep Mutexes
|
|
.It
|
|
pool Mutexes
|
|
.It
|
|
Shared-Exclusive locks
|
|
.It
|
|
Reader-Writer locks
|
|
.It
|
|
Turnstiles
|
|
.It
|
|
Semaphores
|
|
.It
|
|
Condition variables
|
|
.It
|
|
Sleep/wakeup
|
|
.It
|
|
Giant
|
|
.It
|
|
Lockmanager locks
|
|
.El
|
|
.Pp
|
|
The primitives interact and have a number of rules regarding how
|
|
they can and can not be combined.
|
|
There are too many for the average
|
|
human mind and they keep changing.
|
|
(if you disagree, please write replacement text) :-)
|
|
.Pp
|
|
Some of these primitives may be used at the low (interrupt) level and
|
|
some may not.
|
|
.Pp
|
|
There are strict ordering requirements and for some of the types this
|
|
is checked using the
|
|
.Xr witness 4
|
|
code.
|
|
.Pp
|
|
.Ss SPIN Mutexes
|
|
Mutexes are the basic primitive.
|
|
You either hold it or you don't.
|
|
If you don't own it then you just spin, waiting for the holder (on
|
|
another CPU) to release it.
|
|
Hopefully they are doing something fast.
|
|
You
|
|
.Em must not
|
|
do anything that deschedules the thread while you
|
|
are holding a SPIN mutex.
|
|
.Ss Mutexes
|
|
Basically (regular) mutexes will deschedule the thread if the
|
|
mutex can not be acquired.
|
|
A non-spin mutex can be considered to be equivalent
|
|
to getting a write lock on an
|
|
.Em rw_lock
|
|
(see below), and in fact non-spin mutexes and rw_locks may soon become the same thing.
|
|
As in spin mutexes, you either get it or you don't.
|
|
You may only call the
|
|
.Xr sleep 9
|
|
call via
|
|
.Fn msleep
|
|
or the new
|
|
.Fn mtx_sleep
|
|
variant.
|
|
These will atomically drop the mutex and reacquire it
|
|
as part of waking up.
|
|
This is often however a
|
|
.Em BAD
|
|
idea because it generally relies on you having
|
|
such a good knowledge of all the call graph above you
|
|
and what assumptions it is making that there are a lot
|
|
of ways to make hard-to-find mistakes.
|
|
For example you MUST re-test all the assumptions you made before,
|
|
all the way up the call graph to where you got the lock.
|
|
You can not just assume that mtx_sleep can be inserted anywhere.
|
|
If any caller above you has any mutex or
|
|
rwlock, your sleep, will cause a panic.
|
|
If the sleep only happens rarely it may be years before the
|
|
bad code path is found.
|
|
.Ss Pool Mutexes
|
|
A variant of regular mutexes where the allocation of the mutex is handled
|
|
more by the system.
|
|
.Ss Rw_locks
|
|
Reader/writer locks allow shared access to protected data by multiple threads,
|
|
or exclusive access by a single thread.
|
|
The threads with shared access are known as
|
|
.Em readers
|
|
since they should only read the protected data.
|
|
A thread with exclusive access is known as a
|
|
.Em writer
|
|
since it may modify protected data.
|
|
.Pp
|
|
Although reader/writer locks look very similar to
|
|
.Xr sx 9
|
|
(see below) locks, their usage pattern is different.
|
|
Reader/writer locks can be treated as mutexes (see above and
|
|
.Xr mutex 9 )
|
|
with shared/exclusive semantics.
|
|
More specifically, regular mutexes can be
|
|
considered to be equivalent to a write-lock on an
|
|
.Em rw_lock.
|
|
In the future this may in fact
|
|
become literally the fact.
|
|
An
|
|
.Em rw_lock
|
|
can be locked while holding a regular mutex, but
|
|
can
|
|
.Em not
|
|
be held while sleeping.
|
|
The
|
|
.Em rw_lock
|
|
locks have priority propagation like mutexes, but priority
|
|
can be propagated only to an exclusive holder.
|
|
This limitation comes from the fact that shared owners
|
|
are anonymous.
|
|
Another important property is that shared holders of
|
|
.Em rw_lock
|
|
can recurse, but exclusive locks are not allowed to recurse.
|
|
This ability should not be used lightly and
|
|
.Em may go away.
|
|
Users of recursion in any locks should be prepared to
|
|
defend their decision against vigorous criticism.
|
|
.Ss Sx_locks
|
|
Shared/exclusive locks are used to protect data that are read far more often
|
|
than they are written.
|
|
Mutexes are inherently more efficient than shared/exclusive locks, so
|
|
shared/exclusive locks should be used prudently.
|
|
The main reason for using an
|
|
.Em sx_lock
|
|
is that a thread may hold a shared or exclusive lock on an
|
|
.Em sx_lock
|
|
lock while sleeping.
|
|
As a consequence of this however, an
|
|
.Em sx_lock
|
|
lock may not be acquired while holding a mutex.
|
|
The reason for this is that, if one thread slept while holding an
|
|
.Em sx_lock
|
|
lock while another thread blocked on the same
|
|
.Em sx_lock
|
|
lock after acquiring a mutex, then the second thread would effectively
|
|
end up sleeping while holding a mutex, which is not allowed.
|
|
The
|
|
.Em sx_lock
|
|
should be considered to be closely related to
|
|
.Xr sleep 9 .
|
|
In fact it could in some cases be
|
|
considered a conditional sleep.
|
|
.Ss Turnstiles
|
|
Turnstiles are used to hold a queue of threads blocked on
|
|
non-sleepable locks.
|
|
Sleepable locks use condition variables to implement their queues.
|
|
Turnstiles differ from a sleep queue in that turnstile queue's
|
|
are assigned to a lock held by an owning thread.
|
|
Thus, when one thread is enqueued onto a turnstile, it can lend its
|
|
priority to the owning thread.
|
|
If this sounds confusing, we need to describe it better.
|
|
.Ss Semaphores
|
|
.Ss Condition variables
|
|
Condition variables are used in conjunction with mutexes to wait for
|
|
conditions to occur.
|
|
A thread must hold the mutex before calling the
|
|
.Fn cv_wait* ,
|
|
functions.
|
|
When a thread waits on a condition, the mutex
|
|
is atomically released before the thread is blocked, then reacquired
|
|
before the function call returns.
|
|
.Ss Giant
|
|
Giant is a special instance of a sleep lock.
|
|
It has several special characteristics.
|
|
.Bl -enum
|
|
.It
|
|
It is recursive.
|
|
.It
|
|
Drivers can request that Giant be locked around them, but this is
|
|
going away.
|
|
.It
|
|
You can sleep while it has recursed, but other recursive locks cannot.
|
|
.It
|
|
Giant must be locked first before other locks.
|
|
.It
|
|
There are places in the kernel that drop Giant and pick it back up
|
|
again.
|
|
Sleep locks will do this before sleeping.
|
|
Parts of the Network or VM code may do this as well, depending on the
|
|
setting of a sysctl.
|
|
This means that you cannot count on Giant keeping other code from
|
|
running if your code sleeps, even if you want it to.
|
|
.El
|
|
.Ss Sleep/wakeup
|
|
The functions
|
|
.Fn tsleep ,
|
|
.Fn msleep ,
|
|
.Fn msleep_spin ,
|
|
.Fn pause ,
|
|
.Fn wakeup ,
|
|
and
|
|
.Fn wakeup_one
|
|
handle event-based thread blocking.
|
|
If a thread must wait for an external event, it is put to sleep by
|
|
.Fn tsleep ,
|
|
.Fn msleep ,
|
|
.Fn msleep_spin ,
|
|
or
|
|
.Fn pause .
|
|
Threads may also wait using one of the locking primitive sleep routines
|
|
.Xr mtx_sleep 9 ,
|
|
.Xr rw_sleep 9 ,
|
|
or
|
|
.Xr sx_sleep 9 .
|
|
.Pp
|
|
The parameter
|
|
.Fa chan
|
|
is an arbitrary address that uniquely identifies the event on which
|
|
the thread is being put to sleep.
|
|
All threads sleeping on a single
|
|
.Fa chan
|
|
are woken up later by
|
|
.Fn wakeup ,
|
|
often called from inside an interrupt routine, to indicate that the
|
|
resource the thread was blocking on is available now.
|
|
.Pp
|
|
Several of the sleep functions including
|
|
.Fn msleep ,
|
|
.Fn msleep_spin ,
|
|
and the locking primitive sleep routines specify an additional lock
|
|
parameter.
|
|
The lock will be released before sleeping and reacquired
|
|
before the sleep routine returns.
|
|
If
|
|
.Fa priority
|
|
includes the
|
|
.Dv PDROP
|
|
flag, then the lock will not be reacquired before returning.
|
|
The lock is used to ensure that a condition can be checked atomically,
|
|
and that the current thread can be suspended without missing a
|
|
change to the condition, or an associated wakeup.
|
|
In addition, all of the sleep routines will fully drop the
|
|
.Va Giant
|
|
mutex
|
|
(even if recursed)
|
|
while the thread is suspended and will reacquire the
|
|
.Va Giant
|
|
mutex before the function returns.
|
|
.Pp
|
|
.Ss lockmanager locks
|
|
Largely deprecated.
|
|
See the
|
|
.Xr lock 9
|
|
page for more information.
|
|
I don't know what the downsides are but I'm sure someone will fill in this part.
|
|
.Sh Usage tables.
|
|
.Ss Interaction table.
|
|
The following table shows what you can and can not do if you hold
|
|
one of the synchronization primitives discussed here:
|
|
(someone who knows what they are talking about should write this table)
|
|
.Bl -column ".Ic xxxxxxxxxxxxxxxxxxxx" ".Xr XXXXXXXXX" ".Xr XXXXXXX" ".Xr XXXXXXX" ".Xr XXXXXXX" ".Xr XXXXX" -offset indent
|
|
.It Xo
|
|
.Em "You have: You want:" Ta Spin_mtx Ta Slp_mtx Ta sx_lock Ta rw_lock Ta sleep
|
|
.Xc
|
|
.It Ic SPIN mutex Ta \&ok Ta \&no Ta \&no Ta \&no Ta \&no-3
|
|
.It Ic Sleep mutex Ta \&ok Ta \&ok-1 Ta \&no Ta \&ok Ta \&no-3
|
|
.It Ic sx_lock Ta \&ok Ta \&no Ta \&ok-2 Ta \&no Ta \&ok-4
|
|
.It Ic rw_lock Ta \&ok Ta \&ok Ta \&no Ta \&ok-2 Ta \&no-3
|
|
.El
|
|
.Pp
|
|
.Em *1
|
|
Recursion is defined per lock.
|
|
Lock order is important.
|
|
.Pp
|
|
.Em *2
|
|
readers can recurse though writers can not.
|
|
Lock order is important.
|
|
.Pp
|
|
.Em *3
|
|
There are calls atomically release this primitive when going to sleep
|
|
and reacquire it on wakeup (e.g.
|
|
.Fn mtx_sleep ,
|
|
.Fn rw_sleep
|
|
and
|
|
.Fn msleep_spin
|
|
).
|
|
.Pp
|
|
.Em *4
|
|
Though one can sleep holding an sx lock, one can also use
|
|
.Fn sx_sleep
|
|
which atomically release this primitive when going to sleep and
|
|
reacquire it on wakeup.
|
|
.Ss Context mode table.
|
|
The next table shows what can be used in different contexts.
|
|
At this time this is a rather easy to remember table.
|
|
.Bl -column ".Ic Xxxxxxxxxxxxxxxxxxxx" ".Xr XXXXXXXXX" ".Xr XXXXXXX" ".Xr XXXXXXX" ".Xr XXXXXXX" ".Xr XXXXX" -offset indent
|
|
.It Xo
|
|
.Em "Context:" Ta Spin_mtx Ta Slp_mtx Ta sx_lock Ta rw_lock Ta sleep
|
|
.Xc
|
|
.It interrupt: Ta \&ok Ta \&no Ta \&no Ta \&no Ta \&no
|
|
.It idle: Ta \&ok Ta \&no Ta \&no Ta \&no Ta \&no
|
|
.El
|
|
.Sh SEE ALSO
|
|
.Xr condvar 9 ,
|
|
.Xr lock 9 ,
|
|
.Xr mtx_pool 9 ,
|
|
.Xr mutex 9 ,
|
|
.Xr rwlock 9 ,
|
|
.Xr sema 9 ,
|
|
.Xr sleep 9 ,
|
|
.Xr sx 9 ,
|
|
.Xr LOCK_PROFILING 9 ,
|
|
.Xr WITNESS 9
|
|
.Sh HISTORY
|
|
These
|
|
functions appeared in
|
|
.Bsx 4.1
|
|
through
|
|
.Fx 7.0
|