On Sat, Dec 03, 2005 at 10:35:54PM +0100, Tomasz Zielonka wrote:
> so I could export a waitUntil function with type
>
> waitUntil :: Time -> STM ()
>
> but I tripped on something that was reported before, namely that STM
> transactions can't be nested (as a result of unsafePerformIO or
> unsafeInterleaveIO). Is there a plan to support such scenario?
OK, it can be worked around by running the atomically block in a new
transaction. But still it would be nice if the program didn't segfault,
but cause an exception for example.
Updated modules attached.
Best regards
Tomasz
--
I am searching for a programmer who is good at least in some of
[Haskell, ML, C++, Linux, FreeBSD, math] for work in Warsaw, Poland
module Main where
import Debug.Trace
import Control.Concurrent.STM
import Control.Concurrent
import Control.Monad
import TimeVar
import Random
import Control.Exception (finally)
main = do
runTests
[ test 1
, testMany
, test 5
, test 10
]
runTests fs = do
mapM_ (\t -> t >> putStrLn "") fs
test secs = do
putStrLn ("Testing waiting for " ++ show secs ++ " seconds")
-- waitUntil <- liftM waitOnTimeVar initTimeVar
time1 <- getTime
atomically $ do
stmTrace "try"
waitUntil (time1 + secs)
time2 <- getTime
putStrLn $ concat $
[ show time2
, " - "
, show time1
, " = "
, show (time2 - time1)
]
testMany = do
putStrLn "Testing with many threads"
messages <- atomically newTChan
threadCount <- atomically (newTVar 0)
let forkIO' t = do
atomically (modifyTVar threadCount succ)
forkIO (t `finally` atomically (modifyTVar threadCount pred))
replicateM 30 $ forkIO' $ do
secs <- liftM fromIntegral (randomRIO (1 :: Int, 10))
time1 <- getTime
atomically $ do
waitUntil (time1 + secs)
time2 <- getTime
atomically $ writeTChan messages $ concat $
[ "waited for "
, show (time2 - time1)
, " seconds, difference from requested: "
, show ((time2 - time1) - secs)
]
let loop = do
join $ atomically $
(do msg <- readTChan messages
return (putStrLn msg >> loop))
`orElse`
(do n <- readTVar threadCount
guard (n == 0)
return (return ()))
loop
--------------------------------------------------------------------------------
stmTrace s = do
v <- newTVar ()
trace s v `seq` return ()
modifyTVar v f = readTVar v >>= writeTVar v . f
module TimeVar
( Time
, getTime
, waitUntil
, timeVar
) where
import Control.Concurrent.STM
import Control.Concurrent
import Control.Monad
import System.Time (getClockTime, ClockTime(..))
import Data.Bits
import Data.Int
import System.IO.Unsafe (unsafePerformIO)
newtype TimeVar = TimeVar [TVar Bool]
{-# NOINLINE timeVar #-}
timeVar :: TimeVar
timeVar = unsafePerformIO $ do
var <- newEmptyMVar
forkIO $ do
tv <- initTimeVar
putMVar var tv
takeMVar var
waitUntil :: Time -> STM ()
waitUntil = waitOnTimeVar timeVar
type Time = Int32
getTime :: IO Time
getTime = do
TOD secs _ <- getClockTime
return (fromIntegral secs)
initTimeVar :: IO TimeVar
initTimeVar = do
t0 <- liftM toBitsFromMSB getTime
vars <- atomically $ do
sequence
[ do
v <- newTVar b
return v
| b <- t0 ]
forkIO $ do
sequence_ $ repeat $ do
threadDelay 100000
t <- liftM toBitsFromMSB getTime
atomically $ do
sequence_
[ do
old <- readTVar var
when (old /= new) (writeTVar var new)
| (var, new) <- zip vars t ]
return (TimeVar vars)
waitOnTimeVar :: TimeVar -> Time -> STM ()
waitOnTimeVar (TimeVar vars) t = do
let tBits = toBitsFromMSB t
cmp vars tBits
where
cmp (v:vs) (b:bs) = do
vVal <- readTVar v
case compare vVal b of
LT -> retry
EQ -> cmp vs bs
GT -> return ()
cmp [] [] = return ()
toBitsFromMSB :: Bits b => b -> [Bool]
toBitsFromMSB x = [ testBit x i | i <- [nBits-1, nBits-2 .. 0] ]
where
nBits = bitSize x
_______________________________________________
Haskell-Cafe mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/haskell-cafe