9fans archive / 1997 / 05 / 38 / prev next
From: beto@ncu... beto@ncu...
Subject: calling sleep() while holding lock()
Date: Thu, 8 May 97 11:32:19 PDT
In <199705090253.496031.out.bajag@pla...>
David Hogan <dhog@lor...> wrote:
> Good coding. So now the question remains: why is this behaviour
> occuring? One possibility is that we take a fault while holding
> the lock, and we then have to sleep until the memory gets paged in.
> Alberto Nava found a place in the kernel where this is happening, and
> I'm sure there must be others.
>
Here is the example that Dave mentioned:
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 generate a page-fault. This could lead to
seg() calling qlock or sleeping waiting for the actual data.
There are plenty of places where plan9 does that or similar. 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:
if(omode != OREAD)
error(Eperm);
break;
case Qmouse:
lock(&bit);
if(bit.mouseopen){
unlock(&bit);
error(Einuse);
}
bit.mouseopen = 1;
bit.ref++;
unlock(&bit);
break;
case Qbitblt:
lock(&bit);
if(bit.bitbltopen || bit.mouseopen){
unlock(&bit);
error(Einuse);
}
b = smalloc(sizeof(GBitmap));***************************************
smalloc could make the kernel sleep waiting for memory so again
holding spin-lock/sleep.
Actually we have code in qlock and sleep to check for a process holding
spin-lock before the calls.