lock.3 (4972B)
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 182 A 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.