The documentation for performGC should mention its behaviour during unsafe FFI calls
Summary
System.Mem.performGC
(and friends) don't currently mention their behaviour when the GC is unable to run because of an unsafe FFI call. At the moment between their documentation saying that a GC happens immediately and the unsafe FFI documentation saying that GHC guarantees that no GC takes place it's a little ambiguous.
This small program (using inline-c
for convenience) demonstrates that performGC
blocks during unsafe FFI calls. Switch Unsafe.exp
for C.exp
to observe no such blocking behaviour.
import Control.Concurrent
import GHC.Clock
import qualified Language.C.Inline as C
import qualified Language.C.Inline.Unsafe as Unsafe
import System.Mem
C.include "<unistd.h>"
main :: IO ()
main = do
let report s = putStrLn . (<> s) . show =<< getMonotonicTime
finished <- newEmptyMVar
report " forking sleeping thread"
_ <- forkFinally [Unsafe.exp| void { sleep(3); } |]
(\_ -> putMVar finished ())
report " starting GC"
performGC
report " finished GC"
report " waiting for sleeping thread"
_ <- takeMVar finished
report " finished"
Proposed improvements or changes
In the documentation for performGC
and friends add
... unless an @unsafe@ FFI call is in progress, in which case the call to performGC will block until all @unsafe@ calls have returned