File: Test.hs

package info (click to toggle)
haskell-concurrent-extra 0.7.0.12-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 184 kB
  • sloc: haskell: 1,040; makefile: 6
file content (114 lines) | stat: -rw-r--r-- 3,716 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
{-# LANGUAGE CPP, NoImplicitPrelude #-}

module Control.Concurrent.ReadWriteLock.Test ( tests ) where


-------------------------------------------------------------------------------
-- Imports
-------------------------------------------------------------------------------

-- from base:
import Prelude            ( (*) )
import Control.Monad      ( (>>), (>>=), replicateM_ )
import Control.Concurrent ( forkIO, threadDelay )
import Data.Function      ( ($) )
import Data.Foldable      ( sequenceA_ )
import Data.List          ( map, replicate, (++) )
import System.Random      ( randomRIO )

#if __GLASGOW_HASKELL__ < 700
import Prelude            ( fromInteger )
import Control.Monad      ( (>>=), fail )
#endif

-- from async:
import Control.Concurrent.Async ( Concurrently(Concurrently), runConcurrently )

-- from concurrent-extra:
import qualified Control.Concurrent.ReadWriteLock as RWLock
    ( new, acquireWrite, acquireRead, releaseWrite, releaseRead, withRead, withWrite  )

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
        , testCase "stressTest" stressTest
        ]

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

stressTest :: Assertion
stressTest = assert $ within (1000 * a_moment) $ do
  lock <- RWLock.new

  let randomDelay hi = randomRIO (0, hi) >>= threadDelay

      reader = replicateM_ 500 $ do
        randomDelay 100
        RWLock.withRead lock $ randomDelay 10

      writer = replicateM_ 500 $ do
        randomDelay 100
        RWLock.withWrite lock $ randomDelay 10

  runConcurrently $ sequenceA_ $ map Concurrently $
    replicate 10 reader ++ replicate 10 writer