@@ -378,7 +378,7 @@ schedule thread@Thread{
378
378
-- We record a step, in case there is no exception handler on replay.
379
379
let (thread', eff) = stepThread thread0
380
380
control' = advanceControl (threadStepId thread0) control
381
- races' = updateRacesInSimState thread0 simstate
381
+ races' = updateRaces thread0 simstate
382
382
trace <- schedule thread' simstate{ races = races',
383
383
control = control',
384
384
timers = timers'' }
@@ -826,12 +826,13 @@ deschedule Yield thread@Thread { threadId = tid,
826
826
let (thread', eff) = stepThread thread
827
827
runqueue' = insertThread thread' runqueue
828
828
threads' = Map. insert tid thread' threads
829
- control' = advanceControl (threadStepId thread) control in
829
+ control' = advanceControl (threadStepId thread) control
830
+ races' = updateRaces thread simstate in
830
831
831
832
SimPORTrace time tid tstep tlbl (EventEffect vClock eff) <$>
832
833
reschedule simstate { runqueue = runqueue',
833
834
threads = threads',
834
- races = updateRacesInSimState thread simstate ,
835
+ races = races' ,
835
836
control = control' }
836
837
837
838
deschedule Interruptable thread@ Thread {
@@ -875,11 +876,12 @@ deschedule Interruptable thread@Thread{threadId = tid,
875
876
-- Either masked or unmasked but no pending async exceptions.
876
877
-- Either way, just carry on.
877
878
-- Record a step, though, in case on replay there is an async exception.
878
- let (thread', eff) = stepThread thread in
879
+ let (thread', eff) = stepThread thread
880
+ races' = updateRaces thread simstate in
879
881
880
882
SimPORTrace time tid tstep tlbl (EventEffect vClock eff) <$>
881
883
schedule thread'
882
- simstate{ races = updateRacesInSimState thread simstate ,
884
+ simstate{ races = races' ,
883
885
control = advanceControl (threadStepId thread) control }
884
886
885
887
deschedule (Blocked _blockedReason) thread@ Thread { threadId = tid
@@ -902,11 +904,12 @@ deschedule (Blocked blockedReason) thread@Thread{ threadId = tid,
902
904
control } =
903
905
let thread1 = thread { threadStatus = ThreadBlocked blockedReason }
904
906
(thread', eff) = stepThread thread1
905
- threads' = Map. insert (threadId thread') thread' threads in
907
+ threads' = Map. insert (threadId thread') thread' threads
908
+ races' = updateRaces thread1 simstate in
906
909
907
910
SimPORTrace time tid tstep tlbl (EventEffect vClock eff) <$>
908
911
reschedule simstate { threads = threads',
909
- races = updateRacesInSimState thread1 simstate ,
912
+ races = races' ,
910
913
control = advanceControl (threadStepId thread1) control }
911
914
912
915
deschedule Terminated thread@ Thread { threadId = tid, threadLabel = tlbl, threadVClock = vClock, threadEffect = effect }
@@ -920,10 +923,10 @@ deschedule Terminated thread@Thread { threadId = tid, threadLabel = tlbl, thread
920
923
simstate'@ SimState {threads}) =
921
924
unblockThreads False vClock wakeup simstate
922
925
threads' = Map. insert tid thread' threads
926
+ races' = threadTerminatesRaces tid $ updateRaces thread1 simstate
923
927
-- We must keep terminated threads in the state to preserve their vector clocks,
924
928
-- which matters when other threads throwTo them.
925
- ! trace <- reschedule simstate' { races = threadTerminatesRaces tid $
926
- updateRacesInSimState thread1 simstate,
929
+ ! trace <- reschedule simstate' { races = races',
927
930
control = advanceControl (threadStepId thread) control,
928
931
threads = threads' }
929
932
return $ traceMany
@@ -1741,125 +1744,108 @@ data Races = Races { -- These steps may still race with future steps
1741
1744
noRaces :: Races
1742
1745
noRaces = Races [] []
1743
1746
1744
- updateRacesInSimState :: Thread s a -> SimState s a -> Races
1745
- updateRacesInSimState thread SimState { control, threads, races } =
1746
- debugTraceRaces $
1747
- updateRaces step
1748
- (isThreadBlocked thread)
1749
- control
1750
- (Map. keysSet (Map. filter (\ t -> not (isThreadDone t)
1751
- && threadId t `Set.notMember`
1752
- effectForks (stepEffect step)
1753
- ) threads))
1754
- races
1755
- where
1756
- step = currentStep thread
1757
-
1758
1747
-- | 'updateRaces' turns a current 'Step' into 'StepInfo', and updates all
1759
1748
-- 'activeRaces'.
1760
1749
--
1761
1750
-- We take care that steps can only race against threads in their
1762
1751
-- concurrent set. When this becomes empty, a step can be retired into
1763
1752
-- the "complete" category, but only if there are some steps racing
1764
1753
-- with it.
1765
- updateRaces :: Step
1766
- -- ^ executed step
1767
- -> Bool
1768
- -- ^ is the thread blocking
1769
- -> ScheduleControl
1770
- -- ^ schedule control
1771
- -> Set ThreadId
1772
- -- ^ set of runnable threads which are not forked by the step, and
1773
- -- thus can race with it.
1774
- -> Races -> Races
1775
- updateRaces newStep@ Step { stepThreadId = tid, stepEffect = newEffect }
1776
- blocking
1777
- control
1778
- concurrent0
1779
- races@ Races { activeRaces } =
1780
-
1781
- let -- A new step to add to the `activeRaces` list.
1782
- newStepInfo :: Maybe StepInfo
1783
- ! newStepInfo | isNotRacyThreadId tid = Nothing
1784
- -- non-racy threads do not race
1785
-
1786
- | Set. null concurrent = Nothing
1787
- -- cannot race with nothing
1788
-
1789
- | isBlocking = Nothing
1790
- -- no need to defer a blocking transaction
1791
-
1792
- | otherwise =
1793
- Just $! StepInfo { stepInfoStep = newStep,
1794
- stepInfoControl = control,
1795
- stepInfoConcurrent = concurrent,
1796
- stepInfoNonDep = [] ,
1797
- stepInfoRaces = []
1798
- }
1799
- where
1800
- concurrent :: Set ThreadId
1801
- concurrent = foldr Set. delete concurrent0 (effectWakeup newEffect)
1802
-
1803
- isBlocking :: Bool
1804
- isBlocking = blocking && onlyReadEffect newEffect
1805
-
1806
- -- Used to update each `StepInfo` in `activeRaces`.
1807
- updateStepInfo :: StepInfo -> StepInfo
1808
- updateStepInfo stepInfo@ StepInfo { stepInfoStep = step,
1809
- stepInfoConcurrent = concurrent,
1810
- stepInfoNonDep,
1811
- stepInfoRaces } =
1812
- -- if this step depends on the previous step, or is not concurrent,
1813
- -- then any threads that it wakes up become non-concurrent also.
1814
- let ! lessConcurrent = foldr Set. delete concurrent (effectWakeup newEffect) in
1815
-
1816
- if tid `notElem` concurrent
1817
- then stepInfo { stepInfoConcurrent = lessConcurrent }
1818
-
1819
- -- The core of IOSimPOR. Detect if `newStep` is racing with any
1820
- -- previous steps and update each `StepInfo`.
1821
- else let theseStepsRace = step `racingSteps` newStep
1822
- -- `step` happened before `newStep` (`newStep` happened after
1823
- -- `step`)
1824
- happensBefore = step `happensBeforeStep` newStep
1825
-
1826
- -- We will only record the first race with each thread.
1827
- -- Reversing the first race makes the next race detectable.
1828
- -- Thus we remove a thread from the concurrent set after the
1829
- -- first race.
1830
- ! concurrent'
1831
- | happensBefore = Set. delete tid lessConcurrent
1832
- | theseStepsRace = Set. delete tid concurrent
1833
- | otherwise = concurrent
1834
-
1835
- ! stepInfoNonDep'
1836
- -- `newStep` happened after `step`
1837
- | happensBefore = stepInfoNonDep
1838
- -- `newStep` did not happen after `step`
1839
- | otherwise = newStep : stepInfoNonDep
1840
-
1841
- -- Here we record discovered races. We only record a new
1842
- -- race if we are following the default schedule, to avoid
1843
- -- finding the same race in different parts of the search
1844
- -- space.
1845
- ! stepInfoRaces'
1846
- | theseStepsRace && isDefaultSchedule control
1847
- = newStep : stepInfoRaces
1848
- | otherwise = stepInfoRaces
1849
-
1850
- in stepInfo { stepInfoConcurrent = effectForks newEffect
1851
- `Set.union` concurrent',
1852
- stepInfoNonDep = stepInfoNonDep',
1853
- stepInfoRaces = stepInfoRaces'
1854
- }
1855
-
1856
- activeRaces' :: [StepInfo ]
1857
- ! activeRaces' =
1858
- case newStepInfo of
1859
- Nothing -> updateStepInfo <$> activeRaces
1860
- Just si -> si : (updateStepInfo <$> activeRaces)
1861
-
1862
- in normalizeRaces races { activeRaces = activeRaces' }
1754
+ updateRaces :: Thread s a -> SimState s a -> Races
1755
+ updateRaces thread@ Thread { threadId = tid }
1756
+ SimState { control, threads, races = races@ Races { activeRaces } } =
1757
+ let
1758
+ newStep@ Step { stepEffect = newEffect } = currentStep thread
1759
+
1760
+ concurrent0 =
1761
+ Map. keysSet (Map. filter (\ t -> not (isThreadDone t)
1762
+ && threadId t `Set.notMember`
1763
+ effectForks (stepEffect newStep)
1764
+ ) threads)
1765
+
1766
+ -- A new step to add to the `activeRaces` list.
1767
+ newStepInfo :: Maybe StepInfo
1768
+ ! newStepInfo | isNotRacyThreadId tid = Nothing
1769
+ -- non-racy threads do not race
1770
+
1771
+ | Set. null concurrent = Nothing
1772
+ -- cannot race with nothing
1773
+
1774
+ | isBlocking = Nothing
1775
+ -- no need to defer a blocking transaction
1776
+
1777
+ | otherwise =
1778
+ Just $! StepInfo { stepInfoStep = newStep,
1779
+ stepInfoControl = control,
1780
+ stepInfoConcurrent = concurrent,
1781
+ stepInfoNonDep = [] ,
1782
+ stepInfoRaces = []
1783
+ }
1784
+ where
1785
+ concurrent :: Set ThreadId
1786
+ concurrent = foldr Set. delete concurrent0 (effectWakeup newEffect)
1787
+
1788
+ isBlocking :: Bool
1789
+ isBlocking = isThreadBlocked thread && onlyReadEffect newEffect
1790
+
1791
+ -- Used to update each `StepInfo` in `activeRaces`.
1792
+ updateStepInfo :: StepInfo -> StepInfo
1793
+ updateStepInfo stepInfo@ StepInfo { stepInfoStep = step,
1794
+ stepInfoConcurrent = concurrent,
1795
+ stepInfoNonDep,
1796
+ stepInfoRaces } =
1797
+ -- if this step depends on the previous step, or is not concurrent,
1798
+ -- then any threads that it wakes up become non-concurrent also.
1799
+ let ! lessConcurrent = foldr Set. delete concurrent (effectWakeup newEffect) in
1800
+
1801
+ if tid `notElem` concurrent
1802
+ then stepInfo { stepInfoConcurrent = lessConcurrent }
1803
+
1804
+ -- The core of IOSimPOR. Detect if `newStep` is racing with any
1805
+ -- previous steps and update each `StepInfo`.
1806
+ else let theseStepsRace = step `racingSteps` newStep
1807
+ -- `step` happened before `newStep` (`newStep` happened after
1808
+ -- `step`)
1809
+ happensBefore = step `happensBeforeStep` newStep
1810
+
1811
+ -- We will only record the first race with each thread.
1812
+ -- Reversing the first race makes the next race detectable.
1813
+ -- Thus we remove a thread from the concurrent set after the
1814
+ -- first race.
1815
+ ! concurrent'
1816
+ | happensBefore = Set. delete tid lessConcurrent
1817
+ | theseStepsRace = Set. delete tid concurrent
1818
+ | otherwise = concurrent
1819
+
1820
+ ! stepInfoNonDep'
1821
+ -- `newStep` happened after `step`
1822
+ | happensBefore = stepInfoNonDep
1823
+ -- `newStep` did not happen after `step`
1824
+ | otherwise = newStep : stepInfoNonDep
1825
+
1826
+ -- Here we record discovered races. We only record a new
1827
+ -- race if we are following the default schedule, to avoid
1828
+ -- finding the same race in different parts of the search
1829
+ -- space.
1830
+ ! stepInfoRaces'
1831
+ | theseStepsRace && isDefaultSchedule control
1832
+ = newStep : stepInfoRaces
1833
+ | otherwise = stepInfoRaces
1834
+
1835
+ in stepInfo { stepInfoConcurrent = effectForks newEffect
1836
+ `Set.union` concurrent',
1837
+ stepInfoNonDep = stepInfoNonDep',
1838
+ stepInfoRaces = stepInfoRaces'
1839
+ }
1840
+
1841
+ activeRaces' :: [StepInfo ]
1842
+ ! activeRaces' =
1843
+ case newStepInfo of
1844
+ Nothing -> updateStepInfo <$> activeRaces
1845
+ Just si -> si : (updateStepInfo <$> activeRaces)
1846
+
1847
+ in normalizeRaces races { activeRaces = activeRaces' }
1848
+
1863
1849
1864
1850
normalizeRaces :: Races -> Races
1865
1851
normalizeRaces Races { activeRaces, completeRaces } =
@@ -1893,12 +1879,6 @@ quiescentRaces Races{ activeRaces, completeRaces } =
1893
1879
, not (null (stepInfoRaces s))
1894
1880
] ++ completeRaces }
1895
1881
1896
- -- for debugging purposes
1897
- debugTraceRaces :: Races -> Races
1898
- debugTraceRaces r = r
1899
- -- debugTraceRaces r@Races{activeRaces,completeRaces} =
1900
- -- Debug.trace ("Tracking "++show (length (concatMap stepInfoRaces activeRaces)) ++" races") r
1901
-
1902
1882
1903
1883
--
1904
1884
-- Schedule control
0 commit comments