Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_unix/sys/man/2/lock – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
.TH LOCK 2
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 rendezvous locks,
76
and
77
.B Rendezes
78
are rendezvous points.
79
.PP
80
Locks and rendezvous points work in regular programs as
81
well as programs that use the thread library
82
(see
83
.IR thread (2)).
84
The thread library replaces the
85
.IR rendezvous (2)
86
system call
87
with its own implementation,
88
.IR threadrendezvous ,
89
so that threads as well as processes may be synchronized by locking calls
90
in threaded programs.
91
.PP
92
Used carelessly, spin locks can be expensive and can easily generate deadlocks.
93
Their use is discouraged, especially in programs that use the
94
thread library because they prevent context switches between threads.
95
.PP
96
.I Lock
97
blocks until the lock has been obtained.
98
.I Canlock
99
is non-blocking.
100
It tries to obtain a lock and returns a non-zero value if it
101
was successful, 0 otherwise.
102
.I Unlock
103
releases a lock.
104
.PP
105
.B QLocks
106
have the same interface but are not spin locks; instead if the lock is taken
107
.I qlock
108
will suspend execution of the calling task until it is released.
109
.PP
110
Although
111
.B Locks
112
are the more primitive lock, they have limitations; for example,
113
they cannot synchronize between tasks in the same
114
.IR proc .
115
Use
116
.B QLocks
117
instead.
118
.PP
119
.B RWLocks
120
manage access to a data structure that has distinct readers and writers.
121
.I Rlock
122
grants read access;
123
.I runlock
124
releases it.
125
.I Wlock
126
grants write access;
127
.I wunlock
128
releases it.
129
.I Canrlock
130
and
131
.I canwlock
132
are the non-blocking versions.
133
There may be any number of simultaneous readers,
134
but only one writer.
135
Moreover,
136
if write access is granted no one may have
137
read access until write access is released.
138
.PP
139
All types of lock should be initialized to all zeros before use; this
140
puts them in the unlocked state.
141
.PP
142
.B Rendezes
143
are rendezvous points.  Each
144
.B Rendez
145
.I r
146
is protected by a
147
.B QLock
148
.IB r -> l \fR,
149
which must be held by the callers of
150
.IR rsleep ,
151
.IR rwakeup ,
152
and
153
.IR rwakeupall .
154
.I Rsleep
155
atomically releases
156
.IB r -> l
157
and suspends execution of the calling task.
158
After resuming execution,
159
.I rsleep
160
will reacquire
161
.IB r -> l
162
before returning.
163
If any processes are sleeping on
164
.IR r ,
165
.I rwakeup
166
wakes one of them.
167
it returns 1 if a process was awakened, 0 if not.
168
.I Rwakeupall
169
wakes all processes sleeping on
170
.IR r ,
171
returning the number of processes awakened.
172
.I Rwakeup
173
and
174
.I rwakeupall
175
do not release
176
.IB r -> l
177
and do not suspend execution of the current task.
178
.PP
179
Before use,
180
.B Rendezes
181
should be initialized to all zeros except for
182
.IB r -> l
183
pointer, which should point at the
184
.B QLock
185
that will guard
186
.IR r .
187
It is important that this
188
.B QLock
189
is the same one that protects the rendezvous condition; see the example.
190
.PP
191
A
192
.B Ref
193
contains a
194
.B long
195
that can be incremented and decremented atomically:
196
.I Incref
197
increments the
198
.I Ref
199
in one atomic operation.
200
.I Decref
201
atomically decrements the
202
.B Ref
203
and returns zero if the resulting value is zero, non-zero otherwise.
204
.SH EXAMPLE
205
Implement a buffered single-element channel using 
206
.I rsleep
207
and
208
.IR rwakeup :
209
.IP
210
.EX
211
.ta +4n +4n +4n
212
typedef struct Chan
213
{
214
	QLock l;
215
	Rendez full, empty;
216
	int val, haveval;
217
} Chan;
218
.EE
219
.IP
220
.EX
221
.ta +4n +4n +4n
222
Chan*
223
mkchan(void)
224
{
225
	Chan *c;
226
 
227
	c = mallocz(sizeof *c, 1);
228
	c->full.l = &c->l;
229
	c->empty.l = &c->l;
230
	return c;
231
}
232
.EE
233
.IP
234
.EX
235
.ta +4n +4n +4n
236
void
237
send(Chan *c, int val)
238
{
239
	qlock(&c->l);
240
	while(c->haveval)
241
		rsleep(&c->full);
242
	c->haveval = 1;
243
	c->val = val;
244
	rwakeup(&c->empty);  /* no longer empty */
245
	qunlock(&c->l);
246
}
247
.EE
248
.IP
249
.EX
250
.ta +4n +4n +4n
251
int
252
recv(Chan *c)
253
{
254
	int v;
255
 
256
	qlock(&c->l);
257
	while(!c->haveval)
258
		rsleep(&c->empty);
259
	c->haveval = 0;
260
	v = c->val;
261
	rwakeup(&c->full);  /* no longer full */
262
	qunlock(&c->l);
263
	return v;
264
}
265
.EE
266
.LP
267
Note that the 
268
.B QLock
269
protecting the
270
.B Chan
271
is the same
272
.B QLock
273
used for the 
274
.BR Rendez ;
275
this ensures that wakeups are not missed.
276
.SH SOURCE
277
.B /sys/src/libc/port/lock.c
278
.br
279
.B /sys/src/libc/9sys/qlock.c
280
.br
281
.B /sys/src/libthread/ref.c
282
.SH SEE ALSO
283
.I rfork
284
in
285
.IR fork (2)
286
.SH BUGS
287
.B Locks
288
are not strictly spin locks.
289
After each unsuccessful attempt,
290
.I lock
291
calls
292
.B sleep(0)
293
to yield the CPU; this handles the common case
294
where some other process holds the lock.
295
After a thousand unsuccessful attempts,
296
.I lock
297
sleeps for 100ms between attempts.
298
After another thousand unsuccessful attempts,
299
.I lock
300
sleeps for a full second between attempts.
301
.B Locks
302
are not intended to be held for long periods of time.
303
The 100ms and full second sleeps are only heuristics to
304
avoid tying up the CPU when a process deadlocks.
305
As discussed above,
306
if a lock is to be held for much more than a few instructions,
307
the queueing lock types should be almost always be used.
308
.PP
309
It is an error for a program to
310
.I fork
311
when it holds a lock in shared memory, since this will result
312
in two processes holding the same lock at the same time,
313
which should not happen.