There's a deadlock in isoio() on a multiprocessor, arising from a
conflict in order of acquiring locks. (Not just theory: I've seen
it happen on my dual-processor Epia system.) Consider this scenario:
isoio() on cpu1:
1 isoio calls sleep(&e->wr, isoready, e) /sys/src/9/pc/usbuhci.c:1173
2 sleep calls lock(&e->wr) /sys/src/9/port/proc.c:740
3 sleep calls isoready(e) /sys/src/9/port/proc.c:755
4 isoready calls ilock(&ctlr->activends) /sys/src/9/pc/usbuhci.c:1093
5 isoready calls iunlock(&ctlr->activends) /sys/src/9/pc/usbuhci.c:1095
6 sleep calls unlock(&e->wr) /sys/src/9/port/proc.c:762
interrupt() on cpu0:
7 interrupt calls ilock(&ctlr->activends) /sys/src/9/pc/usbuhci.c:1043
8 interrupt calls cleaniso(e, ) /sys/src/9/pc/usbuhci.c:1052
9 cleaniso calls wakeup(&e->wr) /sys/src/9/pc/usbuhci.c:1015
10 wakeup calls lock(&e->wr) /sys/src/9/port/proc.c:864
11 wakeup calls unlock(&e->wr) /sys/src/9/port/proc.c:876
12 interrupt calls iunlock(&ctlr->activends) /sys/src/9/pc/usbuhci.c:1055
An interleaving of events containing 2 - 7 - 10 - 4 leads to deadlock.
I developed a fix which involved locking the individual endpoints instead
of locking ctlr->activends, but when I checked it with Sape he pointed
out that a simple revision to isoreadyx() would mean that it can be
called without locking at all. So here's a simple patch based on Sape's
suggestion. (Tested by playing audio for 24 hours on the above dual-
processor system, without incident.)
-- Richard Miller
|