222 lines
9.8 KiB
HTML
222 lines
9.8 KiB
HTML
<head>
|
|
<title>lock(3) - Plan 9 from User Space</title>
|
|
<meta content="text/html; charset=utf-8" http-equiv=Content-Type>
|
|
</head>
|
|
<body bgcolor=#ffffff>
|
|
<table border=0 cellpadding=0 cellspacing=0 width=100%>
|
|
<tr height=10><td>
|
|
<tr><td width=20><td>
|
|
<tr><td width=20><td><b>LOCK(3)</b><td align=right><b>LOCK(3)</b>
|
|
<tr><td width=20><td colspan=2>
|
|
<br>
|
|
<p><font size=+1><b>NAME </b></font><br>
|
|
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>
|
|
|
|
lock, canlock, unlock, qlock, canqlock, qunlock, rlock, canrlock,
|
|
runlock, wlock, canwlock, wunlock, rsleep, rwakeup, rwakeupall
|
|
incref, decref – spin locks, queueing rendezvous locks, reader-writer
|
|
locks, rendezvous points, and reference counts<br>
|
|
|
|
</table>
|
|
<p><font size=+1><b>SYNOPSIS </b></font><br>
|
|
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>
|
|
|
|
<tt><font size=+1>#include <u.h><br>
|
|
#include <libc.h><br>
|
|
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
|
|
|
|
void lock(Lock *l)<br>
|
|
int canlock(Lock *l)<br>
|
|
void unlock(Lock *l)<br>
|
|
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
|
|
|
|
void qlock(QLock *l)<br>
|
|
int canqlock(QLock *l)<br>
|
|
void qunlock(QLock *l)<br>
|
|
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
|
|
|
|
void rlock(RWLock *l)<br>
|
|
int canrlock(RWLock *l)<br>
|
|
void runlock(RWLock *l)<br>
|
|
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
|
|
|
|
void wlock(RWLock *l)<br>
|
|
int canwlock(RWLock *l)<br>
|
|
void wunlock(RWLock *l)<br>
|
|
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
|
|
|
|
typedef struct Rendez {<br>
|
|
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>
|
|
|
|
QLock *l;<br>
|
|
|
|
</table>
|
|
</font></tt>
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>
|
|
|
|
<i>...<br>
|
|
</i>
|
|
</table>
|
|
<tt><font size=+1>} Rendez;<br>
|
|
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
|
|
|
|
void rsleep(Rendez *r)<br>
|
|
int rwakeup(Rendez *r)<br>
|
|
int rwakeupall(Rendez *r)<br>
|
|
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
|
|
|
|
#include <thread.h><br>
|
|
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
|
|
|
|
typedef struct Ref {<br>
|
|
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>
|
|
|
|
long ref;<br>
|
|
|
|
</table>
|
|
} Ref;<br>
|
|
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
|
|
|
|
void incref(Ref*)<br>
|
|
long decref(Ref*)<br>
|
|
</font></tt>
|
|
</table>
|
|
<p><font size=+1><b>DESCRIPTION </b></font><br>
|
|
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>
|
|
|
|
These routines are used to synchronize processes sharing memory.
|
|
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
|
|
|
|
<tt><font size=+1>Locks</font></tt> are spin locks, <tt><font size=+1>QLocks</font></tt> and <tt><font size=+1>RWLocks</font></tt> are different types of
|
|
queueing locks, and <tt><font size=+1>Rendezes</font></tt> are rendezvous points.
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
|
|
|
|
Locks and rendezvous points have trivial implementations in programs
|
|
not using the thread library (see <a href="../man3/thread.html"><i>thread</i>(3)</a>), since such programs
|
|
have no concurrency.
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
|
|
|
|
Used carelessly, spin locks can be expensive and can easily generate
|
|
deadlocks. Their use is discouraged, especially in programs that
|
|
use the thread library because they prevent context switches between
|
|
threads.
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
|
|
|
|
<i>Lock</i> blocks until the lock has been obtained. <i>Canlock</i> is non-blocking.
|
|
It tries to obtain a lock and returns a non-zero value if it was
|
|
successful, 0 otherwise. <i>Unlock</i> releases a lock.
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
|
|
|
|
<tt><font size=+1>QLocks</font></tt> have the same interface but are not spin locks; instead
|
|
if the lock is taken <i>qlock</i> will suspend execution of the calling
|
|
thread until it is released.
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
|
|
|
|
Although <tt><font size=+1>Locks</font></tt> are the more primitive lock, they have limitations;
|
|
for example, they cannot synchronize between tasks in the same
|
|
<i>proc</i>. Use <tt><font size=+1>QLocks</font></tt> instead.
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
|
|
|
|
<tt><font size=+1>RWLocks</font></tt> manage access to a data structure that has distinct readers
|
|
and writers. <i>Rlock</i> grants read access; <i>runlock</i> releases it. <i>Wlock</i>
|
|
grants write access; <i>wunlock</i> releases it. <i>Canrlock</i> and <i>canwlock</i>
|
|
are the non-blocking versions. There may be any number of simultaneous
|
|
readers, but only one writer. Moreover, if
|
|
write access is granted no one may have read access until write
|
|
access is released.
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
|
|
|
|
All types of lock should be initialized to all zeros before use;
|
|
this puts them in the unlocked state.
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
|
|
|
|
<tt><font size=+1>Rendezes</font></tt> are rendezvous points. Each <tt><font size=+1>Rendez</font></tt> <i>r</i> is protected by
|
|
a <tt><font size=+1>QLock</font></tt> <i>r</i><tt><font size=+1>−></font></tt><i>l</i>, which must be held by the callers of <i>rsleep</i>, <i>rwakeup</i>,
|
|
and <i>rwakeupall</i>. <i>Rsleep</i> atomically releases <i>r</i><tt><font size=+1>−></font></tt><i>l</i> and suspends execution
|
|
of the calling task. After resuming execution, <i>rsleep</i> will reacquire
|
|
<i>r</i><tt><font size=+1>−></font></tt><i>l</i> before returning. If any processes
|
|
are sleeping on <i>r</i>, <i>rwakeup</i> wakes one of them. it returns 1 if
|
|
a process was awakened, 0 if not. <i>Rwakeupall</i> wakes all processes
|
|
sleeping on <i>r</i>, returning the number of processes awakened. <i>Rwakeup</i>
|
|
and <i>rwakeupall</i> do not release <i>r</i><tt><font size=+1>−></font></tt><i>l</i> and do not suspend execution
|
|
of the current task.
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
|
|
|
|
Before use, <tt><font size=+1>Rendezes</font></tt> should be initialized to all zeros except
|
|
for <i>r</i><tt><font size=+1>−></font></tt><i>l</i> pointer, which should point at the <tt><font size=+1>QLock</font></tt> that will guard
|
|
<i>r</i>.
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
|
|
|
|
A <tt><font size=+1>Ref</font></tt> contains a <tt><font size=+1>long</font></tt> that can be incremented and decremented
|
|
atomically: <i>Incref</i> increments the <i>Ref</i> in one atomic operation.
|
|
<i>Decref</i> atomically decrements the <tt><font size=+1>Ref</font></tt> and returns zero if the resulting
|
|
value is zero, non-zero otherwise.<br>
|
|
|
|
</table>
|
|
<p><font size=+1><b>SOURCE </b></font><br>
|
|
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>
|
|
|
|
<tt><font size=+1>/usr/local/plan9/src/lib9/qlock.c<br>
|
|
/usr/local/plan9/src/libthread<br>
|
|
</font></tt>
|
|
</table>
|
|
<p><font size=+1><b>BUGS </b></font><br>
|
|
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>
|
|
|
|
<tt><font size=+1>Locks</font></tt> are not always spin locks. Instead they are usually implemented
|
|
using the <i>pthreads</i> library’s <tt><font size=+1>pthread_mutex_t</font></tt>, whose implementation
|
|
method is not defined.
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
|
|
|
|
On <i>pthreads</i>-based systems, the implementation of <tt><font size=+1>Lock</font></tt> never calls
|
|
<i>pthread_mutex_destroy</i> to free the <tt><font size=+1>pthread_mutex_t</font></tt>’s. This leads
|
|
to resource leaks on FreeBSD 5 (though not on Linux 2.6, where
|
|
<i>pthread_mutex_destroy</i> is a no-op).
|
|
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
|
|
|
|
On systems that do not have a usable <i>pthreads</i> implementation,
|
|
the <tt><font size=+1>Lock</font></tt> implementation provided by <i>libthread</i> is still not exactly
|
|
a spin lock. After each unsuccessful attempt, <i>lock</i> calls <tt><font size=+1>sleep(0)</font></tt>
|
|
to yield the CPU; this handles the common case where some other
|
|
process holds the lock. After a thousand
|
|
unsuccessful attempts, <i>lock</i> sleeps for 100ms between attempts.
|
|
Another another thousand unsuccessful attempts, <i>lock</i> sleeps for
|
|
a full second between attempts. <tt><font size=+1>Locks</font></tt> are not intended to be held
|
|
for long periods of time. The 100ms and full second sleeps are
|
|
only heuristics to avoid tying up the CPU when a
|
|
process deadlocks. As discussed above, if a lock is to be held
|
|
for much more than a few instructions, the queueing lock types
|
|
should be almost always be used.<br>
|
|
|
|
</table>
|
|
|
|
<td width=20>
|
|
<tr height=20><td>
|
|
</table>
|
|
<!-- TRAILER -->
|
|
<table border=0 cellpadding=0 cellspacing=0 width=100%>
|
|
<tr height=15><td width=10><td><td width=10>
|
|
<tr><td><td>
|
|
<center>
|
|
<a href="../../"><img src="../../dist/spaceglenda100.png" alt="Space Glenda" border=1></a>
|
|
</center>
|
|
</table>
|
|
<!-- TRAILER -->
|
|
</body></html>
|