2015-02-01 04:21:42 +03:00
|
|
|
-- | Deterministic scheduling for concurrent computations.
|
|
|
|
module Test.DejaFu.Deterministic.Schedule
|
|
|
|
( Scheduler
|
2014-12-27 15:20:45 +03:00
|
|
|
, ThreadId
|
2015-01-12 18:58:53 +03:00
|
|
|
, NonEmpty(..)
|
2014-12-27 15:20:45 +03:00
|
|
|
-- * Pre-emptive
|
|
|
|
, randomSched
|
|
|
|
, roundRobinSched
|
|
|
|
-- * Non pre-emptive
|
|
|
|
, randomSchedNP
|
|
|
|
, roundRobinSchedNP
|
|
|
|
-- * Utilities
|
|
|
|
, makeNP
|
2015-01-12 18:58:53 +03:00
|
|
|
, toList
|
2014-12-27 15:20:45 +03:00
|
|
|
) where
|
|
|
|
|
2015-01-27 16:46:20 +03:00
|
|
|
import Data.List.Extra
|
2014-12-27 15:20:45 +03:00
|
|
|
import System.Random (RandomGen, randomR)
|
2015-01-31 18:50:54 +03:00
|
|
|
import Test.DejaFu.Deterministic.Internal
|
2014-12-27 15:20:45 +03:00
|
|
|
|
|
|
|
-- | A simple random scheduler which, at every step, picks a random
|
|
|
|
-- thread to run.
|
|
|
|
randomSched :: RandomGen g => Scheduler g
|
2015-01-12 18:58:53 +03:00
|
|
|
randomSched g _ threads = (threads' !! choice, g') where
|
|
|
|
(choice, g') = randomR (0, length threads' - 1) g
|
|
|
|
threads' = toList threads
|
2014-12-27 15:20:45 +03:00
|
|
|
|
|
|
|
-- | A random scheduler which doesn't pre-empt the running
|
|
|
|
-- thread. That is, if the last thread scheduled is still runnable,
|
|
|
|
-- run that, otherwise schedule randomly.
|
|
|
|
randomSchedNP :: RandomGen g => Scheduler g
|
|
|
|
randomSchedNP = makeNP randomSched
|
|
|
|
|
|
|
|
-- | A round-robin scheduler which, at every step, schedules the
|
|
|
|
-- thread with the next 'ThreadId'.
|
|
|
|
roundRobinSched :: Scheduler ()
|
|
|
|
roundRobinSched _ prior threads
|
2015-01-12 18:58:53 +03:00
|
|
|
| prior >= maximum threads' = (minimum threads', ())
|
|
|
|
| otherwise = (minimum $ filter (>prior) threads', ())
|
|
|
|
|
|
|
|
where
|
|
|
|
threads' = toList threads
|
2014-12-27 15:20:45 +03:00
|
|
|
|
|
|
|
-- | A round-robin scheduler which doesn't pre-empt the running
|
|
|
|
-- thread.
|
|
|
|
roundRobinSchedNP :: Scheduler ()
|
|
|
|
roundRobinSchedNP = makeNP roundRobinSched
|
|
|
|
|
|
|
|
-- | Turn a potentially pre-emptive scheduler into a non-preemptive
|
|
|
|
-- one.
|
|
|
|
makeNP :: Scheduler s -> Scheduler s
|
|
|
|
makeNP sched = newsched where
|
|
|
|
newsched s prior threads
|
2015-01-12 18:58:53 +03:00
|
|
|
| prior `elem` toList threads = (prior, s)
|
2014-12-27 15:20:45 +03:00
|
|
|
| otherwise = sched s prior threads
|