-- | Anytime we use the resource, we trigger the deferred the initialization.
withLazyResource :: MVar (LazyResource a) -> (a -> IO r) -> IO r
withLazyResource lazyResourceRef continuation = mask $ \restore -> do
lazyResource <- takeMVar lazyResourceRef
-- We always have to ensure we put back the resource into the cell, to ensure
-- any waiting, are unblocked
let putBackVerbatim = putMVar lazyResourceRef lazyResource
resource <- case lazyResource of
Uninitialized initializer ->
restore initializer `onException` putBackVerbatim
Initialized resource -> pure resource
Finalized -> do
putBackVerbatim
error "Attempted to use a resource after it has been finalized"
-- Same as the above, but we've now initialized the resource.
let putInitialized = putMVar lazyResourceRef (Initialized resource)
result <- restore (continuation resource) `onException` putInitialized
putInitialized
pure result
withPool
:: (forall r. (a -> IO r) -> IO r)
-> Int
-> (Pool a -> IO b)
-> IO b
withPool withResource poolSize action = do
let withPoolResources =
runCodensity $ replicateM poolSize $ Codensity withResource
withPoolResources $ \resources -> do
poolResources <- newIORef resources
qSem <- newQSem poolSize
action $ Pool poolResources qSem