unsafeUnmask unmasks even inside uninterruptibleMask
Control.Exception exports
allowInterrupt :: IO ()
allowInterrupt = unsafeUnmask $ return ()
with documentation:
When invoked inside mask, this function allows a blocked asynchronous exception to be raised, if one exists. It is equivalent to performing an interruptible operation, but does not involve any actual blocking. When called outside mask, or inside uninterruptibleMask, this function has no effect.
However, this is not actually true: unsafeUnmask unmasks exceptions even inside uninterruptibleUnmask, as the attached test demonstrates (the test uses a foreign call just to have something non-interruptible but still observable; in particular, doing a print is interruptible because it uses an MVar under the hood).
I think it is possible to define a better unsafeUnmask in user-land:
interruptible :: IO a -> IO a
interruptible act = do
st <- getMaskingState
case st of
Unmasked -> act
MaskedInterruptible -> unsafeUnmask act
MaskedUninterruptible -> act
but it still seems to be that we should either (i) change the behaviour of unsafeUnmask, or (ii) provide a version of unsafeUnmask with the behaviour as described and then change allowInterrupt to use that new version of unsafeUnmask, or at the very least (iii) change the documentation.
(One question with the above definition of interruptible is what happens when we nest mask and uninterruptibleMask?)
Trac metadata
| Trac field | Value |
|---|---|
| Version | 7.8.2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Runtime System |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | simonmar |
| Operating system | |
| Architecture |