<div dir="ltr"><div><br></div><div style>I just looked at this code and since I don&#39;t know the code I can&#39;t give you good solutions, but for others watching this thread the links might prove interesting.</div><div style>

<br></div><div style>My main theory is that you do have some other thread in FFI-land while you are fork()ing.  The task-&gt;cond, task-&gt;lock seems to be related to this (see quoted comments below).</div><div style><br>

</div><div style>Also, pthread_mutex_destroy is undefined if the lock is locked, so I am guessing that the task-&gt;lock is somehow locked when it shouldn&#39;t be.</div><div style><br></div><div style><div>It isn&#39;t clear from your description whether this is consistently happening on Linux, or whether this only sometimes happens.</div>

<div><br></div><div style>The forkProcess() code seems to hold all capabilities during fork, but that does not include FFI-land threads AFAIU.</div><div><br></div></div><div style>Assuming that this happens only rarely, I am trying to understand what happens if the thread that is in FFI-land returns to the RTS (in the parent) after fork(), but before the freeTask() in the child.  Based on the descriptions I read, it seems likely that this thread will try to inspect task-&gt;cap, which requires holding task-&gt;lock.</div>

<div style><br></div><div style>That would in turn make the pthread_mutex_destroy in the child invalid.</div><div style><br></div><div style><a href="https://github.com/ghc/ghc/blob/master/rts/Task.h#L57">https://github.com/ghc/ghc/blob/master/rts/Task.h#L57</a><br>

</div><div style><br></div><div style>&quot;&quot;&quot;</div><div style> ...</div><div style><div> When a task is migrated from sleeping on one Capability to another,</div><div>   its task-&gt;cap field must be modified.  When the task wakes up, it</div>

<div>   will read the new value of task-&gt;cap to find out which Capability</div><div>   it belongs to.  Hence some synchronisation is required on</div><div>   task-&gt;cap, and this is why we have task-&gt;lock.</div><div>

<br></div><div>   If the Task is not currently owned by task-&gt;id, then the thread is</div><div>   either</div><div><br></div><div>     (a) waiting on the condition task-&gt;cond.  The Task is either</div><div>         (1) a bound Task, the TSO will be on a queue somewhere</div>

<div><span class="" style="white-space:pre">        </span> (2) a worker task, on the spare_workers queue of task-&gt;cap.</div><div>   ...</div><div>&quot;&quot;&quot;<br></div></div><div style><br></div><div style>freeTask:</div>

<div style><a href="https://github.com/ghc/ghc/blob/master/rts/Task.c#L142">https://github.com/ghc/ghc/blob/master/rts/Task.c#L142</a><br></div><div style><br></div><div style>the comment in freeTask refers to this test:</div>

<div style><div><a href="https://github.com/ghc/testsuite/blob/master/tests/concurrent/should_run/conc059.hs">https://github.com/ghc/testsuite/blob/master/tests/concurrent/should_run/conc059.hs</a><br></div><div><br></div>

<div style>That test calls the RTC from C which then forkIOs off actions that are outstanding when the RTS exits.</div><div style><br></div></div><div style>in forkProcess, child code</div><div style><a href="https://github.com/ghc/ghc/blob/master/rts/Schedule.c#L1837">https://github.com/ghc/ghc/blob/master/rts/Schedule.c#L1837</a></div>

<div style><br></div><div style>It look like all this code supports the notion that some other thread can be in foreign code during the fork call.</div><div style><br></div><div style>discardTasksExcept<br></div><div style>

<a href="https://github.com/ghc/ghc/blob/master/rts/Task.c#L305">https://github.com/ghc/ghc/blob/master/rts/Task.c#L305</a></div><div style><br></div><div style><br></div><div style>Alexander</div></div><div class="gmail_extra">

<br><br><div class="gmail_quote">On Mon, Jan 21, 2013 at 12:15 AM, Mark Lentczner <span dir="ltr">&lt;<a href="mailto:mark.lentczner@gmail.com" target="_blank">mark.lentczner@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<div dir="ltr">Sorry to be reviving this thread so long after.... but I seem to be running into similar issues as Michael S. did at the start.<div><br></div><div>In short, I&#39;m using forkProcess with the threaded RTS, and see occasional hangs:</div>



<div class="gmail_extra"><ul><li>I see these only on Linux. On Mac OS X, I never do.</li><li>I&#39;m using GHC 7.4.2</li><li>I noticed the warning in the doc for forkProcess, but assumed I was safe, as I wasn&#39;t holding any shared resources at the time of the fork, and no shared resources in the program are used in the child.</li>



<li>WIth gdb, I&#39;ve traced the hang to here in the run-time: <font face="courier new, monospace">forkProcess &gt; discardTasksExcept &gt; freeTask &gt; closeMutex(&amp;task-&gt;lock) &gt; pthread_mutex_destroy</font></li>



</ul>The discussion in this thread leaves me with these questions:</div><div class="gmail_extra"><ul><li>Is there reason to think the situation has gotten better in 7.6 and later?</li><li>Isn&#39;t the only reason <b>System.Process</b> is safer because it does an immediate exec in the child? Alas, I really want to just <font face="courier new, monospace">fork()</font> sometimes.</li>



<li>Is it really true that even if my program has no shared resources with the child, that the IO subsystem and FFI system do anyway? Surely the RTS would take care of doing the right thing with those, no?</li><li>

There should be no concern with <font face="courier new, monospace">exec</font> w.r.t. library invariants since <span style="font-family:&#39;courier new&#39;,monospace">exec</span> is wholesale replacement - all the libraries will reinitialize. Is there a problem here I&#39;m missing?</li>



</ul>Alas, I&#39;ve stopped using the threaded RTS until I understand this better.</div><span class="HOEnZb"><font color="#888888"><div class="gmail_extra"><br></div><div class="gmail_extra">- Mark</div></font></span></div>


</blockquote></div><br></div>