@@ -849,14 +849,17 @@ reschedule !simstate@SimState{ threads, timers, curTime = time } =
849
849
timeoutSTMAction TimerTimeout {} = return ()
850
850
851
851
unblockThreads :: Bool -> [IOSimThreadId ] -> SimState s a -> ([IOSimThreadId ], SimState s a )
852
- unblockThreads ! onlySTM ! wakeup ! simstate@ SimState {runqueue, threads} =
852
+ unblockThreads ! onlySTM ! wakeup ! simstate@ SimState {runqueue, threads, stdGen } =
853
853
-- To preserve our invariants (that threadBlocked is correct)
854
854
-- we update the runqueue and threads together here
855
855
(unblocked, simstate {
856
- runqueue = runqueue <> Deque. fromList unblocked,
857
- threads = threads'
856
+ runqueue = Deque. fromList shuffledRunqueue,
857
+ threads = threads',
858
+ stdGen = stdGen'
858
859
})
859
860
where
861
+ ! (shuffledRunqueue, stdGen') = fisherYatesShuffle stdGen runqueue'
862
+ ! runqueue' = Deque. toList $ runqueue <> Deque. fromList unblocked
860
863
-- can only unblock if the thread exists and is blocked (not running)
861
864
! unblocked = [ tid
862
865
| tid <- wakeup
@@ -873,6 +876,19 @@ unblockThreads !onlySTM !wakeup !simstate@SimState {runqueue, threads} =
873
876
threads
874
877
unblocked
875
878
879
+ -- Fisher-Yates shuffle implementation
880
+ fisherYatesShuffle :: StdGen -> [a ] -> ([a ], StdGen )
881
+ fisherYatesShuffle gen [] = ([] , gen)
882
+ fisherYatesShuffle gen l =
883
+ let (l', gen') = go (length l - 1 ) l gen
884
+ in (l', gen')
885
+ where
886
+ go 0 lst g = (lst, g)
887
+ go n lst g = let (k, newGen) = randomR (0 , n) g
888
+ (x: xs) = drop k lst
889
+ swapped = take k lst ++ [lst !! n] ++ drop (k + 1 ) lst
890
+ in go (n - 1 ) (take n swapped ++ [x] ++ drop n xs) newGen
891
+
876
892
-- | This function receives a list of TimerTimeout values that represent threads
877
893
-- for which the timeout expired and kills the running thread if needed.
878
894
--
0 commit comments