mirror of
https://github.com/barrucadu/dejafu.git
synced 2024-12-25 22:42:55 +03:00
Add AutoUpdate example to tests
This commit is contained in:
parent
2952b75526
commit
9e68038e2b
126
dejafu-tests/Examples/AutoUpdate.hs
Executable file
126
dejafu-tests/Examples/AutoUpdate.hs
Executable file
@ -0,0 +1,126 @@
|
|||||||
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
|
|
||||||
|
{-
|
||||||
|
The auto-update package:
|
||||||
|
https://hackage.haskell.org/package/auto-update
|
||||||
|
|
||||||
|
Users found a possible deadlock and livelock:
|
||||||
|
https://www.reddit.com/r/haskell/comments/2i5d7m/updating_autoupdate/
|
||||||
|
|
||||||
|
This is the code from Control.AutoUpdate modified to use the
|
||||||
|
@MonadConc@ abstraction, with tests added to verify that the issues
|
||||||
|
identified are caught.. The original code is available under the MIT
|
||||||
|
license, which is reproduced below.
|
||||||
|
|
||||||
|
- - - - -
|
||||||
|
|
||||||
|
Copyright (c) 2014 Michael Snoyman
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included
|
||||||
|
in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
-}
|
||||||
|
|
||||||
|
module Examples.AutoUpdate (tests) where
|
||||||
|
|
||||||
|
import Control.Exception (SomeException)
|
||||||
|
import Control.Monad
|
||||||
|
import Control.Monad.Conc.Class
|
||||||
|
|
||||||
|
-- test imports
|
||||||
|
import Test.DejaFu (Bounds(..), Failure(..), MemType(..), defaultBounds, gives)
|
||||||
|
import Test.Framework (Test)
|
||||||
|
import Test.Framework.Providers.HUnit (hUnitTestToTests)
|
||||||
|
import Test.HUnit (test)
|
||||||
|
import Test.HUnit.DejaFu
|
||||||
|
|
||||||
|
tests :: [Test]
|
||||||
|
tests = hUnitTestToTests $ test
|
||||||
|
[ testDejafu' SequentialConsistency
|
||||||
|
defaultBounds
|
||||||
|
deadlocks
|
||||||
|
"deadlocks"
|
||||||
|
(gives [Left Deadlock, Right ()])
|
||||||
|
|
||||||
|
, testDejafu' SequentialConsistency
|
||||||
|
defaultBounds { preemptionBound = Just 3 }
|
||||||
|
nondeterministic
|
||||||
|
"nondeterministic"
|
||||||
|
(gives [Left Deadlock, Right 0, Right 1])
|
||||||
|
]
|
||||||
|
|
||||||
|
-- This exhibits a deadlock with no preemptions.
|
||||||
|
deadlocks :: MonadConc m => m ()
|
||||||
|
deadlocks = join (mkAutoUpdate defaultUpdateSettings)
|
||||||
|
|
||||||
|
-- This exhibits nondeterminism with three preemptions.
|
||||||
|
nondeterministic :: forall m. MonadConc m => m Int
|
||||||
|
nondeterministic = do
|
||||||
|
var <- newCRef 0
|
||||||
|
let settings = (defaultUpdateSettings :: UpdateSettings m ())
|
||||||
|
{ updateAction = atomicModifyCRef var (\x -> (x+1, x)) }
|
||||||
|
auto <- mkAutoUpdate settings
|
||||||
|
auto
|
||||||
|
auto
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
data UpdateSettings m a = UpdateSettings
|
||||||
|
{ updateFreq :: Int
|
||||||
|
, updateSpawnThreshold :: Int
|
||||||
|
, updateAction :: m a
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultUpdateSettings :: MonadConc m => UpdateSettings m ()
|
||||||
|
defaultUpdateSettings = UpdateSettings
|
||||||
|
{ updateFreq = 1000000
|
||||||
|
, updateSpawnThreshold = 3
|
||||||
|
, updateAction = return ()
|
||||||
|
}
|
||||||
|
|
||||||
|
mkAutoUpdate :: MonadConc m => UpdateSettings m a -> m (m a)
|
||||||
|
mkAutoUpdate us = do
|
||||||
|
currRef <- newCRef Nothing
|
||||||
|
needsRunning <- newEmptyMVar
|
||||||
|
lastValue <- newEmptyMVar
|
||||||
|
|
||||||
|
void $ fork $ forever $ do
|
||||||
|
takeMVar needsRunning
|
||||||
|
|
||||||
|
a <- catchSome $ updateAction us
|
||||||
|
|
||||||
|
writeCRef currRef $ Just a
|
||||||
|
void $ tryTakeMVar lastValue
|
||||||
|
putMVar lastValue a
|
||||||
|
|
||||||
|
threadDelay $ updateFreq us
|
||||||
|
|
||||||
|
writeCRef currRef Nothing
|
||||||
|
void $ takeMVar lastValue
|
||||||
|
|
||||||
|
return $ do
|
||||||
|
mval <- readCRef currRef
|
||||||
|
case mval of
|
||||||
|
Just val -> return val
|
||||||
|
Nothing -> do
|
||||||
|
void $ tryPutMVar needsRunning ()
|
||||||
|
readMVar lastValue
|
||||||
|
|
||||||
|
catchSome :: MonadConc m => m a -> m a
|
||||||
|
catchSome act = catch act $
|
||||||
|
\e -> throw (e :: SomeException)
|
@ -5,8 +5,9 @@ import Test.Framework (defaultMain, testGroup)
|
|||||||
import qualified Cases.SingleThreaded as ST
|
import qualified Cases.SingleThreaded as ST
|
||||||
import qualified Cases.MultiThreaded as MT
|
import qualified Cases.MultiThreaded as MT
|
||||||
import qualified Cases.Litmus as L
|
import qualified Cases.Litmus as L
|
||||||
import qualified Examples.Logger as EL
|
import qualified Examples.AutoUpdate as EA
|
||||||
import qualified Examples.ClassLaws as EC
|
import qualified Examples.ClassLaws as EC
|
||||||
|
import qualified Examples.Logger as EL
|
||||||
import qualified Examples.Philosophers as EP
|
import qualified Examples.Philosophers as EP
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
@ -17,8 +18,9 @@ main = defaultMain
|
|||||||
, testGroup "Litmus" L.tests
|
, testGroup "Litmus" L.tests
|
||||||
]
|
]
|
||||||
, testGroup "Examples"
|
, testGroup "Examples"
|
||||||
[ testGroup "Message Logger" EL.tests
|
[ testGroup "auto-update" EA.tests
|
||||||
, testGroup "Class Laws" EC.tests
|
, testGroup "Class Laws" EC.tests
|
||||||
, testGroup "Dining Philosophers" EP.tests
|
, testGroup "Dining Philosophers" EP.tests
|
||||||
|
, testGroup "Message Logger" EL.tests
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
@ -23,6 +23,7 @@ executable dejafu-tests
|
|||||||
, Cases.MultiThreaded
|
, Cases.MultiThreaded
|
||||||
, Cases.Litmus
|
, Cases.Litmus
|
||||||
|
|
||||||
|
, Examples.AutoUpdate
|
||||||
, Examples.ClassLaws
|
, Examples.ClassLaws
|
||||||
, Examples.Logger
|
, Examples.Logger
|
||||||
, Examples.Philosophers
|
, Examples.Philosophers
|
||||||
|
Loading…
Reference in New Issue
Block a user