Index: libthr/pthread.map =================================================================== --- libthr/pthread.map (revision 239227) +++ libthr/pthread.map (working copy) @@ -157,6 +157,7 @@ system; tcdrain; usleep; + vfork; wait; wait3; wait4; Index: libthr/thread/thr_vfork.c =================================================================== --- libthr/thread/thr_vfork.c (revision 0) +++ libthr/thread/thr_vfork.c (working copy) @@ -0,0 +1,38 @@ +#include "thr_private.h" +#include + +extern pid_t __sys_vfork(void); + +pid_t _vfork(void); + +pid_t +_vfork(void) +{ + struct pthread *curthread = _get_curthread(); + sigset_t set, oset; + pid_t pid; + + SIGFILLSET(set); + __sys_sigprocmask(SIG_SETMASK, &set, &oset); + if (curthread->vfork == 0) + curthread->sigmask = oset; + pid = __sys_vfork(); + if (pid == 0) { + curthread->vfork++; + __sys_sigprocmask(SIG_SETMASK, &oset, NULL); + return (pid); + } else if (pid != -1) { + /* + * stack was changed by child, we need to + * re-fetch the curthread. + */ + curthread = _get_curthread(); + if (curthread->vfork > 0) + curthread->vfork--; + } + if (curthread->vfork == 0) + __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL); + return (pid); +} + +__weak_reference(_vfork, vfork); Index: libthr/thread/thr_sig.c =================================================================== --- libthr/thread/thr_sig.c (revision 239227) +++ libthr/thread/thr_sig.c (working copy) @@ -158,9 +158,12 @@ int err; err = errno; - _thr_rwl_rdlock(&_thr_sigact[sig-1].lock); + /* no locking for vfork */ + if (!curthread->vfork) + _thr_rwl_rdlock(&_thr_sigact[sig-1].lock); act = _thr_sigact[sig-1].sigact; - _thr_rwl_unlock(&_thr_sigact[sig-1].lock); + if (!curthread->vfork) + _thr_rwl_unlock(&_thr_sigact[sig-1].lock); errno = err; /* @@ -510,6 +513,7 @@ int _sigaction(int sig, const struct sigaction * act, struct sigaction * oact) { + struct pthread *curthread = _get_curthread(); struct sigaction newact, oldact, oldact2; sigset_t oldset; int ret = 0, err = 0; @@ -522,28 +526,37 @@ if (act) newact = *act; - __sys_sigprocmask(SIG_SETMASK, &_thr_maskset, &oldset); - _thr_rwl_wrlock(&_thr_sigact[sig-1].lock); + /* no locking for vfork */ + if (!curthread->vfork) { + __sys_sigprocmask(SIG_SETMASK, &_thr_maskset, &oldset); + _thr_rwl_wrlock(&_thr_sigact[sig-1].lock); + } if (act != NULL) { oldact2 = _thr_sigact[sig-1].sigact; - - /* - * if a new sig handler is SIG_DFL or SIG_IGN, - * don't remove old handler from _thr_sigact[], - * so deferred signals still can use the handlers, - * multiple threads invoking sigaction itself is - * a race condition, so it is not a problem. - */ - if (newact.sa_handler != SIG_DFL && - newact.sa_handler != SIG_IGN) { - _thr_sigact[sig-1].sigact = newact; - remove_thr_signals( - &_thr_sigact[sig-1].sigact.sa_mask); - newact.sa_flags &= ~SA_NODEFER; - newact.sa_flags |= SA_SIGINFO; - newact.sa_sigaction = thr_sighandler; - newact.sa_mask = _thr_maskset; /* mask all signals */ + if (curthread->vfork) { + /* vfork child can only use SIG_IGN or SIG_DFL */ + if (newact.sa_handler != SIG_IGN) + newact.sa_handler = SIG_DFL; + } else { + /* + * if a new sig handler is SIG_DFL or SIG_IGN, + * don't remove old handler from _thr_sigact[], + * so deferred signals still can use the handlers, + * multiple threads invoking sigaction itself is + * a race condition, so it is not a problem. + */ + if (newact.sa_handler != SIG_DFL && + newact.sa_handler != SIG_IGN) { + _thr_sigact[sig-1].sigact = newact; + remove_thr_signals( + &_thr_sigact[sig-1].sigact.sa_mask); + newact.sa_flags &= ~SA_NODEFER; + newact.sa_flags |= SA_SIGINFO; + newact.sa_sigaction = thr_sighandler; + /* mask all signals */ + newact.sa_mask = _thr_maskset; + } } if ((ret = __sys_sigaction(sig, &newact, &oldact))) { err = errno; @@ -562,8 +575,10 @@ oldact = _thr_sigact[sig-1].sigact; } - _thr_rwl_unlock(&_thr_sigact[sig-1].lock); - __sys_sigprocmask(SIG_SETMASK, &oldset, NULL); + if (!curthread->vfork) { + _thr_rwl_unlock(&_thr_sigact[sig-1].lock); + __sys_sigprocmask(SIG_SETMASK, &oldset, NULL); + } if (ret == 0) { if (oact != NULL) Index: libthr/thread/Makefile.inc =================================================================== --- libthr/thread/Makefile.inc (revision 239227) +++ libthr/thread/Makefile.inc (working copy) @@ -55,4 +55,5 @@ thr_switch_np.c \ thr_symbols.c \ thr_umtx.c \ + thr_vfork.c \ thr_yield.c Index: libthr/thread/thr_private.h =================================================================== --- libthr/thread/thr_private.h (revision 239227) +++ libthr/thread/thr_private.h (working copy) @@ -523,6 +523,9 @@ /* Deferred threads from pthread_cond_signal. */ unsigned int *defer_waiters[MAX_DEFER_WAITERS]; + + /* nested vfork count */ + int vfork; #define _pthread_endzero wake_addr struct wake_addr *wake_addr;