@@ -28,8 +28,9 @@ type schedulerTestDevice struct {
2828
2929type generationSchedulerTestDevice struct {
3030 * schedulerTestDevice
31- generation atomic.Uint64
32- rejected atomic.Uint64
31+ generation atomic.Uint64
32+ rejected atomic.Uint64
33+ rejectedWake chan struct {}
3334}
3435
3536type fakeEndpointClock struct {
@@ -397,6 +398,12 @@ func (d *generationSchedulerTestDevice) HandleIsoOutTransfer(
397398) bool {
398399 if generation != d .generation .Load () {
399400 d .rejected .Add (1 )
401+ if d .rejectedWake != nil {
402+ select {
403+ case d .rejectedWake <- struct {}{}:
404+ default :
405+ }
406+ }
400407 return false
401408 }
402409 d .HandleTransfer (context .Background (), 1 , usbip .DirOut , payload )
@@ -1157,13 +1164,16 @@ func TestIsoOutUnlinkReleasesLaterJobAndResetInvalidatesGeneration(t *testing.T)
11571164
11581165func TestIsoOutDeviceGenerationRejectsResetRace (t * testing.T ) {
11591166 base := & schedulerTestDevice {desc : testCompositeDescriptor ()}
1160- device := & generationSchedulerTestDevice {schedulerTestDevice : base }
1167+ device := & generationSchedulerTestDevice {
1168+ schedulerTestDevice : base , rejectedWake : make (chan struct {}, 1 ),
1169+ }
11611170 device .generation .Store (1 )
1171+ clock := newFakeEndpointClock (time .Unix (250 , 0 ))
11621172 recorder := newRecordingWriter ()
11631173 ctx , cancel := context .WithCancel (context .Background ())
1164- worker := newEndpointWorker (
1174+ worker := newEndpointWorkerWithClock (
11651175 ctx , device , 1 , usbip .DirOut , isoOutWorker , time .Millisecond ,
1166- 192 , newResponseWriter (recorder , nil ), func (error ) {},
1176+ 192 , newResponseWriter (recorder , nil ), func (error ) {}, clock ,
11671177 )
11681178 defer func () {
11691179 cancel ()
@@ -1172,21 +1182,35 @@ func TestIsoOutDeviceGenerationRejectsResetRace(t *testing.T) {
11721182 }()
11731183
11741184 packets := []usbip.IsoPacketDescriptor {{Length : 1 }}
1185+ firstService := clock .Now ().Add (4 * time .Millisecond )
11751186 require .True (t , worker .enqueueWithGeneration (
1176- 501 , 1 , []byte {0x51 }, packets , time . Now (). Add ( 4 * time . Millisecond ) , 1 ,
1187+ 501 , 1 , []byte {0x51 }, packets , firstService , 1 ,
11771188 ))
1189+ clock .waitForDeadline (t , firstService )
11781190 device .generation .Store (2 ) // Device reset wins the service-boundary race.
1179- time .Sleep (10 * time .Millisecond )
1191+ clock .advance (4 * time .Millisecond )
1192+ // A wall-clock sleep cannot establish that the worker has run. Observe its
1193+ // actual rejection, while the fake clock makes reset-before-service exact.
1194+ select {
1195+ case <- device .rejectedWake :
1196+ case <- time .After (2 * time .Second ):
1197+ t .Fatal ("timed out waiting for old-generation ISO rejection" )
1198+ }
11801199 recorder .mu .Lock ()
11811200 require .Empty (t , recorder .writes )
11821201 recorder .mu .Unlock ()
11831202 require .Equal (t , uint64 (1 ), device .rejected .Load ())
11841203
11851204 require .True (t , worker .enqueueWithGeneration (
1186- 502 , 1 , []byte {0x52 }, packets , time .Now (), 2 ,
1205+ 502 , 1 , []byte {0x52 }, packets , clock .Now (), 2 ,
11871206 ))
1207+ clock .waitForDeadline (t , clock .Now ().Add (time .Millisecond ))
1208+ clock .advance (time .Millisecond )
1209+ clock .waitForDeadline (t , clock .Now ().Add (time .Millisecond ))
1210+ clock .advance (time .Millisecond )
11881211 writes := recorder .waitForWrites (t , 1 )
11891212 require .Equal (t , uint32 (502 ), binary .BigEndian .Uint32 (writes [0 ].packet [4 :8 ]))
1213+ require .Equal (t , uint64 (1 ), device .rejected .Load ())
11901214 base .mu .Lock ()
11911215 require .Equal (t , [][]byte {{0x52 }}, base .isoOutPayloads )
11921216 base .mu .Unlock ()
0 commit comments