summaryrefslogtreecommitdiff
path: root/sys/src/9/pc/ether82563.c
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@gmx.de>2013-07-26 01:51:03 +0200
committercinap_lenrek <cinap_lenrek@gmx.de>2013-07-26 01:51:03 +0200
commitac52599eef2ab79a64c30a8046a51b62501ca9ab (patch)
tree3857c15103a82a5a61fc0219b3590eeb040cba7d /sys/src/9/pc/ether82563.c
parent2759b81decc991f756044942459ecc8ba92b32fd (diff)
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.
Diffstat (limited to 'sys/src/9/pc/ether82563.c')
-rw-r--r--sys/src/9/pc/ether82563.c9
1 files changed, 1 insertions, 8 deletions
diff --git a/sys/src/9/pc/ether82563.c b/sys/src/9/pc/ether82563.c
index eb6e35998..f4eab6a0f 100644
--- a/sys/src/9/pc/ether82563.c
+++ b/sys/src/9/pc/ether82563.c
@@ -792,14 +792,9 @@ static int
icansleep(void *v)
{
Rbpool *p;
- int r;
p = v;
- ilock(p);
- r = p->starve == 0;
- iunlock(p);
-
- return r;
+ return p->b != nil;
}
static Block*
@@ -1058,9 +1053,7 @@ i82563replenish(Ctlr *ctlr, int maysleep)
print("i82563%d: no rx buffers\n", ctlr->pool);
if(maysleep == 0)
return -1;
- ilock(p);
p->starve = 1;
- iunlock(p);
sleep(p, icansleep, p);
goto redux;
}