[M3devel] 5.8.6 LINUXLIBC6 breakage, kernel 2.6.23, glibc-2.6-4

Jay K jay.krell at cornell.edu
Thu Apr 21 02:27:15 CEST 2011


> > soon afterwards in the child process, thus resetting all states. In the
> > meantime, only a short list of async-signal-safe library routines are
> > promised to be available."


Any idea why? I don't know.


Is this such a burden?
We need a global lock order for it. Unreasonable?
I understand pthread_atfork is causing a problem with user threads, but
  - It really ought not. The libc vs. libpthread design is broken. I believe many systems
    don't have this broken design, but I guess some do. The broken design is that
    libc and libpthread implement some functions with the same name, and you get
    to chose which one. And some of them might be thread-safe.


 >  In Modula-3, every application has *always*
 > had to assume that there are other threads floating around.  There is


This is the case in C too.
I can't assume any library I link to doesn't create some helper threads with pthreads.
pthreads should be assumed always in use, and there should be no ramifications of this.
I shouldn't have a choice e.g. of a malloc/free/strtok that aren't thread safe vs. ones that are.


We really need pthreads to work and to worry less about user threads imho.


I believe we have seen the same problems with Win32 threads as with pthreads.
  (Yes, I know, some people might protest that Win32 threads work fine, but pthreads
  work very well too. It is only the new stress testing that is turning up problems as I understand,
  and it turns up problems in pthreads and Win32 threads. Ok, there is now some new mention
  of problems with other programs?) I suspect the problem is in the allocator/garbage collector,
  but that user threads don't stress it enough. I suspect I suspect I suspect...whatever.. real
  debugging is needed, (my own) suspicion and speculation isn't going to help much.
  It would of course be good if someone anyone can find a point in the history where
  pthreads and Win32 threads are really solid, with these new one or two test programs,
  if such a point exists -- I'm not sure one does, or that recent changes are the problem.
  But, again, I don't know. Time, debugging, investigation is needed.




 - Jay


