aboutsummaryrefslogtreecommitdiff
path: root/man/man3/lock.html
blob: 72d66e128daccc735b2302d08c0d195e177d3753 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
<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 &ndash; 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 &lt;u.h&gt;<br>
    #include &lt;libc.h&gt;<br>
    
    <table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
    
    void lock(Lock *l)<br>
    int &nbsp;&nbsp;&nbsp;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 &nbsp;&nbsp;&nbsp;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 &nbsp;&nbsp;&nbsp;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 &nbsp;&nbsp;&nbsp;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 &nbsp;&nbsp;&nbsp;rwakeup(Rendez *r)<br>
    int &nbsp;&nbsp;&nbsp;rwakeupall(Rendez *r)<br>
    
    <table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
    
    #include &lt;thread.h&gt;<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>&#8722;&gt;</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>&#8722;&gt;</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>&#8722;&gt;</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>&#8722;&gt;</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>&#8722;&gt;</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&#8217;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>&#8217;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>