13e12c5d1SDavid du Colombier #include "u.h"
23e12c5d1SDavid du Colombier #include "../port/lib.h"
33e12c5d1SDavid du Colombier #include "mem.h"
43e12c5d1SDavid du Colombier #include "dat.h"
53e12c5d1SDavid du Colombier #include "fns.h"
63e12c5d1SDavid du Colombier
77dd7cddfSDavid du Colombier struct {
87dd7cddfSDavid du Colombier ulong rlock;
97dd7cddfSDavid du Colombier ulong rlockq;
107dd7cddfSDavid du Colombier ulong wlock;
117dd7cddfSDavid du Colombier ulong wlockq;
127dd7cddfSDavid du Colombier ulong qlock;
137dd7cddfSDavid du Colombier ulong qlockq;
147dd7cddfSDavid du Colombier } rwstats;
153e12c5d1SDavid du Colombier
163e12c5d1SDavid du Colombier void
qlock(QLock * q)173e12c5d1SDavid du Colombier qlock(QLock *q)
183e12c5d1SDavid du Colombier {
193ff48bf5SDavid du Colombier Proc *p;
203ff48bf5SDavid du Colombier
213ff48bf5SDavid du Colombier if(m->ilockdepth != 0)
22567483c8SDavid du Colombier print("qlock: %#p: ilockdepth %d\n", getcallerpc(&q), m->ilockdepth);
23e288d156SDavid du Colombier if(up != nil && up->nlocks.ref)
24567483c8SDavid du Colombier print("qlock: %#p: nlocks %lud\n", getcallerpc(&q), up->nlocks.ref);
253e12c5d1SDavid du Colombier
26dc5a79c1SDavid du Colombier if(q->use.key == 0x55555555)
27567483c8SDavid du Colombier panic("qlock: q %#p, key 5*\n", q);
283e12c5d1SDavid du Colombier lock(&q->use);
297dd7cddfSDavid du Colombier rwstats.qlock++;
303e12c5d1SDavid du Colombier if(!q->locked) {
313e12c5d1SDavid du Colombier q->locked = 1;
32*6bbfed0dSDavid du Colombier q->qpc = getcallerpc(&q);
333e12c5d1SDavid du Colombier unlock(&q->use);
343e12c5d1SDavid du Colombier return;
353e12c5d1SDavid du Colombier }
363ff48bf5SDavid du Colombier if(up == 0)
373ff48bf5SDavid du Colombier panic("qlock");
387dd7cddfSDavid du Colombier rwstats.qlockq++;
393e12c5d1SDavid du Colombier p = q->tail;
403e12c5d1SDavid du Colombier if(p == 0)
413ff48bf5SDavid du Colombier q->head = up;
423e12c5d1SDavid du Colombier else
433ff48bf5SDavid du Colombier p->qnext = up;
443ff48bf5SDavid du Colombier q->tail = up;
453ff48bf5SDavid du Colombier up->qnext = 0;
463ff48bf5SDavid du Colombier up->state = Queueing;
477dd7cddfSDavid du Colombier up->qpc = getcallerpc(&q);
4839734e7eSDavid du Colombier unlock(&q->use);
493e12c5d1SDavid du Colombier sched();
50*6bbfed0dSDavid du Colombier q->qpc = getcallerpc(&q);
513e12c5d1SDavid du Colombier }
523e12c5d1SDavid du Colombier
533e12c5d1SDavid du Colombier int
canqlock(QLock * q)543e12c5d1SDavid du Colombier canqlock(QLock *q)
553e12c5d1SDavid du Colombier {
56219b2ee8SDavid du Colombier if(!canlock(&q->use))
57219b2ee8SDavid du Colombier return 0;
583e12c5d1SDavid du Colombier if(q->locked){
593e12c5d1SDavid du Colombier unlock(&q->use);
603e12c5d1SDavid du Colombier return 0;
613e12c5d1SDavid du Colombier }
623e12c5d1SDavid du Colombier q->locked = 1;
63*6bbfed0dSDavid du Colombier q->qpc = getcallerpc(&q);
643e12c5d1SDavid du Colombier unlock(&q->use);
653e12c5d1SDavid du Colombier return 1;
663e12c5d1SDavid du Colombier }
673e12c5d1SDavid du Colombier
683e12c5d1SDavid du Colombier void
qunlock(QLock * q)693e12c5d1SDavid du Colombier qunlock(QLock *q)
703e12c5d1SDavid du Colombier {
713e12c5d1SDavid du Colombier Proc *p;
723e12c5d1SDavid du Colombier
733e12c5d1SDavid du Colombier lock(&q->use);
74ccaac148SDavid du Colombier if (q->locked == 0)
75ccaac148SDavid du Colombier print("qunlock called with qlock not held, from %#p\n",
76ccaac148SDavid du Colombier getcallerpc(&q));
773e12c5d1SDavid du Colombier p = q->head;
783e12c5d1SDavid du Colombier if(p){
793e12c5d1SDavid du Colombier q->head = p->qnext;
803e12c5d1SDavid du Colombier if(q->head == 0)
813e12c5d1SDavid du Colombier q->tail = 0;
823e12c5d1SDavid du Colombier unlock(&q->use);
833e12c5d1SDavid du Colombier ready(p);
843e12c5d1SDavid du Colombier return;
853e12c5d1SDavid du Colombier }
863e12c5d1SDavid du Colombier q->locked = 0;
87*6bbfed0dSDavid du Colombier q->qpc = 0;
883e12c5d1SDavid du Colombier unlock(&q->use);
893e12c5d1SDavid du Colombier }
903e12c5d1SDavid du Colombier
913e12c5d1SDavid du Colombier void
rlock(RWlock * q)927dd7cddfSDavid du Colombier rlock(RWlock *q)
933e12c5d1SDavid du Colombier {
943ff48bf5SDavid du Colombier Proc *p;
957dd7cddfSDavid du Colombier
967dd7cddfSDavid du Colombier lock(&q->use);
977dd7cddfSDavid du Colombier rwstats.rlock++;
987dd7cddfSDavid du Colombier if(q->writer == 0 && q->head == nil){
997dd7cddfSDavid du Colombier /* no writer, go for it */
1007dd7cddfSDavid du Colombier q->readers++;
1017dd7cddfSDavid du Colombier unlock(&q->use);
1027dd7cddfSDavid du Colombier return;
1037dd7cddfSDavid du Colombier }
1047dd7cddfSDavid du Colombier
1057dd7cddfSDavid du Colombier rwstats.rlockq++;
1067dd7cddfSDavid du Colombier p = q->tail;
1073ff48bf5SDavid du Colombier if(up == nil)
1087dd7cddfSDavid du Colombier panic("rlock");
1097dd7cddfSDavid du Colombier if(p == 0)
1103ff48bf5SDavid du Colombier q->head = up;
1117dd7cddfSDavid du Colombier else
1123ff48bf5SDavid du Colombier p->qnext = up;
1133ff48bf5SDavid du Colombier q->tail = up;
1143ff48bf5SDavid du Colombier up->qnext = 0;
1153ff48bf5SDavid du Colombier up->state = QueueingR;
11639734e7eSDavid du Colombier unlock(&q->use);
1177dd7cddfSDavid du Colombier sched();
1183e12c5d1SDavid du Colombier }
1193e12c5d1SDavid du Colombier
1203e12c5d1SDavid du Colombier void
runlock(RWlock * q)1217dd7cddfSDavid du Colombier runlock(RWlock *q)
1223e12c5d1SDavid du Colombier {
1237dd7cddfSDavid du Colombier Proc *p;
1247dd7cddfSDavid du Colombier
1257dd7cddfSDavid du Colombier lock(&q->use);
1267dd7cddfSDavid du Colombier p = q->head;
1277dd7cddfSDavid du Colombier if(--(q->readers) > 0 || p == nil){
1287dd7cddfSDavid du Colombier unlock(&q->use);
1297dd7cddfSDavid du Colombier return;
1307dd7cddfSDavid du Colombier }
1317dd7cddfSDavid du Colombier
1327dd7cddfSDavid du Colombier /* start waiting writer */
1337dd7cddfSDavid du Colombier if(p->state != QueueingW)
1347dd7cddfSDavid du Colombier panic("runlock");
1357dd7cddfSDavid du Colombier q->head = p->qnext;
1367dd7cddfSDavid du Colombier if(q->head == 0)
1377dd7cddfSDavid du Colombier q->tail = 0;
1387dd7cddfSDavid du Colombier q->writer = 1;
1397dd7cddfSDavid du Colombier unlock(&q->use);
1407dd7cddfSDavid du Colombier ready(p);
1413e12c5d1SDavid du Colombier }
1423e12c5d1SDavid du Colombier
1433e12c5d1SDavid du Colombier void
wlock(RWlock * q)1447dd7cddfSDavid du Colombier wlock(RWlock *q)
1453e12c5d1SDavid du Colombier {
1463ff48bf5SDavid du Colombier Proc *p;
1477dd7cddfSDavid du Colombier
1487dd7cddfSDavid du Colombier lock(&q->use);
1497dd7cddfSDavid du Colombier rwstats.wlock++;
1507dd7cddfSDavid du Colombier if(q->readers == 0 && q->writer == 0){
1517dd7cddfSDavid du Colombier /* noone waiting, go for it */
1527dd7cddfSDavid du Colombier q->wpc = getcallerpc(&q);
1537dd7cddfSDavid du Colombier q->wproc = up;
1547dd7cddfSDavid du Colombier q->writer = 1;
1557dd7cddfSDavid du Colombier unlock(&q->use);
1567dd7cddfSDavid du Colombier return;
1577dd7cddfSDavid du Colombier }
1587dd7cddfSDavid du Colombier
1597dd7cddfSDavid du Colombier /* wait */
1607dd7cddfSDavid du Colombier rwstats.wlockq++;
1617dd7cddfSDavid du Colombier p = q->tail;
1623ff48bf5SDavid du Colombier if(up == nil)
1637dd7cddfSDavid du Colombier panic("wlock");
1647dd7cddfSDavid du Colombier if(p == nil)
1653ff48bf5SDavid du Colombier q->head = up;
1667dd7cddfSDavid du Colombier else
1673ff48bf5SDavid du Colombier p->qnext = up;
1683ff48bf5SDavid du Colombier q->tail = up;
1693ff48bf5SDavid du Colombier up->qnext = 0;
1703ff48bf5SDavid du Colombier up->state = QueueingW;
17139734e7eSDavid du Colombier unlock(&q->use);
1727dd7cddfSDavid du Colombier sched();
1733e12c5d1SDavid du Colombier }
1743e12c5d1SDavid du Colombier
1753e12c5d1SDavid du Colombier void
wunlock(RWlock * q)1767dd7cddfSDavid du Colombier wunlock(RWlock *q)
1773e12c5d1SDavid du Colombier {
1787dd7cddfSDavid du Colombier Proc *p;
1797dd7cddfSDavid du Colombier
1807dd7cddfSDavid du Colombier lock(&q->use);
1817dd7cddfSDavid du Colombier p = q->head;
1827dd7cddfSDavid du Colombier if(p == nil){
1837dd7cddfSDavid du Colombier q->writer = 0;
1847dd7cddfSDavid du Colombier unlock(&q->use);
1857dd7cddfSDavid du Colombier return;
1867dd7cddfSDavid du Colombier }
1877dd7cddfSDavid du Colombier if(p->state == QueueingW){
1887dd7cddfSDavid du Colombier /* start waiting writer */
1897dd7cddfSDavid du Colombier q->head = p->qnext;
1907dd7cddfSDavid du Colombier if(q->head == nil)
1917dd7cddfSDavid du Colombier q->tail = nil;
1927dd7cddfSDavid du Colombier unlock(&q->use);
1937dd7cddfSDavid du Colombier ready(p);
1947dd7cddfSDavid du Colombier return;
1957dd7cddfSDavid du Colombier }
1967dd7cddfSDavid du Colombier
1977dd7cddfSDavid du Colombier if(p->state != QueueingR)
1987dd7cddfSDavid du Colombier panic("wunlock");
1997dd7cddfSDavid du Colombier
2007dd7cddfSDavid du Colombier /* waken waiting readers */
2017dd7cddfSDavid du Colombier while(q->head != nil && q->head->state == QueueingR){
2027dd7cddfSDavid du Colombier p = q->head;
2037dd7cddfSDavid du Colombier q->head = p->qnext;
2047dd7cddfSDavid du Colombier q->readers++;
2057dd7cddfSDavid du Colombier ready(p);
2067dd7cddfSDavid du Colombier }
2077dd7cddfSDavid du Colombier if(q->head == nil)
2087dd7cddfSDavid du Colombier q->tail = nil;
2097dd7cddfSDavid du Colombier q->writer = 0;
2107dd7cddfSDavid du Colombier unlock(&q->use);
2117dd7cddfSDavid du Colombier }
2127dd7cddfSDavid du Colombier
2139a747e4fSDavid du Colombier /* same as rlock but punts if there are any writers waiting */
2147dd7cddfSDavid du Colombier int
canrlock(RWlock * q)2157dd7cddfSDavid du Colombier canrlock(RWlock *q)
2167dd7cddfSDavid du Colombier {
2177dd7cddfSDavid du Colombier lock(&q->use);
2187dd7cddfSDavid du Colombier rwstats.rlock++;
2197dd7cddfSDavid du Colombier if(q->writer == 0 && q->head == nil){
2207dd7cddfSDavid du Colombier /* no writer, go for it */
2217dd7cddfSDavid du Colombier q->readers++;
2227dd7cddfSDavid du Colombier unlock(&q->use);
2237dd7cddfSDavid du Colombier return 1;
2247dd7cddfSDavid du Colombier }
2257dd7cddfSDavid du Colombier unlock(&q->use);
2267dd7cddfSDavid du Colombier return 0;
2273e12c5d1SDavid du Colombier }
228