xref: /plan9-contrib/sys/src/9k/port/qlock.c (revision d46407a37b53d968b453d19c0e464c526df5e227)
19ef1f84bSDavid du Colombier #include "u.h"
29ef1f84bSDavid du Colombier #include "../port/lib.h"
39ef1f84bSDavid du Colombier #include "mem.h"
49ef1f84bSDavid du Colombier #include "dat.h"
59ef1f84bSDavid du Colombier #include "fns.h"
69ef1f84bSDavid du Colombier 
7*d46407a3SDavid du Colombier #include <ptrace.h>
8*d46407a3SDavid du Colombier 
99ef1f84bSDavid du Colombier struct {
109ef1f84bSDavid du Colombier 	ulong rlock;
119ef1f84bSDavid du Colombier 	ulong rlockq;
129ef1f84bSDavid du Colombier 	ulong wlock;
139ef1f84bSDavid du Colombier 	ulong wlockq;
149ef1f84bSDavid du Colombier 	ulong qlock;
159ef1f84bSDavid du Colombier 	ulong qlockq;
169ef1f84bSDavid du Colombier } rwstats;
179ef1f84bSDavid du Colombier 
189ef1f84bSDavid du Colombier void
qlock(QLock * q)199ef1f84bSDavid du Colombier qlock(QLock *q)
209ef1f84bSDavid du Colombier {
219ef1f84bSDavid du Colombier 	Proc *p;
22*d46407a3SDavid du Colombier 	void (*pt)(Proc*, int, vlong, vlong);
239ef1f84bSDavid du Colombier 
249ef1f84bSDavid du Colombier 	if(m->ilockdepth != 0)
259ef1f84bSDavid du Colombier 		print("qlock: %#p: ilockdepth %d\n", getcallerpc(&q), m->ilockdepth);
269ef1f84bSDavid du Colombier 	if(up != nil && up->nlocks)
279ef1f84bSDavid du Colombier 		print("qlock: %#p: nlocks %d\n", getcallerpc(&q), up->nlocks);
289ef1f84bSDavid du Colombier 
299ef1f84bSDavid du Colombier 	lock(&q->use);
309ef1f84bSDavid du Colombier 	rwstats.qlock++;
319ef1f84bSDavid du Colombier 	if(!q->locked) {
329ef1f84bSDavid du Colombier 		q->locked = 1;
33406c76faSDavid du Colombier 		q->qpc = getcallerpc(&q);
349ef1f84bSDavid du Colombier 		unlock(&q->use);
359ef1f84bSDavid du Colombier 		return;
369ef1f84bSDavid du Colombier 	}
379ef1f84bSDavid du Colombier 	if(up == nil)
389ef1f84bSDavid du Colombier 		panic("qlock");
399ef1f84bSDavid du Colombier 	rwstats.qlockq++;
409ef1f84bSDavid du Colombier 	p = q->tail;
419ef1f84bSDavid du Colombier 	if(p == 0)
429ef1f84bSDavid du Colombier 		q->head = up;
439ef1f84bSDavid du Colombier 	else
449ef1f84bSDavid du Colombier 		p->qnext = up;
459ef1f84bSDavid du Colombier 	q->tail = up;
469ef1f84bSDavid du Colombier 	up->qnext = 0;
479ef1f84bSDavid du Colombier 	up->state = Queueing;
489ef1f84bSDavid du Colombier 	up->qpc = getcallerpc(&q);
49*d46407a3SDavid du Colombier 	if(up->trace && (pt = proctrace) != nil)
50*d46407a3SDavid du Colombier 		pt(up, SSleep, 0, Queueing | (up->qpc<<8));
519ef1f84bSDavid du Colombier 	unlock(&q->use);
529ef1f84bSDavid du Colombier 	sched();
53406c76faSDavid du Colombier 	q->qpc = getcallerpc(&q);
549ef1f84bSDavid du Colombier }
559ef1f84bSDavid du Colombier 
569ef1f84bSDavid du Colombier int
canqlock(QLock * q)579ef1f84bSDavid du Colombier canqlock(QLock *q)
589ef1f84bSDavid du Colombier {
599ef1f84bSDavid du Colombier 	if(!canlock(&q->use))
609ef1f84bSDavid du Colombier 		return 0;
619ef1f84bSDavid du Colombier 	if(q->locked){
629ef1f84bSDavid du Colombier 		unlock(&q->use);
639ef1f84bSDavid du Colombier 		return 0;
649ef1f84bSDavid du Colombier 	}
659ef1f84bSDavid du Colombier 	q->locked = 1;
66406c76faSDavid du Colombier 	q->qpc = getcallerpc(&q);
679ef1f84bSDavid du Colombier 	unlock(&q->use);
689ef1f84bSDavid du Colombier 
699ef1f84bSDavid du Colombier 	return 1;
709ef1f84bSDavid du Colombier }
719ef1f84bSDavid du Colombier 
729ef1f84bSDavid du Colombier void
qunlock(QLock * q)739ef1f84bSDavid du Colombier qunlock(QLock *q)
749ef1f84bSDavid du Colombier {
759ef1f84bSDavid du Colombier 	Proc *p;
769ef1f84bSDavid du Colombier 
779ef1f84bSDavid du Colombier 	lock(&q->use);
789ef1f84bSDavid du Colombier 	if (q->locked == 0)
799ef1f84bSDavid du Colombier 		print("qunlock called with qlock not held, from %#p\n",
809ef1f84bSDavid du Colombier 			getcallerpc(&q));
819ef1f84bSDavid du Colombier 	p = q->head;
829ef1f84bSDavid du Colombier 	if(p){
839ef1f84bSDavid du Colombier 		q->head = p->qnext;
849ef1f84bSDavid du Colombier 		if(q->head == 0)
859ef1f84bSDavid du Colombier 			q->tail = 0;
869ef1f84bSDavid du Colombier 		unlock(&q->use);
879ef1f84bSDavid du Colombier 		ready(p);
889ef1f84bSDavid du Colombier 		return;
899ef1f84bSDavid du Colombier 	}
909ef1f84bSDavid du Colombier 	q->locked = 0;
91406c76faSDavid du Colombier 	q->qpc = 0;
929ef1f84bSDavid du Colombier 	unlock(&q->use);
939ef1f84bSDavid du Colombier }
949ef1f84bSDavid du Colombier 
959ef1f84bSDavid du Colombier void
rlock(RWlock * q)969ef1f84bSDavid du Colombier rlock(RWlock *q)
979ef1f84bSDavid du Colombier {
989ef1f84bSDavid du Colombier 	Proc *p;
99*d46407a3SDavid du Colombier 	void (*pt)(Proc*, int, vlong, vlong);
100*d46407a3SDavid du Colombier 	uintptr pc;
1019ef1f84bSDavid du Colombier 
1029ef1f84bSDavid du Colombier 	lock(&q->use);
1039ef1f84bSDavid du Colombier 	rwstats.rlock++;
1049ef1f84bSDavid du Colombier 	if(q->writer == 0 && q->head == nil){
1059ef1f84bSDavid du Colombier 		/* no writer, go for it */
1069ef1f84bSDavid du Colombier 		q->readers++;
1079ef1f84bSDavid du Colombier 		unlock(&q->use);
1089ef1f84bSDavid du Colombier 		return;
1099ef1f84bSDavid du Colombier 	}
1109ef1f84bSDavid du Colombier 
1119ef1f84bSDavid du Colombier 	rwstats.rlockq++;
1129ef1f84bSDavid du Colombier 	p = q->tail;
1139ef1f84bSDavid du Colombier 	if(up == nil)
1149ef1f84bSDavid du Colombier 		panic("rlock");
1159ef1f84bSDavid du Colombier 	if(p == 0)
1169ef1f84bSDavid du Colombier 		q->head = up;
1179ef1f84bSDavid du Colombier 	else
1189ef1f84bSDavid du Colombier 		p->qnext = up;
1199ef1f84bSDavid du Colombier 	q->tail = up;
1209ef1f84bSDavid du Colombier 	up->qnext = 0;
1219ef1f84bSDavid du Colombier 	up->state = QueueingR;
122*d46407a3SDavid du Colombier 	if(up->trace && (pt = proctrace) != nil){
123*d46407a3SDavid du Colombier 		pc = getcallerpc(&q);
124*d46407a3SDavid du Colombier 		pt(up, SSleep, 0, QueueingR | (pc<<8));
125*d46407a3SDavid du Colombier 	}
1269ef1f84bSDavid du Colombier 	unlock(&q->use);
1279ef1f84bSDavid du Colombier 	sched();
1289ef1f84bSDavid du Colombier }
1299ef1f84bSDavid du Colombier 
1309ef1f84bSDavid du Colombier void
runlock(RWlock * q)1319ef1f84bSDavid du Colombier runlock(RWlock *q)
1329ef1f84bSDavid du Colombier {
1339ef1f84bSDavid du Colombier 	Proc *p;
1349ef1f84bSDavid du Colombier 
1359ef1f84bSDavid du Colombier 	lock(&q->use);
1369ef1f84bSDavid du Colombier 	p = q->head;
1379ef1f84bSDavid du Colombier 	if(--(q->readers) > 0 || p == nil){
1389ef1f84bSDavid du Colombier 		unlock(&q->use);
1399ef1f84bSDavid du Colombier 		return;
1409ef1f84bSDavid du Colombier 	}
1419ef1f84bSDavid du Colombier 
1429ef1f84bSDavid du Colombier 	/* start waiting writer */
1439ef1f84bSDavid du Colombier 	if(p->state != QueueingW)
1449ef1f84bSDavid du Colombier 		panic("runlock");
1459ef1f84bSDavid du Colombier 	q->head = p->qnext;
1469ef1f84bSDavid du Colombier 	if(q->head == 0)
1479ef1f84bSDavid du Colombier 		q->tail = 0;
1489ef1f84bSDavid du Colombier 	q->writer = 1;
1499ef1f84bSDavid du Colombier 	unlock(&q->use);
1509ef1f84bSDavid du Colombier 	ready(p);
1519ef1f84bSDavid du Colombier }
1529ef1f84bSDavid du Colombier 
1539ef1f84bSDavid du Colombier void
wlock(RWlock * q)1549ef1f84bSDavid du Colombier wlock(RWlock *q)
1559ef1f84bSDavid du Colombier {
1569ef1f84bSDavid du Colombier 	Proc *p;
157*d46407a3SDavid du Colombier 	uintptr pc;
158*d46407a3SDavid du Colombier 	void (*pt)(Proc*, int, vlong, vlong);
1599ef1f84bSDavid du Colombier 
1609ef1f84bSDavid du Colombier 	lock(&q->use);
1619ef1f84bSDavid du Colombier 	rwstats.wlock++;
1629ef1f84bSDavid du Colombier 	if(q->readers == 0 && q->writer == 0){
1639ef1f84bSDavid du Colombier 		/* noone waiting, go for it */
1649ef1f84bSDavid du Colombier 		q->wpc = getcallerpc(&q);
1659ef1f84bSDavid du Colombier 		q->wproc = up;
1669ef1f84bSDavid du Colombier 		q->writer = 1;
1679ef1f84bSDavid du Colombier 		unlock(&q->use);
1689ef1f84bSDavid du Colombier 		return;
1699ef1f84bSDavid du Colombier 	}
1709ef1f84bSDavid du Colombier 
1719ef1f84bSDavid du Colombier 	/* wait */
1729ef1f84bSDavid du Colombier 	rwstats.wlockq++;
1739ef1f84bSDavid du Colombier 	p = q->tail;
1749ef1f84bSDavid du Colombier 	if(up == nil)
1759ef1f84bSDavid du Colombier 		panic("wlock");
1769ef1f84bSDavid du Colombier 	if(p == nil)
1779ef1f84bSDavid du Colombier 		q->head = up;
1789ef1f84bSDavid du Colombier 	else
1799ef1f84bSDavid du Colombier 		p->qnext = up;
1809ef1f84bSDavid du Colombier 	q->tail = up;
1819ef1f84bSDavid du Colombier 	up->qnext = 0;
1829ef1f84bSDavid du Colombier 	up->state = QueueingW;
183*d46407a3SDavid du Colombier 	if(up->trace && (pt = proctrace) != nil){
184*d46407a3SDavid du Colombier 		pc = getcallerpc(&q);
185*d46407a3SDavid du Colombier 		pt(up, SSleep, 0, QueueingW|(pc<<8));
186*d46407a3SDavid du Colombier 	}
1879ef1f84bSDavid du Colombier 	unlock(&q->use);
1889ef1f84bSDavid du Colombier 	sched();
1899ef1f84bSDavid du Colombier }
1909ef1f84bSDavid du Colombier 
1919ef1f84bSDavid du Colombier void
wunlock(RWlock * q)1929ef1f84bSDavid du Colombier wunlock(RWlock *q)
1939ef1f84bSDavid du Colombier {
1949ef1f84bSDavid du Colombier 	Proc *p;
1959ef1f84bSDavid du Colombier 
1969ef1f84bSDavid du Colombier 	lock(&q->use);
1979ef1f84bSDavid du Colombier 	p = q->head;
1989ef1f84bSDavid du Colombier 	if(p == nil){
1999ef1f84bSDavid du Colombier 		q->writer = 0;
2009ef1f84bSDavid du Colombier 		unlock(&q->use);
2019ef1f84bSDavid du Colombier 		return;
2029ef1f84bSDavid du Colombier 	}
2039ef1f84bSDavid du Colombier 	if(p->state == QueueingW){
2049ef1f84bSDavid du Colombier 		/* start waiting writer */
2059ef1f84bSDavid du Colombier 		q->head = p->qnext;
2069ef1f84bSDavid du Colombier 		if(q->head == nil)
2079ef1f84bSDavid du Colombier 			q->tail = nil;
2089ef1f84bSDavid du Colombier 		unlock(&q->use);
2099ef1f84bSDavid du Colombier 		ready(p);
2109ef1f84bSDavid du Colombier 		return;
2119ef1f84bSDavid du Colombier 	}
2129ef1f84bSDavid du Colombier 
2139ef1f84bSDavid du Colombier 	if(p->state != QueueingR)
2149ef1f84bSDavid du Colombier 		panic("wunlock");
2159ef1f84bSDavid du Colombier 
2169ef1f84bSDavid du Colombier 	/* waken waiting readers */
2179ef1f84bSDavid du Colombier 	while(q->head != nil && q->head->state == QueueingR){
2189ef1f84bSDavid du Colombier 		p = q->head;
2199ef1f84bSDavid du Colombier 		q->head = p->qnext;
2209ef1f84bSDavid du Colombier 		q->readers++;
2219ef1f84bSDavid du Colombier 		ready(p);
2229ef1f84bSDavid du Colombier 	}
2239ef1f84bSDavid du Colombier 	if(q->head == nil)
2249ef1f84bSDavid du Colombier 		q->tail = nil;
2259ef1f84bSDavid du Colombier 	q->writer = 0;
2269ef1f84bSDavid du Colombier 	unlock(&q->use);
2279ef1f84bSDavid du Colombier }
2289ef1f84bSDavid du Colombier 
2299ef1f84bSDavid du Colombier /* same as rlock but punts if there are any writers waiting */
2309ef1f84bSDavid du Colombier int
canrlock(RWlock * q)2319ef1f84bSDavid du Colombier canrlock(RWlock *q)
2329ef1f84bSDavid du Colombier {
2339ef1f84bSDavid du Colombier 	lock(&q->use);
2349ef1f84bSDavid du Colombier 	rwstats.rlock++;
2359ef1f84bSDavid du Colombier 	if(q->writer == 0 && q->head == nil){
2369ef1f84bSDavid du Colombier 		/* no writer, go for it */
2379ef1f84bSDavid du Colombier 		q->readers++;
2389ef1f84bSDavid du Colombier 		unlock(&q->use);
2399ef1f84bSDavid du Colombier 		return 1;
2409ef1f84bSDavid du Colombier 	}
2419ef1f84bSDavid du Colombier 	unlock(&q->use);
2429ef1f84bSDavid du Colombier 	return 0;
2439ef1f84bSDavid du Colombier }
244