
Andreas Voellmy
When an unsafe call is made, the OS thread currently running on the HEC makes the call without releasing the HEC. If the main thread was on the run queue of the HEC making the foreign unsafe call when the foreign call was made, then no other HECs will pick up the main thread. Hence the two sleep calls in your program happen sequentially instead of concurrently.
Is this the bound-main-thread issue? That is, would wrapping the main thread in 'runInUnboundThread' help here?
I'm not completely sure what is causing the busy wait, but here is one guess: when a GC is triggered on one HEC, it signals to all the other HECs to stop the mutator and run the collection. This waiting may be a busy wait, because the wait is typically brief. If this is true, then since one thread is off in a unsafe foreign call, there is one HEC that refuses to start the GC and all the other HECs are busy-waiting for the signal. The GC could be triggered by a period of inactivity. Again, this is just a guess - you might try to verify this by turning off the periodic triggering of GC and checking whether the start GC barrier is a busy-wait.
that seems to be a rather good guess: I inhibited the GC by disabling the idle-timer using "+RTS -N4 -I0" and with that the HEC busy-waiting is gone; So actually this isn't FFI-specific at all, as I could trigger the very same effect by using a non-allocating/tight-loop evaluation such as the following: do _ <- forkIO (evaluate (busyfun 0 0) >> putStrLnTime "busyfun finished") where busyfun :: Int -> Int -> Int busyfun !n !m = if m < 0 then n else busyfun (n+1) (m+1) cheers, hvr