{-# OPTIONS_GHC -F -pgmF htfpp #-}
module Main where
import BasePrelude
import Test.Framework
import Test.QuickCheck.Instances
import qualified SlaveThread as S
import qualified Control.Concurrent.SSem as SSem
main =
htfMain $ htf_thisModulesTests
test_forkedThreadsRunFine =
replicateM 100000 $ do
var <- newMVar 0
let increment = modifyMVar_ var (return . succ)
semaphore <- SSem.new 0
S.fork $ do
increment
semaphore' <- SSem.new (-1)
S.fork $ do
increment
SSem.signal semaphore'
S.fork $ do
increment
SSem.signal semaphore'
SSem.wait semaphore'
SSem.signal semaphore
SSem.wait semaphore
assertEqual 3 =<< readMVar var
test_killingAThreadKillsDeepSlaves =
replicateM 100000 $ do
var <- newMVar 0
semaphore <- SSem.new 0
thread <-
S.forkFinally (SSem.signal semaphore) $ do
join $ forkWait $ do
join $ forkWait $ do
w <- forkWait $ do
threadDelay $ 10^6
modifyMVar_ var (return . succ)
threadDelay $ 10^6
modifyMVar_ var (return . succ)
w
killThread thread
SSem.wait semaphore
assertEqual 0 =<< readMVar var
test_dyingNormallyKillsSlaves =
replicateM 100000 $ do
var <- newIORef 0
let increment = modifyIORef var (+1)
semaphore <- SSem.new 0
S.forkFinally (SSem.signal semaphore) $ do
S.fork $ do
threadDelay $ 10^6
increment
S.fork $ do
threadDelay $ 10^6
increment
SSem.wait semaphore
assertEqual 0 =<< readIORef var
test_finalizationOrder =
replicateM 100000 $ do
var <- newMVar []
semaphore <- SSem.new 0
S.forkFinally (uninterruptibleMask_ (modifyMVar_ var (return . (1:)) >> SSem.signal semaphore)) $ do
semaphore' <- SSem.new 0
S.forkFinally (uninterruptibleMask_ (modifyMVar_ var (return . (2:)) >> SSem.signal semaphore')) $ do
S.forkFinally (uninterruptibleMask_ (modifyMVar_ var (return . (3:)))) $ return ()
S.forkFinally (uninterruptibleMask_ (modifyMVar_ var (return . (3:)))) $ return ()
SSem.wait semaphore'
SSem.wait semaphore
assertEqual [1,2,3,3] =<< readMVar var
test_exceptionsDontGetLost =
replicateM 100000 $ do
assertThrowsSomeIO $ do
S.fork $ do
S.fork $ do
error "!"
threadDelay $ 10^6
threadDelay $ 10^6
forkWait :: IO a -> IO (IO ())
forkWait io =
do
v <- newEmptyMVar
S.fork $ do
r <- try io
putMVar v ()
either (throwIO :: SomeException -> IO a) return r
return $ takeMVar v