| <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> |