Skip to content

Commit 96d0f3d

Browse files
committed
io-sim-por: return internal errors
This makes it much easier to debug ones. In the future we might turn more assertion failures into `FailureInternal`.
1 parent 1af1f0c commit 96d0f3d

File tree

4 files changed

+35
-5
lines changed

4 files changed

+35
-5
lines changed

io-sim/src/Control/Monad/IOSim.hs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ selectTraceEvents fn =
132132
Deadlock _ threads -> throw (FailureDeadlock threads)
133133
MainReturn _ _ _ -> []
134134
Loop -> error "Impossible: selectTraceEvents _ TraceLoop{}"
135+
InternalError msg -> throw (FailureInternal msg)
135136
)
136137
( \ b acc -> b : acc )
137138
[]
@@ -336,6 +337,12 @@ data Failure =
336337
-- This could be an internal assertion failure of `io-sim` or an
337338
-- unhandled exception in the simulation.
338339
| FailureEvaluation SomeException
340+
341+
-- | An internal failure of the simulator.
342+
--
343+
-- Please open an issue at
344+
-- <https://github.com/input-output-hk/io-sim/issues>.
345+
| FailureInternal String
339346
deriving Show
340347

341348
instance Exception Failure where
@@ -350,7 +357,18 @@ instance Exception Failure where
350357
, intercalate ", " (show `map` threads)
351358
, ">>"
352359
]
353-
displayException (FailureEvaluation err) = "evaluation error:" ++ displayException err
360+
displayException (FailureEvaluation err) =
361+
concat [ "<<evaluation error: "
362+
, displayException err
363+
, ">>"
364+
]
365+
displayException (FailureInternal msg) =
366+
concat [ "<<internal failure: "
367+
, msg
368+
, ">>\n"
369+
, "please report the issue at\n"
370+
, "https://github.com/input-output-hk/io-sim/issues"
371+
]
354372

355373

356374
-- | 'IOSim' is a pure monad.
@@ -402,6 +420,7 @@ traceResult strict = unsafePerformIO . eval
402420
go (TraceMainException _ e _) = pure $ Left (FailureException e)
403421
go (TraceDeadlock _ threads) = pure $ Left (FailureDeadlock threads)
404422
go TraceLoop{} = error "Impossible: traceResult TraceLoop{}"
423+
go (TraceInternalError msg) = pure $ Left (FailureInternal msg)
405424

406425
-- | Turn 'SimTrace' into a list of timestamped events.
407426
--

io-sim/src/Control/Monad/IOSim/Types.hs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ module Control.Monad.IOSim.Types
5050
, SimEvent (..)
5151
, SimResult (..)
5252
, SimTrace
53-
, Trace.Trace (SimTrace, SimPORTrace, TraceMainReturn, TraceMainException, TraceDeadlock, TraceRacesFound, TraceLoop)
53+
, Trace.Trace (SimTrace, SimPORTrace, TraceMainReturn, TraceMainException, TraceDeadlock, TraceRacesFound, TraceLoop, TraceInternalError)
5454
, ppTrace
5555
, ppTrace_
5656
, ppSimEvent
@@ -917,7 +917,10 @@ pattern TraceDeadlock time threads = Trace.Nil (Deadlock time threads)
917917
pattern TraceLoop :: SimTrace a
918918
pattern TraceLoop = Trace.Nil Loop
919919

920-
{-# COMPLETE SimTrace, SimPORTrace, TraceMainReturn, TraceMainException, TraceDeadlock, TraceLoop #-}
920+
pattern TraceInternalError :: String -> SimTrace a
921+
pattern TraceInternalError msg = Trace.Nil (InternalError msg)
922+
923+
{-# COMPLETE SimTrace, SimPORTrace, TraceMainReturn, TraceMainException, TraceDeadlock, TraceLoop, TraceInternalError #-}
921924

922925

923926
-- | Events recorded by the simulation.

io-sim/src/Control/Monad/IOSimPOR/Internal.hs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -966,12 +966,18 @@ deschedule Sleep thread@Thread { threadId = tid , threadEffect = effect' }
966966
reschedule :: SimState s a -> ST s (SimTrace a)
967967

968968
-- If we are following a controlled schedule, just do that.
969+
reschedule simstate@SimState { runqueue, control = control@(ControlFollow ((tid,_):_) _) }
970+
| not (Down tid `PSQ.member` runqueue) =
971+
return (Trace.Nil (InternalError ("assertion failure: " ++ ppIOSimThreadId tid ++ " not runnable")))
972+
973+
reschedule simstate@SimState { threads, control = control@(ControlFollow ((tid,_):_) _) }
974+
| not (tid `Map.member` threads) =
975+
return (Trace.Nil (InternalError ("assertion failure: " ++ ppIOSimThreadId tid ++ " not in threads")))
976+
969977
reschedule simstate@SimState { runqueue, threads,
970978
control = control@(ControlFollow ((tid,tstep):_) _),
971979
curTime = time } =
972980
fmap (SimPORTrace time tid tstep Nothing (EventReschedule control)) $
973-
assert (Down tid `PSQ.member` runqueue) $
974-
assert (tid `Map.member` threads) $
975981
invariant Nothing simstate $
976982
let thread = threads Map.! tid in
977983
assert (threadId thread == tid) $

io-sim/test/Test/Control/Monad/IOSimPOR.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,8 @@ propExploration cmp (Shrink2 ts@(Tasks tasks)) =
356356
counterexample (noExceptions $ Trace.ppTrace show (ppSimEvent 0 0 0) trace) $
357357
case traceResult False trace of
358358
Right (m,a) -> property (m >= a)
359+
Left (FailureInternal msg)
360+
-> counterexample msg False
359361
Left _ -> property True
360362

361363

0 commit comments

Comments
 (0)