packages feed

threads 0.5.1.2 → 0.5.1.3

raw patch · 5 files changed

+131/−128 lines, 5 filesdep −base-unicode-symbolsdep ~basePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies removed: base-unicode-symbols

Dependency ranges changed: base

API changes (from Hackage documentation)

- Control.Concurrent.Thread: forkIO :: IO α -> IO (ThreadId, IO (Result α))
+ Control.Concurrent.Thread: forkIO :: IO a -> IO (ThreadId, IO (Result a))
- Control.Concurrent.Thread: forkIOWithUnmask :: ((forall β. IO β -> IO β) -> IO α) -> IO (ThreadId, IO (Result α))
+ Control.Concurrent.Thread: forkIOWithUnmask :: ((forall b. IO b -> IO b) -> IO a) -> IO (ThreadId, IO (Result a))
- Control.Concurrent.Thread: forkOS :: IO α -> IO (ThreadId, IO (Result α))
+ Control.Concurrent.Thread: forkOS :: IO a -> IO (ThreadId, IO (Result a))
- Control.Concurrent.Thread: forkOn :: Int -> IO α -> IO (ThreadId, IO (Result α))
+ Control.Concurrent.Thread: forkOn :: Int -> IO a -> IO (ThreadId, IO (Result a))
- Control.Concurrent.Thread: forkOnWithUnmask :: Int -> ((forall β. IO β -> IO β) -> IO α) -> IO (ThreadId, IO (Result α))
+ Control.Concurrent.Thread: forkOnWithUnmask :: Int -> ((forall b. IO b -> IO b) -> IO a) -> IO (ThreadId, IO (Result a))
- Control.Concurrent.Thread: result :: Result α -> IO α
+ Control.Concurrent.Thread: result :: Result a -> IO a
- Control.Concurrent.Thread: type Result α = Either SomeException α
+ Control.Concurrent.Thread: type Result a = Either SomeException a
- Control.Concurrent.Thread.Group: forkIO :: ThreadGroup -> IO α -> IO (ThreadId, IO (Result α))
+ Control.Concurrent.Thread.Group: forkIO :: ThreadGroup -> IO a -> IO (ThreadId, IO (Result a))
- Control.Concurrent.Thread.Group: forkIOWithUnmask :: ThreadGroup -> ((forall β. IO β -> IO β) -> IO α) -> IO (ThreadId, IO (Result α))
+ Control.Concurrent.Thread.Group: forkIOWithUnmask :: ThreadGroup -> ((forall b. IO b -> IO b) -> IO a) -> IO (ThreadId, IO (Result a))
- Control.Concurrent.Thread.Group: forkOS :: ThreadGroup -> IO α -> IO (ThreadId, IO (Result α))
+ Control.Concurrent.Thread.Group: forkOS :: ThreadGroup -> IO a -> IO (ThreadId, IO (Result a))
- Control.Concurrent.Thread.Group: forkOn :: Int -> ThreadGroup -> IO α -> IO (ThreadId, IO (Result α))
+ Control.Concurrent.Thread.Group: forkOn :: Int -> ThreadGroup -> IO a -> IO (ThreadId, IO (Result a))
- Control.Concurrent.Thread.Group: forkOnWithUnmask :: Int -> ThreadGroup -> ((forall β. IO β -> IO β) -> IO α) -> IO (ThreadId, IO (Result α))
+ Control.Concurrent.Thread.Group: forkOnWithUnmask :: Int -> ThreadGroup -> ((forall b. IO b -> IO b) -> IO a) -> IO (ThreadId, IO (Result a))

Files

