module MultiSetRewrite.ConcurrentList where
import IO
import GHC.IOBase
import Monad
import Data.IORef
import Control.Concurrent.STM
data List a = Node { val :: a
, verify :: TVar Bool
, next :: IORef (List a) }
| DelNode { verify :: TVar Bool
, next :: IORef (List a) }
| Null
| Head { next :: IORef (List a) } deriving Eq
data ListHandle a = ListHandle { headList :: IORef (IORef (List a)),
tailList :: IORef (IORef (List a)) }
type Iterator a = IORef (IORef (List a))
while b cmd = if b then do {cmd; while b cmd}
else return ()
repeatUntil cmd = do { b <- cmd; if b then return ()
else repeatUntil cmd }
repeatUntilCnt cmd = do { (b,c) <- cmd; if b then return c
else repeatUntilCnt cmd }
atomCAS :: Eq a => IORef a -> a -> a -> IO Bool
atomCAS ptr old new =
atomicModifyIORef ptr (\ cur -> if cur == old
then (new, True)
else (cur, False))
atomicWrite :: IORef a -> a -> IO ()
atomicWrite ptr x =
atomicModifyIORef ptr (\ _ -> (x,()))
newList :: IO (ListHandle a)
newList =
do nullPtr <- newIORef Null
hd <- newIORef (Head {next = nullPtr })
hdPtr <- newIORef hd
tailPtr <- newIORef nullPtr
return (ListHandle {headList = hdPtr, tailList = tailPtr})
addToTail :: Eq a => ListHandle a -> a -> IO (IORef (List a))
addToTail (ListHandle {tailList = tailPtrPtr}) x =
do nullPtr <- newIORef Null
tPtr <- repeatUntilCnt
(do tailPtr <- readIORef tailPtrPtr
v <- atomically $ newTVar True
b <- atomCAS tailPtr Null (Node {val = x, verify = v, next = nullPtr})
return (b,tailPtr) )
atomicWrite tailPtrPtr nullPtr
return tPtr
newIterator :: ListHandle a -> IO (Iterator a)
newIterator (ListHandle {headList = hd}) =
do hdPtr <- readIORef hd
it <- newIORef hdPtr
return it
assignIterator :: Iterator a -> Iterator a -> IO ()
assignIterator lhs rhs =
do rhsVal <- readIORef rhs
writeIORef lhs rhsVal
iterateList :: Eq a => Iterator a -> IO (Maybe (IORef (List a)))
iterateList itPtrPtr =
let go prevPtr =
do do prevNode <- readIORef prevPtr
let curPtr = next prevNode
curNode <- readIORef curPtr
case curNode of
Node {} -> do writeIORef itPtrPtr curPtr
return (Just curPtr)
Null -> return Nothing
DelNode {next = nextNode} ->
case prevNode of
Node {} -> do b <- atomCAS prevPtr prevNode (Node {val = val prevNode,
verify = verify prevNode,
next = nextNode})
if b then go prevPtr
else go curPtr
Head {} -> do b <- atomCAS prevPtr prevNode (Head {next = nextNode})
if b then go prevPtr
else go curPtr
DelNode {} -> go curPtr
in do startPtr <- readIORef itPtrPtr
go startPtr
printList :: Show a => ListHandle a -> IO ()
printList (ListHandle {headList = ptrPtr}) =
do startptr <- (
do ptr <- readIORef ptrPtr
Head {next = startptr} <- readIORef ptr
return startptr)
printListHelp startptr
printListHelp :: Show a => IORef (List a) -> IO ()
printListHelp curNodePtr =
do { curNode <- readIORef curNodePtr
; case curNode of
Null -> putStr "Nil"
Node {val = curval, next = curnext} ->
do { putStr (show curval ++ " -> ")
; printListHelp curnext }
DelNode {next = curnext} ->
do { putStr ("DEAD -> ")
; printListHelp curnext }
}
printElement :: Show a => IORef (List a) -> IO ()
printElement curNodePtr =
do { curNode <- readIORef curNodePtr
; case curNode of
Null -> putStr "Nil"
DelNode {} ->
do putStr ("DEL ")
Node {val = curval} ->
do putStr $ (show curval) ++ " "
}
cntList :: Show a => ListHandle a -> IO Int
cntList (ListHandle {headList = ptrPtr}) =
do startptr <- (
do ptr <- readIORef ptrPtr
Head {next = startptr} <- readIORef ptr
return startptr)
cntListHelp startptr 0
cntListHelp :: Show a => IORef (List a) -> Int -> IO Int
cntListHelp curNodePtr i =
do { curNode <- readIORef curNodePtr
; case curNode of
Null -> return i
Node {next = curnext} ->
cntListHelp curnext (i+1)
DelNode {next = curnext} ->
cntListHelp curnext (i+1)
}