Opened 3 years ago

Closed 3 years ago

#9965 closed bug (fixed)

getChanContents BlockedIndefinitelyOnMVar on 7.10 RC1

Reported by: jberryman Owned by:
Priority: normal Milestone:
Component: libraries/base Version: 7.10.1-rc1
Keywords: Cc: hvr, ekmett
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Incorrect result at runtime Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description

All of the stanzas work on 7.8.3, but the middle one works incorrectly on 7.10:

module Main where

import Control.Concurrent.Chan
import Control.Monad

main = do
    io <- newChan
    let inp = [0] :: [Int]
    mapM_ (writeChan io) inp
{-
    -- WORKS:
    outp <- getChanContents io
    if 0 == head outp
        then putStrLn "OK"
        else error $ "Smoke test failed"
-}
    -- BROKEN ON 7.10 (BlockedIndefinitelyOnMVar):
    outp <- getChanContents io
    if and (zipWith (==) inp outp)
        then putStrLn "OK"
        else error $ "Smoke test failed"
{-
    -- WORKS:
    forM_ inp $ \xIn-> do
        xOut <- readChan io
        unless (xIn == xOut) $
            error $ "Smoke test failed"
-}

I first noticed the behavior in a Chan-like library I wrote, whose internals are completely different from Chan, but where the getChanContents is a copy-paste from Chan. So I assume it has something to do with unsafeInterleaveIO.

Attachments (4)

Main.dump-simpl.7.8.new (8.3 KB) - added by jberryman 3 years ago.
new version of getChanContents, compiled with GHC 7.8
Main.dump-simpl.7.8.old (7.1 KB) - added by jberryman 3 years ago.
Existing version of getChanContents, compiled with GHC 7.8
Main.dump-simpl.7.10.ok (8.5 KB) - added by jberryman 3 years ago.
New, working version of getChanContents, compiled with 7.10
Main.dump-simpl.7.10.bad (7.4 KB) - added by jberryman 3 years ago.
Existing, non-working version of getChanContents, compiled with 7.10

Download all attachments as: .zip

Change History (6)

comment:1 Changed 3 years ago by jberryman

Adding another unsafeInterleaveIO seems to solve this, but I don't really understand why:

getChanContents :: Chan a -> IO [a]
getChanContents ch 
  = unsafeInterleaveIO (do
        x  <- unsafeInterleaveIO $ readChan ch --   <------ unsafeInterleaveIO
        xs <- getChanContents ch
        return (x:xs)
    )

I'll attach the output of ghc --make -O2 -fforce-recomp -ddump-to-file -ddump-simpl -dsuppress-module-prefixes -dsuppress-uniques Main.hs for both 7.8 and 7.10, using both the old version of getChanContents and the new version above.

Changed 3 years ago by jberryman

Attachment: Main.dump-simpl.7.8.new added

new version of getChanContents, compiled with GHC 7.8

Changed 3 years ago by jberryman

Attachment: Main.dump-simpl.7.8.old added

Existing version of getChanContents, compiled with GHC 7.8

Changed 3 years ago by jberryman

Attachment: Main.dump-simpl.7.10.ok added

New, working version of getChanContents, compiled with 7.10

Changed 3 years ago by jberryman

Attachment: Main.dump-simpl.7.10.bad added

Existing, non-working version of getChanContents, compiled with 7.10

comment:2 Changed 3 years ago by rwbarton

Resolution: fixed
Status: newclosed

Works for me with 7.10 RC 2 and 7.10.1, highly likely to have been a result of #9949.

Note: See TracTickets for help on using tickets.