{-# LANGUAGE NamedFieldPuns #-}
module Lifetimes.Gc
( Cell
, readCell
, acquireCell
, moveToGc
, newCell
, addFinalizer
) where
import Control.Concurrent.MVar (MVar, mkWeakMVar, newEmptyMVar)
import Control.Concurrent.STM
import Control.Exception (mask)
import Control.Monad.STM.Class
import Lifetimes
import Zhp
newtype Cell a
= Cell (TVar (CellData a))
deriving(Cell a -> Cell a -> Bool
(Cell a -> Cell a -> Bool)
-> (Cell a -> Cell a -> Bool) -> Eq (Cell a)
forall a. Cell a -> Cell a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Cell a -> Cell a -> Bool
$c/= :: forall a. Cell a -> Cell a -> Bool
== :: Cell a -> Cell a -> Bool
$c== :: forall a. Cell a -> Cell a -> Bool
Eq)
data CellData a = CellData
{ CellData a -> a
value :: a
, CellData a -> [MVar ()]
finalizers :: [MVar ()]
}
deriving(CellData a -> CellData a -> Bool
(CellData a -> CellData a -> Bool)
-> (CellData a -> CellData a -> Bool) -> Eq (CellData a)
forall a. Eq a => CellData a -> CellData a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: CellData a -> CellData a -> Bool
$c/= :: forall a. Eq a => CellData a -> CellData a -> Bool
== :: CellData a -> CellData a -> Bool
$c== :: forall a. Eq a => CellData a -> CellData a -> Bool
Eq)
readCell :: Cell a -> STM a
readCell :: Cell a -> STM a
readCell (Cell TVar (CellData a)
state) = CellData a -> a
forall a. CellData a -> a
value (CellData a -> a) -> STM (CellData a) -> STM a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TVar (CellData a) -> STM (CellData a)
forall a. TVar a -> STM a
readTVar TVar (CellData a)
state
newCell :: MonadSTM m => a -> m (Cell a)
newCell :: a -> m (Cell a)
newCell a
value = STM (Cell a) -> m (Cell a)
forall (m :: * -> *) a. MonadSTM m => STM a -> m a
liftSTM (STM (Cell a) -> m (Cell a)) -> STM (Cell a) -> m (Cell a)
forall a b. (a -> b) -> a -> b
$ TVar (CellData a) -> Cell a
forall a. TVar (CellData a) -> Cell a
Cell (TVar (CellData a) -> Cell a)
-> STM (TVar (CellData a)) -> STM (Cell a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> CellData a -> STM (TVar (CellData a))
forall a. a -> STM (TVar a)
newTVar CellData :: forall a. a -> [MVar ()] -> CellData a
CellData { a
value :: a
value :: a
value, finalizers :: [MVar ()]
finalizers = [] }
addFinalizer :: Cell a -> IO () -> IO ()
addFinalizer :: Cell a -> IO () -> IO ()
addFinalizer (Cell TVar (CellData a)
stateVar) IO ()
fin = do
MVar ()
mvar <- IO (MVar ())
forall a. IO (MVar a)
newEmptyMVar
Weak (MVar ())
_ <- MVar () -> IO () -> IO (Weak (MVar ()))
forall a. MVar a -> IO () -> IO (Weak (MVar a))
mkWeakMVar MVar ()
mvar IO ()
fin
STM () -> IO ()
forall a. STM a -> IO a
atomically (STM () -> IO ()) -> STM () -> IO ()
forall a b. (a -> b) -> a -> b
$ TVar (CellData a) -> (CellData a -> CellData a) -> STM ()
forall a. TVar a -> (a -> a) -> STM ()
modifyTVar' TVar (CellData a)
stateVar ((CellData a -> CellData a) -> STM ())
-> (CellData a -> CellData a) -> STM ()
forall a b. (a -> b) -> a -> b
$ \state :: CellData a
state@CellData{[MVar ()]
finalizers :: [MVar ()]
finalizers :: forall a. CellData a -> [MVar ()]
finalizers} ->
CellData a
state { finalizers :: [MVar ()]
finalizers = MVar ()
mvar MVar () -> [MVar ()] -> [MVar ()]
forall a. a -> [a] -> [a]
: [MVar ()]
finalizers }
moveToGc :: Resource a -> IO (Cell a)
moveToGc :: Resource a -> IO (Cell a)
moveToGc Resource a
r =
((forall a. IO a -> IO a) -> IO (Cell a)) -> IO (Cell a)
forall b. ((forall a. IO a -> IO a) -> IO b) -> IO b
mask (((forall a. IO a -> IO a) -> IO (Cell a)) -> IO (Cell a))
-> ((forall a. IO a -> IO a) -> IO (Cell a)) -> IO (Cell a)
forall a b. (a -> b) -> a -> b
$ \forall a. IO a -> IO a
_ -> IO (IO (Cell a)) -> IO (Cell a)
forall (m :: * -> *) a. Monad m => m (m a) -> m a
join (IO (IO (Cell a)) -> IO (Cell a))
-> IO (IO (Cell a)) -> IO (Cell a)
forall a b. (a -> b) -> a -> b
$ STM (IO (Cell a)) -> IO (IO (Cell a))
forall a. STM a -> IO a
atomically (STM (IO (Cell a)) -> IO (IO (Cell a)))
-> STM (IO (Cell a)) -> IO (IO (Cell a))
forall a b. (a -> b) -> a -> b
$ do
a
value <- Resource a -> STM a
forall (m :: * -> *) a. MonadSTM m => Resource a -> m a
mustGetResource Resource a
r
IO ()
fin <- Resource a -> STM (IO ())
forall (m :: * -> *) a. MonadSTM m => Resource a -> m (IO ())
detach Resource a
r
Cell a
cell <- a -> STM (Cell a)
forall (m :: * -> *) a. MonadSTM m => a -> m (Cell a)
newCell a
value
IO (Cell a) -> STM (IO (Cell a))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (IO (Cell a) -> STM (IO (Cell a)))
-> IO (Cell a) -> STM (IO (Cell a))
forall a b. (a -> b) -> a -> b
$ do
Cell a -> IO () -> IO ()
forall a. Cell a -> IO () -> IO ()
addFinalizer Cell a
cell IO ()
fin
Cell a -> IO (Cell a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Cell a
cell
acquireCell :: Cell a -> Acquire a
acquireCell :: Cell a -> Acquire a
acquireCell (Cell TVar (CellData a)
var) = IO a -> (a -> IO ()) -> Acquire a
forall a. IO a -> (a -> IO ()) -> Acquire a
mkAcquire
(STM a -> IO a
forall a. STM a -> IO a
atomically (STM a -> IO a) -> STM a -> IO a
forall a b. (a -> b) -> a -> b
$ CellData a -> a
forall a. CellData a -> a
value (CellData a -> a) -> STM (CellData a) -> STM a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TVar (CellData a) -> STM (CellData a)
forall a. TVar a -> STM a
readTVar TVar (CellData a)
var)
(\a
_ -> STM () -> IO ()
forall a. STM a -> IO a
atomically (STM () -> IO ()) -> STM () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
CellData{} <- TVar (CellData a) -> STM (CellData a)
forall a. TVar a -> STM a
readTVar TVar (CellData a)
var
() -> STM ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
)