
On Thu, 2014-11-13 at 10:58 +0000, Simon Marlow wrote:
On 11/11/2014 23:28, Yuras Shumovich wrote:
The correct cleanup probably should look like the next:
closeDB (DB h1 h2) = hClose h1 `finally` hClose h2
Note: the initial version is buggy with respect to both async and sync exceptions, and uninterruptibleMask will fix it only with respect to async exceptions.
But in order to know that this is correct, you have to know how hClose works, namely that if an async exception is raised then it has safely closed the handle anyway.
hClose should mention that in it's contract. And I believe it should mention *any* behavior it implements.
If you didn't know that, then you would have to code it like this instead
closeDB (DB h1 h2) = cleanup1 where cleanup1 = (hClose h1 `onException` cleanup1) >> cleanup2 cleanup2 = hClose h2 `onException` cleanup2
Does this really work? I think so, but I haven't tested it...
I think your point about async exceptions under mask just being a special case of sync exceptions is a good one, though. I'm now wondering whether maybe the right solution is to make it easier to use the idiom in the above code.
But actually it is not *my* point, that is stated by Control.Exception docs about interruptible actions:
In many cases these operations may themselves raise exceptions, such as I/O errors, so the caller will usually be prepared to handle exceptions arising from the operation anyway
Thanks, Yuras