Document a surprising {{{unsafeDupablePerformIO}}} limitation.
We just discussed the following code on #ghc.
import System.IO.Unsafe
import Control.Concurrent.MVar
import Control.Concurrent
import GHC.Conc (par, pseq)
x :: MVar Int -> Int -> Int
x m a = unsafeDupablePerformIO $
withMVar m $ \i -> do
sum [1..1000000 + a] `seq` return i
main1 = do
m <- newMVar 42
let w = x m 0
w `par` print w
{-
spark: thread blocked indefinitely in an MVar operation
-}
main2 = do
m <- newMVar 42
let w = x m 0
forkIO $ print w
forkIO $ print w
print w
{-
spark: <<loop>>
spark: <<loop>>
-}
main = main2
This is not a bug; what happens is that the RTS suspends one of the duplicated computations of w, effectively killing the IO action that was passed to unsafeDupablePerformIO in the middle. This limitation of unsafeDupablePerformIO should be documented.
Trac metadata
| Trac field | Value |
|---|---|
| Version | 7.6.3 |
| Type | Task |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | libraries/base |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture |