\begin{code}
-{-# OPTIONS -fno-implicit-prelude #-}
+{-# OPTIONS_GHC -XNoImplicitPrelude #-}
+{-# OPTIONS_HADDOCK hide #-}
-----------------------------------------------------------------------------
-- |
-- Module : GHC.Weak
--
-----------------------------------------------------------------------------
+-- #hide
module GHC.Weak where
import GHC.Base
import Data.Maybe
-import GHC.IOBase ( IO(..), unIO )
+import Data.Typeable
{-|
A weak pointer object with a key and a value. The value has type @v@.
the value to the key does /not/ keep the key alive.
A weak pointer may also have a finalizer of type @IO ()@; if it does,
-then the finalizer will be run once, and once only, at a time after
-the key has become unreachable by the program (\"dead\"). The storage
-manager attempts to run the finalizer(s) for an object soon after the
-object dies, but promptness is not guaranteed.
+then the finalizer will be run at most once, at a time after the key
+has become unreachable by the program (\"dead\"). The storage manager
+attempts to run the finalizer(s) for an object soon after the object
+dies, but promptness is not guaranteed.
+
+It is not guaranteed that a finalizer will eventually run, and no
+attempt is made to run outstanding finalizers when the program exits.
+Therefore finalizers should not be relied on to clean up resources -
+other methods (eg. exception handlers) should be employed, possibly in
+addition to finalisers.
References from the finalizer to the key are treated in the same way
as references from the value to the key: they do not keep the key
-}
data Weak v = Weak (Weak# v)
+#include "Typeable.h"
+INSTANCE_TYPEABLE1(Weak,weakTc,"Weak")
+
-- | Establishes a weak pointer to @k@, with value @v@ and a finalizer.
--
-- This is the most general interface for building a weak pointer.
--
-mkWeak :: k -- ^ key
- -> v -- ^ value
- -> Maybe (IO ()) -- ^ finalizer
- -> IO (Weak v) -- ^ returns: a weak pointer object
+mkWeak :: k -- ^ key
+ -> v -- ^ value
+ -> Maybe (IO ()) -- ^ finalizer
+ -> IO (Weak v) -- ^ returns: a weak pointer object
mkWeak key val (Just finalizer) = IO $ \s ->
case mkWeak# key val finalizer s of { (# s1, w #) -> (# s1, Weak w #) }
case mkWeak# key val (unsafeCoerce# 0#) s of { (# s1, w #) -> (# s1, Weak w #) }
{-|
- A specialised version of 'mkWeak', where the key and the value are the
- same object:
+Dereferences a weak pointer. If the key is still alive, then
+@'Just' v@ is returned (where @v@ is the /value/ in the weak pointer), otherwise
+'Nothing' is returned.
- > mkWeakPtr key finalizer = mkWeak key key finalizer
--}
-mkWeakPtr :: k -> Maybe (IO ()) -> IO (Weak k)
-mkWeakPtr key finalizer = mkWeak key key finalizer
-
-{-|
- A specialised version of 'mkWeakPtr', where the 'Weak' object
- returned is simply thrown away (however the finalizer will be
- remembered by the garbage collector, and will still be run
- when the key becomes unreachable).
+The return value of 'deRefWeak' depends on when the garbage collector
+runs, hence it is in the 'IO' monad.
-}
-addFinalizer :: key -> IO () -> IO ()
-addFinalizer key finalizer = do
- mkWeakPtr key (Just finalizer) -- throw it away
- return ()
+deRefWeak :: Weak v -> IO (Maybe v)
+deRefWeak (Weak w) = IO $ \s ->
+ case deRefWeak# w s of
+ (# s1, flag, p #) -> case flag of
+ 0# -> (# s1, Nothing #)
+ _ -> (# s1, Just p #)
+
+-- | Causes a the finalizer associated with a weak pointer to be run
+-- immediately.
+finalize :: Weak v -> IO ()
+finalize (Weak w) = IO $ \s ->
+ case finalizeWeak# w s of
+ (# s1, 0#, _ #) -> (# s1, () #) -- already dead, or no finaliser
+ (# s1, _, f #) -> f s1
{-
Instance Eq (Weak v) where
runFinalizerBatch :: Int -> Array# (IO ()) -> IO ()
runFinalizerBatch (I# n) arr =
let go m = IO $ \s ->
- case m of
- 0# -> (# s, () #)
- _ -> let m' = m -# 1# in
- case indexArray# arr m' of { (# io #) ->
- case unIO io s of { (# s, _ #) ->
- unIO (go m') s
- }}
+ case m of
+ 0# -> (# s, () #)
+ _ -> let !m' = m -# 1# in
+ case indexArray# arr m' of { (# io #) ->
+ case unIO io s of { (# s', _ #) ->
+ unIO (go m') s'
+ }}
in
go n