Domanda

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?

È stato utile?

Soluzione

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top