@@ -42,6 +42,10 @@ tests =
42
42
, testProperty " timers (IOSim)" (withMaxSuccess 1000 prop_timers_ST)
43
43
-- fails since we just use `threadDelay` to schedule timers in `IO`.
44
44
, testProperty " timers (IO)" (expectFailure prop_timers_IO)
45
+ , testProperty " timeout (IOSim): no deadlock"
46
+ prop_timeout_no_deadlock_Sim
47
+ , testProperty " timeout (IO): no deadlock"
48
+ prop_timeout_no_deadlock_IO
45
49
, testProperty " threadId order (IOSim)" (withMaxSuccess 1000 prop_threadId_order_order_Sim)
46
50
, testProperty " forkIO order (IOSim)" (withMaxSuccess 1000 prop_fork_order_ST)
47
51
, testProperty " order (IO)" (expectFailure prop_fork_order_IO)
@@ -852,6 +856,36 @@ prop_stm_referenceM (SomeTerm _tyrep t) = do
852
856
return (r1 === r2)
853
857
854
858
859
+ -- | Check that 'timeout' does not deadlock when executed with asynchronous
860
+ -- exceptions uninterruptibly masked.
861
+ --
862
+ prop_timeout_no_deadlockM :: forall m . ( MonadFork m , MonadSTM m , MonadTimer m , MonadMask m )
863
+ => m Bool
864
+ prop_timeout_no_deadlockM = do
865
+ v <- registerDelay' 0.01
866
+ r <- uninterruptibleMask_ $ timeout 0.02 $ do
867
+ atomically $ do
868
+ readTVar v >>= check
869
+ return True
870
+ case r of
871
+ Nothing -> return False
872
+ Just b -> return b
873
+ where
874
+ -- Like 'registerDelay', but does not require threaded RTS in the @m ~ IO@
875
+ -- case.
876
+ registerDelay' :: DiffTime -> m (StrictTVar m Bool )
877
+ registerDelay' delta = do
878
+ v <- newTVarIO False
879
+ _ <- forkIO $ do
880
+ threadDelay delta
881
+ atomically (writeTVar v True )
882
+ return v
883
+
884
+ prop_timeout_no_deadlock_Sim :: Bool
885
+ prop_timeout_no_deadlock_Sim = runSimOrThrow prop_timeout_no_deadlockM
886
+
887
+ prop_timeout_no_deadlock_IO :: Property
888
+ prop_timeout_no_deadlock_IO = ioProperty prop_timeout_no_deadlockM
855
889
856
890
--
857
891
-- Utils
0 commit comments