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