ether82563: avoid deadlock due to icansleep() trying to acquire Rbpool.Lock
icansleep() violates the lock ordering due to the following cases: rbfree(): ilock(Rbpool.Lock) -> wakeup(): spli(), lock(Rbpool.Rendez) sleep(): splhi(), lock(Rbpool.Rendez) -> icansleep(): ilock(Rbpool.Lock) erik fixed this moving the wakeup() out of the ilock() in rbfree(), but i think it is an error to try acquiering a ilock in sleeps wait condition function in general. so this is what we do: in the icansleep() function, we check for the *real* event we care about; that is, if theres a buffer available in the Rbpool. this is to handle the case when rbfree() makes a buffer available *before* it sees us setting p->starve = 1. p->starve is now just used to gate rbfree() from calling wakeup() as an optimization. this might cause spurious wakeups but they are not a problem. missed wakeups is the thing we have to prevent.
This commit is contained in:
parent
2759b81dec
commit
ac52599eef
1 changed files with 1 additions and 8 deletions
|
@ -792,14 +792,9 @@ static int
|
||||||
icansleep(void *v)
|
icansleep(void *v)
|
||||||
{
|
{
|
||||||
Rbpool *p;
|
Rbpool *p;
|
||||||
int r;
|
|
||||||
|
|
||||||
p = v;
|
p = v;
|
||||||
ilock(p);
|
return p->b != nil;
|
||||||
r = p->starve == 0;
|
|
||||||
iunlock(p);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Block*
|
static Block*
|
||||||
|
@ -1058,9 +1053,7 @@ i82563replenish(Ctlr *ctlr, int maysleep)
|
||||||
print("i82563%d: no rx buffers\n", ctlr->pool);
|
print("i82563%d: no rx buffers\n", ctlr->pool);
|
||||||
if(maysleep == 0)
|
if(maysleep == 0)
|
||||||
return -1;
|
return -1;
|
||||||
ilock(p);
|
|
||||||
p->starve = 1;
|
p->starve = 1;
|
||||||
iunlock(p);
|
|
||||||
sleep(p, icansleep, p);
|
sleep(p, icansleep, p);
|
||||||
goto redux;
|
goto redux;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue