From owner-freebsd-hackers@FreeBSD.ORG Fri Nov 28 15:25:30 2003 Return-Path: Delivered-To: freebsd-hackers@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 30F7416A4CE for ; Fri, 28 Nov 2003 15:25:30 -0800 (PST) Received: from stork.mail.pas.earthlink.net (stork.mail.pas.earthlink.net [207.217.120.188]) by mx1.FreeBSD.org (Postfix) with ESMTP id 9C9EE43FBF for ; Fri, 28 Nov 2003 15:25:27 -0800 (PST) (envelope-from tlambert2@mindspring.com) Received: from user-38lc0ef.dialup.mindspring.com ([209.86.1.207] helo=mindspring.com) by stork.mail.pas.earthlink.net with asmtp (SSLv3:RC4-MD5:128) (Exim 3.33 #1) id 1APryQ-00037Z-00; Fri, 28 Nov 2003 15:24:31 -0800 Message-ID: <3FC7D905.D244EF2C@mindspring.com> Date: Fri, 28 Nov 2003 15:23:49 -0800 From: Terry Lambert X-Mailer: Mozilla 4.79 [en] (Win98; U) X-Accept-Language: en MIME-Version: 1.0 To: rmkml References: Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-ELNK-Trace: b1a02af9316fbb217a47c185c03b154d40683398e744b8a401989662b1858b129202e10628c4cfe9548b785378294e88350badd9bab72f9c350badd9bab72f9c cc: freebsd-hackers@freebsd.org Subject: Re: question about _exit() function X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 28 Nov 2003 23:25:30 -0000 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