Control/Concurrent/Raw.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE UnicodeSyntax, NoImplicitPrelude, MagicHash, UnboxedTuples #-}+{-# LANGUAGE NoImplicitPrelude, MagicHash, UnboxedTuples #-}  module Control.Concurrent.Raw ( rawForkIO, rawForkOn ) where @@ -11,11 +11,11 @@ -- handler: saves a bit of time when we will be installing our own -- exception handler. {-# INLINE rawForkIO #-}-rawForkIO ∷ IO () → IO ThreadId-rawForkIO action = IO $ \s →-   case (fork# action s) of (# s1, tid #) → (# s1, ThreadId tid #)+rawForkIO :: IO () -> IO ThreadId+rawForkIO action = IO $ \s ->+   case (fork# action s) of (# s1, tid #) -> (# s1, ThreadId tid #)  {-# INLINE rawForkOn #-}-rawForkOn ∷ Int → IO () → IO ThreadId-rawForkOn (I# cpu) action = IO $ \s →-   case (forkOn# cpu action s) of (# s1, tid #) → (# s1, ThreadId tid #)+rawForkOn :: Int -> IO () -> IO ThreadId+rawForkOn (I# cpu) action = IO $ \s ->+   case (forkOn# cpu action s) of (# s1, tid #) -> (# s1, ThreadId tid #)
Control/Concurrent/Thread.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, NoImplicitPrelude, UnicodeSyntax, RankNTypes, ImpredicativeTypes #-}+{-# LANGUAGE CPP, NoImplicitPrelude, RankNTypes, ImpredicativeTypes #-}  #if __GLASGOW_HASKELL__ >= 701 {-# LANGUAGE Trustworthy #-}@@ -65,13 +65,10 @@ import Control.Exception            ( SomeException, try, throwIO, mask ) import Control.Monad                ( return, (>>=) ) import Data.Either                  ( Either(..), either )-import Data.Function                ( ($) )+import Data.Function                ( (.), ($) ) import Data.Int                     ( Int ) import System.IO                    ( IO ) --- from base-unicode-symbols:-import Data.Function.Unicode        ( (∘) )- -- from threads: import Control.Concurrent.Raw       ( rawForkIO, rawForkOn ) @@ -83,51 +80,54 @@ -- | Like @Control.Concurrent.'Control.Concurrent.forkIO'@ but returns -- a computation that when executed blocks until the thread terminates -- then returns the final value of the thread.-forkIO ∷ IO α → IO (ThreadId, IO (Result α))+forkIO :: IO a -> IO (ThreadId, IO (Result a)) forkIO = fork rawForkIO  -- | Like @Control.Concurrent.'Control.Concurrent.forkOS'@ but returns -- a computation that when executed blocks until the thread terminates -- then returns the final value of the thread.-forkOS ∷ IO α → IO (ThreadId, IO (Result α))+forkOS :: IO a -> IO (ThreadId, IO (Result a)) forkOS = fork Control.Concurrent.forkOS  -- | Like @Control.Concurrent.'Control.Concurrent.forkOn'@ but returns -- a computation that when executed blocks until the thread terminates -- then returns the final value of the thread.-forkOn ∷ Int → IO α → IO (ThreadId, IO (Result α))-forkOn = fork ∘ rawForkOn+forkOn :: Int -> IO a -> IO (ThreadId, IO (Result a))+forkOn = fork . rawForkOn  -- | Like @Control.Concurrent.'Control.Concurrent.forkIOWithUnmask'@ but returns -- a computation that when executed blocks until the thread terminates -- then returns the final value of the thread.-forkIOWithUnmask ∷ ((∀ β. IO β → IO β) → IO α) → IO (ThreadId, IO (Result α))+forkIOWithUnmask+    :: ((forall b. IO b -> IO b) -> IO a) -> IO (ThreadId, IO (Result a)) forkIOWithUnmask = forkWithUnmask Control.Concurrent.forkIOWithUnmask  -- | Like @Control.Concurrent.'Control.Concurrent.forkOnWithUnmask'@ but returns -- a computation that when executed blocks until the thread terminates -- then returns the final value of the thread.-forkOnWithUnmask ∷ Int → ((∀ β. IO β → IO β) → IO α) → IO (ThreadId, IO (Result α))-forkOnWithUnmask = forkWithUnmask ∘ Control.Concurrent.forkOnWithUnmask+forkOnWithUnmask+    :: Int -> ((forall b. IO b -> IO b) -> IO a) -> IO (ThreadId, IO (Result a))+forkOnWithUnmask = forkWithUnmask . Control.Concurrent.forkOnWithUnmask   -------------------------------------------------------------------------------- -- Utils -------------------------------------------------------------------------------- -fork ∷ (IO () → IO ThreadId) → (IO α → IO (ThreadId, IO (Result α)))-fork doFork = \a → do-  res ← newEmptyMVar-  tid ← mask $ \restore → doFork $ try (restore a) >>= putMVar res+fork :: (IO () -> IO ThreadId) -> (IO a -> IO (ThreadId, IO (Result a)))+fork doFork = \a -> do+  res <- newEmptyMVar+  tid <- mask $ \restore -> doFork $ try (restore a) >>= putMVar res   return (tid, readMVar res) -forkWithUnmask ∷ (((∀ β. IO β → IO β) → IO ()) → IO ThreadId)-               →  ((∀ β. IO β → IO β) → IO α)  → IO (ThreadId, IO (Result α))-forkWithUnmask doForkWithUnmask = \f → do-  res ← newEmptyMVar-  tid ← mask $ \restore →-          doForkWithUnmask $ \unmask →-            try (restore $ f unmask) >>= putMVar res+forkWithUnmask+    :: (((forall b. IO b -> IO b) -> IO ()) -> IO ThreadId)+    ->  ((forall b. IO b -> IO b) -> IO a)  -> IO (ThreadId, IO (Result a))+forkWithUnmask doForkWithUnmask = \f -> do+  res <- newEmptyMVar+  tid <- mask $ \restore ->+           doForkWithUnmask $ \unmask ->+             try (restore $ f unmask) >>= putMVar res   return (tid, readMVar res)  @@ -137,10 +137,10 @@  -- | A result of a thread is either some exception that was thrown in the thread -- and wasn't catched or the actual value that was returned by the thread.-type Result α = Either SomeException α+type Result a = Either SomeException a  -- | Retrieve the actual value from the result. -- -- When the result is 'SomeException' the exception is thrown.-result ∷ Result α → IO α+result :: Result a -> IO a result = either throwIO return
Control/Concurrent/Thread/Group.hs view
@@ -1,7 +1,6 @@ {-# LANGUAGE CPP            , DeriveDataTypeable            , NoImplicitPrelude-           , UnicodeSyntax            , ImpredicativeTypes            , RankNTypes #-} @@ -60,18 +59,15 @@ import Control.Concurrent.MVar          ( newEmptyMVar, putMVar, readMVar ) import Control.Exception                ( try, mask ) import Control.Monad                    ( return, (>>=), when )-import Data.Function                    ( ($) )+import Data.Function                    ( (.), ($) ) import Data.Functor                     ( fmap ) import Data.Eq                          ( Eq )+import Data.Ord                         ( (>=) ) import Data.Int                         ( Int ) import Data.Typeable                    ( Typeable ) import Prelude                          ( ($!), (+), subtract ) import System.IO                        ( IO ) --- from base-unicode-symbols:-import Data.Ord.Unicode                 ( (≥) )-import Data.Function.Unicode            ( (∘) )- -- from stm: import Control.Concurrent.STM.TVar      ( TVar, newTVarIO, readTVar, writeTVar ) import Control.Concurrent.STM           ( STM, atomically, retry )@@ -115,7 +111,7 @@ newtype ThreadGroup = ThreadGroup (TVar Int) deriving (Eq, Typeable)  -- | Create an empty group of threads.-new ∷ IO ThreadGroup+new :: IO ThreadGroup new = fmap ThreadGroup $ newTVarIO 0  {-| Yield a transaction that returns the number of running threads in the@@ -124,18 +120,18 @@ Note that because this function yields a 'STM' computation, the returned number is guaranteed to be consistent inside the transaction. -}-nrOfRunning ∷ ThreadGroup → STM Int+nrOfRunning :: ThreadGroup -> STM Int nrOfRunning (ThreadGroup numThreadsTV) = readTVar numThreadsTV  -- | Block until all threads in the group have terminated. -- -- Note that: @wait = 'waitN' 1@.-wait ∷ ThreadGroup → IO ()+wait :: ThreadGroup -> IO () wait = waitN 1  -- | Block until there are fewer than @N@ running threads in the group.-waitN ∷ Int -> ThreadGroup → IO ()-waitN i tg = atomically $ nrOfRunning tg >>= \n → when (n ≥ i) retry+waitN :: Int -> ThreadGroup -> IO ()+waitN i tg = atomically $ nrOfRunning tg >>= \n -> when (n >= i) retry   --------------------------------------------------------------------------------@@ -144,59 +140,72 @@  -- | Same as @Control.Concurrent.Thread.'Thread.forkIO'@ but additionaly adds -- the thread to the group.-forkIO ∷ ThreadGroup → IO α → IO (ThreadId, IO (Result α))+forkIO :: ThreadGroup -> IO a -> IO (ThreadId, IO (Result a)) forkIO = fork rawForkIO  -- | Same as @Control.Concurrent.Thread.'Thread.forkOS'@ but additionaly adds -- the thread to the group.-forkOS ∷ ThreadGroup → IO α → IO (ThreadId, IO (Result α))+forkOS :: ThreadGroup -> IO a -> IO (ThreadId, IO (Result a)) forkOS = fork Control.Concurrent.forkOS  -- | Same as @Control.Concurrent.Thread.'Thread.forkOn'@ but -- additionaly adds the thread to the group.-forkOn ∷ Int → ThreadGroup → IO α → IO (ThreadId, IO (Result α))-forkOn = fork ∘ rawForkOn+forkOn :: Int -> ThreadGroup -> IO a -> IO (ThreadId, IO (Result a))+forkOn = fork . rawForkOn  -- | Same as @Control.Concurrent.Thread.'Thread.forkIOWithUnmask'@ but -- additionaly adds the thread to the group.-forkIOWithUnmask ∷ ThreadGroup → ((∀ β. IO β → IO β) → IO α) → IO (ThreadId, IO (Result α))+forkIOWithUnmask+    :: ThreadGroup+    -> ((forall b. IO b -> IO b) -> IO a)+    -> IO (ThreadId, IO (Result a)) forkIOWithUnmask = forkWithUnmask Control.Concurrent.forkIOWithUnmask  -- | Like @Control.Concurrent.Thread.'Thread.forkOnWithUnmask'@ but -- additionaly adds the thread to the group.-forkOnWithUnmask ∷ Int → ThreadGroup → ((∀ β. IO β → IO β) → IO α) → IO (ThreadId, IO (Result α))-forkOnWithUnmask = forkWithUnmask ∘ Control.Concurrent.forkOnWithUnmask+forkOnWithUnmask+    :: Int+    -> ThreadGroup+    -> ((forall b. IO b -> IO b) -> IO a)+    -> IO (ThreadId, IO (Result a))+forkOnWithUnmask = forkWithUnmask . Control.Concurrent.forkOnWithUnmask   -------------------------------------------------------------------------------- -- Utils -------------------------------------------------------------------------------- -fork ∷ (IO () → IO ThreadId) → ThreadGroup → IO α → IO (ThreadId, IO (Result α))+fork :: (IO () -> IO ThreadId)+     -> ThreadGroup+     -> IO a+     -> IO (ThreadId, IO (Result a)) fork doFork (ThreadGroup numThreadsTV) a = do-  res ← newEmptyMVar-  tid ← mask $ \restore → do+  res <- newEmptyMVar+  tid <- mask $ \restore -> do     atomically $ modifyTVar numThreadsTV (+ 1)     doFork $ do       try (restore a) >>= putMVar res       atomically $ modifyTVar numThreadsTV (subtract 1)   return (tid, readMVar res) -forkWithUnmask ∷ (((∀ β. IO β → IO β) → IO ()) → IO ThreadId)-               → ThreadGroup → ((∀ β. IO β → IO β) → IO α) → IO (ThreadId, IO (Result α))-forkWithUnmask doForkWithUnmask = \(ThreadGroup numThreadsTV) f → do-  res ← newEmptyMVar-  tid ← mask $ \restore → do+forkWithUnmask+    :: (((forall b. IO b -> IO b) -> IO ()) -> IO ThreadId)+    -> ThreadGroup+    -> ((forall b. IO b -> IO b) -> IO a)+    -> IO (ThreadId, IO (Result a))+forkWithUnmask doForkWithUnmask = \(ThreadGroup numThreadsTV) f -> do+  res <- newEmptyMVar+  tid <- mask $ \restore -> do     atomically $ modifyTVar numThreadsTV (+ 1)-    doForkWithUnmask $ \unmask → do+    doForkWithUnmask $ \unmask -> do       try (restore $ f unmask) >>= putMVar res       atomically $ modifyTVar numThreadsTV (subtract 1)   return (tid, readMVar res)  -- | Strictly modify the contents of a 'TVar'.-modifyTVar ∷ TVar α → (α → α) → STM ()-modifyTVar tv f = readTVar tv >>= writeTVar tv ∘! f+modifyTVar :: TVar a -> (a -> a) -> STM ()+modifyTVar tv f = readTVar tv >>= writeTVar tv .! f  -- | Strict function composition-(∘!) ∷ (β → γ) → (α → β) → (α → γ)-f ∘! g = \x → f $! g x+(.!) :: (b -> c) -> (a -> b) -> (a -> c)+f .! g = \x -> f $! g x
test/test.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE NoImplicitPrelude, UnicodeSyntax, DeriveDataTypeable #-}+{-# LANGUAGE NoImplicitPrelude, DeriveDataTypeable, ImpredicativeTypes #-}  module Main where @@ -17,7 +17,7 @@ import Data.Bool          ( Bool(False, True) ) import Data.Eq            ( Eq, (==) ) import Data.Either        ( either )-import Data.Function      ( ($), id, const, flip )+import Data.Function      ( (.), ($), id, const, flip ) import Data.Functor       ( Functor(fmap), (<$>) ) import Data.Int           ( Int ) import Data.Maybe         ( Maybe, maybe )@@ -26,11 +26,7 @@ import System.Timeout     ( timeout ) import System.IO          ( IO ) import Text.Show          ( Show )---- from base-unicode-symbols:-import Data.Eq.Unicode       ( (≡) )-import Prelude.Unicode       ( (⋅) )-import Data.Function.Unicode ( (∘) )+import Prelude            ( (*) )  -- from concurrent-extra: import qualified Control.Concurrent.Lock as Lock@@ -59,10 +55,10 @@ -- Tests -------------------------------------------------------------------------------- -main ∷ IO ()+main :: IO () main = defaultMain tests -tests ∷ [Test]+tests :: [Test] tests = [ testGroup "Thread" $           [ testGroup "forkIO" $             [ testCase "wait"            $ test_wait            Thread.forkIO@@ -126,22 +122,22 @@             , testCase "sync exception"    $ wrapIOWithUnmask test_sync_exception             , testCase "async exception"   $ wrapIOWithUnmask test_async_exception -            , testCase "group single wait" $ test_group_single_wait $ wrapUnmask ∘ ThreadGroup.forkIOWithUnmask-            , testCase "group nrOfRunning" $ test_group_nrOfRunning $ wrapUnmask ∘ ThreadGroup.forkIOWithUnmask+            , testCase "group single wait" $ test_group_single_wait $ wrapUnmask . ThreadGroup.forkIOWithUnmask+            , testCase "group nrOfRunning" $ test_group_nrOfRunning $ wrapUnmask . ThreadGroup.forkIOWithUnmask             ]           , testGroup "forkOnWithUnmask 0" $             [ testCase "wait"              $ wrapOnWithUnmask test_wait             , testCase "sync exception"    $ wrapOnWithUnmask test_sync_exception             , testCase "async exception"   $ wrapOnWithUnmask test_async_exception -            , testCase "group single wait" $ test_group_single_wait $ wrapUnmask ∘ ThreadGroup.forkOnWithUnmask 0-            , testCase "group nrOfRunning" $ test_group_nrOfRunning $ wrapUnmask ∘ ThreadGroup.forkOnWithUnmask 0+            , testCase "group single wait" $ test_group_single_wait $ wrapUnmask . ThreadGroup.forkOnWithUnmask 0+            , testCase "group nrOfRunning" $ test_group_nrOfRunning $ wrapUnmask . ThreadGroup.forkOnWithUnmask 0             ]           ]         ]  -- Exactly 1 moment. Currently equal to 0.005 seconds.-a_moment ∷ Int+a_moment :: Int a_moment = 5000  @@ -149,48 +145,48 @@ -- General properties -------------------------------------------------------------------------------- -type Fork α = IO α → IO (ThreadId, IO (Result α))+type Fork a = IO a -> IO (ThreadId, IO (Result a)) -wrapUnmask ∷ ((β → α) → t) → α → t+wrapUnmask :: ((b -> a) -> t) -> a -> t wrapUnmask forkWithUnmask = \m -> forkWithUnmask $ const m -test_wait ∷ Fork () → Assertion-test_wait fork = assert $ fmap isJustTrue $ timeout (10 ⋅ a_moment) $ do-  r ← newIORef False-  (_, wait) ← fork $ do-    threadDelay $ 2 ⋅ a_moment+test_wait :: Fork () -> Assertion+test_wait fork = assert $ fmap isJustTrue $ timeout (10 * a_moment) $ do+  r <- newIORef False+  (_, wait) <- fork $ do+    threadDelay $ 2 * a_moment     writeIORef r True-  _ ← wait+  _ <- wait   readIORef r -test_maskingState ∷ Fork Bool → Assertion-test_maskingState fork = do (_, wait) ← mask_ $ fork $+test_maskingState :: Fork Bool -> Assertion+test_maskingState fork = do (_, wait) <- mask_ $ fork $                               (MaskedInterruptible ==) <$> getMaskingState                             wait >>= result >>= assert -test_sync_exception ∷ Fork () → Assertion+test_sync_exception :: Fork () -> Assertion test_sync_exception fork = assert $ do-  (_, wait) ← fork $ throwIO MyException+  (_, wait) <- fork $ throwIO MyException   waitForException MyException wait -waitForException ∷ (Exception e, Eq e) ⇒ e → IO (Result α) → IO Bool-waitForException e wait = wait <$$> either (justEq e ∘ fromException)-                                           (const False)+waitForException :: (Exception e, Eq e) => e -> IO (Result a) -> IO Bool+waitForException e wait = wait <&> either (justEq e . fromException)+                                          (const False) -test_async_exception ∷ Fork () → Assertion+test_async_exception :: Fork () -> Assertion test_async_exception fork = assert $ do-  l ← Lock.newAcquired-  (tid, wait) ← fork $ Lock.acquire l+  l <- Lock.newAcquired+  (tid, wait) <- fork $ Lock.acquire l   throwTo tid MyException   waitForException MyException wait  data MyException = MyException deriving (Show, Eq, Typeable) instance Exception MyException -test_killThread ∷ Fork () → Assertion+test_killThread :: Fork () -> Assertion test_killThread fork = assert $ do-  l ← Lock.newAcquired-  (tid, wait) ← fork $ Lock.acquire l+  l <- Lock.newAcquired+  (tid, wait) <- fork $ Lock.acquire l   killThread tid   waitForException ThreadKilled wait @@ -199,46 +195,46 @@ -- ThreadGroup -------------------------------------------------------------------------------- -wrapIO ∷ (Fork α → IO β) → IO β+wrapIO :: (Fork a -> IO b) -> IO b wrapIO = wrap ThreadGroup.forkIO -wrapOS ∷ (Fork α → IO β) → IO β+wrapOS :: (Fork a -> IO b) -> IO b wrapOS = wrap ThreadGroup.forkOS -wrapOn_0 ∷ (Fork α → IO β) → IO β+wrapOn_0 :: (Fork a -> IO b) -> IO b wrapOn_0 = wrap $ ThreadGroup.forkOn 0 -wrapIOWithUnmask ∷ (Fork α → IO β) → IO β+wrapIOWithUnmask :: (Fork a -> IO b) -> IO b wrapIOWithUnmask = wrap $ \tg m -> ThreadGroup.forkIOWithUnmask tg $ const m -wrapOnWithUnmask ∷ (Fork α → IO β) → IO β+wrapOnWithUnmask :: (Fork a -> IO b) -> IO b wrapOnWithUnmask = wrap $ \tg m -> ThreadGroup.forkOnWithUnmask 0 tg $ const m -wrap ∷ (ThreadGroup → Fork α) → (Fork α → IO β) → IO β-wrap doFork test = ThreadGroup.new >>= test ∘ doFork+wrap :: (ThreadGroup -> Fork a) -> (Fork a -> IO b) -> IO b+wrap doFork test = ThreadGroup.new >>= test . doFork -test_group_single_wait ∷ (ThreadGroup → Fork ()) → Assertion-test_group_single_wait doFork = assert $ fmap isJustTrue $ timeout (10 ⋅ a_moment) $ do-  tg ← ThreadGroup.new-  r ← newIORef False-  _ ← doFork tg $ do-    threadDelay $ 2 ⋅ a_moment+test_group_single_wait :: (ThreadGroup -> Fork ()) -> Assertion+test_group_single_wait doFork = assert $ fmap isJustTrue $ timeout (10 * a_moment) $ do+  tg <- ThreadGroup.new+  r <- newIORef False+  _ <- doFork tg $ do+    threadDelay $ 2 * a_moment     writeIORef r True-  _ ← ThreadGroup.wait tg+  _ <- ThreadGroup.wait tg   readIORef r -test_group_nrOfRunning ∷ (ThreadGroup → Fork ()) → Assertion-test_group_nrOfRunning doFork = assert $ fmap isJustTrue $ timeout (10 ⋅ a_moment) $ do-  tg ← ThreadGroup.new-  l ← Lock.newAcquired+test_group_nrOfRunning :: (ThreadGroup -> Fork ()) -> Assertion+test_group_nrOfRunning doFork = assert $ fmap isJustTrue $ timeout (10 * a_moment) $ do+  tg <- ThreadGroup.new+  l <- Lock.newAcquired   replicateM_ n $ doFork tg $ Lock.acquire l-  true ← fmap (≡ n) $ (atomically $ ThreadGroup.nrOfRunning tg ∷ IO Int)+  true <- fmap (== n) $ (atomically $ ThreadGroup.nrOfRunning tg :: IO Int)   Lock.release l   return true     where       -- Don't set this number too big otherwise forkOS might throw an exception       -- indicating that too many OS threads have been created:-      n ∷ Int+      n :: Int       n = 100  @@ -247,13 +243,13 @@ --------------------------------------------------------------------------------  -- | Check if the given value equals 'Just' 'True'.-isJustTrue ∷ Maybe Bool → Bool+isJustTrue :: Maybe Bool -> Bool isJustTrue = maybe False id  -- | Check if the given value in the 'Maybe' equals the given reference value.-justEq ∷ Eq α ⇒ α → Maybe α → Bool-justEq = maybe False ∘ (≡)+justEq :: Eq a => a -> Maybe a -> Bool+justEq = maybe False . (==)  -- | A flipped '<$>'.-(<$$>) ∷ Functor f ⇒ f α → (α → β) → f β-(<$$>) = flip (<$>)+(<&>) :: (Functor f) => f a -> (a -> b) -> f b+(<&>) = flip (<$>)
threads.cabal view
@@ -1,5 +1,5 @@ name:          threads-version:       0.5.1.2+version:       0.5.1.3 cabal-version: >= 1.9.2 build-type:    Custom stability:     experimental@@ -45,8 +45,7 @@ -------------------------------------------------------------------------------  library-  build-depends: base                 >= 4.4   && < 4.8-               , base-unicode-symbols >= 0.1.1 && < 0.3+  build-depends: base                 >= 4.4   && < 4.9                , stm                  >= 2.1   && < 2.5   exposed-modules: Control.Concurrent.Thread                  , Control.Concurrent.Thread.Group@@ -62,8 +61,7 @@   ghc-options:    -Wall -threaded    build-depends: threads-               , base                 >= 4.4   && < 4.8-               , base-unicode-symbols >= 0.1.1 && < 0.3+               , base                 >= 4.4   && < 4.9                , stm                  >= 2.1   && < 2.5                , concurrent-extra     >= 0.5.1 && < 0.8                , HUnit                >= 1.2.2 && < 1.3