Blob


1 .TH LOCK 3
2 .SH NAME
3 lock, canlock, unlock,
4 qlock, canqlock, qunlock,
5 rlock, canrlock, runlock,
6 wlock, canwlock, wunlock,
7 rsleep, rwakeup, rwakeupall
8 incref, decref
9 \- spin locks, queueing rendezvous locks, reader-writer locks, rendezvous points, and reference counts
10 .SH SYNOPSIS
11 .ft L
12 .nf
13 #include <u.h>
14 #include <libc.h>
15 .PP
16 .ft L
17 .nf
18 void lock(Lock *l)
19 int canlock(Lock *l)
20 void unlock(Lock *l)
21 .PP
22 .ft L
23 .nf
24 void qlock(QLock *l)
25 int canqlock(QLock *l)
26 void qunlock(QLock *l)
27 .PP
28 .ft L
29 .nf
30 void rlock(RWLock *l)
31 int canrlock(RWLock *l)
32 void runlock(RWLock *l)
33 .PP
34 .ft L
35 .nf
36 void wlock(RWLock *l)
37 int canwlock(RWLock *l)
38 void wunlock(RWLock *l)
39 .PP
40 .ft L
41 .nf
42 typedef struct Rendez {
43 QLock *l;
44 \fI...\fP
45 } Rendez;
46 .PP
47 .ft L
48 .nf
49 void rsleep(Rendez *r)
50 int rwakeup(Rendez *r)
51 int rwakeupall(Rendez *r)
52 .PP
53 .ft L
54 #include <thread.h>
55 .PP
56 .ft L
57 .nf
58 typedef struct Ref {
59 long ref;
60 } Ref;
61 .PP
62 .ft L
63 .nf
64 void incref(Ref*)
65 long decref(Ref*)
66 .fi
67 .SH DESCRIPTION
68 These routines are used to synchronize processes sharing memory.
69 .PP
70 .B Locks
71 are spin locks,
72 .B QLocks
73 and
74 .B RWLocks
75 are different types of queueing locks,
76 and
77 .B Rendezes
78 are rendezvous points.
79 .PP
80 Locks and rendezvous points have trivial implementations in programs
81 not using the thread library
82 (see
83 .MR thread (3) ),
84 since such programs have no concurrency.
85 .PP
86 Used carelessly, spin locks can be expensive and can easily generate deadlocks.
87 Their use is discouraged, especially in programs that use the
88 thread library because they prevent context switches between threads.
89 .PP
90 .I Lock
91 blocks until the lock has been obtained.
92 .I Canlock
93 is non-blocking.
94 It tries to obtain a lock and returns a non-zero value if it
95 was successful, 0 otherwise.
96 .I Unlock
97 releases a lock.
98 .PP
99 .B QLocks
100 have the same interface but are not spin locks; instead if the lock is taken
101 .I qlock
102 will suspend execution of the calling thread until it is released.
103 .PP
104 Although
105 .B Locks
106 are the more primitive lock, they have limitations; for example,
107 they cannot synchronize between tasks in the same
108 .IR proc .
109 Use
110 .B QLocks
111 instead.
112 .PP
113 .B RWLocks
114 manage access to a data structure that has distinct readers and writers.
115 .I Rlock
116 grants read access;
117 .I runlock
118 releases it.
119 .I Wlock
120 grants write access;
121 .I wunlock
122 releases it.
123 .I Canrlock
124 and
125 .I canwlock
126 are the non-blocking versions.
127 There may be any number of simultaneous readers,
128 but only one writer.
129 Moreover,
130 if write access is granted no one may have
131 read access until write access is released.
132 .PP
133 All types of lock should be initialized to all zeros before use; this
134 puts them in the unlocked state.
135 .PP
136 .B Rendezes
137 are rendezvous points. Each
138 .B Rendez
139 .I r
140 is protected by a
141 .B QLock
142 .IB r -> l \fR,
143 which must be held by the callers of
144 .IR rsleep ,
145 .IR rwakeup ,
146 and
147 .IR rwakeupall .
148 .I Rsleep
149 atomically releases
150 .IB r -> l
151 and suspends execution of the calling task.
152 After resuming execution,
153 .I rsleep
154 will reacquire
155 .IB r -> l
156 before returning.
157 If any processes are sleeping on
158 .IR r ,
159 .I rwakeup
160 wakes one of them.
161 It returns 1 if a process was awakened, 0 if not.
162 .I Rwakeupall
163 wakes all processes sleeping on
164 .IR r ,
165 returning the number of processes awakened.
166 .I Rwakeup
167 and
168 .I rwakeupall
169 do not release
170 .IB r -> l
171 and do not suspend execution of the current task.
172 .PP
173 Before use,
174 .B Rendezes
175 should be initialized to all zeros except for
176 .IB r -> l
177 pointer, which should point at the
178 .B QLock
179 that will guard
180 .IR r .
181 .PP
183 .B Ref
184 contains a
185 .B long
186 that can be incremented and decremented atomically:
187 .I Incref
188 increments the
189 .I Ref
190 in one atomic operation.
191 .I Decref
192 atomically decrements the
193 .B Ref
194 and returns zero if the resulting value is zero, non-zero otherwise.
195 .SH SOURCE
196 .B \*9/src/lib9/qlock.c
197 .br
198 .B \*9/src/libthread
199 .SH BUGS
200 .B Locks
201 are not always spin locks.
202 Instead they are usually implemented using the
203 .I pthreads
204 library's
205 .BR pthread_mutex_t ,
206 whose implementation method is not defined.
207 .PP
208 On
209 .IR pthreads -based
210 systems, the implementation of
211 .B Lock
212 never calls
213 .I pthread_mutex_destroy
214 to free the
215 .BR pthread_mutex_t 's.
216 This leads to resource leaks on FreeBSD 5
217 (though not on Linux 2.6, where
218 .I pthread_mutex_destroy
219 is a no-op).
220 .BR
221 .PP
222 On systems that do not have a usable
223 .I pthreads
224 implementation, the
225 .B Lock
226 implementation provided by
227 .I libthread
228 is still not exactly a spin lock.
229 After each unsuccessful attempt,
230 .I lock
231 calls
232 .B sleep(0)
233 to yield the CPU; this handles the common case
234 where some other process holds the lock.
235 After a thousand unsuccessful attempts,
236 .I lock
237 sleeps for 100ms between attempts.
238 Another another thousand unsuccessful attempts,
239 .I lock
240 sleeps for a full second between attempts.
241 .B Locks
242 are not intended to be held for long periods of time.
243 The 100ms and full second sleeps are only heuristics to
244 avoid tying up the CPU when a process deadlocks.
245 As discussed above,
246 if a lock is to be held for much more than a few instructions,
247 the queueing lock types should be almost always be used.