xref: /plan9-contrib/sys/src/9/port/qlock.c (revision 6bbfed0d85c6d7248503ef0614d0f1e40438b735)
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