<html>
<head>
<style><!--
.hmmessage P
{
margin:0px;
padding:0px
}
body.hmmessage
{
font-size: 10pt;
font-family:Verdana
}
--></style>
</head>
<body class='hmmessage'>
Please start here:<BR>
<A href="http://www.opengroup.org/onlinepubs/009695399/functions/pthread_atfork.html">http://www.opengroup.org/onlinepubs/009695399/functions/pthread_atfork.html</A><BR>
  "There are at least two serious problems with the semantics of <A href="http://www.opengroup.org/onlinepubs/009695399/functions/fork.html"><I>fork</I>()</A> in a multi-threaded program"<BR>
 <BR>
 <BR>
I've been looking at cvsup a while now.<BR>
Lots of RTIO.PutText, etc.<BR>
pthread_atfork usage in RTCollector and ThreadPThread.m3.<BR>
   Reinitialize in the child, mark the gc threads as not being created yet.<BR>
Been using @M3nogc. It helps. I think I understand why.<BR>
 <BR>
 <BR>
I have a somewhat wild educated guess as to the problem.<BR>
It is "fork1" vs. "forkall", sort of.<BR>
 <BR>
 <BR>
In user threads, when you fork(), you get all the user Modula-3 threads continuing<BR>
to run in the child. Because their existance is an artifact of a bunch of data<BR>
that we maintain and gets carried into the new process.<BR>
 <BR>
 <BR>
With kernel threads (with the exception of using Solaris forkall()), you get<BR>
just the thread that called fork().<BR>
 <BR>
 <BR>
See my reference to the RTCollector/Allocator atfork change, which I show here (not yet commited):<BR>
 <BR>
 <BR>
PROCEDURE AtForkPrepare() =<BR>  BEGIN<BR>  END AtForkPrepare;<BR>
 <BR>
PROCEDURE AtForkParent() =<BR>  BEGIN<BR>  END AtForkParent;<BR>
 <BR>
PROCEDURE AtForkChild() =<BR>  VAR r: INTEGER;<BR>  BEGIN<BR>    r := Thread.PThreadAtFork(AtForkPrepare, AtForkParent, AtForkChild);<BR>    <* ASSERT r = 0 *><BR>    startedBackground := FALSE;<BR>    startedForeground := FALSE;<BR>  END AtForkChild;<BR>
 <BR>
PROCEDURE Init () =<BR>  VAR r: INTEGER;<BR>  BEGIN<BR>    r := Thread.PThreadAtFork(AtForkPrepare, AtForkParent, AtForkChild);<BR>    <* ASSERT r = 0 *><BR><BR>
 <BR>
Some threads may need to be recreated in the child, some not.<BR>
The default is not.<BR>
I think we mainly have to adjust cvsup to recreate its threads.<BR>
And a little bit of pthread_atfork use in m3core (a bunch of<BR>
  it shown believe, and reinitialization in ThreadPThread.m3).<BR>
 <BR>
 <BR>
Like the Apple/Darwin warnings, I don't think most libraries can be considered<BR>
"fork safe". That is you can fork, but only if you exec soon thereafter.<BR>
Making code "fork safe" I believe equates to reviewing it a bunch<BR>
and using pthread_atfork selectively. One thing to watch for is if<BR>
the library creates any worker threads during "initialization" or<BR>
even "on demand" -- to either recreate them in the child, or note<BR>
that they don't exist in the child.<BR>
We can make m3core fork safe, I guess, to satisfy cvsup.<BR>
 <BR>
 <BR>
Maybe write the code to duplicate all threads in a child, subject to<BR>
some configuration setting? Something like @M3forkall, but it'd<BR>
be something that e.g. cvsup would specify when it builds, and<BR>
then user wouldn't have to list it anywhere.<BR>
Kind of like the flags for incremental and vm gc that get recorded<BR>
by the compiler.<BR>
 <BR>
 <BR>
Anyway, let me see about recreating cvsup's threads manually.<BR>
Probably by using the Thread.PThreadAtFork I added.<BR>
 <BR>
I think the initial hang I described fits my theory -- the dispatcher thread<BR>
doesn't exist in the child, so hang. And then when I avoid that<BR>
with a local edit I get a hang later. I compared without -C and I <BR>
see other stuff happening..I think on other threads that fork() is abandoning..<BR>
 <BR>
 <BR>
Thread.PThreadAtFork is wierd, but I think reasonable.<BR>
It will do nothing on user threads and Win32.<BR>
It will only do anything on PThreads.<BR>
Libraries can use it to achieve compatibility with pthreads programs<BR>
that use fork.<BR>
 <BR>
 - Jay<BR><BR> <BR>> Date: Wed, 17 Mar 2010 10:19:59 +0100<BR>> From: wagner@elegosoft.com<BR>> To: m3devel@elegosoft.com<BR>> Subject: Re: [M3devel] cvsup<BR>> <BR>> Quoting Daniel Solaz <m3@sol42.com>:<BR>> <BR>> > On 16 Mar 2010, at 20:32, Tony Hosking wrote:<BR>> >> fork should still work with pthreads. Why wouldn't it?<BR>> > Chapter 6.1 of Butenhof's pthreads book deals with this, and well, <BR>> > it is a mess. According to him only the calling thread exists on <BR>> > return from fork() in the child process, but the other pthread <BR>> > *states* (mutexes, conditions, data keys, etc.) are replicated as <BR>> > well. And I'm sure the details vary from system to system.<BR>> > This is the chapter's first sentence: "Avoid using fork in a <BR>> > threaded program (if you can) unless you intend to exec a new <BR>> > program immediately."<BR>> <BR>> Is this about kernel threads or user level threads? Or about a specific<BR>> implementation of one or the other?<BR>> <BR>> I don't know the book, but I always thought about pthreads as being the<BR>> POSIX specification of threads, and I don't think there's anything<BR>> in that relating to fork, AFAIR, but that was years ago.<BR>> <BR>> Can anyone enlighten us about the POSIX specs and if they define the<BR>> semantics of fork in presence of threaded processes? Or does it really<BR>> boil down to the above `avoid it if you can'?<BR>> <BR>> Olaf<BR>> -- <BR>> Olaf Wagner -- elego Software Solutions GmbH<BR>> Gustav-Meyer-Allee 25 / Gebäude 12, 13355 Berlin, Germany<BR>> phone: +49 30 23 45 86 96 mobile: +49 177 2345 869 fax: +49 30 23 45 86 95<BR>> http://www.elegosoft.com | Geschäftsführer: Olaf Wagner | Sitz: Berlin<BR>> Handelregister: Amtsgericht Charlottenburg HRB 77719 | USt-IdNr: DE163214194<BR>> <BR>                                      </body>
</html>