1
0

lock 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  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. c = mallocz(sizeof *c, 1);
  227. c->full.l = &c->l;
  228. c->empty.l = &c->l;
  229. return c;
  230. }
  231. .EE
  232. .IP
  233. .EX
  234. .ta +4n +4n +4n
  235. void
  236. send(Chan *c, int val)
  237. {
  238. qlock(&c->l);
  239. while(c->haveval)
  240. rsleep(&c->full);
  241. c->haveval = 1;
  242. c->val = val;
  243. rwakeup(&c->empty); /* no longer empty */
  244. qunlock(&c->l);
  245. }
  246. .EE
  247. .IP
  248. .EX
  249. .ta +4n +4n +4n
  250. int
  251. recv(Chan *c)
  252. {
  253. int v;
  254. qlock(&c->l);
  255. while(!c->haveval)
  256. rsleep(&c->empty);
  257. c->haveval = 0;
  258. v = c->val;
  259. rwakeup(&c->full); /* no longer full */
  260. qunlock(&c->l);
  261. return v;
  262. }
  263. .EE
  264. .LP
  265. Note that the
  266. .B QLock
  267. protecting the
  268. .B Chan
  269. is the same
  270. .B QLock
  271. used for the
  272. .BR Rendez ;
  273. this ensures that wakeups are not missed.
  274. .SH SOURCE
  275. .B /sys/src/libc/port/lock.c
  276. .br
  277. .B /sys/src/libc/9sys/qlock.c
  278. .br
  279. .B /sys/src/libthread/ref.c
  280. .SH SEE ALSO
  281. .I rfork
  282. in
  283. .IR fork (2),
  284. .IR semacquire (2)
  285. .SH BUGS
  286. .B Locks
  287. are not actually spin locks.
  288. After one unsuccessful attempt,
  289. .I lock
  290. calls
  291. .I semacquire
  292. repeatedly (thus yielding the CPU)
  293. until it succeeds in acquiring a semaphore internal to the
  294. .BR Lock .
  295. .B Locks
  296. are not intended to be held for long periods of time.
  297. As discussed above,
  298. if a lock is to be held for much more than a few instructions,
  299. the queueing lock types should be almost always be used.
  300. .PP
  301. It is an error for a program to
  302. .I fork
  303. when it holds a lock in shared memory, since this will result
  304. in two processes holding the same lock at the same time,
  305. which should not happen.