Skip to content

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
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information