
Hi Phil,
Thanks for the reply, however that just gives me a forced deadlock removal
as before.
new bound thread (1)
cap 0: schedule()
cap 0: running thread 1 (ThreadRunGHC)
cap 0: thread 1 stopped (blocked on an MVar)
thread 1 @ 0000000003205388 is blocked on an MVar @
00000000032040c8 (TSO_DIRTY)
deadlocked, forcing major GC...
all threads:
threads on capability 0:
other threads:
thread 1 @ 0000000003205388 is blocked on an MVar @
00000000032040c8 (TSO_DIRTY)
cap 0: starting GC
I don't believe any solution involving MVars will work for the non-threaded
RTS. Though I'd love to be wrong here...
Regards,
Tamar
On Sun, Jan 6, 2019 at 9:38 PM Phil Ruffwind
What if you wrap the MVar in a foreign closure?
import Control.Concurrent.MVar (newEmptyMVar, putMVar, takeMVar) import Control.Exception (bracket) import Foreign.Ptr (FunPtr, freeHaskellFunPtr)
foreign import ccall "wrapper" wrapAwaken :: IO () -> IO (FunPtr (IO ()))
main = do mvar <- newEmptyMVar bracket (wrapAwaken (putMVar mvar ())) freeHaskellFunPtr $ \ awaken -> do -- giveToExternalCode awaken takeMVar mvar
On Sun, Jan 6, 2019, at 10:37, Phyx wrote:
Hi All,
I'm looking for a way to block a task indefinitely until it is woken up by an external event in both the threaded and non-threaded RTS and returns a value that was stored/passed. MVar works great for the threaded RTS, but for the non-threaded there's a bunch of deadlock detection in the scheduler that would forcibly free the lock and resume the task with an opaque exception. This means that MVar and anything derived from it is not usable.
STMs are more expensive but also have the same deadlock code. So again no go. The reason it looks like a deadlock to the RTS is that the "Wake-up" call in the non-threaded rts will come from C code running inside the RTS. The RTS essentially just sees all tasks blocked on it's main capability and (usually rightly so) assumes a deadlock occurred.
You have other states like BlockedOnForeign etc but those are not usable as a primitive. Previous iterations of I/O managers have each invented primitives for this such as asyncRead#, but they are not general and can't be re-used, and requires a different solution for threaded and non-threaded.
I have started making a new primitive IOPort for this, based on the MVar code, but this is not trivial... (currently I'm getting a segfault *somewhere* in the primitive's cmm code). The reason is that the semantics are decidedly different from what MVars guarantee. I should also mention that this is meant to be internal to base (i.e no exported).
So before I continue down this path and some painful debugging..., does anyone know of a way to block a task, unblock it later and pass a value back? It does not need to support anything complicated such as multiple take/put requests etc.
Cheers, Tamar _______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs