Plan 9 from Bell Labs’s /usr/web/sources/contrib/quanstro/root/sys/src/fs/pc/lock.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


 #include	"u.h"
#include	"lib.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"mem.h"

void	_xinc(long*);
long	_xdec(long*);

#define deccnt(x)	if(x)  _xdec(&x->nlock)
#define inccnt(x) if(x)  _xinc(&x->nlock)

void
printlocks(User *up)
{
	int i;

	for(i = 0; i < up->nlock; i++){
		print("%p:%p", up->lstack[i], up->pstack[i]);
		if((i%4) == 0)
			print("\n");
	}
	if(i>0 && i%4)
 		print("\n");
}

void
lock(Lock *l)
{
	int /*i,*/ nl;
	ulong pc;

	pc = getcallerpc(&l);
	nl = 0;
	if(u)
		nl = u->nlock;
loop:
	inccnt(u);		/* prevent being scheded */
	if(tas(l) == 0) {
		l->pc = pc;
		if(u){
			u->lstack[nl] = l;
			u->pstack[nl] = pc;
		}
		return;
	}
	deccnt(u);

#ifdef multiprocessor
	for(i = 0; i < 1000000; i++){
		if(l->sbsem)
			continue;
 		inccnt(u);
   		if(tas(l) == 0) {
			l->pc = pc;
			if(u){
				u->lstack[nl] = l;
				u->pstack[nl] = pc;
			}
			return;
		}
		deccnt(u);
	}
#endif
	l->sbsem = 0;	// BOTCH

	print("lock loop %d:%#p called by %#p held by pc %#p\n", u?u->pid:-1, l, pc, l->pc);
	if(u)
		dumpstack(u);
	dotrace(0);
	if(getstatus() & IFLAG)
		sched();
	else
		print("ilock deadlock\n");
	goto loop;
}

void
unlock(Lock *l)
{
	if(l->sbsem == 0)
		print("unlock: not locked: pc %#p\n", getcallerpc(&l));
	l->pc = 0;
	l->sbsem = 0;
	coherence();

	if(u && _xdec(&u->nlock) == 0)
	if(u->delaysched)
	if(getstatus() & IFLAG){
		/*
		 * Call sched if the need arose while locks were held
		 * But, don't do it from interrupt routines, hence the islo() test
		 */
		u->delaysched = 0;
		sched();
	}
}

int
canlock(Lock *l)
{
	inccnt(u);
	if(tas(l)){
		deccnt(u);
		return 0;
	}
	l->pc = getcallerpc(&l);
	return 1;
}

void
ilock(Lock *l)
{
	ulong x, pc;

	pc = getcallerpc(&l);

	x = splhi();
	if(tas(l) == 0)
		goto acquire;

	if(!l->isilock)
		panic("ilock: not ilock %p", pc);
	if(l->m == MACHP(m->machno))
		panic("ilock: deadlock cpu%d pc %p lpc %p\n", m->machno, pc, l->pc);
	for(;;){
		splx(x);
#ifdef multiprocessor
		while(l->sbsem)
			;
#else
		if(getstatus() & IFLAG)
			sched();
		else
			panic("ilock: locked & splhi\n");
#endif
		x = splhi();
		if(tas(l) == 0)
			goto acquire;
	}
acquire:
//	m->ilockdepth++;
//	if(u)
//		u->lastilock = l;
	l->sr = x;
	l->pc = pc;
	l->p = u;
	l->isilock = 1;
	l->m = MACHP(m->machno);
}

void
iunlock(Lock *l)
{
	ulong sr;

	if(l->sbsem == 0)
		panic("iunlock nolock: pc %p", getcallerpc(&l));
	if(l->isilock == 0)
		print("iunlock lock: pc %p held by %p\n", getcallerpc(&l), l->pc);
	if((getstatus()&IFLAG) != 0)
		print("iunlock lo: %p held by %p\n", getcallerpc(&l), l->pc);

	sr = l->sr;
	l->m = 0;
	l->sbsem = 0;
//	m->ilockdepth--;
	
	coherence();

//	if(u)
//		u->lastilock = 0;
	splx(sr);
}

