Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 28 Nov 2003 15:23:49 -0800
From:      Terry Lambert <tlambert2@mindspring.com>
To:        rmkml <rmkml@wanadoo.fr>
Cc:        freebsd-hackers@freebsd.org
Subject:   Re: question about _exit() function
Message-ID:  <3FC7D905.D244EF2C@mindspring.com>
References:  <Pine.LNX.4.58.0311272019050.16308@hp.mgn.net> <Pine.LNX.4.58.0311281539380.22334@hp.mgn.net>

next in thread | previous in thread | raw e-mail | index | archive | help
rmkml wrote:
> Thanks a lot for the answer. I will change vfork() with fork().
> 
> An another question: in the man page of vfork() it is mentionned that
> the fork() function has to use _exit(0) too when something wrong with the
> execve() happens!

I can see how you might read it this way, but that's not really
correct.

The purpose of _exit() instead of exit() is to avoid calling the
atexit() handler, the per thread data cleanup handlers, and the
cancellation routines.

In the case of a vfork(), it's undefined as to whether you will
be operating against resources currently allocated and appropriately
reference counted to the child, or whether you are operating against
that of the parent.  In the case of fork(), you are guaranteed to
operate in the context of the child.

Which you should use is dependent on your application.  The normal
operation of a fork() in a threaded program is to duplicate only
the calling thread.  If you have registered atexit(), per thread
data cleanup handlers, or cancellation routines (or, in some cases,
signal handlers), then when you call exit(), these things will be
invoked.

Consider that the thread forking has perhaps the responsibility of
cleaning up a shared memory segment created by a task.  You do *not*
want to do this cleanup (which happens on an interface that you are
manually resource tracking) in the child process in this case, since
it could rip the shared memory segment out from under other processes
which are using it.

Rather than calling _exit() to avoid this, you probably want to call
exit()... however, you must deal with detaching your registered
handlers and avoiding your manual cleanup process.  The correct way
to do this is to disable them in the child by utilizing the function
pthread_atfork() to disentangle them at fork time.

See:
    http://www.opengroup.org/onlinepubs/007904975/functions/pthread_atfork.html


> Is the child a real process or because of the thread context a part of
> the parent process, so a new thread.

It is a real process; the only thread running in this real process
is a copy of the thread that was running at the time of the fork().
This is the primary reason that vfork() cautions against its use in
POSIX documentation, and why it only permits either an _exit() or an
execve(), and why you should avoid vfork().


> In this case a pthread_exit() may be a better solution.
> Is that point a view complety wrong ?

You likely do not want to use pthread_exit() in this case, since you
are the only thread in a process.  If you were to use this with vfork(),
the combination would likely cause a program malfunction.  If you were
to use it with fork(), the combination may or may not be a problem.  In
the second case, the reason for this is that there exists the possibility
that when you create the new process, it will link with object files with
statically declared instances whose .init routines create worker threads.
For example, the Netscape LDAP library is not threads-safe, so at one
point I wrote a wrapper library that queued requests to a single worker
thread that was created at the time the library reference was instanced
via a .init section.  Calls into the library queued requests, which were
then serialized to the Netscape library, and responses were sent back out.
The result looked like an LDAP client library that could be reentered,
but which would serialize work to the non-thread-reentrant library under
the covers.

So the reason pthread_exit() should not be used is that you may not be
the only thread running, and if so, there will be no pthread_join()
called to reap your thread, and the other threads will continue
indefinitely: you can't depend on not creating threads as a side effect
of using various libraries or shared objects.


> Currently, is some indeterminate case, a part of my program freeze just
> after the vfork().
> So, I try to understand what may cause the calling thread of vfork() to
> freeze ...

Without more detail, this is hard to pinpoint, since I don't really
know what you mean by "freeze", and there appears to be a language
barrier to a precise explanation.

Most likely, this is an interaction between the user space scheduler
and the vfork().  Realize that in the 4.x series of FreeBSD, the pthreads
are implemented with a user space scheduler.  This means that following
a vfork(), since there is only one schedulable entity, the process, all
threads are suspended until your _exit(0 or execve() call (assuming that
these do the right thing in the vfork() case interacting with threads,
and POSIX says that it's undefined if this will happen).  If you want
other threads in your main applicaion to run concurrently with the child,
you *must* use fork() instead of vfork().

-- Terry



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3FC7D905.D244EF2C>