Can exceptions sneak between restore and mask?

asynchronous, exception, haskell, resources

Solution

Yes, in GHC, when the unmask occurs we eagerly check for blocked exceptions and raise them.

Problem

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?

Original source