packages feed

concurrent-extra 0.7.0.1 → 0.7.0.2

raw patch · 17 files changed

+676/−25 lines, 17 filesdep ~basePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base

API changes (from Hackage documentation)

Files

Control/Concurrent/Broadcast.hs view
@@ -205,6 +205,3 @@ -- | Set a broadcast to the \"silent\" state. silence ∷ Broadcast α → IO () silence (Broadcast mv) = purelyModifyMVar mv $ either Left $ const $ Left []----- The End ---------------------------------------------------------------------
+ Control/Concurrent/Broadcast/Test.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE NoImplicitPrelude+           , UnicodeSyntax+  #-}++module Control.Concurrent.Broadcast.Test ( tests ) where+++-------------------------------------------------------------------------------+-- Imports+-------------------------------------------------------------------------------++-- from base:+import Control.Concurrent ( )++-- from base-unicode-symbols:+import Prelude.Unicode       ( )++-- from concurrent-extra:+import qualified Control.Concurrent.Broadcast as Broadcast ( )+import TestUtils ( )++-- from HUnit:+import Test.HUnit (  )++-- from test-framework:+import Test.Framework  ( Test )++-- from test-framework-hunit:+import Test.Framework.Providers.HUnit ( )+++-------------------------------------------------------------------------------+-- Tests for Broadcast+-------------------------------------------------------------------------------++tests ∷ [Test]+tests = []
Control/Concurrent/Event.hs view
@@ -178,6 +178,3 @@ -} clear ∷ Event → IO () clear = Broadcast.silence ∘ evBroadcast----- The End ---------------------------------------------------------------------
+ Control/Concurrent/Event/Test.hs view
@@ -0,0 +1,108 @@+{-# LANGUAGE CPP, NoImplicitPrelude, UnicodeSyntax, ScopedTypeVariables #-}++module Control.Concurrent.Event.Test ( tests ) where++-------------------------------------------------------------------------------+-- Imports+-------------------------------------------------------------------------------++-- from base:+import Control.Exception  ( catch, throwTo, ErrorCall(..) )+import Control.Concurrent ( forkIO )+import Control.Monad      ( return, mapM_, replicateM, replicateM_ )+import Data.Function      ( ($) )+import Data.Int           ( Int )+import Data.Bool          ( not )+import Prelude            ( toInteger )++#if __GLASGOW_HASKELL__ < 700+import Prelude            ( fromInteger )+import Control.Monad      ( (>>=), (>>), fail )+#endif++-- from base-unicode-symbols:+import Prelude.Unicode ( (⋅) )++-- from concurrent-extra:+import qualified Control.Concurrent.Event as Event+import TestUtils++-- from HUnit:+import Test.HUnit ( Assertion, assert )++-- from test-framework:+import Test.Framework  ( Test )++-- from test-framework-hunit:+import Test.Framework.Providers.HUnit ( testCase )+++-------------------------------------------------------------------------------+-- Tests for Event+-------------------------------------------------------------------------------++tests ∷ [Test]+tests = [ testCase "set wait a"    $ test_event_1 1 1+        , testCase "set wait b"    $ test_event_1 5 1+        , testCase "set wait c"    $ test_event_1 1 5+        , testCase "set wait d"    $ test_event_1 5 5+        , testCase "conc set wait" $ test_event_2+        , testCase "multi wake"    $ test_event_3 10+        , testCase "exception"     $ test_event_4+        , testCase "wait timeout"  $ test_event_5+        , testCase "wait blocks"   $ test_event_6+        ]++-- Set an event 's' times then wait for it 'w' times. This should+-- terminate within a few moments.+test_event_1 ∷ Int → Int → Assertion+test_event_1 s w = assert $ within (10 ⋅ a_moment) $ do+  e ← Event.new+  replicateM_ s $ Event.set  e+  replicateM_ w $ Event.wait e++test_event_2 ∷ Assertion+test_event_2 = assert $ within (10 ⋅ a_moment) $ do+  e1 ← Event.new+  e2 ← Event.new+  _ ← forkIO $ do+    Event.wait e1+    Event.set  e2+  wait_a_moment+  Event.set  e1+  Event.wait e2++-- Waking multiple threads with a single Event.+test_event_3 ∷ Int → Assertion+test_event_3 n = assert $ within (10 ⋅ a_moment) $ do+  e1 ← Event.new+  es ← replicateM n $ do+    e2 ← Event.new+    _ ← forkIO $ do+      Event.wait e1+      Event.set  e2+    return e2+  wait_a_moment+  Event.set e1+  mapM_ Event.wait es++-- Exception handling while waiting for an Event.+test_event_4 ∷ Assertion+test_event_4 = assert $ within (10 ⋅ a_moment) $ do+  e1 ← Event.new+  e2 ← Event.new+  helperId ← forkIO $ catch (Event.wait e1) $ \(_ ∷ ErrorCall) → Event.set e2+  wait_a_moment+  throwTo helperId $ ErrorCall "Boo!"+  Event.wait e2++test_event_5 ∷ Assertion+test_event_5 = assert $ within (10 ⋅ a_moment) $ do+  e ← Event.new+  notTimedOut ← Event.waitTimeout e $ toInteger a_moment+  return $ not notTimedOut++test_event_6 ∷ Assertion+test_event_6 = assert $ notWithin (10 ⋅ a_moment) $ do+  e ← Event.new+  Event.wait e
Control/Concurrent/Lock.hs view
@@ -221,6 +221,3 @@ -} locked ∷ Lock → IO Bool locked = isEmptyMVar ∘ un----- The End ---------------------------------------------------------------------
+ Control/Concurrent/Lock/Test.hs view
@@ -0,0 +1,103 @@+{-# LANGUAGE CPP+           , NoImplicitPrelude+           , UnicodeSyntax+           , ScopedTypeVariables+  #-}++module Control.Concurrent.Lock.Test ( tests ) where++-------------------------------------------------------------------------------+-- Imports+-------------------------------------------------------------------------------++-- from base:+import Control.Concurrent ( forkIO )+import Control.Monad      ( return, (>>=), (>>) )+import Data.Bool          ( Bool(False, True), not, (&&) )+import Data.Function      ( ($) )+import Data.Functor       ( fmap )+import Data.IORef         ( newIORef, writeIORef, readIORef )++#if __GLASGOW_HASKELL__ < 700+import Prelude            ( fromInteger )+import Control.Monad      ( fail )+#endif++-- from base-unicode-symbols:+import Data.Function.Unicode ( (∘) )+import Prelude.Unicode       ( (⋅) )++-- from concurrent-extra:+import qualified Control.Concurrent.Lock as Lock+import TestUtils++-- from HUnit:+import Test.HUnit ( Assertion, assert )++-- from test-framework:+import Test.Framework  ( Test )++-- from test-framework-hunit:+import Test.Framework.Providers.HUnit ( testCase )+++-------------------------------------------------------------------------------+-- Tests for Lock+-------------------------------------------------------------------------------++tests ∷ [Test]+tests = [ testCase "acquire release"    test_lock_1+        , testCase "acquire acquire"    test_lock_2+        , testCase "new release"        test_lock_3+        , testCase "new unlocked"       test_lock_4+        , testCase "newAcquired locked" test_lock_5+        , testCase "acq rel unlocked"   test_lock_6+        , testCase "conc release"       test_lock_7+        , testCase "wait"               test_lock_8+        ]++test_lock_1 ∷ Assertion+test_lock_1 = assert $ within a_moment $ do+  l ← Lock.new+  Lock.acquire l+  Lock.release l++test_lock_2 ∷ Assertion+test_lock_2 = assert $ notWithin (10 ⋅ a_moment) $ do+  l ← Lock.new+  Lock.acquire l+  Lock.acquire l++test_lock_3 ∷ Assertion+test_lock_3 = assertException "" $ Lock.new >>= Lock.release++test_lock_4 ∷ Assertion+test_lock_4 = assert $ Lock.new >>= fmap not ∘ Lock.locked++test_lock_5 ∷ Assertion+test_lock_5 = assert $ Lock.newAcquired >>= Lock.locked++test_lock_6 ∷ Assertion+test_lock_6 = assert $ do+  l ← Lock.new+  Lock.acquire l+  Lock.release l+  fmap not $ Lock.locked l++test_lock_7 ∷ Assertion+test_lock_7 = assert ∘ within (10 ⋅ a_moment) $ do+  l ← Lock.newAcquired+  _ ← forkIO $ wait_a_moment >> Lock.release l+  Lock.acquire l++test_lock_8 ∷ Assertion+test_lock_8 = assert $ do+  ioRef ← newIORef False+  l ← Lock.newAcquired+  _ ← forkIO $ do wait_a_moment+                  writeIORef ioRef True+                  Lock.release l+  Lock.wait l+  set ← readIORef ioRef+  locked ← Lock.locked l+  return $ set && not locked
Control/Concurrent/RLock.hs view
@@ -296,6 +296,3 @@ -} state ∷ RLock → IO State state = fmap fst ∘ readMVar ∘ un----- The End ---------------------------------------------------------------------
+ Control/Concurrent/RLock/Test.hs view
@@ -0,0 +1,83 @@+{-# LANGUAGE CPP+           , NoImplicitPrelude+           , UnicodeSyntax+           , ScopedTypeVariables  +  #-}++module Control.Concurrent.RLock.Test ( tests ) where+++-------------------------------------------------------------------------------+-- Imports+-------------------------------------------------------------------------------++-- from base:+import Control.Concurrent ( forkIO, threadDelay )+import Control.Monad      ( replicateM_ )+import Data.Function      ( ($) )+import Data.Int           ( Int )++#if __GLASGOW_HASKELL__ < 700+import Prelude            ( fromInteger )+import Control.Monad      ( (>>=), fail, (>>) )+#endif++-- from base-unicode-symbols:+import Data.Function.Unicode ( (∘) )+import Prelude.Unicode       ( (⋅) )++-- from concurrent-extra:+import qualified Control.Concurrent.Event as Event ( new, set, wait )+import qualified Control.Concurrent.RLock as RLock+import TestUtils++-- from HUnit:+import Test.HUnit ( Assertion, assert )++-- from test-framework:+import Test.Framework  ( Test )++-- from test-framework-hunit:+import Test.Framework.Providers.HUnit ( testCase )+++-------------------------------------------------------------------------------+-- Tests for RLock+-------------------------------------------------------------------------------++tests ∷ [Test]+tests = [ testCase "recursive acquire"  $ test_rlock_1 5+        , testCase "conc acquire"       $ test_rlock_2+        ]++test_rlock_1 ∷ Int → Assertion+test_rlock_1 n = assert ∘ within (10 ⋅ a_moment) $ do+  l ← RLock.new+  replicateM_ n $ RLock.acquire l+  replicateM_ n $ RLock.release l++-- Tests for bug found by Felipe Lessa.+test_rlock_2 ∷ Assertion+test_rlock_2 = assert ∘ within (20 ⋅ a_moment) $ do+  rl           ← RLock.new+  t1_has_rlock ← Event.new+  t1_done      ← Event.new+  t2_done      ← Event.new++  -- Thread 1+  _ ← forkIO $ do+    RLock.acquire rl+    Event.set t1_has_rlock+    threadDelay $ 10 ⋅ a_moment+    RLock.release rl+    Event.set t1_done++  -- Thread 2+  _ ← forkIO $ do+    Event.wait t1_has_rlock+    RLock.acquire rl+    RLock.release rl+    Event.set t2_done++  Event.wait t1_done+  Event.wait t2_done
Control/Concurrent/ReadWriteLock.hs view
@@ -354,6 +354,3 @@  moduleName ∷ String moduleName = "Control.Concurrent.ReadWriteLock"----- The End --------------------------------------------------------------------
+ Control/Concurrent/ReadWriteLock/Test.hs view
@@ -0,0 +1,92 @@+{-# LANGUAGE CPP, NoImplicitPrelude , UnicodeSyntax #-}++module Control.Concurrent.ReadWriteLock.Test ( tests ) where+++-------------------------------------------------------------------------------+-- Imports+-------------------------------------------------------------------------------++-- from base:+import Control.Monad      ( (>>) )+import Control.Concurrent ( forkIO, threadDelay )+import Data.Function      ( ($) )++#if __GLASGOW_HASKELL__ < 700+import Prelude            ( fromInteger )+import Control.Monad      ( (>>=), fail )+#endif++-- from base-unicode-symbols:+import Prelude.Unicode    ( (⋅) )++-- from concurrent-extra:+import qualified Control.Concurrent.ReadWriteLock as RWLock+    ( new, acquireWrite, acquireRead, releaseWrite, releaseRead  )++import TestUtils ( within, a_moment )++import Utils ( void )++-- from HUnit:+import Test.HUnit ( Assertion, assert )++-- from test-framework:+import Test.Framework  ( Test )++-- from test-framework-hunit:+import Test.Framework.Providers.HUnit ( testCase )+++-------------------------------------------------------------------------------+-- Tests for ReadWriteLock+-------------------------------------------------------------------------------++tests ∷ [Test]+tests = [ testCase "test1" test1+        , testCase "test2" test2+        ]++test1 ∷ Assertion+test1 = assert $ within (10 ⋅ a_moment) $ do+          -- Create a new read-write-lock (in the "Free" state):+          rwl ← RWLock.new++          -- Put the read-write-lock in the "Write" state:+          RWLock.acquireWrite rwl++          -- Fork a thread that releases the write-lock after a moment:+          void $ forkIO $ threadDelay a_moment >> RWLock.releaseWrite rwl++          -- This blocks until the write-lock is released in the above thread.+          RWLock.acquireRead rwl++          -- Release the read-lock so that the read-write-lock can either be+          -- acquired again by 'acquireRead' or 'acquireWrite':+          RWLock.releaseRead rwl++          -- The read-write-lock should now be in the "Free" state so the+          -- following shouldn't deadlock:+          RWLock.acquireWrite rwl++test2 ∷ Assertion+test2 = assert $ within (10 ⋅ a_moment) $ do+          -- Create a new read-write-lock (in the "Free" state):+          rwl ← RWLock.new++          -- Put the read-write-lock in the "Read" state:+          RWLock.acquireRead rwl++          -- Fork a thread that releases the read-lock after a moment:+          void $ forkIO $ threadDelay a_moment >> RWLock.releaseRead rwl++          -- This blocks until the read-lock is released in the above thread.+          RWLock.acquireWrite rwl++          -- Release the write-lock so that the read-write-lock can either be+          -- acquired again by 'acquireRead' or 'acquireWrite':+          RWLock.releaseWrite rwl++          -- The read-write-lock should now be in the "Free" state so the+          -- following shouldn't deadlock:+          RWLock.acquireRead rwl
Control/Concurrent/ReadWriteVar.hs view
@@ -153,6 +153,3 @@ -} tryModify ∷ RWVar α → (α → IO (α, β)) → IO (Maybe β) tryModify (RWVar l r) = RWLock.tryWithWrite l ∘ modifyIORefM r----- The End --------------------------------------------------------------------
+ Control/Concurrent/ReadWriteVar/Test.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE NoImplicitPrelude+           , UnicodeSyntax+  #-}++module Control.Concurrent.ReadWriteVar.Test ( tests ) where+++-------------------------------------------------------------------------------+-- Imports+-------------------------------------------------------------------------------++-- from base:+import Control.Concurrent ( )++-- from base-unicode-symbols:+import Prelude.Unicode       ( )++-- from concurrent-extra:+import qualified Control.Concurrent.ReadWriteVar as RWVar ( )+import TestUtils ( )++-- from HUnit:+import Test.HUnit (  )++-- from test-framework:+import Test.Framework  ( Test )++-- from test-framework-hunit:+import Test.Framework.Providers.HUnit ( )+++-------------------------------------------------------------------------------+-- Tests for ReadWriteVar+-------------------------------------------------------------------------------++tests ∷ [Test]+tests = []
Control/Concurrent/STM/Lock.hs view
@@ -199,6 +199,3 @@ -} locked ∷ Lock → STM Bool locked = isEmptyTMVar ∘ un----- The End ---------------------------------------------------------------------
+ Control/Concurrent/STM/Lock/Test.hs view
@@ -0,0 +1,106 @@+{-# LANGUAGE CPP+           , NoImplicitPrelude+           , UnicodeSyntax+           , ScopedTypeVariables+  #-}++module Control.Concurrent.STM.Lock.Test ( tests ) where++-------------------------------------------------------------------------------+-- Imports+-------------------------------------------------------------------------------++-- from base:+import Control.Concurrent ( forkIO )+import Control.Monad      ( return, (>>=), (>>) )+import Data.Bool          ( Bool(False, True), not, (&&) )+import Data.Function      ( ($) )+import Data.Functor       ( fmap )+import Data.IORef         ( newIORef, writeIORef, readIORef )++#if __GLASGOW_HASKELL__ < 700+import Prelude            ( fromInteger )+import Control.Monad      ( fail )+#endif++-- from base-unicode-symbols:+import Data.Function.Unicode ( (∘) )+import Prelude.Unicode       ( (⋅) )++-- from stm:+import Control.Concurrent.STM ( atomically )++-- from concurrent-extra:+import qualified Control.Concurrent.STM.Lock as Lock+import TestUtils++-- from HUnit:+import Test.HUnit ( Assertion, assert )++-- from test-framework:+import Test.Framework  ( Test )++-- from test-framework-hunit:+import Test.Framework.Providers.HUnit ( testCase )+++-------------------------------------------------------------------------------+-- Tests for Lock+-------------------------------------------------------------------------------++tests ∷ [Test]+tests = [ testCase "acquire release"    test_lock_1+        , testCase "acquire acquire"    test_lock_2+        , testCase "new release"        test_lock_3+        , testCase "new unlocked"       test_lock_4+        , testCase "newAcquired locked" test_lock_5+        , testCase "acq rel unlocked"   test_lock_6+        , testCase "conc release"       test_lock_7+        , testCase "wait"               test_lock_8+        ]++test_lock_1 ∷ Assertion+test_lock_1 = assert $ within a_moment $ atomically $ do+  l ← Lock.new+  Lock.acquire l+  Lock.release l++test_lock_2 ∷ Assertion+test_lock_2 = assert $ notWithin (10 ⋅ a_moment) $ atomically $ do+  l ← Lock.new+  Lock.acquire l+  Lock.acquire l++test_lock_3 ∷ Assertion+test_lock_3 = assertException "" $ atomically $ Lock.new >>= Lock.release++test_lock_4 ∷ Assertion+test_lock_4 = assert $ atomically $ Lock.new >>= fmap not ∘ Lock.locked++test_lock_5 ∷ Assertion+test_lock_5 = assert $ atomically $ Lock.newAcquired >>= Lock.locked++test_lock_6 ∷ Assertion+test_lock_6 = assert $ atomically $ do+  l ← Lock.new+  Lock.acquire l+  Lock.release l+  fmap not $ Lock.locked l++test_lock_7 ∷ Assertion+test_lock_7 = assert ∘ within (10 ⋅ a_moment) $ do+  l ← atomically $ Lock.newAcquired+  _ ← forkIO $ wait_a_moment >> atomically (Lock.release l)+  atomically $ Lock.acquire l++test_lock_8 ∷ Assertion+test_lock_8 = assert $ do+  ioRef ← newIORef False+  l ← atomically Lock.newAcquired+  _ ← forkIO $ do wait_a_moment+                  writeIORef ioRef True+                  atomically $ Lock.release l+  atomically $ Lock.wait l+  set ← readIORef ioRef+  locked ← atomically $ Lock.locked l+  return $ set && not locked
+ TestUtils.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE CPP+           , NoImplicitPrelude+           , ScopedTypeVariables+           , UnicodeSyntax  +  #-}++module TestUtils where+++-------------------------------------------------------------------------------+-- Imports+-------------------------------------------------------------------------------++-- from base:+import Control.Applicative ( (<$>) )+import Control.Concurrent  ( threadDelay )+import Control.Exception   ( try, SomeException )+import Control.Monad       ( return )+import Data.Bool           ( Bool, not )+import Data.Either         ( Either(Left, Right) )+import Data.Int            ( Int )+import Data.Maybe          ( isJust )+import Prelude             ( String )+import System.IO           ( IO )+import System.Timeout      ( timeout )++#if __GLASGOW_HASKELL__ < 700+import Prelude             ( fromInteger )+import Control.Monad       ( (>>=), fail )+#endif++-- from HUnit:+import Test.HUnit          ( Assertion, assertFailure )+++-------------------------------------------------------------------------------+-- Utilities for testing+-------------------------------------------------------------------------------++-- Exactly 1 moment. Currently equal to 0.005 seconds.+a_moment ∷ Int+a_moment = 5000++wait_a_moment ∷ IO ()+wait_a_moment = threadDelay a_moment++-- True if the action 'a' evaluates within 't' μs.+within ∷ Int → IO α → IO Bool+within t a = isJust <$> timeout t a++notWithin ∷ Int → IO α → IO Bool+notWithin t a = not <$> within t a++assertException ∷ String → IO α → Assertion+assertException errMsg a = do e ← try a+                              case e of+                                Left (_ ∷ SomeException ) → return ()+                                Right _ → assertFailure errMsg+++-- The End ---------------------------------------------------------------------
concurrent-extra.cabal view
@@ -1,5 +1,5 @@ name:          concurrent-extra-version:       0.7.0.1+version:       0.7.0.2 cabal-version: >= 1.8 build-type:    Custom stability:     experimental@@ -10,7 +10,7 @@ copyright:     (c) 2010-2011 Bas van Dijk & Roel van Dijk license:       BSD3 license-file:  LICENSE-homepage:      https://github.com/basvandijk/concurrent-extra/+homepage:      https://github.com/basvandijk/concurrent-extra bug-reports:   https://github.com/basvandijk/concurrent-extra/issues category:      Concurrency synopsis:      Extra concurrency primitives@@ -50,7 +50,7 @@ -------------------------------------------------------------------------------  library-  build-depends: base                 >= 3       && < 4.5+  build-depends: base                 >= 3       && < 4.6                , base-unicode-symbols >= 0.1.1   && < 0.3                , stm                  >= 2.1.2.1 && < 2.3                , unbounded-delays     >= 0.1     && < 0.2@@ -80,7 +80,7 @@    ghc-options: -Wall -  build-depends: base                 >= 3       && < 4.5+  build-depends: base                 >= 3       && < 4.6                , base-unicode-symbols >= 0.1.1   && < 0.3                , stm                  >= 2.1.2.1 && < 2.3                , unbounded-delays     >= 0.1     && < 0.2
+ test.hs view
@@ -0,0 +1,45 @@+{-# LANGUAGE NoImplicitPrelude, UnicodeSyntax #-}++module Main where++-------------------------------------------------------------------------------+-- Imports+-------------------------------------------------------------------------------++-- from base:+import System.IO ( IO )++-- from concurrent-extra:+import qualified Control.Concurrent.Event.Test         as Event     ( tests )+import qualified Control.Concurrent.Lock.Test          as Lock      ( tests )+import qualified Control.Concurrent.STM.Lock.Test      as STM.Lock  ( tests )+import qualified Control.Concurrent.RLock.Test         as RLock     ( tests )+import qualified Control.Concurrent.Broadcast.Test     as Broadcast ( tests )+import qualified Control.Concurrent.ReadWriteLock.Test as RWLock    ( tests )+import qualified Control.Concurrent.ReadWriteVar.Test  as RWVar     ( tests )++-- from test-framework:+import Test.Framework ( Test, defaultMain, testGroup )+++-------------------------------------------------------------------------------+-- Tests+-------------------------------------------------------------------------------++main ∷ IO ()+main = defaultMain tests++tests ∷ [Test]+tests = [ testGroup "Pessimistic locking"+          [ testGroup "Event"         Event.tests+          , testGroup "Lock"          Lock.tests+          , testGroup "STM.Lock"      STM.Lock.tests+          , testGroup "RLock"         RLock.tests+          , testGroup "Broadcast"     Broadcast.tests+          , testGroup "ReadWriteLock" RWLock.tests+          , testGroup "ReadWriteVar"  RWVar.tests+          ]+        ]+++-- The End ---------------------------------------------------------------------