module Language.Erlang.NodeState ( NodeState()
, newNodeState
, new_pid
, new_port
, new_ref
, putMailboxForPid
, getMailboxForPid
, putMailboxForName
, getMailboxForName
, putConnectionForNode
, getConnectionForNode
, removeConnectionForNode
, getConnectedNodes
)
where
import Control.Monad (when)
import Control.Concurrent.STM
import Data.Word
import qualified Data.Map.Strict as M
import Util.IOx
data NodeState p n m c = NodeState { serial :: TVar Word32
, pidId :: TVar Word32
, portId :: TVar Word32
, refId0 :: TVar Word32
, refId1 :: TVar Word32
, refId2 :: TVar Word32
, pid2Mbox :: TVar (M.Map p m)
, name2Mbox :: TVar (M.Map n m)
, node2Conn :: TVar (M.Map n c)
}
instance Show (NodeState p n m c) where
show _ = "#NodeState<>"
newNodeState :: IOx (NodeState p n m c)
newNodeState = toIOx $ do
NodeState <$>
newTVarIO 0 <*>
newTVarIO 1 <*>
newTVarIO 1 <*>
newTVarIO 0 <*>
newTVarIO 0 <*>
newTVarIO 0 <*>
newTVarIO M.empty <*>
newTVarIO M.empty <*>
newTVarIO M.empty
new_pid :: NodeState p n m c -> IOx (Word32, Word32)
new_pid NodeState {..} = atomicallyX $ do
let p = (,) <$> readTVar pidId <*> readTVar serial
whenM (inc pidId _15bits) $
voidM (inc serial _13bits)
p
new_port :: NodeState p n m c -> IOx Word32
new_port NodeState {..} = atomicallyX $ do
let p = readTVar portId
voidM (inc portId _28bits)
p
new_ref :: NodeState p n m c -> IOx (Word32, Word32, Word32)
new_ref NodeState {..} = atomicallyX $ do
let r = (,,) <$> readTVar refId0 <*> readTVar refId1 <*> readTVar refId2
whenM (inc refId0 _18bits) $
whenM (inc refId1 _32bits) $
voidM (inc refId2 _32bits)
r
putMailboxForPid :: (Ord p) => NodeState p n m c -> p -> m -> IOx ()
putMailboxForPid NodeState {..} pid mbox = do
atomicallyX $ modifyTVar' pid2Mbox (M.insert pid mbox)
getMailboxForPid :: (Ord p, Show p) => NodeState p n m c -> p -> IOx m
getMailboxForPid NodeState {..} pid = do
m <- atomicallyX $ readTVar pid2Mbox
maybeErrorX doesNotExistErrorType (show pid) (M.lookup pid m)
putMailboxForName :: (Ord n) => NodeState p n m c -> n -> m -> IOx ()
putMailboxForName NodeState {..} pid name = do
atomicallyX $ modifyTVar' name2Mbox (M.insert pid name)
getMailboxForName :: (Ord n, Show n) => NodeState p n m c -> n -> IOx m
getMailboxForName NodeState {..} name = do
m <- atomicallyX $ readTVar name2Mbox
maybeErrorX doesNotExistErrorType (show name) (M.lookup name m)
putConnectionForNode :: (Ord n) => NodeState p n m c -> n -> c -> IOx ()
putConnectionForNode NodeState {..} conn name = do
atomicallyX $ modifyTVar' node2Conn (M.insert conn name)
getConnectionForNode :: (Ord n, Show n) => NodeState p n m c -> n -> IOx c
getConnectionForNode NodeState {..} name = do
m <- atomicallyX $ readTVar node2Conn
maybeErrorX doesNotExistErrorType (show name) (M.lookup name m)
removeConnectionForNode :: (Ord n) => NodeState p n m c -> n -> IOx ()
removeConnectionForNode NodeState {..} name = do
atomicallyX $ modifyTVar' node2Conn (M.delete name)
getConnectedNodes :: NodeState p n m c -> IOx [(n, c)]
getConnectedNodes NodeState {..} = do
m <- atomicallyX $ readTVar node2Conn
return $ M.toList m
_13bits, _15bits, _18bits, _28bits, _32bits :: Word32
_13bits = 0x00001fff
_15bits = 0x00007fff
_18bits = 0x0003ffff
_28bits = 0x0fffffff
_32bits = 0xffffffff
inc :: TVar Word32 -> Word32 -> STM Bool
inc tV maxV = do
modifyTVar' tV (+1)
v <- readTVar tV
if v > maxV
then do writeTVar tV 0 ; return True
else do return False
whenM :: Monad m => m Bool -> m () -> m ()
whenM mt mc = do t <- mt ; when t mc
voidM :: Monad m => m a -> m ()
voidM ma = do _ <- ma ; return ()