Suppose I have some code written like so:
import Control.Exception (bracketOnError, finally, mask)
import Client (acquireB, releaseB, doStuff) -- theoretical
import MyStuff (preliminary, doMoreStuff) -- theoretical
clientAction = bracketOnError acquireB releaseB $ \b ->
doStuff b
return (b, releaseB b)
myAction = mask $ \restore ->
a <- preliminary
(thing, releaseThing) <- restore clientAction
doMoreStuff a thing `finally` releaseThing
I have to do some preliminary
stuff, my client acquires b
and then has to doStuff
with b
, and then I have to doMoreStuff
with b
. And b
needs to be released, even if an asynchronous exception occurs. But I don't know how to release b
, so my client tells me how. Written this way, we are both prepared to release b
if an exception happens during "our" code.
My question is this: Is it ever possible for an async exception to cause releaseB
not to be performed? Specifically, is there a gap between "my code" and "my client's code" where an async exception can squeeze in? Let me inline clientAction
and bracketOnException
to explain.
myAction = mask $ \restore -> do
a <- preliminary
(thing, releaseThing) <- restore $ mask $ \restore2 -> do
b <- acquireB
restore2 (doStuff b >> return (b, releaseB b))
`onException` releaseB b
doMoreStuff a thing `finally` releaseThing
The concern is this: is there a moment right here
... restore $ mask ...
Right when the client's mask
is lifted, but before the end of my restore
surrounding it, where an exception could sneak through?
Yes, in GHC, when the unmask occurs we eagerly check for blocked exceptions and raise them.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With