threads/101323: fork(2) in threaded programs broken.

Daniel Eischen deischen at freebsd.org
Thu Aug 3 18:34:18 UTC 2006


On Thu, 3 Aug 2006, Poul-Henning Kamp wrote:

> In message <Pine.GSO.4.64.0608031348490.13543 at sea.ntplx.net>, Daniel Eischen writes:
>> On Thu, 3 Aug 2006, Poul-Henning Kamp wrote:
>>
>>> 	Forking a threaded process and starting a thread in the
>>> 	child process does not work.
>>>
>>> 	Tested on -current and releng_6 and both fails with more or
>>> 	less the same error message:
>>>
>>> 	Fatal error 'mutex is on list' at line 540 in file
>>> 	    /usr/src/lib/libpthread/thread/thr_mutex.c (errno = 0)
>>
>> fork()ing from a threaded process and making calls to functions
>> other than those defined as async-signal-safe is not allowed
>> by POSIX.  libpthread intentionally doesn't support this.
>
> As you may probably be aware, I don't hold great respect for
> POSIX when it comes to writing useful APIs :-)
>
> First of all, there is a difference between POSIX explicitly
> disallowing something and POSIX not guaranteeing that something
> works.
>
> I belive we are in the second range here.

You should read section 2.4.3 of "Signal Concepts" in
the POSIX spec.

> Both Solaris and Linux support the usage which FreeBSD fails and
> as far as I can tell from our source-code, we also go a long way
> to make it work, just not long enough.
>
> As far as I can tell, all that's need to make it work correctly is
> the attached patch (which I've sent to Jason Evans since it's malloc related.)

No, that's not nearly enough.  This has been discussed in
-threads before.

Forking from a multi-threaded program is just like an
asynchronous signal in an unthreaded program.  You have
no idea what state any of the libraries or application data
is in.  Other threads may have taken either library or
application locks and left things in an inconsistent
state.  The only sure way to safely fork() from a threaded
process is to suspend threads while assuring they are
not in critical regions, then fork() and reinitialize
any necessary library global data in the child, and
resume the suspended threads in the parent after the
fork().

It may seem simple to #define NOTYET in
src/lib/libpthread/thread/thr_kern.c but that isn't
going to guarantee that libc or other library data is
left in a consistent state and that their locks are
reinitialized.

-- 
DE


More information about the freebsd-threads mailing list