Safe Haskell | Safe-Inferred |
---|---|
Language | GHC2021 |
Control.RefCount
Synopsis
- data Ref obj where
- releaseRef :: (RefCounted m obj, PrimMonad m, MonadMask m) => Ref obj -> m ()
- withRef :: forall m obj a. (PrimMonad m, MonadThrow m) => Ref obj -> (obj -> m a) -> m a
- dupRef :: forall m obj. (RefCounted m obj, PrimMonad m, MonadThrow m) => Ref obj -> m (Ref obj)
- data RefException
- = RefUseAfterRelease RefId CallStack CallStack CallStack
- | RefDoubleRelease RefId CallStack CallStack CallStack
- | RefNeverReleased RefId CallStack
- newtype WeakRef a = WeakRef a
- mkWeakRef :: Ref obj -> WeakRef obj
- mkWeakRefFromRaw :: obj -> WeakRef obj
- deRefWeak :: (RefCounted m obj, PrimMonad m) => WeakRef obj -> m (Maybe (Ref obj))
- class RefCounted m obj | obj -> m where
- getRefCounter :: obj -> RefCounter m
- newRef :: (RefCounted m obj, PrimMonad m) => m () -> (RefCounter m -> obj) -> m (Ref obj)
- data RefCounter m = RefCounter !(PrimVar (PrimState m) Int) !(m ())
- newRefCounter :: PrimMonad m => m () -> m (RefCounter m)
- incrementRefCounter :: PrimMonad m => RefCounter m -> m ()
- decrementRefCounter :: (PrimMonad m, MonadMask m) => RefCounter m -> m ()
- tryIncrementRefCounter :: PrimMonad m => RefCounter m -> m Bool
- checkForgottenRefs :: forall m. (PrimMonad m, MonadThrow m) => m ()
- ignoreForgottenRefs :: (PrimMonad m, MonadCatch m) => m ()
- enableForgottenRefChecks :: IO ()
- disableForgottenRefChecks :: IO ()
Using references
A reference to an object of type a
. Use references to support prompt
finalisation of object resources.
Rules of use:
- Each
Ref
must eventually be released exactly once withreleaseRef
. - Use
withRef
, orDeRef
to (temporarily) obtain the underlying object. - After calling
releaseRef
, the operationswithRef
and patternDeRef
must not be used. - After calling
releaseRef
, an object obtained previously fromDeRef
must not be used. For this reason, it is advisable to usewithRef
where possible, and be careful with use ofDeRef
. - A
Ref
may be duplicated usingdupRef
to produce an independent reference (which must itself be released withreleaseRef
).
All of these operations are thread safe. They are not async-exception safe
however: the operations that allocate or deallocate must be called with
async exceptions masked. This includes newRef
, dupRef
and releaseRef
.
Provided that all these rules are followed, this guarantees that the object's finaliser will be run exactly once, promptly, when the final reference is released.
In debug mode (when using CPP define NO_IGNORE_ASSERTS
), adherence to
these rules are checked dynamically. These dynamic checks are however not
thread safe, so it is not guaranteed that all violations are always detected.
Bundled Patterns
pattern DeRef :: obj -> Ref obj | Get the object in a |
releaseRef :: (RefCounted m obj, PrimMonad m, MonadMask m) => Ref obj -> m () Source #
Release a reference to an object that will no longer be used (via this reference).
dupRef :: forall m obj. (RefCounted m obj, PrimMonad m, MonadThrow m) => Ref obj -> m (Ref obj) Source #
Duplicate an existing reference, to produce a new reference.
data RefException Source #
Constructors
RefUseAfterRelease | |
RefDoubleRelease | |
RefNeverReleased RefId CallStack | Allocation site |
Instances
Exception RefException Source # | |
Defined in Control.RefCount Methods toException :: RefException -> SomeException # fromException :: SomeException -> Maybe RefException # displayException :: RefException -> String # | |
Show RefException Source # | |
Defined in Control.RefCount Methods showsPrec :: Int -> RefException -> ShowS # show :: RefException -> String # showList :: [RefException] -> ShowS # |
Weak references
A "weak" reference to an object: that is, a reference that does not
guarantee to keep the object alive. If however the object is still alive
(due to other normal references still existing) then it can be converted
back into a normal reference with deRefWeak
.
Weak references do not themselves need to be released.
Constructors
WeakRef a |
mkWeakRef :: Ref obj -> WeakRef obj Source #
Given an existing normal reference, create a new weak reference.
mkWeakRefFromRaw :: obj -> WeakRef obj Source #
Given an existing raw reference, create a new weak reference.
deRefWeak :: (RefCounted m obj, PrimMonad m) => WeakRef obj -> m (Maybe (Ref obj)) Source #
If the object is still alive, obtain a new normal reference. The normal
rules for Ref
apply, including the need to eventually call releaseRef
.
Implementing objects with finalisers
class RefCounted m obj | obj -> m where Source #
Class of objects which support Ref
.
For objects in this class the guarantee is that (when the Ref
rules are
followed) the object's finaliser is called exactly once.
Methods
getRefCounter :: obj -> RefCounter m Source #
newRef :: (RefCounted m obj, PrimMonad m) => m () -> (RefCounter m -> obj) -> m (Ref obj) Source #
Make a new reference.
The given finaliser is run when the last reference is released. The finaliser is run with async exceptions masked.
Low level reference counts
data RefCounter m Source #
A reference counter with an optional finaliser action. Once the reference
count reaches 0
, the finaliser will be run.
Constructors
RefCounter !(PrimVar (PrimState m) Int) !(m ()) |
Instances
Show (RefCounter m) Source # | |
Defined in Control.RefCount Methods showsPrec :: Int -> RefCounter m -> ShowS # show :: RefCounter m -> String # showList :: [RefCounter m] -> ShowS # | |
NFData (RefCounter m) Source # | NOTE: Only strict in the variable and not the referenced value. |
Defined in Control.RefCount Methods rnf :: RefCounter m -> () # |
newRefCounter :: PrimMonad m => m () -> m (RefCounter m) Source #
Make a reference counter with initial value 1
.
The given finaliser is run when the reference counter reaches 0
. The
finaliser is run with async exceptions masked.
incrementRefCounter :: PrimMonad m => RefCounter m -> m () Source #
Increase the reference counter by one.
The count must be known (from context) to be non-zero already. Typically this will be because the caller has a reference already and is handing out another reference to some other code.
decrementRefCounter :: (PrimMonad m, MonadMask m) => RefCounter m -> m () Source #
Decrease the reference counter by one.
The count must be known (from context) to be non-zero. Typically this will be because the caller has a reference already (that they took out themselves or were given).
tryIncrementRefCounter :: PrimMonad m => RefCounter m -> m Bool Source #
Try to turn a "weak" reference on something into a proper reference.
This is by analogy with deRefWeak :: Weak v -> IO (Maybe v)
, but for
reference counts.
This amounts to trying to increase the reference count, but if it is already
zero then this will fail. And unlike with addReference
where such failure
would be a programmer error, this corresponds to the case when the thing the
reference count is tracking has been closed already.
The result is True
when a strong reference has been obtained and False
when upgrading fails.
Test API
checkForgottenRefs :: forall m. (PrimMonad m, MonadThrow m) => m () Source #
Run a GC to try and see if any refs have been forgotten without being released. If so, this will throw a synchronous exception.
Note however that this is not the only place where RefNeverReleased
exceptions can be thrown. All Ref operations poll for forgotten refs.
ignoreForgottenRefs :: (PrimMonad m, MonadCatch m) => m () Source #
Ignore and reset the state of forgotten reference tracking. This ensures that any stale fogotten references are not reported later.
This is especillay important in QC tests with shrinking which otherwise leads to confusion.
enableForgottenRefChecks :: IO () Source #
Enable forgotten reference checks.
disableForgottenRefChecks :: IO () Source #
Disable forgotten reference checks. This will error if there are already forgotten references while we are trying to disable the checks.