17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier
47dd7cddfSDavid du Colombier static struct {
57dd7cddfSDavid du Colombier QLp *p;
67dd7cddfSDavid du Colombier QLp x[1024];
77dd7cddfSDavid du Colombier } ql = {
87dd7cddfSDavid du Colombier ql.x
97dd7cddfSDavid du Colombier };
107dd7cddfSDavid du Colombier
117dd7cddfSDavid du Colombier enum
127dd7cddfSDavid du Colombier {
137dd7cddfSDavid du Colombier Queuing,
147dd7cddfSDavid du Colombier QueuingR,
157dd7cddfSDavid du Colombier QueuingW,
16679c15e8SDavid du Colombier Sleeping,
177dd7cddfSDavid du Colombier };
187dd7cddfSDavid du Colombier
1974f16c81SDavid du Colombier static void* (*_rendezvousp)(void*, void*) = rendezvous;
207dd7cddfSDavid du Colombier
217dd7cddfSDavid du Colombier /* this gets called by the thread library ONLY to get us to use its rendezvous */
227dd7cddfSDavid du Colombier void
_qlockinit(void * (* r)(void *,void *))2374f16c81SDavid du Colombier _qlockinit(void* (*r)(void*, void*))
247dd7cddfSDavid du Colombier {
257dd7cddfSDavid du Colombier _rendezvousp = r;
267dd7cddfSDavid du Colombier }
277dd7cddfSDavid du Colombier
287dd7cddfSDavid du Colombier /* find a free shared memory location to queue ourselves in */
297dd7cddfSDavid du Colombier static QLp*
getqlp(void)307dd7cddfSDavid du Colombier getqlp(void)
317dd7cddfSDavid du Colombier {
327dd7cddfSDavid du Colombier QLp *p, *op;
337dd7cddfSDavid du Colombier
347dd7cddfSDavid du Colombier op = ql.p;
357dd7cddfSDavid du Colombier for(p = op+1; ; p++){
367dd7cddfSDavid du Colombier if(p == &ql.x[nelem(ql.x)])
377dd7cddfSDavid du Colombier p = ql.x;
387dd7cddfSDavid du Colombier if(p == op)
397dd7cddfSDavid du Colombier abort();
407dd7cddfSDavid du Colombier if(_tas(&(p->inuse)) == 0){
417dd7cddfSDavid du Colombier ql.p = p;
427dd7cddfSDavid du Colombier p->next = nil;
437dd7cddfSDavid du Colombier break;
447dd7cddfSDavid du Colombier }
457dd7cddfSDavid du Colombier }
467dd7cddfSDavid du Colombier return p;
477dd7cddfSDavid du Colombier }
487dd7cddfSDavid du Colombier
497dd7cddfSDavid du Colombier void
qlock(QLock * q)507dd7cddfSDavid du Colombier qlock(QLock *q)
517dd7cddfSDavid du Colombier {
527dd7cddfSDavid du Colombier QLp *p, *mp;
537dd7cddfSDavid du Colombier
547dd7cddfSDavid du Colombier lock(&q->lock);
557dd7cddfSDavid du Colombier if(!q->locked){
567dd7cddfSDavid du Colombier q->locked = 1;
577dd7cddfSDavid du Colombier unlock(&q->lock);
587dd7cddfSDavid du Colombier return;
597dd7cddfSDavid du Colombier }
607dd7cddfSDavid du Colombier
617dd7cddfSDavid du Colombier
627dd7cddfSDavid du Colombier /* chain into waiting list */
637dd7cddfSDavid du Colombier mp = getqlp();
647dd7cddfSDavid du Colombier p = q->tail;
657dd7cddfSDavid du Colombier if(p == nil)
667dd7cddfSDavid du Colombier q->head = mp;
677dd7cddfSDavid du Colombier else
687dd7cddfSDavid du Colombier p->next = mp;
697dd7cddfSDavid du Colombier q->tail = mp;
707dd7cddfSDavid du Colombier mp->state = Queuing;
717dd7cddfSDavid du Colombier unlock(&q->lock);
727dd7cddfSDavid du Colombier
737dd7cddfSDavid du Colombier /* wait */
7474f16c81SDavid du Colombier while((*_rendezvousp)(mp, (void*)1) == (void*)~0)
759a747e4fSDavid du Colombier ;
767dd7cddfSDavid du Colombier mp->inuse = 0;
777dd7cddfSDavid du Colombier }
787dd7cddfSDavid du Colombier
797dd7cddfSDavid du Colombier void
qunlock(QLock * q)807dd7cddfSDavid du Colombier qunlock(QLock *q)
817dd7cddfSDavid du Colombier {
827dd7cddfSDavid du Colombier QLp *p;
837dd7cddfSDavid du Colombier
847dd7cddfSDavid du Colombier lock(&q->lock);
85*14cc0f53SDavid du Colombier if (q->locked == 0)
86*14cc0f53SDavid du Colombier fprint(2, "qunlock called with qlock not held, from %#p\n",
87*14cc0f53SDavid du Colombier getcallerpc(&q));
887dd7cddfSDavid du Colombier p = q->head;
897dd7cddfSDavid du Colombier if(p != nil){
907dd7cddfSDavid du Colombier /* wakeup head waiting process */
917dd7cddfSDavid du Colombier q->head = p->next;
927dd7cddfSDavid du Colombier if(q->head == nil)
937dd7cddfSDavid du Colombier q->tail = nil;
947dd7cddfSDavid du Colombier unlock(&q->lock);
9574f16c81SDavid du Colombier while((*_rendezvousp)(p, (void*)0x12345) == (void*)~0)
969a747e4fSDavid du Colombier ;
977dd7cddfSDavid du Colombier return;
987dd7cddfSDavid du Colombier }
997dd7cddfSDavid du Colombier q->locked = 0;
1007dd7cddfSDavid du Colombier unlock(&q->lock);
1017dd7cddfSDavid du Colombier }
1027dd7cddfSDavid du Colombier
1037dd7cddfSDavid du Colombier int
canqlock(QLock * q)1047dd7cddfSDavid du Colombier canqlock(QLock *q)
1057dd7cddfSDavid du Colombier {
1066b6b9ac8SDavid du Colombier if(!canlock(&q->lock))
1076b6b9ac8SDavid du Colombier return 0;
1087dd7cddfSDavid du Colombier if(!q->locked){
1097dd7cddfSDavid du Colombier q->locked = 1;
1107dd7cddfSDavid du Colombier unlock(&q->lock);
1117dd7cddfSDavid du Colombier return 1;
1127dd7cddfSDavid du Colombier }
1137dd7cddfSDavid du Colombier unlock(&q->lock);
1147dd7cddfSDavid du Colombier return 0;
1157dd7cddfSDavid du Colombier }
1167dd7cddfSDavid du Colombier
1177dd7cddfSDavid du Colombier void
rlock(RWLock * q)1187dd7cddfSDavid du Colombier rlock(RWLock *q)
1197dd7cddfSDavid du Colombier {
1207dd7cddfSDavid du Colombier QLp *p, *mp;
1217dd7cddfSDavid du Colombier
1227dd7cddfSDavid du Colombier lock(&q->lock);
1237dd7cddfSDavid du Colombier if(q->writer == 0 && q->head == nil){
1247dd7cddfSDavid du Colombier /* no writer, go for it */
1257dd7cddfSDavid du Colombier q->readers++;
1267dd7cddfSDavid du Colombier unlock(&q->lock);
1277dd7cddfSDavid du Colombier return;
1287dd7cddfSDavid du Colombier }
1297dd7cddfSDavid du Colombier
1307dd7cddfSDavid du Colombier mp = getqlp();
1317dd7cddfSDavid du Colombier p = q->tail;
1327dd7cddfSDavid du Colombier if(p == 0)
1337dd7cddfSDavid du Colombier q->head = mp;
1347dd7cddfSDavid du Colombier else
1357dd7cddfSDavid du Colombier p->next = mp;
1367dd7cddfSDavid du Colombier q->tail = mp;
1377dd7cddfSDavid du Colombier mp->next = nil;
1387dd7cddfSDavid du Colombier mp->state = QueuingR;
1397dd7cddfSDavid du Colombier unlock(&q->lock);
1407dd7cddfSDavid du Colombier
1417dd7cddfSDavid du Colombier /* wait in kernel */
14274f16c81SDavid du Colombier while((*_rendezvousp)(mp, (void*)1) == (void*)~0)
1439a747e4fSDavid du Colombier ;
1447dd7cddfSDavid du Colombier mp->inuse = 0;
1457dd7cddfSDavid du Colombier }
1467dd7cddfSDavid du Colombier
1479a747e4fSDavid du Colombier int
canrlock(RWLock * q)1489a747e4fSDavid du Colombier canrlock(RWLock *q)
1499a747e4fSDavid du Colombier {
1509a747e4fSDavid du Colombier lock(&q->lock);
1519a747e4fSDavid du Colombier if (q->writer == 0 && q->head == nil) {
1529a747e4fSDavid du Colombier /* no writer; go for it */
1539a747e4fSDavid du Colombier q->readers++;
1549a747e4fSDavid du Colombier unlock(&q->lock);
1559a747e4fSDavid du Colombier return 1;
1569a747e4fSDavid du Colombier }
1579a747e4fSDavid du Colombier unlock(&q->lock);
1589a747e4fSDavid du Colombier return 0;
1599a747e4fSDavid du Colombier }
1609a747e4fSDavid du Colombier
1617dd7cddfSDavid du Colombier void
runlock(RWLock * q)1627dd7cddfSDavid du Colombier runlock(RWLock *q)
1637dd7cddfSDavid du Colombier {
1647dd7cddfSDavid du Colombier QLp *p;
1657dd7cddfSDavid du Colombier
1667dd7cddfSDavid du Colombier lock(&q->lock);
1679a747e4fSDavid du Colombier if(q->readers <= 0)
1689a747e4fSDavid du Colombier abort();
1697dd7cddfSDavid du Colombier p = q->head;
1707dd7cddfSDavid du Colombier if(--(q->readers) > 0 || p == nil){
1717dd7cddfSDavid du Colombier unlock(&q->lock);
1727dd7cddfSDavid du Colombier return;
1737dd7cddfSDavid du Colombier }
1747dd7cddfSDavid du Colombier
1757dd7cddfSDavid du Colombier /* start waiting writer */
1767dd7cddfSDavid du Colombier if(p->state != QueuingW)
1777dd7cddfSDavid du Colombier abort();
1787dd7cddfSDavid du Colombier q->head = p->next;
1797dd7cddfSDavid du Colombier if(q->head == 0)
1807dd7cddfSDavid du Colombier q->tail = 0;
1817dd7cddfSDavid du Colombier q->writer = 1;
1827dd7cddfSDavid du Colombier unlock(&q->lock);
1837dd7cddfSDavid du Colombier
1847dd7cddfSDavid du Colombier /* wakeup waiter */
18574f16c81SDavid du Colombier while((*_rendezvousp)(p, 0) == (void*)~0)
1869a747e4fSDavid du Colombier ;
1877dd7cddfSDavid du Colombier }
1887dd7cddfSDavid du Colombier
1897dd7cddfSDavid du Colombier void
wlock(RWLock * q)1907dd7cddfSDavid du Colombier wlock(RWLock *q)
1917dd7cddfSDavid du Colombier {
1927dd7cddfSDavid du Colombier QLp *p, *mp;
1937dd7cddfSDavid du Colombier
1947dd7cddfSDavid du Colombier lock(&q->lock);
1957dd7cddfSDavid du Colombier if(q->readers == 0 && q->writer == 0){
1967dd7cddfSDavid du Colombier /* noone waiting, go for it */
1977dd7cddfSDavid du Colombier q->writer = 1;
1987dd7cddfSDavid du Colombier unlock(&q->lock);
1997dd7cddfSDavid du Colombier return;
2007dd7cddfSDavid du Colombier }
2017dd7cddfSDavid du Colombier
2027dd7cddfSDavid du Colombier /* wait */
2037dd7cddfSDavid du Colombier p = q->tail;
2047dd7cddfSDavid du Colombier mp = getqlp();
2057dd7cddfSDavid du Colombier if(p == nil)
2067dd7cddfSDavid du Colombier q->head = mp;
2077dd7cddfSDavid du Colombier else
2087dd7cddfSDavid du Colombier p->next = mp;
2097dd7cddfSDavid du Colombier q->tail = mp;
2107dd7cddfSDavid du Colombier mp->next = nil;
2117dd7cddfSDavid du Colombier mp->state = QueuingW;
2127dd7cddfSDavid du Colombier unlock(&q->lock);
2137dd7cddfSDavid du Colombier
2147dd7cddfSDavid du Colombier /* wait in kernel */
21574f16c81SDavid du Colombier while((*_rendezvousp)(mp, (void*)1) == (void*)~0)
2169a747e4fSDavid du Colombier ;
2177dd7cddfSDavid du Colombier mp->inuse = 0;
2187dd7cddfSDavid du Colombier }
2197dd7cddfSDavid du Colombier
2209a747e4fSDavid du Colombier int
canwlock(RWLock * q)2219a747e4fSDavid du Colombier canwlock(RWLock *q)
2229a747e4fSDavid du Colombier {
2239a747e4fSDavid du Colombier lock(&q->lock);
2249a747e4fSDavid du Colombier if (q->readers == 0 && q->writer == 0) {
2259a747e4fSDavid du Colombier /* no one waiting; go for it */
2269a747e4fSDavid du Colombier q->writer = 1;
2279a747e4fSDavid du Colombier unlock(&q->lock);
2289a747e4fSDavid du Colombier return 1;
2299a747e4fSDavid du Colombier }
2309a747e4fSDavid du Colombier unlock(&q->lock);
2319a747e4fSDavid du Colombier return 0;
2329a747e4fSDavid du Colombier }
2339a747e4fSDavid du Colombier
2347dd7cddfSDavid du Colombier void
wunlock(RWLock * q)2357dd7cddfSDavid du Colombier wunlock(RWLock *q)
2367dd7cddfSDavid du Colombier {
2377dd7cddfSDavid du Colombier QLp *p;
2387dd7cddfSDavid du Colombier
2397dd7cddfSDavid du Colombier lock(&q->lock);
2409a747e4fSDavid du Colombier if(q->writer == 0)
2419a747e4fSDavid du Colombier abort();
2427dd7cddfSDavid du Colombier p = q->head;
2437dd7cddfSDavid du Colombier if(p == nil){
2447dd7cddfSDavid du Colombier q->writer = 0;
2457dd7cddfSDavid du Colombier unlock(&q->lock);
2467dd7cddfSDavid du Colombier return;
2477dd7cddfSDavid du Colombier }
2487dd7cddfSDavid du Colombier if(p->state == QueuingW){
2497dd7cddfSDavid du Colombier /* start waiting writer */
2507dd7cddfSDavid du Colombier q->head = p->next;
2517dd7cddfSDavid du Colombier if(q->head == nil)
2527dd7cddfSDavid du Colombier q->tail = nil;
2537dd7cddfSDavid du Colombier unlock(&q->lock);
25474f16c81SDavid du Colombier while((*_rendezvousp)(p, 0) == (void*)~0)
2559a747e4fSDavid du Colombier ;
2567dd7cddfSDavid du Colombier return;
2577dd7cddfSDavid du Colombier }
2587dd7cddfSDavid du Colombier
2597dd7cddfSDavid du Colombier if(p->state != QueuingR)
2607dd7cddfSDavid du Colombier abort();
2617dd7cddfSDavid du Colombier
2629a747e4fSDavid du Colombier /* wake waiting readers */
2637dd7cddfSDavid du Colombier while(q->head != nil && q->head->state == QueuingR){
2647dd7cddfSDavid du Colombier p = q->head;
2657dd7cddfSDavid du Colombier q->head = p->next;
2667dd7cddfSDavid du Colombier q->readers++;
26774f16c81SDavid du Colombier while((*_rendezvousp)(p, 0) == (void*)~0)
2689a747e4fSDavid du Colombier ;
2697dd7cddfSDavid du Colombier }
2707dd7cddfSDavid du Colombier if(q->head == nil)
2717dd7cddfSDavid du Colombier q->tail = nil;
2727dd7cddfSDavid du Colombier q->writer = 0;
2737dd7cddfSDavid du Colombier unlock(&q->lock);
2747dd7cddfSDavid du Colombier }
275679c15e8SDavid du Colombier
276679c15e8SDavid du Colombier void
rsleep(Rendez * r)277679c15e8SDavid du Colombier rsleep(Rendez *r)
278679c15e8SDavid du Colombier {
279679c15e8SDavid du Colombier QLp *t, *me;
280679c15e8SDavid du Colombier
281679c15e8SDavid du Colombier if(!r->l)
282679c15e8SDavid du Colombier abort();
283679c15e8SDavid du Colombier lock(&r->l->lock);
284679c15e8SDavid du Colombier /* we should hold the qlock */
285679c15e8SDavid du Colombier if(!r->l->locked)
286679c15e8SDavid du Colombier abort();
287679c15e8SDavid du Colombier
288679c15e8SDavid du Colombier /* add ourselves to the wait list */
289679c15e8SDavid du Colombier me = getqlp();
290679c15e8SDavid du Colombier me->state = Sleeping;
291679c15e8SDavid du Colombier if(r->head == nil)
292679c15e8SDavid du Colombier r->head = me;
293679c15e8SDavid du Colombier else
294679c15e8SDavid du Colombier r->tail->next = me;
295679c15e8SDavid du Colombier me->next = nil;
296679c15e8SDavid du Colombier r->tail = me;
297679c15e8SDavid du Colombier
298679c15e8SDavid du Colombier /* pass the qlock to the next guy */
299679c15e8SDavid du Colombier t = r->l->head;
300679c15e8SDavid du Colombier if(t){
301679c15e8SDavid du Colombier r->l->head = t->next;
302679c15e8SDavid du Colombier if(r->l->head == nil)
303679c15e8SDavid du Colombier r->l->tail = nil;
304679c15e8SDavid du Colombier unlock(&r->l->lock);
30574f16c81SDavid du Colombier while((*_rendezvousp)(t, (void*)0x12345) == (void*)~0)
306679c15e8SDavid du Colombier ;
307679c15e8SDavid du Colombier }else{
308679c15e8SDavid du Colombier r->l->locked = 0;
309679c15e8SDavid du Colombier unlock(&r->l->lock);
310679c15e8SDavid du Colombier }
311679c15e8SDavid du Colombier
312679c15e8SDavid du Colombier /* wait for a wakeup */
31374f16c81SDavid du Colombier while((*_rendezvousp)(me, (void*)1) == (void*)~0)
314679c15e8SDavid du Colombier ;
315679c15e8SDavid du Colombier me->inuse = 0;
316679c15e8SDavid du Colombier }
317679c15e8SDavid du Colombier
318679c15e8SDavid du Colombier int
rwakeup(Rendez * r)319679c15e8SDavid du Colombier rwakeup(Rendez *r)
320679c15e8SDavid du Colombier {
321679c15e8SDavid du Colombier QLp *t;
322679c15e8SDavid du Colombier
323679c15e8SDavid du Colombier /*
324679c15e8SDavid du Colombier * take off wait and put on front of queue
325679c15e8SDavid du Colombier * put on front so guys that have been waiting will not get starved
326679c15e8SDavid du Colombier */
327679c15e8SDavid du Colombier
328679c15e8SDavid du Colombier if(!r->l)
329679c15e8SDavid du Colombier abort();
330679c15e8SDavid du Colombier lock(&r->l->lock);
331679c15e8SDavid du Colombier if(!r->l->locked)
332679c15e8SDavid du Colombier abort();
333679c15e8SDavid du Colombier
334679c15e8SDavid du Colombier t = r->head;
335679c15e8SDavid du Colombier if(t == nil){
336679c15e8SDavid du Colombier unlock(&r->l->lock);
337679c15e8SDavid du Colombier return 0;
338679c15e8SDavid du Colombier }
339679c15e8SDavid du Colombier
340679c15e8SDavid du Colombier r->head = t->next;
341679c15e8SDavid du Colombier if(r->head == nil)
342679c15e8SDavid du Colombier r->tail = nil;
343679c15e8SDavid du Colombier
344679c15e8SDavid du Colombier t->next = r->l->head;
345679c15e8SDavid du Colombier r->l->head = t;
346679c15e8SDavid du Colombier if(r->l->tail == nil)
347679c15e8SDavid du Colombier r->l->tail = t;
348679c15e8SDavid du Colombier
349679c15e8SDavid du Colombier t->state = Queuing;
350679c15e8SDavid du Colombier unlock(&r->l->lock);
351679c15e8SDavid du Colombier return 1;
352679c15e8SDavid du Colombier }
353679c15e8SDavid du Colombier
354679c15e8SDavid du Colombier int
rwakeupall(Rendez * r)355679c15e8SDavid du Colombier rwakeupall(Rendez *r)
356679c15e8SDavid du Colombier {
357679c15e8SDavid du Colombier int i;
358679c15e8SDavid du Colombier
359679c15e8SDavid du Colombier for(i=0; rwakeup(r); i++)
360679c15e8SDavid du Colombier ;
361679c15e8SDavid du Colombier return i;
362679c15e8SDavid du Colombier }
363679c15e8SDavid du Colombier
364