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*
getqlp(void)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
qlock(QLock * q)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
qunlock(QLock * q)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
canqlock(QLock * q)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