9fans archive / 1997 / 05 / 47 /    prev next

From: beto@ncu... beto@ncu...
Subject: sleep while holding spin-lock
Date: Fri, 9 May 97 12:38:49 PDT

Here is the problem dhog mentioned a couple of
days ago.

long
bitread(Chan *c, void *va, long n, ulong offset)
{
	uchar *p, *q;
	long miny, maxy, t, x, y;
	ulong l, nw, ws, rv, gv, bv;
	int off, j;
	Fontchar *i;
	GBitmap *src;
	BSubfont *s;
	static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 };

	if(!conf.monitor)
		error(Egreg);
	if(c->qid.path & CHDIR)
		return devdirread(c, va, n, bitdir, NBIT, devgen);

	if(c->qid.path == Qmouse){
		/*
		 * mouse:
		 *	'm'		1
		 *	buttons		1
		 * 	point		8
		 * 	msec		4
		 */
		if(n < 14)
			error(Ebadblt);
		while(mousechanged(0) == 0)
			sleep(&mouse.r, mousechanged, 0);
		lock(&cursor);
		p = va; ************************

accessing va could cause a page fault which could
sleep in a qlock in seg() or reading the page.

A simple solution is to add

 	uchar buf[14];
	
and then replace 

		lock(&cursor);
		p = buf; 
		p[0] = 'm';
		......
		unlock(&cursor);
		memmove(va,buf,14);

There are plenty of places in plan9 where we could
sleep holding a spin-lock. For example in the same driver

Chan*
bitopen(Chan *c, int omode)
{
	GBitmap *b;

	if(!conf.monitor)
		error(Egreg);
	switch(c->qid.path){
	case CHDIR:
	...
	case Qmouse:
	...
	case Qbitblt:
		lock(&bit);
		if(bit.bitbltopen || bit.mouseopen){
			unlock(&bit);
			error(Einuse);
		}
		b = smalloc(sizeof(GBitmap));***************

smalloc could sleep while holding bit.

We actually added some code to qlock and sleep so
we capture calls while holding spin-locks.