1 #define _LOCK_EXTENSION 2 #define _QLOCK_EXTENSION 3 #define _RESEARCH_SOURCE 4 #include <u.h> 5 #include <lock.h> 6 #include <qlock.h> 7 #include <stdlib.h> 8 #include "sys9.h" 9 10 #define rendezvous _RENDEZVOUS 11 #define _rendezvousp rendezvous 12 #define _tas tas 13 #define nelem(x) (sizeof(x)/sizeof((x)[0])) 14 15 static struct { 16 QLp *p; 17 QLp x[1024]; 18 } ql = { 19 ql.x 20 }; 21 22 enum 23 { 24 Queuing, 25 QueuingR, 26 QueuingW, 27 Sleeping, 28 }; 29 30 /* find a free shared memory location to queue ourselves in */ 31 static QLp* 32 getqlp(void) 33 { 34 QLp *p, *op; 35 36 op = ql.p; 37 for(p = op+1; ; p++){ 38 if(p == &ql.x[nelem(ql.x)]) 39 p = ql.x; 40 if(p == op) 41 abort(); 42 if(_tas(&(p->inuse)) == 0){ 43 ql.p = p; 44 p->next = nil; 45 break; 46 } 47 } 48 return p; 49 } 50 51 void 52 qlock(QLock *q) 53 { 54 QLp *p, *mp; 55 56 lock(&q->lock); 57 if(!q->locked){ 58 q->locked = 1; 59 unlock(&q->lock); 60 return; 61 } 62 63 64 /* chain into waiting list */ 65 mp = getqlp(); 66 p = q->tail; 67 if(p == nil) 68 q->head = mp; 69 else 70 p->next = mp; 71 q->tail = mp; 72 mp->state = Queuing; 73 unlock(&q->lock); 74 75 /* wait */ 76 while((*_rendezvousp)((ulong)mp, 1) == ~0) 77 ; 78 mp->inuse = 0; 79 } 80 81 void 82 qunlock(QLock *q) 83 { 84 QLp *p; 85 86 lock(&q->lock); 87 p = q->head; 88 if(p != nil){ 89 /* wakeup head waiting process */ 90 q->head = p->next; 91 if(q->head == nil) 92 q->tail = nil; 93 unlock(&q->lock); 94 while((*_rendezvousp)((ulong)p, 0x12345) == ~0) 95 ; 96 return; 97 } 98 q->locked = 0; 99 unlock(&q->lock); 100 } 101 102 int 103 canqlock(QLock *q) 104 { 105 if(!canlock(&q->lock)) 106 return 0; 107 if(!q->locked){ 108 q->locked = 1; 109 unlock(&q->lock); 110 return 1; 111 } 112 unlock(&q->lock); 113 return 0; 114 } 115 116 #if 0 117 118 void 119 rlock(RWLock *q) 120 { 121 QLp *p, *mp; 122 123 lock(&q->lock); 124 if(q->writer == 0 && q->head == nil){ 125 /* no writer, go for it */ 126 q->readers++; 127 unlock(&q->lock); 128 return; 129 } 130 131 mp = getqlp(); 132 p = q->tail; 133 if(p == 0) 134 q->head = mp; 135 else 136 p->next = mp; 137 q->tail = mp; 138 mp->next = nil; 139 mp->state = QueuingR; 140 unlock(&q->lock); 141 142 /* wait in kernel */ 143 while((*_rendezvousp)((ulong)mp, 1) == ~0) 144 ; 145 mp->inuse = 0; 146 } 147 148 int 149 canrlock(RWLock *q) 150 { 151 lock(&q->lock); 152 if (q->writer == 0 && q->head == nil) { 153 /* no writer; go for it */ 154 q->readers++; 155 unlock(&q->lock); 156 return 1; 157 } 158 unlock(&q->lock); 159 return 0; 160 } 161 162 void 163 runlock(RWLock *q) 164 { 165 QLp *p; 166 167 lock(&q->lock); 168 if(q->readers <= 0) 169 abort(); 170 p = q->head; 171 if(--(q->readers) > 0 || p == nil){ 172 unlock(&q->lock); 173 return; 174 } 175 176 /* start waiting writer */ 177 if(p->state != QueuingW) 178 abort(); 179 q->head = p->next; 180 if(q->head == 0) 181 q->tail = 0; 182 q->writer = 1; 183 unlock(&q->lock); 184 185 /* wakeup waiter */ 186 while((*_rendezvousp)((ulong)p, 0) == ~0) 187 ; 188 } 189 190 void 191 wlock(RWLock *q) 192 { 193 QLp *p, *mp; 194 195 lock(&q->lock); 196 if(q->readers == 0 && q->writer == 0){ 197 /* noone waiting, go for it */ 198 q->writer = 1; 199 unlock(&q->lock); 200 return; 201 } 202 203 /* wait */ 204 p = q->tail; 205 mp = getqlp(); 206 if(p == nil) 207 q->head = mp; 208 else 209 p->next = mp; 210 q->tail = mp; 211 mp->next = nil; 212 mp->state = QueuingW; 213 unlock(&q->lock); 214 215 /* wait in kernel */ 216 while((*_rendezvousp)((ulong)mp, 1) == ~0) 217 ; 218 mp->inuse = 0; 219 } 220 221 int 222 canwlock(RWLock *q) 223 { 224 lock(&q->lock); 225 if (q->readers == 0 && q->writer == 0) { 226 /* no one waiting; go for it */ 227 q->writer = 1; 228 unlock(&q->lock); 229 return 1; 230 } 231 unlock(&q->lock); 232 return 0; 233 } 234 235 void 236 wunlock(RWLock *q) 237 { 238 QLp *p; 239 240 lock(&q->lock); 241 if(q->writer == 0) 242 abort(); 243 p = q->head; 244 if(p == nil){ 245 q->writer = 0; 246 unlock(&q->lock); 247 return; 248 } 249 if(p->state == QueuingW){ 250 /* start waiting writer */ 251 q->head = p->next; 252 if(q->head == nil) 253 q->tail = nil; 254 unlock(&q->lock); 255 while((*_rendezvousp)((ulong)p, 0) == ~0) 256 ; 257 return; 258 } 259 260 if(p->state != QueuingR) 261 abort(); 262 263 /* wake waiting readers */ 264 while(q->head != nil && q->head->state == QueuingR){ 265 p = q->head; 266 q->head = p->next; 267 q->readers++; 268 while((*_rendezvousp)((ulong)p, 0) == ~0) 269 ; 270 } 271 if(q->head == nil) 272 q->tail = nil; 273 q->writer = 0; 274 unlock(&q->lock); 275 } 276 277 void 278 rsleep(Rendez *r) 279 { 280 QLp *t, *me; 281 282 if(!r->l) 283 abort(); 284 lock(&r->l->lock); 285 /* we should hold the qlock */ 286 if(!r->l->locked) 287 abort(); 288 289 /* add ourselves to the wait list */ 290 me = getqlp(); 291 me->state = Sleeping; 292 if(r->head == nil) 293 r->head = me; 294 else 295 r->tail->next = me; 296 me->next = nil; 297 r->tail = me; 298 299 /* pass the qlock to the next guy */ 300 t = r->l->head; 301 if(t){ 302 r->l->head = t->next; 303 if(r->l->head == nil) 304 r->l->tail = nil; 305 unlock(&r->l->lock); 306 while((*_rendezvousp)((ulong)t, 0x12345) == ~0) 307 ; 308 }else{ 309 r->l->locked = 0; 310 unlock(&r->l->lock); 311 } 312 313 /* wait for a wakeup */ 314 while((*_rendezvousp)((ulong)me, 1) == ~0) 315 ; 316 me->inuse = 0; 317 } 318 319 int 320 rwakeup(Rendez *r) 321 { 322 QLp *t; 323 324 /* 325 * take off wait and put on front of queue 326 * put on front so guys that have been waiting will not get starved 327 */ 328 329 if(!r->l) 330 abort(); 331 lock(&r->l->lock); 332 if(!r->l->locked) 333 abort(); 334 335 t = r->head; 336 if(t == nil){ 337 unlock(&r->l->lock); 338 return 0; 339 } 340 341 r->head = t->next; 342 if(r->head == nil) 343 r->tail = nil; 344 345 t->next = r->l->head; 346 r->l->head = t; 347 if(r->l->tail == nil) 348 r->l->tail = t; 349 350 t->state = Queuing; 351 unlock(&r->l->lock); 352 return 1; 353 } 354 355 int 356 rwakeupall(Rendez *r) 357 { 358 int i; 359 360 for(i=0; rwakeup(r); i++) 361 ; 362 return i; 363 } 364 365 #endif 366