concurrent-st-0.1: src/Control/Concurrent/ST.hs
{-| This module provides a way to use concurrent haskell
inside of 'ST'. Using these function subverts the
usual guarentee we have that 'ST' is deterministic.
-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE MagicHash #-}
{-# OPTIONS_GHC -Wall #-}
module Control.Concurrent.ST
( -- * Threads
ThreadId(..)
, forkST
, forkST_
-- * MVar
, MVar
, newEmptyMVar
, newMVar
, takeMVar
, putMVar
, readMVar
, tryTakeMVar
, tryPutMVar
, isEmptyMVar
, tryReadMVar
) where
import GHC.Prim
import GHC.Exts (isTrue#)
import GHC.ST (ST(..))
data ThreadId s = ThreadId ThreadId#
-- | Creates a new thread to run the 'ST' computation passed
-- as the argument. Since using the 'ThreadId' often
-- leads to non-determinism, the function 'forkST_'
-- is typically to be preferred.
forkST :: ST s () -> ST s (ThreadId s)
forkST action = ST $ \s1 -> case forkST# action s1 of
(# s2, tid #) -> (# s2, ThreadId tid #)
-- | Creates a new thread to run the 'ST' computation and
-- discard the 'ThreadId'.
forkST_ :: ST s () -> ST s ()
forkST_ action = ST $ \s1 -> case forkST# action s1 of
(# s2, _ #) -> (# s2, () #)
forkST# :: a -> State# s -> (# State# s, ThreadId# #)
forkST# = unsafeCoerce# fork#
data MVar s a = MVar (MVar# s a)
instance Eq (MVar s a) where
(MVar mvar1#) == (MVar mvar2#) = isTrue# (sameMVar# mvar1# mvar2#)
newEmptyMVar :: ST s (MVar s a)
newEmptyMVar = ST $ \s1 -> case newMVar# s1 of
(# s2, v #) -> (# s2, MVar v #)
takeMVar :: MVar s a -> ST s a
takeMVar (MVar mvar#) = ST $ \ s# -> takeMVar# mvar# s#
putMVar :: MVar s a -> a -> ST s ()
putMVar (MVar mvar#) x = ST $ \ s# ->
case putMVar# mvar# x s# of
s2# -> (# s2#, () #)
tryTakeMVar :: MVar s a -> ST s (Maybe a)
tryTakeMVar (MVar m) = ST $ \ s ->
case tryTakeMVar# m s of
(# s', 0#, _ #) -> (# s', Nothing #) -- MVar is empty
(# s', _, a #) -> (# s', Just a #) -- MVar is full
tryPutMVar :: MVar s a -> a -> ST s Bool
tryPutMVar (MVar mvar#) x = ST $ \ s# ->
case tryPutMVar# mvar# x s# of
(# s, 0# #) -> (# s, False #)
(# s, _ #) -> (# s, True #)
tryReadMVar :: MVar s a -> ST s (Maybe a)
tryReadMVar (MVar m) = ST $ \ s ->
case tryReadMVar# m s of
(# s', 0#, _ #) -> (# s', Nothing #) -- MVar is empty
(# s', _, a #) -> (# s', Just a #) -- MVar is full
isEmptyMVar :: MVar s a -> ST s Bool
isEmptyMVar (MVar mv#) = ST $ \ s# ->
case isEmptyMVar# mv# s# of
(# s2#, flg #) -> (# s2#, isTrue# (flg /=# 0#) #)
newMVar :: a -> ST s (MVar s a)
newMVar value = do
mvar <- newEmptyMVar
putMVar mvar value
return mvar
readMVar :: MVar s a -> ST s a
readMVar (MVar mvar#) = ST $ \ s# -> readMVar# mvar# s#