Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 13 Aug 2012 19:27:01 +0800
From:      David Xu <listlog2011@gmail.com>
To:        Jilles Tjoelker <jilles@stack.nl>
Cc:        Konstantin Belousov <kostikbel@gmail.com>, freebsd-hackers@freebsd.org, David Xu <davidxu@freebsd.org>
Subject:   Re: system() using vfork() or posix_spawn() and libthr
Message-ID:  <5028E485.3040506@gmail.com>
In-Reply-To: <20120811131048.GA29572@stack.nl>
References:  <20120730102408.GA19983@stack.nl> <20120730105303.GU2676@deviant.kiev.zoral.com.ua> <20120805215432.GA28704@stack.nl> <20120806082535.GI2676@deviant.kiev.zoral.com.ua> <20120809105648.GA79814@stack.nl> <50246EE4.9090409@freebsd.org> <20120811131048.GA29572@stack.nl>

next in thread | previous in thread | raw e-mail | index | archive | help
On 2012/08/11 21:10, Jilles Tjoelker wrote:
> On Fri, Aug 10, 2012 at 10:16:04AM +0800, David Xu wrote:
>> On 2012/08/09 18:56, Jilles Tjoelker wrote:
>>> On Mon, Aug 06, 2012 at 11:25:35AM +0300, Konstantin Belousov wrote:
>>>> On Sun, Aug 05, 2012 at 11:54:32PM +0200, Jilles Tjoelker wrote:
>>>>> On Mon, Jul 30, 2012 at 01:53:03PM +0300, Konstantin Belousov wrote:
>>>>>> On Mon, Jul 30, 2012 at 12:24:08PM +0200, Jilles Tjoelker wrote:
>>>>>>> People sometimes use system() from large address spaces where it would
>>>>>>> improve performance greatly to use vfork() instead of fork().
>>>>>>> A simple approach is to change fork() to vfork(), although I have not
>>>>>>> tried this. It seems safe enough to use sigaction and sigprocmask system
>>>>>>> calls in the vforked process.
>>>>>>> Alternatively, we can have posix_spawn() do the vfork() with signal
>>>>>>> changes. This avoids possible whining from compilers and static
>>>>>>> analyzers about using vfork() in system.c. However, I do not like the
>>>>>>> tricky code for signals and that it adds lines of code.
>>>>>>> This is lightly tested.
>>>>>> It is interesting to note that for some time our vfork(2) no longer
>>>>>> stops the whole forked process (parent), only the forking thread is
>>>>>> waiting for the child exit or exec. I am not sure is this point
>>>>>> important for system(3), but determined code can notice the difference
>>>>>> from the fork->vfork switch.
>>>>> Neither fork nor vfork call thread_single(SINGLE_BOUNDARY), so this is
>>>>> not a difference.
>>>> It is the difference, because vforked child shares parent address space.
>>>>> Thread singling may be noticeable from a failing execve() (but only in
>>>>> the process doing execve()) and in the rare case of rfork() without
>>>>> RFPROC.
>>>> No, other running threads in parent affect vforked child till exec or exit.
>>>> In fact, I would classify this as bug, but not a serious one.
>>> There are some ugly ways this parallel execution is depended on. If the
>>> vforked child calls sigaction() while another thread is also in
>>> sigaction() for that signal, the vforked child needs to wait for the
>>> other thread to release the lock.
>>> This uses a per-process lock to synchronize threads in different
>>> processes, which may not work properly.
>>> If the vforked child is killed (such as by SIGKILL) while holding the
>>> lock, the parent is not killed but its _thr_sigact is damaged.
>>> These problems could be avoided in libthr by skipping the lock in
>>> _sigaction() if a signal action is being set to SIG_DFL or SIG_IGN and
>>> the old action is not queried. In those cases, _thr_sigact is not
>>> touched so no lock is required. This change also helps applications,
>>> provided they call sigaction() and not signal().
>>> Alternatively, posix_spawn() and system() could use the sigaction system
>>> call directly, bypassing libthr (if present). However, this will not
>>> help applications that call vfork() and sigaction() themselves (such as
>>> a shell that wants to implement ...&  using vfork()).
>>> posix_spawn() likely still needs some adjustment so that having it reset
>>> all signals (sigfillset()) to the default action will not cause it to
>>> [EINVAL] because libthr does not allow changing SIGTHR's disposition.
>>> Index: lib/libthr/thread/thr_sig.c
>>> ===================================================================
>>> --- lib/libthr/thread/thr_sig.c	(revision 238970)
>>> +++ lib/libthr/thread/thr_sig.c	(working copy)
>>> @@ -519,8 +519,16 @@
>>>    		return (-1);
>>>    	}
>>>
>>> -	if (act)
>>> +	if (act) {
>>>    		newact = *act;
>>> +		/*
>>> +		 * Short-circuit cases where we do not touch _thr_sigact.
>>> +		 * This allows performing these safely in a vforked child.
>>> +		 */
>>> +		if ((newact.sa_handler == SIG_DFL ||
>>> +		    newact.sa_handler == SIG_IGN)&&  oact == NULL)
>>> +			return (__sys_sigaction(sig,&newact, NULL));
>>> +	}
>>>
>>>    	__sys_sigprocmask(SIG_SETMASK,&_thr_maskset,&oldset);
>>>    	_thr_rwl_wrlock(&_thr_sigact[sig-1].lock);
>>>
>> Your patch is better than nothing, I don't object.
>> The problem is visble to you, but there is also invisible user - rtld.
>> If a symbol is never used in parent process, but now it is used
>> in a vforked child, the rtld will be involved, if the child
>> is killed, the rtld's data structure may be in inconsistent state,
>> such as locking or link list etcs...
>> I think this problem might be a non-fixable problem.
> Hmm. Rtld cannot be fixed like libthr because its data structures are
> inherently in userland.
>
> Perhaps signal handling should be different for a vforked child, like
> the default action of a signal sent to a thread affects the entire
> process and not just the thread. This cannot be implemented in the
> calling code because resolving execve() itself also needs rtld (ugly
> hacks like performing an execve() call that is guaranteed to fail
> aside).
>
> The rtld problem can be avoided specifically by linking with '-z now'.
> This might be acceptable for sh and csh; most applications can use
> posix_spawn() which would have to become a system call.
>
Or the libc's posix_spawn() should use each system call directly, it should
not call a function which is exported from libc globally, otherwise a PLT
resolving will cause rtld locking to be acquired, if it dies, the parent is
locked.




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?5028E485.3040506>