> From: hosking at cs.purdue.edu
> Date: Wed, 20 Apr 2011 10:58:06 -0400
> To: mika at async.caltech.edu
> CC: m3devel at elegosoft.com; jay.krell at cornell.edu
> Subject: Re: [M3devel] 5.8.6 LINUXLIBC6 breakage, kernel 2.6.23, glibc-2.6-4
> 
> Agreed.  But CVSup used it and we were trying to be supportive.
> 
> Antony Hosking | Associate Professor | Computer Science | Purdue University
> 305 N. University Street | West Lafayette | IN 47907 | USA
> Office +1 765 494 6001 | Mobile +1 765 427 5484
> 
> 
> 
> 
> On Apr 20, 2011, at 1:55 AM, Mika Nystrom wrote:
> 
> > 
> > The rationale you directed us to says:
> > 
> > "It is suggested that programs that use fork() call an exec function very
> > soon afterwards in the child process, thus resetting all states. In the
> > meantime, only a short list of async-signal-safe library routines are
> > promised to be available."
> > 
> > and later
> > 
> > "Application programs may not be aware that a multi-threaded library
> > is in use, and they feel free to call any number of library routines
> > between the fork() and exec calls, just as they always have. Indeed,
> > they may be extant single-threaded programs and cannot, therefore,
> > be expected to obey new restrictions imposed by the threads library."
> > 
> > In C maybe that is true.  In Modula-3, every application has *always*
> > had to assume that there are other threads floating around.  There is
> > no such thing as a "single-threaded" Modula-3 program---or at least,
> > the distinction doesn't matter.
> > 
> > I really think fork-and-do-more-work is just a bug.  Maybe it is a special
> > pattern used by some special program---maybe.  In any case support for it
> > I do not think belongs in m3core.
> > 
> >     Mika
> > 
> > 
> > 
> > Jay K writes:
> >> --_0203aac2-5c8e-49c7-9074-6bc448ecf342_
> >> Content-Type: text/plain; charset="iso-8859-1"
> >> Content-Transfer-Encoding: quoted-printable
> >> 
> >> 
> >>> This change depends on pthread_atfork=2C for pthreads and user threads.
> >> 
> >> 
> >> Clarification: There's no change described there for pthreads=2C and indeed=
> >> =2C getting
> >> this behavior with pthreads doesn't depend on using pthread_atfork. That is=
> >> just
> >> how pthreads are -- except optionally on Solaris (fork1() vs. forkall() vs.=
> >> fork()).
> >> The Solaris default used to be fork =3D> forkall().
> >> The current Solaris default is fork =3D> fork1().
> >> There really do exist on Solaris to functions you can call=2C fork1() and f=
> >> orkall().
> >> All other systems and the Posix specification have the "fork1" semantic for=
> >> fork.
> >> Therefore "fork1" is what we should provide unconditionally.
> >> If you really want "forkall"=2C then you write:
> >> #ifdef __sun
> >> forkall()
> >> #else
> >> #error
> >> #endif
> >> 
> >> 
> >> 
> >> and/or you go and hack up m3core/src/thread/POSIX=2C branch off m3core/src/=
> >> thread/POSIX_FORKALL or such.
> >> I don't expect anyone to ever do that.
> >> 
> >> 
> >> 
> >> The need for pthread_atfork is sort of different for user threads vs. pthre=
> >> ads=2C but it is needed either way.
> >> For pthreads=2C there is this problem -- at the time a thread calls fork()=
> >> =2C what are other threads doing?
> >> Answer: Anything.
> >> Follow up question: What locks might they hold?
> >> Answer: Any.
> >> Follow up: So=2C if arbitrary locks are held=2C and you fork=2C and don't e=
> >> xec=2C and the child process
> >> attempts to use some of the locks that were held in the parent=2C and only =
> >> the forking thread survived=2C
> >> then the other threads will never leave their locks=2C and later attempts t=
> >> o acquire them in the children
> >> will deadlock. Therefore=2C what pthread_atfork provides for=2C what you ar=
> >> e supposed to use it for=2C
> >> is roughly speaking=2C right before fork()=2C in the parent=2C acquire all =
> >> locks=2C and then fork()=2C and then in the
> >> parent and children=2C release all locks. Therefore=2C you have to come up =
> >> with a locking order.
> >> 
> >> 
> >> 
> >> Things are a little different for user threads.
> >> In user threads=2C the existance of threads is established by virtue of a g=
> >> lobal array or list of data describing the threads.
> >> And a timer to occasionally preempt. When the timer interrupts=2C the sched=
> >> uler picks another thread from the global
> >> array/list. Previously=2C the data went unchanged when fork() was called. T=
> >> herefore all threads survived.
> >> What we do now is that in the child "handler" for pthread_atfork=2C is rein=
> >> itialize the various data=2C so as to forget about
> >> all but the current thread. Something like that.
> >> 
> >> 
> >> 
> >> I suspect if we had RTProcess.ForkBeforeExec and RTProcess.ForkBeforeMoreWo=
> >> rk=2C then ForkBeforeExec
> >> might get away with just fork() and ignore all this.
> >> So far we have not drawn this line -- there is just the one fork and it is =
> >> used prior to exec or do-more-work
> >> and does the same thing w/o knowing what is to follow.
> >> 
> >> 
> >> The Posix documentation I think describes this all fairly well.
> >> Bing for "posix opengroup pthread_atfork".
> >> Really. I think it is saying much of the same thing I am saying=2C but in l=
> >> anguage that has received
> >> much more thought. Be sure to read the "rationale" part.
> >> 
> >> 
> >> - Jay
> >> 
> >> 
> >> From: jay.krell at cornell.edu
> >> To: mika at async.caltech.edu
> >> CC: m3devel at elegosoft.com
> >> Subject: RE: [M3devel] 5.8.6 LINUXLIBC6 breakage=2C kernel 2.6.23=2C glibc-=
> >> 2.6-4
> >> Date: Tue=2C 19 Apr 2011 15:06:38 +0000
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >> Previously: user threads: all threads survived fork()
> >> Previously: pthreads: only the thread calling fork() survived fork()
> >> Now: user threads and pthreads: only the thread calling fork() survives for=
> >> k()
> >> This must be how pthreads behave=2C and this makes user threads and pthread=
> >> s consistent.
> >> 
> >> This change depends on pthread_atfork=2C for pthreads and user threads.
> >> It only really matters to the rare "fork + do more work" program=2C such as=
> >> cvsupd.
> >> Most programs either never fork=2C or exec almost immediately after fork.
> >> 
> >> 
> >> pthread_atfork offers a good model.
> >> A sort of "distributed" model.
> >> You don't have to go and change all the calls to fork().
> >> Each module with a need to do something before/after fork=2C calls the cent=
> >> ral pthread_atfork=2C
> >> and fork and pthread_atfork cooperate to do what is needed.
> >> 
> >> 
> >> No function pointer is needed.
> >> Instead move the code to m3core/thread.
> >> 
> >> 
> >> If you really must not use -pthread=2C then you must implement pthread_atfo=
> >> rk functionality
> >> yourself and have all fork() calls go through your own fork() wrapper that =
> >> cooperates
> >> with your pthread_atfork replacement.
> >> There is no free lunch -- there is a downside to this approach=2C as plain =
> >> fork() calls
> >> are ok and correct if pthread_atfork is used=2C but now become incorrect.
> >> Pick your poison:
> >> user thread/pthread inconsistency
> >> cvsupd incompatibility with pthreads=20
> >> user threads using pthread_atfork/-pthread=20
> >> fork() calls having to go through a wrapper (ok -- you could miss this an=
> >> d=20
> >>  not likely notice -- only fork() calls in fork+do-more-work programs nee=
> >> d the wrapper).=20
> >> 
> >> 
> >> (Most of this has been explained multiple times=2C but people only pay atte=
> >> ntion
> >> when they think it affects them. I'm guilty of the same thing.)
> >> 
> >> 
> >> - Jay
> >> 
> >> 
> >>> To: jay.krell at cornell.edu
> >>> Date: Mon=2C 18 Apr 2011 19:30:58 -0700
> >>> From: mika at async.caltech.edu
> >>> CC: m3devel at elegosoft.com
> >>> Subject: Re: [M3devel] 5.8.6 LINUXLIBC6 breakage=2C kernel 2.6.23=2C glib=
> >> c-2.6-4
> >>> =20
> >>> =20
> >>> If you or Tony could describe roughly what you think needs to be done
> >>> I'd be happy to look into it.
> >>> =20
> >>> The basic problem is that a decision that's made/described in
> >>> m3core/thread/m3makefile needs to someone find its way to controlling
> >>> what C code gets compiled elsewhere in the system.  Or maybe there should
> >>> be an indirection into the thread library to pick up pthread_atfork (or n=
> >> ot).
> >>> =20
> >>> But then again you still haven't explained why you made the user threads =
> >> use
> >>> pthread_atfork.  I just remove it from my installations=2C but then again=
> >> I'm
> >>> not trying to run CVSup so I don't know if it breaks that program to do s=
> >> o.
> >>> =20
> >>>     Mika
> >>> =20
> >>> Jay K writes:
> >>>> --_3dd397d4-ac1d-4148-a9ff-059d27dd794a_
> >>>> Content-Type: text/plain=3B charset=3D"iso-8859-1"
> >>>> Content-Transfer-Encoding: quoted-printable
> >>>> 
> >>>> 
> >>>>> The following code from RTProcessC.c ensures that it is neeeded on eve=
> >> ry =3D
> >>>> Unix except
> >>>>>> /* NOTE: Even userthreads now depends
> >>>>>> * on availability of pthreads.
> >>>>>> * This can be fixed if need be.
> >>>>>> */
> >>>> 
> >>>> =3D20
> >>>> Ok=3D2C "we" should probably go ahead and fix that.
> >>>> I'll try to=3D2C but no promises=3D2C sorry.
> >>>> =3D20
> >>>> - Jay
> >>>> =3D20
> >>>>> From: hosking at cs.purdue.edu
> >>>>> Date: Mon=3D2C 18 Apr 2011 18:11:26 -0400
> >>>>> To: mika at async.caltech.edu
> >>>>> CC: m3devel at elegosoft.com
> >>>>> Subject: Re: [M3devel] 5.8.6 LINUXLIBC6 breakage=3D2C kernel 2.6.23=3D=
> >> 2C glib=3D
> >>>> c-2.6-4
> >>>>> =3D20
> >>>>> Probably unnecessary=3D2C given that I think there is another entry po=
> >> int t=3D
> >>>> o forking a process (I forget where) in the thread-specific portion of m=
> >> 3co=3D
> >>>> re. In which case the necessary work might be done there?
> >>>>> =3D20
> >>>>> On Apr 18=3D2C 2011=3D2C at 2:45 PM=3D2C Mika Nystrom wrote:
> >>>>> =3D20
> >>>>>> Tony Hosking writes:
> >>>>>> ...
> >>>>>>> pthread_atfork should not be needed under user threads.
> >>>>>> ...
> >>>>>> =3D20
> >>>>>> The following code from RTProcessC.c ensures that it is neeeded on e=
> >> ver=3D
> >>>> y Unix except
> >>>>>> FreeBSD before 6. The comment is from the checked-in source file.
> >>>>>> =3D20
> >>>>>> /* NOTE: Even userthreads now depends
> >>>>>> * on availability of pthreads.
> >>>>>> * This can be fixed if need be.
> >>>>>> */
> >>>>>> =3D20
> >>>>>> INTEGER
> >>>>>> __cdecl
> >>>>>> RTProcess__RegisterForkHandlers(
> >>>>>> ForkHandler prepare=3D2C
> >>>>>> ForkHandler parent=3D2C
> >>>>>> ForkHandler child)
> >>>>>> {
> >>>>>> /* FreeBSD < 6 lacks pthread_atfork. Would be good to use autoconf.
> >>>>>> * VMS lacks pthread_atfork? Would be good to use autoconf.
> >>>>>> * Win32 lacks pthread_atfork and fork. OK.
> >>>>>> *
> >>>>>> * As well=3D2C for all Posix systems=3D2C we could implement
> >>>>>> * atfork ourselves=3D2C as long as we provide a fork()
> >>>>>> * wrapper that code uses.
> >>>>>> */
> >>>>>> #if defined(_WIN32) \
> >>>>>> || defined(__vms) \
> >>>>>> || (defined(__FreeBSD__) /* && (__FreeBSD__ < 6)*/ )
> >>>>>> return 0=3D3B
> >>>>>> #else
> >>>>>> while (1)
> >>>>>> {
> >>>>>> int i =3D3D pthread_atfork(prepare=3D2C parent=3D2C child)=3D3B
> >>>>>> if (i !=3D3D EAGAIN)
> >>>>>> return i=3D3B
> >>>>>> sleep(0)=3D3B
> >>>>>> }
> >>>>>> #endif
> >>>>>> }
> >>>>> =3D20
> >>>> 		 	   		  =3D
> >>>> 
> >>>> --_3dd397d4-ac1d-4148-a9ff-059d27dd794a_
> >>>> Content-Type: text/html=3B charset=3D"iso-8859-1"
> >>>> Content-Transfer-Encoding: quoted-printable
> >>>> 
> >>>> <html>
> >>>> <head>
> >>>> <style><!--
> >>>> .hmmessage P
> >>>> {
> >>>> margin:0px=3D3B
> >>>> padding:0px
> >>>> }
> >>>> body.hmmessage
> >>>> {
> >>>> font-size: 10pt=3D3B
> >>>> font-family:Tahoma
> >>>> }
> >>>> --></style>
> >>>> </head>
> >>>> <body class=3D3D'hmmessage'>
> >>>> &gt=3D3B The following code from RTProcessC.c ensures that it is neeeded=
> >> on e=3D
> >>>> very Unix except<BR>&gt=3D3B &gt=3D3B /* NOTE: Even userthreads now depe=
> >> nds<BR>=3D
> >>>> &gt=3D3B &gt=3D3B * on availability of pthreads.<BR>&gt=3D3B &gt=3D3B * =
> >> This can be=3D
> >>>> fixed if need be.<BR>&gt=3D3B &gt=3D3B */<BR><BR>
> >>>> &nbsp=3D3B<BR>
> >>>> Ok=3D2C "we" should probably go ahead and fix that.<BR>
> >>>> I'll try to=3D2C but no&nbsp=3D3Bpromises=3D2C sorry.<BR>
> >>>> &nbsp=3D3B<BR>
> >>>> &nbsp=3D3B- Jay<BR>&nbsp=3D3B<BR>
> >>>> &gt=3D3B From: hosking at cs.purdue.edu<BR>&gt=3D3B Date: Mon=3D2C 18 Apr 2=
> >> 011 18:11=3D
> >>>> :26 -0400<BR>&gt=3D3B To: mika at async.caltech.edu<BR>&gt=3D3B CC: m3devel=
> >> @elegos=3D
> >>>> oft.com<BR>&gt=3D3B Subject: Re: [M3devel] 5.8.6 LINUXLIBC6 breakage=3D2=
> >> C kerne=3D
> >>>> l 2.6.23=3D2C glibc-2.6-4<BR>&gt=3D3B <BR>&gt=3D3B Probably unnecessary=
> >> =3D2C given =3D
> >>>> that I think there is another entry point to forking a process (I forget=
> >> wh=3D
> >>>> ere) in the thread-specific portion of m3core. In which case the necessa=
> >> ry =3D
> >>>> work might be done there?<BR>&gt=3D3B <BR>&gt=3D3B On Apr 18=3D2C 2011=
> >> =3D2C at 2:45=3D
> >>>> PM=3D2C Mika Nystrom wrote:<BR>&gt=3D3B <BR>&gt=3D3B &gt=3D3B Tony Hosk=
> >> ing writes:=3D
> >>>> <BR>&gt=3D3B &gt=3D3B ...<BR>&gt=3D3B &gt=3D3B&gt=3D3B pthread_atfork sh=
> >> ould not be n=3D
> >>>> eeded under user threads.<BR>&gt=3D3B &gt=3D3B ...<BR>&gt=3D3B &gt=3D3B =
> >> <BR>&gt=3D3B =3D
> >>>> &gt=3D3B The following code from RTProcessC.c ensures that it is neeeded=
> >> on e=3D
> >>>> very Unix except<BR>&gt=3D3B &gt=3D3B FreeBSD before 6. The comment is f=
> >> rom the=3D
> >>>> checked-in source file.<BR>&gt=3D3B &gt=3D3B <BR>&gt=3D3B &gt=3D3B /* N=
> >> OTE: Even u=3D
> >>>> serthreads now depends<BR>&gt=3D3B &gt=3D3B * on availability of pthread=
> >> s.<BR>&=3D
> >>>> gt=3D3B &gt=3D3B * This can be fixed if need be.<BR>&gt=3D3B &gt=3D3B */=
> >> <BR>&gt=3D3B =3D
> >>>> &gt=3D3B <BR>&gt=3D3B &gt=3D3B INTEGER<BR>&gt=3D3B &gt=3D3B __cdecl<BR>&=
> >> gt=3D3B &gt=3D3B =3D
> >>>> RTProcess__RegisterForkHandlers(<BR>&gt=3D3B &gt=3D3B ForkHandler prepar=
> >> e=3D2C<BR=3D
> >>>>> &gt=3D3B &gt=3D3B ForkHandler parent=3D2C<BR>&gt=3D3B &gt=3D3B ForkHand=
> >> ler child)<BR=3D
> >>>>> &gt=3D3B &gt=3D3B {<BR>&gt=3D3B &gt=3D3B /* FreeBSD &lt=3D3B 6 lacks pt=
> >> hread_atfork.=3D
> >>>> Would be good to use autoconf.<BR>&gt=3D3B &gt=3D3B * VMS lacks pthread=
> >> _atfork=3D
> >>>> ? Would be good to use autoconf.<BR>&gt=3D3B &gt=3D3B * Win32 lacks pthr=
> >> ead_atf=3D
> >>>> ork and fork. OK.<BR>&gt=3D3B &gt=3D3B *<BR>&gt=3D3B &gt=3D3B * As well=
> >> =3D2C for all =3D
> >>>> Posix systems=3D2C we could implement<BR>&gt=3D3B &gt=3D3B * atfork ours=
> >> elves=3D2C =3D
> >>>> as long as we provide a fork()<BR>&gt=3D3B &gt=3D3B * wrapper that code =
> >> uses.<B=3D
> >>>> R>&gt=3D3B &gt=3D3B */<BR>&gt=3D3B &gt=3D3B #if defined(_WIN32) \<BR>&gt=
> >> =3D3B &gt=3D3B =3D
> >>>> || defined(__vms) \<BR>&gt=3D3B &gt=3D3B || (defined(__FreeBSD__) /* &am=
> >> p=3D3B&am=3D
> >>>> p=3D3B (__FreeBSD__ &lt=3D3B 6)*/ )<BR>&gt=3D3B &gt=3D3B return 0=3D3B<B=
> >> R>&gt=3D3B &gt=3D
> >>>> =3D3B #else<BR>&gt=3D3B &gt=3D3B while (1)<BR>&gt=3D3B &gt=3D3B {<BR>&gt=
> >> =3D3B &gt=3D3B in=3D
> >>>> t i =3D3D pthread_atfork(prepare=3D2C parent=3D2C child)=3D3B<BR>&gt=3D3=
> >> B &gt=3D3B if (=3D
> >>>> i !=3D3D EAGAIN)<BR>&gt=3D3B &gt=3D3B return i=3D3B<BR>&gt=3D3B &gt=3D3B=
> >> sleep(0)=3D3B<BR=3D
> >>>>> &gt=3D3B &gt=3D3B }<BR>&gt=3D3B &gt=3D3B #endif<BR>&gt=3D3B &gt=3D3B }<=
> >> BR>&gt=3D3B <BR> =3D
> >>>> 		 	   		  </body>
> >>>> </html>=3D
> >>>> 
> >>>> --_3dd397d4-ac1d-4148-a9ff-059d27dd794a_--
> >> 		 	   		  =
> >> 
> >> --_0203aac2-5c8e-49c7-9074-6bc448ecf342_
> >> Content-Type: text/html; charset="iso-8859-1"
> >> Content-Transfer-Encoding: quoted-printable
> >> 
> >> <html>
> >> <head>
> >> <style><!--
> >> .hmmessage P
> >> {
> >> margin:0px=3B
> >> padding:0px
> >> }
> >> body.hmmessage
> >> {
> >> font-size: 10pt=3B
> >> font-family:Tahoma
> >> }
> >> --></style>
> >> </head>
> >> <body class=3D'hmmessage'>
> >> &nbsp=3B&gt=3B This change depends on pthread_atfork=2C for pthreads and us=
> >> er threads.<br><br><br>Clarification: There's no change described there for=
> >> pthreads=2C and indeed=2C getting<br>this behavior with pthreads doesn't d=
> >> epend on using pthread_atfork. That is just<br>how pthreads are -- except o=
> >> ptionally on Solaris (fork1() vs. forkall() vs. fork()).<br>The Solaris def=
> >> ault used to be fork =3D&gt=3B forkall().<br>The current Solaris default is=
> >> fork =3D&gt=3B fork1().<br>There really do exist on Solaris to functions y=
> >> ou can call=2C fork1() and forkall().<br>All other systems and the Posix sp=
> >> ecification have the "fork1" semantic for fork.<br>Therefore "fork1" is wha=
> >> t we should provide unconditionally.<br>If you really want "forkall"=2C the=
> >> n you write:<br>#ifdef __sun<br>&nbsp=3B forkall()<br>#else<br>&nbsp=3B #er=
> >> ror<br>#endif<br><br><br><br>and/or you go and hack up m3core/src/thread/PO=
> >> SIX=2C branch off m3core/src/thread/POSIX_FORKALL or such.<br>I don't expec=
> >> t anyone to ever do that.<br><br><br><br>The need for pthread_atfork is sor=
> >> t of different for user threads vs. pthreads=2C but it is needed either way=
> >> .<br>For pthreads=2C there is this problem -- at the time a thread calls fo=
> >> rk()=2C what are other threads doing?<br>Answer: Anything.<br>Follow up que=
> >> stion: What locks might they hold?<br>Answer: Any.<br>Follow up: So=2C if a=
> >> rbitrary locks are held=2C and you fork=2C and don't exec=2C and the child =
> >> process<br>attempts to use some of the locks that were held in the parent=
> >> =2C and only the forking thread survived=2C<br>then the other threads will =
> >> never leave their locks=2C and later attempts to acquire them in the childr=
> >> en<br>will deadlock. Therefore=2C what pthread_atfork provides for=2C what =
> >> you are supposed to use it for=2C<br>is roughly speaking=2C right before fo=
> >> rk()=2C in the parent=2C acquire all locks=2C and then fork()=2C and then i=
> >> n the<br>parent and children=2C release all locks. Therefore=2C you have to=
> >> come up with a locking order.<br><br><br><br>Things are a little different=
> >> for user threads.<br>In user threads=2C the existance of threads is establ=
> >> ished by virtue of a global array or list of data describing the threads.<b=
> >> r>And a timer to occasionally preempt. When the timer interrupts=2C the sch=
> >> eduler picks another thread from the global<br>array/list. Previously=2C th=
> >> e data went unchanged when fork() was called. Therefore all threads survive=
> >> d.<br>What we do now is that in the child "handler" for pthread_atfork=2C i=
> >> s reinitialize the various data=2C so as to forget about<br>all but the cur=
> >> rent thread. Something like that.<br><br><br><br>I suspect if we had RTProc=
> >> ess.ForkBeforeExec and RTProcess.ForkBeforeMoreWork=2C then ForkBeforeExec<=
> >> br>might get away with just fork() and ignore all this.<br>So far we have n=
> >> ot drawn this line -- there is just the one fork and it is used prior to ex=
> >> ec or do-more-work<br>and does the same thing w/o knowing what is to follow=
> >> .<br><br><br>The Posix documentation I think describes this all fairly well=
> >> .<br>Bing for "posix opengroup pthread_atfork".<br>Really. I think it is sa=
> >> ying much of the same thing I am saying=2C but in language that has receive=
> >> d<br>much more thought. Be sure to read the "rationale" part.<br><br><br>&n=
> >> bsp=3B- Jay<br><br><br><hr id=3D"stopSpelling">From: jay.krell at cornell.edu<=
> >> br>To: mika at async.caltech.edu<br>CC: m3devel at elegosoft.com<br>Subject: RE: =
> >> [M3devel] 5.8.6 LINUXLIBC6 breakage=2C kernel 2.6.23=2C glibc-2.6-4<br>Date=
> >> : Tue=2C 19 Apr 2011 15:06:38 +0000<br><br>
> >> 
> >> <meta http-equiv=3D"Content-Type" content=3D"text/html=3B charset=3Dunicode=
> >> ">
> >> <meta name=3D"Generator" content=3D"Microsoft SafeHTML">
> >> <style>
> >> .ExternalClass .ecxhmmessage P
> >> {padding:0px=3B}
> >> .ExternalClass body.ecxhmmessage
> >> {font-size:10pt=3Bfont-family:Tahoma=3B}
> >> 
> >> </style>
> >> 
> >> 
> >> Previously: user threads: all threads survived fork()<br>Previously: pthrea=
> >> ds: only the thread calling fork() survived fork()<br>Now: user threads and=
> >> pthreads: only the thread calling fork() survives fork()<br>This must be h=
> >> ow pthreads behave=2C and this makes user threads and pthreads consistent.<=
> >> br>
> >> This change depends on pthread_atfork=2C for pthreads and user threads.<br>=
> >> It only really matters to the rare "fork + do more work" program=2C such as=
> >> cvsupd.<br>Most programs either never fork=2C or exec almost immediately a=
> >> fter fork.<br><br><br>pthread_atfork offers a good model.<br>A sort of "dis=
> >> tributed" model.<br>You don't have to go and change all the calls to fork()=
> >> .<br>Each module with a need to do something before/after fork=2C calls the=
> >> central pthread_atfork=2C<br>and fork and pthread_atfork cooperate to do w=
> >> hat is needed.<br><br><br>No function pointer is needed.<br>Instead move th=
> >> e code to m3core/thread.<br><br><br>If you really must not use -pthread=2C =
> >> then you must implement pthread_atfork functionality<br>yourself and have a=
> >> ll fork() calls go through your own fork() wrapper that cooperates<br>with =
> >> your pthread_atfork replacement.<br>There is no free lunch -- there is a do=
> >> wnside to this approach=2C as plain fork() calls<br>are ok and correct if p=
> >> thread_atfork is used=2C but now become incorrect.<br>Pick your poison:<br>=
> >> &nbsp=3B user thread/pthread inconsistency<br>&nbsp=3B cvsupd incompatibili=
> >> ty with pthreads <br>&nbsp=3B user threads using pthread_atfork/-pthread <b=
> >> r>&nbsp=3B fork() calls having to go through a wrapper (ok -- you could mis=
> >> s this and <br>&nbsp=3B&nbsp=3B not likely notice -- only fork() calls in f=
> >> ork+do-more-work programs need the wrapper). <br><br><br>(Most of this has =
> >> been explained multiple times=2C but people only pay attention<br>when they=
> >> think it affects them. I'm guilty of the same thing.)<br><br><br>&nbsp=3B-=
> >> Jay<br><br><br>&gt=3B To: jay.krell at cornell.edu<br>&gt=3B Date: Mon=2C 18 =
> >> Apr 2011 19:30:58 -0700<br>&gt=3B From: mika at async.caltech.edu<br>&gt=3B CC=
> >> : m3devel at elegosoft.com<br>&gt=3B Subject: Re: [M3devel] 5.8.6 LINUXLIBC6 b=
> >> reakage=2C kernel 2.6.23=2C glibc-2.6-4<br>&gt=3B <br>&gt=3B <br>&gt=3B If =
> >> you or Tony could describe roughly what you think needs to be done<br>&gt=
> >> =3B I'd be happy to look into it.<br>&gt=3B <br>&gt=3B The basic problem is=
> >> that a decision that's made/described in<br>&gt=3B m3core/thread/m3makefil=
> >> e needs to someone find its way to controlling<br>&gt=3B what C code gets c=
> >> ompiled elsewhere in the system.  Or maybe there should<br>&gt=3B be an ind=
> >> irection into the thread library to pick up pthread_atfork (or not).<br>&gt=
> >> =3B <br>&gt=3B But then again you still haven't explained why you made the =
> >> user threads use<br>&gt=3B pthread_atfork.  I just remove it from my instal=
> >> lations=2C but then again I'm<br>&gt=3B not trying to run CVSup so I don't =
> >> know if it breaks that program to do so.<br>&gt=3B <br>&gt=3B      Mika<br>=
> >> &gt=3B <br>&gt=3B Jay K writes:<br>&gt=3B &gt=3B--_3dd397d4-ac1d-4148-a9ff-=
> >> 059d27dd794a_<br>&gt=3B &gt=3BContent-Type: text/plain=3B charset=3D"iso-88=
> >> 59-1"<br>&gt=3B &gt=3BContent-Transfer-Encoding: quoted-printable<br>&gt=3B=
> >> &gt=3B<br>&gt=3B &gt=3B<br>&gt=3B &gt=3B&gt=3B The following code from RTP=
> >> rocessC.c ensures that it is neeeded on every =3D<br>&gt=3B &gt=3BUnix exce=
> >> pt<br>&gt=3B &gt=3B&gt=3B &gt=3B /* NOTE: Even userthreads now depends<br>&=
> >> gt=3B &gt=3B&gt=3B &gt=3B * on availability of pthreads.<br>&gt=3B &gt=3B&g=
> >> t=3B &gt=3B * This can be fixed if need be.<br>&gt=3B &gt=3B&gt=3B &gt=3B *=
> >> /<br>&gt=3B &gt=3B<br>&gt=3B &gt=3B=3D20<br>&gt=3B &gt=3BOk=3D2C "we" shoul=
> >> d probably go ahead and fix that.<br>&gt=3B &gt=3BI'll try to=3D2C but no p=
> >> romises=3D2C sorry.<br>&gt=3B &gt=3B=3D20<br>&gt=3B &gt=3B - Jay<br>&gt=3B =
> >> &gt=3B=3D20<br>&gt=3B &gt=3B&gt=3B From: hosking at cs.purdue.edu<br>&gt=3B &g=
> >> t=3B&gt=3B Date: Mon=3D2C 18 Apr 2011 18:11:26 -0400<br>&gt=3B &gt=3B&gt=3B=
> >> To: mika at async.caltech.edu<br>&gt=3B &gt=3B&gt=3B CC: m3devel at elegosoft.co=
> >> m<br>&gt=3B &gt=3B&gt=3B Subject: Re: [M3devel] 5.8.6 LINUXLIBC6 breakage=
> >> =3D2C kernel 2.6.23=3D2C glib=3D<br>&gt=3B &gt=3Bc-2.6-4<br>&gt=3B &gt=3B&g=
> >> t=3B=3D20<br>&gt=3B &gt=3B&gt=3B Probably unnecessary=3D2C given that I thi=
> >> nk there is another entry point t=3D<br>&gt=3B &gt=3Bo forking a process (I=
> >> forget where) in the thread-specific portion of m3co=3D<br>&gt=3B &gt=3Bre=
> >> . In which case the necessary work might be done there?<br>&gt=3B &gt=3B&gt=
> >> =3B=3D20<br>&gt=3B &gt=3B&gt=3B On Apr 18=3D2C 2011=3D2C at 2:45 PM=3D2C Mi=
> >> ka Nystrom wrote:<br>&gt=3B &gt=3B&gt=3B=3D20<br>&gt=3B &gt=3B&gt=3B &gt=3B=
> >> Tony Hosking writes:<br>&gt=3B &gt=3B&gt=3B &gt=3B ...<br>&gt=3B &gt=3B&gt=
> >> =3B &gt=3B&gt=3B pthread_atfork should not be needed under user threads.<br=
> >>> &gt=3B &gt=3B&gt=3B &gt=3B ...<br>&gt=3B &gt=3B&gt=3B &gt=3B=3D20<br>&gt=
> >> =3B &gt=3B&gt=3B &gt=3B The following code from RTProcessC.c ensures that i=
> >> t is neeeded on ever=3D<br>&gt=3B &gt=3By Unix except<br>&gt=3B &gt=3B&gt=
> >> =3B &gt=3B FreeBSD before 6. The comment is from the checked-in source file=
> >> .<br>&gt=3B &gt=3B&gt=3B &gt=3B=3D20<br>&gt=3B &gt=3B&gt=3B &gt=3B /* NOTE:=
> >> Even userthreads now depends<br>&gt=3B &gt=3B&gt=3B &gt=3B * on availabili=
> >> ty of pthreads.<br>&gt=3B &gt=3B&gt=3B &gt=3B * This can be fixed if need b=
> >> e.<br>&gt=3B &gt=3B&gt=3B &gt=3B */<br>&gt=3B &gt=3B&gt=3B &gt=3B=3D20<br>&=
> >> gt=3B &gt=3B&gt=3B &gt=3B INTEGER<br>&gt=3B &gt=3B&gt=3B &gt=3B __cdecl<br>=
> >> &gt=3B &gt=3B&gt=3B &gt=3B RTProcess__RegisterForkHandlers(<br>&gt=3B &gt=
> >> =3B&gt=3B &gt=3B ForkHandler prepare=3D2C<br>&gt=3B &gt=3B&gt=3B &gt=3B For=
> >> kHandler parent=3D2C<br>&gt=3B &gt=3B&gt=3B &gt=3B ForkHandler child)<br>&g=
> >> t=3B &gt=3B&gt=3B &gt=3B {<br>&gt=3B &gt=3B&gt=3B &gt=3B /* FreeBSD &lt=3B =
> >> 6 lacks pthread_atfork. Would be good to use autoconf.<br>&gt=3B &gt=3B&gt=
> >> =3B &gt=3B * VMS lacks pthread_atfork? Would be good to use autoconf.<br>&g=
> >> t=3B &gt=3B&gt=3B &gt=3B * Win32 lacks pthread_atfork and fork. OK.<br>&gt=
> >> =3B &gt=3B&gt=3B &gt=3B *<br>&gt=3B &gt=3B&gt=3B &gt=3B * As well=3D2C for =
> >> all Posix systems=3D2C we could implement<br>&gt=3B &gt=3B&gt=3B &gt=3B * a=
> >> tfork ourselves=3D2C as long as we provide a fork()<br>&gt=3B &gt=3B&gt=3B =
> >> &gt=3B * wrapper that code uses.<br>&gt=3B &gt=3B&gt=3B &gt=3B */<br>&gt=3B=
> >> &gt=3B&gt=3B &gt=3B #if defined(_WIN32) \<br>&gt=3B &gt=3B&gt=3B &gt=3B ||=
> >> defined(__vms) \<br>&gt=3B &gt=3B&gt=3B &gt=3B || (defined(__FreeBSD__) /*=
> >> &amp=3B&amp=3B (__FreeBSD__ &lt=3B 6)*/ )<br>&gt=3B &gt=3B&gt=3B &gt=3B re=
> >> turn 0=3D3B<br>&gt=3B &gt=3B&gt=3B &gt=3B #else<br>&gt=3B &gt=3B&gt=3B &gt=
> >> =3B while (1)<br>&gt=3B &gt=3B&gt=3B &gt=3B {<br>&gt=3B &gt=3B&gt=3B &gt=3B=
> >> int i =3D3D pthread_atfork(prepare=3D2C parent=3D2C child)=3D3B<br>&gt=3B =
> >> &gt=3B&gt=3B &gt=3B if (i !=3D3D EAGAIN)<br>&gt=3B &gt=3B&gt=3B &gt=3B retu=
> >> rn i=3D3B<br>&gt=3B &gt=3B&gt=3B &gt=3B sleep(0)=3D3B<br>&gt=3B &gt=3B&gt=
> >> =3B &gt=3B }<br>&gt=3B &gt=3B&gt=3B &gt=3B #endif<br>&gt=3B &gt=3B&gt=3B &g=
> >> t=3B }<br>&gt=3B &gt=3B&gt=3B=3D20<br>&gt=3B &gt=3B 		 	   		  =3D<br>&gt=
> >> =3B &gt=3B<br>&gt=3B &gt=3B--_3dd397d4-ac1d-4148-a9ff-059d27dd794a_<br>&gt=
> >> =3B &gt=3BContent-Type: text/html=3B charset=3D"iso-8859-1"<br>&gt=3B &gt=
> >> =3BContent-Transfer-Encoding: quoted-printable<br>&gt=3B &gt=3B<br>&gt=3B &=
> >> gt=3B&lt=3Bhtml&gt=3B<br>&gt=3B &gt=3B&lt=3Bhead&gt=3B<br>&gt=3B &gt=3B&lt=
> >> =3Bstyle&gt=3B&lt=3B!--<br>&gt=3B &gt=3B.hmmessage P<br>&gt=3B &gt=3B{<br>&=
> >> gt=3B &gt=3Bmargin:0px=3D3B<br>&gt=3B &gt=3Bpadding:0px<br>&gt=3B &gt=3B}<b=
> >> r>&gt=3B &gt=3Bbody.hmmessage<br>&gt=3B &gt=3B{<br>&gt=3B &gt=3Bfont-size: =
> >> 10pt=3D3B<br>&gt=3B &gt=3Bfont-family:Tahoma<br>&gt=3B &gt=3B}<br>&gt=3B &g=
> >> t=3B--&gt=3B&lt=3B/style&gt=3B<br>&gt=3B &gt=3B&lt=3B/head&gt=3B<br>&gt=3B =
> >> &gt=3B&lt=3Bbody class=3D3D'hmmessage'&gt=3B<br>&gt=3B &gt=3B&amp=3Bgt=3D3B=
> >> The following code from RTProcessC.c ensures that it is neeeded on e=3D<br=
> >>> &gt=3B &gt=3Bvery Unix except&lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B /=
> >> * NOTE: Even userthreads now depends&lt=3BBR&gt=3B=3D<br>&gt=3B &gt=3B&amp=
> >> =3Bgt=3D3B &amp=3Bgt=3D3B * on availability of pthreads.&lt=3BBR&gt=3B&amp=
> >> =3Bgt=3D3B &amp=3Bgt=3D3B * This can be=3D<br>&gt=3B &gt=3B fixed if need b=
> >> e.&lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B */&lt=3BBR&gt=3B&lt=3BBR&gt=
> >> =3B<br>&gt=3B &gt=3B&amp=3Bnbsp=3D3B&lt=3BBR&gt=3B<br>&gt=3B &gt=3BOk=3D2C =
> >> "we" should probably go ahead and fix that.&lt=3BBR&gt=3B<br>&gt=3B &gt=3BI=
> >> 'll try to=3D2C but no&amp=3Bnbsp=3D3Bpromises=3D2C sorry.&lt=3BBR&gt=3B<br=
> >>> &gt=3B &gt=3B&amp=3Bnbsp=3D3B&lt=3BBR&gt=3B<br>&gt=3B &gt=3B&amp=3Bnbsp=3D=
> >> 3B- Jay&lt=3BBR&gt=3B&amp=3Bnbsp=3D3B&lt=3BBR&gt=3B<br>&gt=3B &gt=3B&amp=3B=
> >> gt=3D3B From: hosking at cs.purdue.edu&lt=3BBR&gt=3B&amp=3Bgt=3D3B Date: Mon=
> >> =3D2C 18 Apr 2011 18:11=3D<br>&gt=3B &gt=3B:26 -0400&lt=3BBR&gt=3B&amp=3Bgt=
> >> =3D3B To: mika at async.caltech.edu&lt=3BBR&gt=3B&amp=3Bgt=3D3B CC: m3devel at el=
> >> egos=3D<br>&gt=3B &gt=3Boft.com&lt=3BBR&gt=3B&amp=3Bgt=3D3B Subject: Re: [M=
> >> 3devel] 5.8.6 LINUXLIBC6 breakage=3D2C kerne=3D<br>&gt=3B &gt=3Bl 2.6.23=3D=
> >> 2C glibc-2.6-4&lt=3BBR&gt=3B&amp=3Bgt=3D3B &lt=3BBR&gt=3B&amp=3Bgt=3D3B Pro=
> >> bably unnecessary=3D2C given =3D<br>&gt=3B &gt=3Bthat I think there is anot=
> >> her entry point to forking a process (I forget wh=3D<br>&gt=3B &gt=3Bere) i=
> >> n the thread-specific portion of m3core. In which case the necessary =3D<br=
> >>> &gt=3B &gt=3Bwork might be done there?&lt=3BBR&gt=3B&amp=3Bgt=3D3B &lt=3BB=
> >> R&gt=3B&amp=3Bgt=3D3B On Apr 18=3D2C 2011=3D2C at 2:45=3D<br>&gt=3B &gt=3B =
> >> PM=3D2C Mika Nystrom wrote:&lt=3BBR&gt=3B&amp=3Bgt=3D3B &lt=3BBR&gt=3B&amp=
> >> =3Bgt=3D3B &amp=3Bgt=3D3B Tony Hosking writes:=3D<br>&gt=3B &gt=3B&lt=3BBR&=
> >> gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B ...&lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=3Bg=
> >> t=3D3B&amp=3Bgt=3D3B pthread_atfork should not be n=3D<br>&gt=3B &gt=3Beede=
> >> d under user threads.&lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B ...&lt=3BB=
> >> R&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B &lt=3BBR&gt=3B&amp=3Bgt=3D3B =3D<br>&g=
> >> t=3B &gt=3B&amp=3Bgt=3D3B The following code from RTProcessC.c ensures that=
> >> it is neeeded on e=3D<br>&gt=3B &gt=3Bvery Unix except&lt=3BBR&gt=3B&amp=
> >> =3Bgt=3D3B &amp=3Bgt=3D3B FreeBSD before 6. The comment is from the=3D<br>&=
> >> gt=3B &gt=3B checked-in source file.&lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=
> >> =3D3B &lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B /* NOTE: Even u=3D<br>&gt=
> >> =3B &gt=3Bserthreads now depends&lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B=
> >> * on availability of pthreads.&lt=3BBR&gt=3B&amp=3B=3D<br>&gt=3B &gt=3Bgt=
> >> =3D3B &amp=3Bgt=3D3B * This can be fixed if need be.&lt=3BBR&gt=3B&amp=3Bgt=
> >> =3D3B &amp=3Bgt=3D3B */&lt=3BBR&gt=3B&amp=3Bgt=3D3B =3D<br>&gt=3B &gt=3B&am=
> >> p=3Bgt=3D3B &lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B INTEGER&lt=3BBR&gt=
> >> =3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B __cdecl&lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=
> >> =3Bgt=3D3B =3D<br>&gt=3B &gt=3BRTProcess__RegisterForkHandlers(&lt=3BBR&gt=
> >> =3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B ForkHandler prepare=3D2C&lt=3BBR=3D<br>&gt=
> >> =3B &gt=3B&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B ForkHandler parent=3D2C&lt=3B=
> >> BR&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B ForkHandler child)&lt=3BBR=3D<br>&gt=
> >> =3B &gt=3B&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B {&lt=3BBR&gt=3B&amp=3Bgt=3D3B=
> >> &amp=3Bgt=3D3B /* FreeBSD &amp=3Blt=3D3B 6 lacks pthread_atfork.=3D<br>&gt=
> >> =3B &gt=3B Would be good to use autoconf.&lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=
> >> =3Bgt=3D3B * VMS lacks pthread_atfork=3D<br>&gt=3B &gt=3B? Would be good to=
> >> use autoconf.&lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B * Win32 lacks pth=
> >> read_atf=3D<br>&gt=3B &gt=3Bork and fork. OK.&lt=3BBR&gt=3B&amp=3Bgt=3D3B &=
> >> amp=3Bgt=3D3B *&lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B * As well=3D2C f=
> >> or all =3D<br>&gt=3B &gt=3BPosix systems=3D2C we could implement&lt=3BBR&gt=
> >> =3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B * atfork ourselves=3D2C =3D<br>&gt=3B &gt=
> >> =3Bas long as we provide a fork()&lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3=
> >> B * wrapper that code uses.&lt=3BB=3D<br>&gt=3B &gt=3BR&gt=3B&amp=3Bgt=3D3B=
> >> &amp=3Bgt=3D3B */&lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B #if defined(_=
> >> WIN32) \&lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B =3D<br>&gt=3B &gt=3B|| =
> >> defined(__vms) \&lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B || (defined(__F=
> >> reeBSD__) /* &amp=3Bamp=3D3B&amp=3Bam=3D<br>&gt=3B &gt=3Bp=3D3B (__FreeBSD_=
> >> _ &amp=3Blt=3D3B 6)*/ )&lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B return 0=
> >> =3D3B&lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D<br>&gt=3B &gt=3B=3D3B #else&=
> >> lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B while (1)&lt=3BBR&gt=3B&amp=3Bgt=
> >> =3D3B &amp=3Bgt=3D3B {&lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B in=3D<br>=
> >> &gt=3B &gt=3Bt i =3D3D pthread_atfork(prepare=3D2C parent=3D2C child)=3D3B&=
> >> lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B if (=3D<br>&gt=3B &gt=3Bi !=3D3D=
> >> EAGAIN)&lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B return i=3D3B&lt=3BBR&g=
> >> t=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B sleep(0)=3D3B&lt=3BBR=3D<br>&gt=3B &gt=3B=
> >> &gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B }&lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=
> >> =3D3B #endif&lt=3BBR&gt=3B&amp=3Bgt=3D3B &amp=3Bgt=3D3B }&lt=3BBR&gt=3B&amp=
> >> =3Bgt=3D3B &lt=3BBR&gt=3B =3D<br>&gt=3B &gt=3B		 	   		  &lt=3B/body&gt=3B<=
> >> br>&gt=3B &gt=3B&lt=3B/html&gt=3B=3D<br>&gt=3B &gt=3B<br>&gt=3B &gt=3B--_3d=
> >> d397d4-ac1d-4148-a9ff-059d27dd794a_--<br> 		 	   		  </body>
> >> </html>=
> >> 
> >> --_0203aac2-5c8e-49c7-9074-6bc448ecf342_--
> 
 		 	   		  
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://m3lists.elegosoft.com/pipermail/m3devel/attachments/20110421/89437189/attachment-0002.html>


More information about the M3devel mailing list