{-# LANGUAGE ForeignFunctionInterface #-}

import Foreign
import System.IO.Unsafe
import System.Mem
import Control.Concurrent

foreign export ccall "performGC_" performGC' :: IO ()
performGC' = do putMVar m (); yield; performGC

foreign import ccall "performGC_" f :: IO ()

{-# NOINLINE m #-}
m = unsafePerformIO newEmptyMVar

main = do
  forkIO f
  takeMVar m

-- This tests for a bug in the garbage collector, whereby a main
-- thread that has completed may be GC'd before its return value is
-- propagated back to the caller of rts_evalIO().
--
-- The sequence we hope to create is:
--      - main thread (1) forks off thread (2)
--      - thread (2) invokes new main thread (3) via a 'safe' ccall
--      - thread (3) yields to thread (1)
--      - thread (1) completes, but cannot return yet because (3)
--        is the current main thread (unless we
--        are in SMP or RTS_SUPPORTS_THREADS mode)
--      - thread (3) invokes a GC
--      - thread (1) is GC'd, unless we're careful!