void
qlock(QLock *q)
{
	User *p;
	int i;

	lock(q);
	if(!q->locked){
		q->locked = 1;
		unlock(q);
		goto out;
	}
	if(u) {
		for(i=0; i<NHAS; i++)
			if(u->has.q[i] == q) {
				print("circular qlock by %d at 0x%lux (other 0x%lux, 0x%lux)\n",
					u->pid, getcallerpc(&q), u->has.pc[i], q->pc);
				dumpstack(u);
				break;
			}
	}
	p = q->tail;
	if(p == 0)
		q->head = u;
	else
		p->qnext = u;
	q->tail = u;
	u->qnext = 0;
	u->state = Queueing;
	u->has.want = q;
	unlock(q);
	sched();
	u->has.want = 0;

out:
	if(u) {
		for(i=0; i<NHAS; i++)
			if(u->has.q[i] == 0) {
				u->has.q[i] = q;
				u->has.pc[i] = getcallerpc(&q);
				return;
			}
		print("NHAS(%d) too small\n", NHAS);
	}
}

int
canqlock(QLock *q)
{
	int i;

	lock(q);
	if(q->locked){
		unlock(q);
		return 0;
	}
	q->locked = 1;
	unlock(q);

	if(u){
		for(i=0; i<NHAS; i++)
			if(u->has.q[i] == 0) {
				u->has.q[i] = q;
				u->has.pc[i] = getcallerpc(&q);
				return 1;
			}
		print("NHAS(%d) too small\n", NHAS);
	}
	return 1;
}

void
qunlock(QLock *q)
{
	User *p;
	int i;

	lock(q);
	p = q->head;
	if(p) {
		q->head = p->qnext;
		if(q->head == 0)
			q->tail = 0;
		unlock(q);
		ready(p);
	} else {
		q->locked = 0;
		unlock(q);
	}

	if(u){
		for(i=0; i<NHAS; i++)
			if(u->has.q[i] == q) {
				u->has.q[i] = 0;
				return;
			}
		panic("qunlock: not there %p, called from %p\n",
			q, getcallerpc(&q));
	}
}

/*
 * readers/writers lock
 * allows 1 writer or many readers
 */
void
rlock(RWlock *l)
{
	QLock *q;

	qlock(&l->wr);			/* wait here for writers and exclusion */

	q = &l->rd;			/* first reader in, qlock(&l->rd) */
	lock(q);
	q->locked = 1;
	l->nread++;
	unlock(q);

	qunlock(&l->wr);

	if(u){
		int i;
		int found;

		found = 0;
		for(i=0; i<NHAS; i++){
			if(u->has.q[i] == q){
				print("circular rlock by %d at 0x%lux (other 0x%lux)\n",
					u->pid, getcallerpc(&l), u->has.pc[i]);
				dumpstack(u);
			}
			if(!found && u->has.q[i] == 0) {
				u->has.q[i] = q;
				u->has.pc[i] = getcallerpc(&l);
				found = 1;
			}
		}
		if(!found)
			print("NHAS(%d) too small\n", NHAS);
	}
}

void
runlock(RWlock *l)
{
	QLock *q;
	User *p;
	int n;

	q = &l->rd;
	lock(q);
	n = l->nread - 1;
	l->nread = n;
	if(n == 0) {			/* last reader out, qunlock(&l->rd) */
		p = q->head;
		if(p) {
			q->head = p->qnext;
			if(q->head == 0)
				q->tail = 0;
			unlock(q);
			ready(p);
			goto accounting;
		} 
		q->locked = 0;
	}
	unlock(q);

accounting:
	if(u){
		int i;
		for(i=0; i<NHAS; i++)
			if(u->has.q[i] == q) {
				u->has.q[i] = 0;
				return;
			}
		panic("runlock: not there %p, called from %p\n",
			(ulong)q, getcallerpc(&l));
	}
}

void
wlock(RWlock *l)
{
	qlock(&l->wr);			/* wait here for writers and exclusion */
	qlock(&l->rd);			/* wait here for last reader */
}

void
wunlock(RWlock *l)
{
	qunlock(&l->rd);
	qunlock(&l->wr);
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].