Index: thread/thr_sig.c =================================================================== --- thread/thr_sig.c (revision 211861) +++ thread/thr_sig.c (working copy) @@ -32,11 +32,10 @@ #include #include #include -#include -#include #include #include #include "un-namespace.h" +#include "libc_private.h" #include "thr_private.h" @@ -47,7 +46,18 @@ #define DBG_MSG(x...) #endif -extern int __pause(void); +struct usigaction { + struct sigaction sigact; + struct urwlock lock; +}; + +static struct usigaction _thr_sigact[_SIG_MAXSIG]; + +static void thr_sighandler(int, siginfo_t *, void *); +static void handle_deferred_signal(struct pthread *); +static void handle_signal(struct sigaction *, int, siginfo_t *, ucontext_t *); +static void suspend_check(struct pthread *); + int ___pause(void); int _raise(int); int __sigtimedwait(const sigset_t *set, siginfo_t *info, @@ -59,9 +69,48 @@ int __sigwait(const sigset_t *set, int *sig); int _sigwait(const sigset_t *set, int *sig); int __sigsuspend(const sigset_t *sigmask); +int _sigaction(int, const struct sigaction *, struct sigaction *); int _setcontext(const ucontext_t *); int _swapcontext(ucontext_t *, const ucontext_t *); +static const sigset_t _thr_deferset={{ + 0xffffffff & ~(_SIG_BIT(SIGBUS)|_SIG_BIT(SIGILL)|_SIG_BIT(SIGFPE)| + _SIG_BIT(SIGSEGV)|_SIG_BIT(SIGTRAP)|_SIG_BIT(SIGSYS)), + 0xffffffff, + 0xffffffff, + 0xffffffff}}; + +static const sigset_t _thr_maskset={{ + 0xffffffff, + 0xffffffff, + 0xffffffff, + 0xffffffff}}; + +void +_thr_signal_block(struct pthread *curthread) +{ + + if (curthread->sigblock > 0) { + curthread->sigblock++; + return; + } + __sys_sigprocmask(SIG_BLOCK, &_thr_maskset, &curthread->sigmask); + curthread->sigblock++; +} + +void +_thr_signal_unblock(struct pthread *curthread) +{ + if (--curthread->sigblock == 0) + __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL); +} + +int +_thr_send_sig(struct pthread *thread, int sig) +{ + return thr_kill(thread->tid, sig); +} + static void remove_thr_signals(sigset_t *set) { @@ -72,42 +121,42 @@ static const sigset_t * thr_remove_thr_signals(const sigset_t *set, sigset_t *newset) { - const sigset_t *pset; - - if (SIGISMEMBER(*set, SIGCANCEL)) { - *newset = *set; - SIGDELSET(*newset, SIGCANCEL); - pset = newset; - } else - pset = set; - return (pset); + *newset = *set; + SIGDELSET(*newset, SIGCANCEL); + return (newset); } static void sigcancel_handler(int sig __unused, - siginfo_t *info __unused, ucontext_t *ucp __unused) + siginfo_t *info __unused, ucontext_t *ucp) { - struct pthread *curthread = _get_curthread(); - curthread->in_sigcancel_handler++; - _thr_ast(curthread); - curthread->in_sigcancel_handler--; + _thr_ast(_get_curthread(), sig, ucp); } void -_thr_ast(struct pthread *curthread) +_thr_ast(struct pthread *curthread, int sig, ucontext_t *ucp) { - if (THR_IN_CRITICAL(curthread)) + if (__predict_false(THR_IN_CRITICAL(curthread))) return; - if (curthread->cancel_pending && curthread->cancel_enable - && !curthread->cancelling) { + handle_deferred_signal(curthread); + + suspend_check(curthread); + + /* reschedule cancellation */ + if (__predict_false(curthread->cancel_pending && curthread->cancel_enable + && !curthread->cancelling)) { if (curthread->cancel_async) { /* * asynchronous cancellation mode, act upon - * immediately. + * immediately. note that new thread created by + * this thread's cleanup handler should unblock + * SIGCANCEL. */ + if (sig == SIGCANCEL) + curthread->unblock_sigcancel = 1; _pthread_exit(PTHREAD_CANCELED); } else { /* @@ -115,8 +164,8 @@ * cancel point, tell kernel to not block the current * thread on next cancelable system call. * - * There are two cases we should call thr_wake() to - * turn on TDP_WAKEUP in kernel: + * There are three cases we should call thr_wake() to + * turn on TDP_WAKEUP or send SIGCANCEL in kernel: * 1) we are going to call a cancelable system call, * non-zero cancel_point means we are already in * cancelable state, next system call is cancelable. @@ -127,28 +176,185 @@ * those routines may clear the TDP_WAKEUP flag by * invoking some system calls, in those cases, we * also should reenable the flag. + * 3) thread is in sigsuspend(), and the syscall insists + * on getting a signal before it agrees to return. */ if (curthread->cancel_point) { - if (curthread->cancel_defer) - thr_wake(curthread->tid); - else + if (curthread->cancel_defer) { + if (curthread->in_sigsuspend) { + if (ucp) { + sigset_t set; + SIGEMPTYSET(set); + SIGADDSET(set, SIGCANCEL); + SIGADDSET(ucp->uc_sigmask, SIGCANCEL); + __sys_sigprocmask(SIG_BLOCK, &set, NULL); + curthread->unblock_sigcancel = 1; + _thr_send_sig(curthread, SIGCANCEL); + } + } + else + thr_wake(curthread->tid); + } else { + if (sig == SIGCANCEL) + curthread->unblock_sigcancel = 1; _pthread_exit(PTHREAD_CANCELED); + } } } } +} - if (__predict_false((curthread->flags & - (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED)) - == THR_FLAGS_NEED_SUSPEND)) - _thr_suspend_check(curthread); +typedef void (*ohandler)(int sig, int code, + struct sigcontext *scp, char *addr, __sighandler_t *catcher); + +/* + * The signal handler wrapper is entered with all signal masked. + */ +static void +thr_sighandler(int sig, siginfo_t *info, void *_ucp) +{ + struct pthread *curthread = _get_curthread(); + ucontext_t *ucp = _ucp; + struct sigaction act; + + _thr_rwl_rdlock(&_thr_sigact[sig-1].lock); + act = _thr_sigact[sig-1].sigact; + _thr_rwl_unlock(&_thr_sigact[sig-1].lock); + + /* + * if a thread is in critical region, for example it holds low level locks, + * try to defer the signal processing, however if the signal is synchronous + * signal, it means a bad thing has happened, this is a programming error, + * resuming to fault point does not help anything, so here we let user code + * handle it immediately. + */ + if (THR_IN_CRITICAL(curthread) && SIGISMEMBER(_thr_deferset, sig)) { + memcpy(&curthread->deferred_sigact, &act, sizeof(struct sigaction)); + memcpy(&curthread->deferred_siginfo, info, sizeof(siginfo_t)); + curthread->deferred_sigmask = ucp->uc_sigmask; + /* mask all signals, will restore it later. */ + ucp->uc_sigmask = _thr_deferset; + return; + } + + handle_signal(&act, sig, info, ucp); } -void -_thr_suspend_check(struct pthread *curthread) +static void +handle_signal(struct sigaction *actp, int sig, siginfo_t *info, ucontext_t *ucp) { + struct pthread *curthread = _get_curthread(); + ucontext_t uc2; + __siginfohandler_t *sigfunc; + int cancel_defer; + int cancel_point; + int cancel_async; + int cancel_enable; + int in_sigsuspend; + + sigfunc = actp->sa_sigaction; + + /* add previous level mask */ + SIGSETOR(actp->sa_mask, ucp->uc_sigmask); + + /* add this signal's mask */ + if (!(actp->sa_flags & SA_NODEFER)) + SIGADDSET(actp->sa_mask, sig); + + in_sigsuspend = curthread->in_sigsuspend; + curthread->in_sigsuspend = 0; + + /* + * if thread is in deferred cancellation mode, disable cancellation + * in signal handler. + * if user signal handler calls a cancellation point function, e.g, + * it calls write() to write data to file, because write() is a + * cancellation point, the thread is immediately cancelled if + * cancelling is pending, to avoid this problem while thread is in + * deferring mode, cancellation is temporarily disabled. + */ + cancel_defer = curthread->cancel_defer; + cancel_point = curthread->cancel_point; + cancel_async = curthread->cancel_async; + cancel_enable = curthread->cancel_enable; + curthread->cancel_point = 0; + curthread->cancel_defer = 0; + if (!cancel_async) + curthread->cancel_enable = 0; + + /* restore correct mask before calling user handler */ + __sys_sigprocmask(SIG_SETMASK, &actp->sa_mask, NULL); + + /* + * We have already reset cancellation point flags, so if user's code + * longjmp()s out of its signal handler, wish its jmpbuf was set + * outside of a cancellation point, in most cases, this would be + * true. however, ther is no way to save cancel_enable in jmpbuf, + * so after setjmps() returns once more, the user code may need to + * re-set cancel_enable flag by calling pthread_setcancelstate(). + */ + if ((actp->sa_flags & SA_SIGINFO) != 0) + (*(sigfunc))(sig, info, ucp); + else { + ((ohandler)(*sigfunc))( + sig, info->si_code, (struct sigcontext *)ucp, + info->si_addr, (__sighandler_t *)sigfunc); + } + + curthread->in_sigsuspend = in_sigsuspend; + curthread->cancel_defer = cancel_defer; + curthread->cancel_point = cancel_point; + curthread->cancel_enable = cancel_enable; + + memcpy(&uc2, ucp, sizeof(uc2)); + SIGDELSET(uc2.uc_sigmask, SIGCANCEL); + + /* reschedule cancellation */ + _thr_ast(curthread, 0, &uc2); + __sys_sigreturn(&uc2); +} + +static void +handle_deferred_signal(struct pthread *curthread) +{ + ucontext_t uc; + struct sigaction act; + siginfo_t info; + volatile int first; + + if (__predict_true(curthread->deferred_siginfo.si_signo == 0)) + return; + first = 1; + getcontext(&uc); + if (first) { + first = 0; + act = curthread->deferred_sigact; + uc.uc_sigmask = curthread->deferred_sigmask; + memcpy(&info, &curthread->deferred_siginfo, sizeof(siginfo_t)); + /* remove signal */ + curthread->deferred_siginfo.si_signo = 0; + if (act.sa_flags & SA_RESETHAND) { + struct sigaction tact; + + tact = act; + tact.sa_handler = SIG_DFL; + _sigaction(info.si_signo, &tact, NULL); + } + handle_signal(&act, info.si_signo, &info, &uc); + } +} + +static void +suspend_check(struct pthread *curthread) +{ uint32_t cycle; int err; + if (__predict_true((curthread->flags & + (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED)) + != THR_FLAGS_NEED_SUSPEND)) + return; + if (curthread->force_exit) return; @@ -188,13 +394,6 @@ THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock); curthread->critical_count--; - /* - * Unblocks SIGCANCEL, it is possible a new SIGCANCEL is ready and - * a new signal frame will nest us, this seems a problem because - * stack will grow and overflow, but because kernel will automatically - * mask the SIGCANCEL when delivering the signal, so we at most only - * have one nesting signal frame, this should be fine. - */ _thr_signal_unblock(curthread); errno = err; } @@ -204,14 +403,95 @@ { struct sigaction act; - /* Install cancel handler. */ + /* Install SIGCANCEL handler. */ SIGEMPTYSET(act.sa_mask); - act.sa_flags = SA_SIGINFO | SA_RESTART; + act.sa_flags = SA_SIGINFO; act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler; __sys_sigaction(SIGCANCEL, &act, NULL); +#if 0 + int i; + /* Install signal handler wrapper for existing handler */ + for (i = 1; i <= _SIG_MAXSIG; ++i) { + if (i != SIGCANCEL) { + __sys_sigaction(i, NULL, &act); + if (act.sa_handler != SIG_DFL && + act.sa_handler != SIG_IGN) + _sigaction(i, &act, NULL); + } + } +#endif + + sigset_t set; + SIGEMPTYSET(set); + SIGADDSET(set, SIGCANCEL); + __sys_sigprocmask(SIG_UNBLOCK, &set, NULL); } +/* + * called from rtld with rtld_lock locked, because rtld_lock is + * a critical region, so all signals have already beeen masked. + */ void +_thr_sigact_unload(struct dl_phdr_info *phdr_info) +{ + struct urwlock *rwlp; + struct sigaction *actp; + struct sigaction kact; + void (*handler)(int); + int sig; + + for (sig = 1; sig < _SIG_MAXSIG; sig++) { + actp = &_thr_sigact[sig].sigact; +retry: + handler = actp->sa_handler; + if (handler != SIG_DFL && handler != SIG_IGN && + __elf_phdr_match_addr(phdr_info, handler)) { + rwlp = &_thr_sigact[sig].lock; + _thr_rwl_wrlock(rwlp); + if (handler != actp->sa_handler) { + _thr_rwl_unlock(rwlp); + goto retry; + } + actp->sa_handler = SIG_DFL; + actp->sa_flags = SA_SIGINFO; + SIGEMPTYSET(actp->sa_mask); + if (__sys_sigaction(sig, NULL, &kact) == 0 && + kact.sa_handler != SIG_DFL && + kact.sa_handler != SIG_IGN) + __sys_sigaction(sig, actp, NULL); + _thr_rwl_unlock(rwlp); + } + } +} + +void +_thr_signal_prefork(void) +{ + int i; + + for (i = 1; i < _SIG_MAXSIG; ++i) + _thr_rwl_rdlock(&_thr_sigact[i-1].lock); +} + +void +_thr_signal_postfork(void) +{ + int i; + + for (i = 1; i < _SIG_MAXSIG; ++i) + _thr_rwl_unlock(&_thr_sigact[i-1].lock); +} + +void +_thr_signal_postfork_child(void) +{ + int i; + + for (i = 1; i < _SIG_MAXSIG; ++i) + bzero(&_thr_sigact[i-1].lock, sizeof(struct urwlock)); +} + +void _thr_signal_deinit(void) { } @@ -221,14 +501,11 @@ int ___pause(void) { - struct pthread *curthread = _get_curthread(); - int ret; + sigset_t oset; - _thr_cancel_enter(curthread); - ret = __pause(); - _thr_cancel_leave(curthread); - - return ret; + if (_sigprocmask(SIG_BLOCK, NULL, &oset) == -1) + return (-1); + return (__sigsuspend(&oset)); } __weak_reference(_raise, raise); @@ -236,13 +513,7 @@ int _raise(int sig) { - int ret; - - if (!_thr_isthreaded()) - ret = kill(getpid(), sig); - else - ret = _thr_send_sig(_get_curthread(), sig); - return (ret); + return _thr_send_sig(_get_curthread(), sig); } __weak_reference(_sigaction, sigaction); @@ -250,14 +521,65 @@ int _sigaction(int sig, const struct sigaction * act, struct sigaction * oact) { - /* Check if the signal number is out of range: */ + struct sigaction newact, oldact, oldact2; + sigset_t oldset; + int ret = 0, err = 0; + if (!_SIG_VALID(sig) || sig == SIGCANCEL) { - /* Return an invalid argument: */ errno = EINVAL; return (-1); } - return __sys_sigaction(sig, act, oact); + if (act) + newact = *act; + + __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 ((ret = __sys_sigaction(sig, &newact, &oldact))) { + err = errno; + _thr_sigact[sig-1].sigact = oldact2; + } + } else if (oact != NULL) { + ret = __sys_sigaction(sig, NULL, &oldact); + err = errno; + } + + if (oldact.sa_handler != SIG_DFL && + oldact.sa_handler != SIG_IGN) { + oldact = _thr_sigact[sig-1].sigact; + } + + _thr_rwl_unlock(&_thr_sigact[sig-1].lock); + __sys_sigprocmask(SIG_SETMASK, &oldset, NULL); + + if (ret == 0) { + if (oact != NULL) + *oact = oldact; + } else { + errno = err; + } + return (ret); } __weak_reference(_sigprocmask, sigprocmask); @@ -303,11 +625,20 @@ { struct pthread *curthread = _get_curthread(); sigset_t newset; - int ret; + int ret, old; - _thr_cancel_enter(curthread); + old = curthread->in_sigsuspend; + curthread->in_sigsuspend = 1; + _thr_cancel_enter_defer(curthread, 1); ret = __sys_sigsuspend(thr_remove_thr_signals(set, &newset)); - _thr_cancel_leave(curthread); + _thr_cancel_leave_defer(curthread, 1); + curthread->in_sigsuspend = old; + if (curthread->unblock_sigcancel) { + curthread->unblock_sigcancel = 0; + SIGEMPTYSET(newset); + SIGADDSET(newset, SIGCANCEL); + __sys_sigprocmask(SIG_UNBLOCK, &newset, NULL); + } return (ret); } @@ -404,9 +735,8 @@ { ucontext_t uc; - (void) memcpy(&uc, ucp, sizeof (uc)); + (void) memcpy(&uc, ucp, sizeof(uc)); remove_thr_signals(&uc.uc_sigmask); - return __sys_setcontext(&uc); } @@ -416,7 +746,7 @@ { ucontext_t uc; - (void) memcpy(&uc, ucp, sizeof (uc)); + (void) memcpy(&uc, ucp, sizeof(uc)); remove_thr_signals(&uc.uc_sigmask); return __sys_swapcontext(oucp, &uc); } Index: thread/thr_syscalls.c =================================================================== --- thread/thr_syscalls.c (revision 211861) +++ thread/thr_syscalls.c (working copy) @@ -351,9 +351,9 @@ struct pthread *curthread = _get_curthread(); int ret; - _thr_cancel_enter(curthread); + _thr_cancel_enter_defer(curthread, 1); ret = __sys_nanosleep(time_to_sleep, time_remaining); - _thr_cancel_leave(curthread); + _thr_cancel_leave_defer(curthread, 1); return (ret); } @@ -603,9 +603,9 @@ struct pthread *curthread = _get_curthread(); unsigned int ret; - _thr_cancel_enter(curthread); + _thr_cancel_enter_defer(curthread, 1); ret = __sleep(seconds); - _thr_cancel_leave(curthread); + _thr_cancel_leave_defer(curthread, 1); return (ret); } @@ -618,9 +618,9 @@ struct pthread *curthread = _get_curthread(); int ret; - _thr_cancel_enter(curthread); + _thr_cancel_enter_defer(curthread, 1); ret = __system(string); - _thr_cancel_leave(curthread); + _thr_cancel_leave_defer(curthread, 1); return ret; } @@ -652,9 +652,9 @@ struct pthread *curthread = _get_curthread(); int ret; - _thr_cancel_enter(curthread); + _thr_cancel_enter_defer(curthread, 1); ret = __usleep(useconds); - _thr_cancel_leave(curthread); + _thr_cancel_leave_defer(curthread, 1); return (ret); } Index: thread/thr_kern.c =================================================================== --- thread/thr_kern.c (revision 211861) +++ thread/thr_kern.c (working copy) @@ -61,38 +61,6 @@ } void -_thr_signal_block(struct pthread *curthread) -{ - sigset_t set; - - if (curthread->sigblock > 0) { - curthread->sigblock++; - return; - } - SIGFILLSET(set); - SIGDELSET(set, SIGBUS); - SIGDELSET(set, SIGILL); - SIGDELSET(set, SIGFPE); - SIGDELSET(set, SIGSEGV); - SIGDELSET(set, SIGTRAP); - __sys_sigprocmask(SIG_BLOCK, &set, &curthread->sigmask); - curthread->sigblock++; -} - -void -_thr_signal_unblock(struct pthread *curthread) -{ - if (--curthread->sigblock == 0) - __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL); -} - -int -_thr_send_sig(struct pthread *thread, int sig) -{ - return thr_kill(thread->tid, sig); -} - -void _thr_assert_lock_level() { PANIC("locklevel <= 0"); Index: thread/thr_private.h =================================================================== --- thread/thr_private.h (revision 211861) +++ thread/thr_private.h (working copy) @@ -376,12 +376,21 @@ /* Thread temporary signal mask. */ sigset_t sigmask; - /* Thread is in SIGCANCEL handler. */ - int in_sigcancel_handler; - - /* New thread should unblock SIGCANCEL. */ + /* Thread should unblock SIGCANCEL. */ int unblock_sigcancel; + /* In sigsuspend state */ + int in_sigsuspend; + + /* deferred signal info */ + siginfo_t deferred_siginfo; + + /* signal mask to restore. */ + sigset_t deferred_sigmask; + + /* the sigaction should be used for deferred signal. */ + struct sigaction deferred_sigact; + /* Force new thread to exit. */ int force_exit; @@ -463,7 +472,7 @@ #define THR_CRITICAL_LEAVE(thrd) \ do { \ (thrd)->critical_count--; \ - _thr_ast(thrd); \ + _thr_ast(thrd, 0, NULL); \ } while (0) #define THR_UMUTEX_TRYLOCK(thrd, lck) \ @@ -499,7 +508,7 @@ THR_ASSERT_LOCKLEVEL(thrd); \ _thr_umutex_unlock((lck), TID(thrd)); \ (thrd)->locklevel--; \ - _thr_ast(thrd); \ + _thr_ast(thrd, 0, NULL); \ } while (0) #define THR_LOCK(curthrd) THR_LOCK_ACQUIRE(curthrd, &(curthrd)->lock) @@ -629,6 +638,7 @@ int _thr_find_thread(struct pthread *, struct pthread *, int) __hidden; void _thr_rtld_init(void) __hidden; void _thr_rtld_fini(void) __hidden; +void _thr_rtld_postfork_child(void) __hidden; int _thr_stack_alloc(struct pthread_attr *) __hidden; void _thr_stack_free(struct pthread_attr *) __hidden; void _thr_free(struct pthread *, struct pthread *) __hidden; @@ -653,15 +663,17 @@ struct pthread *_thr_hash_find(struct pthread *) __hidden; void _thr_link(struct pthread *, struct pthread *) __hidden; void _thr_unlink(struct pthread *, struct pthread *) __hidden; -void _thr_suspend_check(struct pthread *) __hidden; void _thr_assert_lock_level(void) __hidden __dead2; -void _thr_ast(struct pthread *) __hidden; +void _thr_ast(struct pthread *, int, ucontext_t *) __hidden; void _thr_once_init(void) __hidden; void _thr_report_creation(struct pthread *curthread, struct pthread *newthread) __hidden; void _thr_report_death(struct pthread *curthread) __hidden; int _thr_getscheduler(lwpid_t, int *, struct sched_param *) __hidden; int _thr_setscheduler(lwpid_t, int, const struct sched_param *) __hidden; +void _thr_signal_prefork(void) __hidden; +void _thr_signal_postfork(void) __hidden; +void _thr_signal_postfork_child(void) __hidden; int _rtp_to_schedparam(const struct rtprio *rtp, int *policy, struct sched_param *param) __hidden; int _schedparam_to_rtp(int policy, const struct sched_param *param, @@ -687,7 +699,7 @@ int __sys_sigpending(sigset_t *); int __sys_sigprocmask(int, const sigset_t *, sigset_t *); int __sys_sigsuspend(const sigset_t *); -int __sys_sigreturn(ucontext_t *); +int __sys_sigreturn(const ucontext_t *); int __sys_sigaltstack(const struct sigaltstack *, struct sigaltstack *); int __sys_sigwait(const sigset_t *, int *); int __sys_sigtimedwait(const sigset_t *, siginfo_t *, @@ -740,6 +752,7 @@ struct dl_phdr_info; void __pthread_cxa_finalize(struct dl_phdr_info *phdr_info); void _thr_tsd_unload(struct dl_phdr_info *phdr_info) __hidden; +void _thr_sigact_unload(struct dl_phdr_info *phdr_info) __hidden; __END_DECLS Index: thread/thr_cancel.c =================================================================== --- thread/thr_cancel.c (revision 211861) +++ thread/thr_cancel.c (working copy) @@ -136,14 +136,15 @@ { struct pthread *curthread = _get_curthread(); - _thr_cancel_enter(curthread); - _thr_cancel_leave(curthread); + curthread->cancel_point = 1; + testcancel(curthread); + curthread->cancel_point = 0; } void _thr_cancel_enter(struct pthread *curthread) { - curthread->cancel_point++; + curthread->cancel_point = 1; if (curthread->cancel_enable) testcancel(curthread); } @@ -151,8 +152,8 @@ void _thr_cancel_enter_defer(struct pthread *curthread, int maycancel) { - curthread->cancel_defer++; - curthread->cancel_point++; + curthread->cancel_defer = 1; + curthread->cancel_point = 1; if (__predict_false(SHOULD_CANCEL(curthread) && !THR_IN_CRITICAL(curthread))) { if (!maycancel) @@ -165,7 +166,7 @@ void _thr_cancel_leave(struct pthread *curthread) { - curthread->cancel_point--; + curthread->cancel_point = 0; } void @@ -173,7 +174,7 @@ { if (curthread->cancel_enable && maycancel) testcancel(curthread); - curthread->cancel_point--; + curthread->cancel_point = 0; } void @@ -181,6 +182,6 @@ { if (curthread->cancel_enable && maycancel) testcancel(curthread); - curthread->cancel_point--; - curthread->cancel_defer--; + curthread->cancel_point = 0; + curthread->cancel_defer = 0; } Index: thread/thr_umtx.c =================================================================== --- thread/thr_umtx.c (revision 211861) +++ thread/thr_umtx.c (working copy) @@ -217,3 +217,42 @@ { return _umtx_op_err(rwlock, UMTX_OP_RW_UNLOCK, 0, NULL, NULL); } + +void +_thr_rwl_rdlock(struct urwlock *rwlock) +{ + int ret; + + for (;;) { + if (_thr_rwlock_tryrdlock(rwlock, 0) == 0) + return; + ret = __thr_rwlock_rdlock(rwlock, 0, NULL); + if (ret == 0) + return; + if (ret != EINTR) + PANIC("rdlock error"); + } +} + +void +_thr_rwl_wrlock(struct urwlock *rwlock) +{ + int ret; + + for (;;) { + if (_thr_rwlock_trywrlock(rwlock) == 0) + return; + ret = __thr_rwlock_wrlock(rwlock, NULL); + if (ret == 0) + return; + if (ret != EINTR) + PANIC("wrlock error"); + } +} + +void +_thr_rwl_unlock(struct urwlock *rwlock) +{ + if (_thr_rwlock_unlock(rwlock)) + PANIC("unlock error"); +} Index: thread/thr_fork.c =================================================================== --- thread/thr_fork.c (revision 211861) +++ thread/thr_fork.c (working copy) @@ -115,6 +115,7 @@ } THR_UMUTEX_UNLOCK(curthread, &_thr_atfork_lock); _thr_tsd_unload(phdr_info); + _thr_sigact_unload(phdr_info); } __weak_reference(_fork, fork); @@ -161,6 +162,7 @@ * Block all signals until we reach a safe point. */ _thr_signal_block(curthread); + _thr_signal_prefork(); /* Fork a new process: */ if ((ret = __sys_fork()) == 0) { @@ -182,6 +184,8 @@ _thr_umutex_init(&curthread->lock); _thr_umutex_init(&_thr_atfork_lock); + _thr_signal_postfork_child(); + if (was_threaded) _rtld_atfork_post(rtld_locks); _thr_setthreaded(0); @@ -211,6 +215,8 @@ /* Parent process */ errsave = errno; + _thr_signal_postfork(); + /* Ready to continue, unblock signals. */ _thr_signal_unblock(curthread); Index: thread/thr_umtx.h =================================================================== --- thread/thr_umtx.h (revision 211861) +++ thread/thr_umtx.h (working copy) @@ -58,6 +58,10 @@ int __thr_rwlock_wrlock(struct urwlock *rwlock, struct timespec *tsp) __hidden; int __thr_rwlock_unlock(struct urwlock *rwlock) __hidden; +void _thr_rwl_rdlock(struct urwlock *rwlock) __hidden; +void _thr_rwl_wrlock(struct urwlock *rwlock) __hidden; +void _thr_rwl_unlock(struct urwlock *rwlock) __hidden; + static inline int _thr_umutex_trylock(struct umutex *mtx, uint32_t id) { Index: thread/thr_init.c =================================================================== --- thread/thr_init.c (revision 211861) +++ thread/thr_init.c (working copy) @@ -66,6 +66,7 @@ int _thread_active_threads = 1; atfork_head _thr_atfork_list = TAILQ_HEAD_INITIALIZER(_thr_atfork_list); struct umutex _thr_atfork_lock = DEFAULT_UMUTEX; +int _thr_ever_threaded = 0; struct pthread_prio _thr_priorities[3] = { {RTP_PRIO_MIN, RTP_PRIO_MAX, 0}, /* FIFO */ @@ -289,7 +290,6 @@ _libpthread_init(struct pthread *curthread) { int fd, first = 0; - sigset_t sigset, oldset; /* Check if this function has already been called: */ if ((_thr_initial != NULL) && (curthread == NULL)) @@ -347,13 +347,8 @@ _tcb_set(curthread->tcb); if (first) { - SIGFILLSET(sigset); - SIGDELSET(sigset, SIGTRAP); - __sys_sigprocmask(SIG_SETMASK, &sigset, &oldset); - _thr_signal_init(); _thr_initial = curthread; - SIGDELSET(oldset, SIGCANCEL); - __sys_sigprocmask(SIG_SETMASK, &oldset, NULL); + _thr_signal_init(); if (_thread_event_mask & TD_CREATE) _thr_report_creation(curthread, curthread); } Index: thread/thr_create.c =================================================================== --- thread/thr_create.c (revision 211861) +++ thread/thr_create.c (working copy) @@ -127,10 +127,7 @@ if (new_thread->attr.flags & PTHREAD_CREATE_DETACHED) new_thread->tlflags |= TLFLAGS_DETACHED; - if (curthread->in_sigcancel_handler) - new_thread->unblock_sigcancel = 1; - else - new_thread->unblock_sigcancel = 0; + new_thread->unblock_sigcancel = curthread->unblock_sigcancel; /* Add the new thread. */ new_thread->refcount = 1; @@ -266,6 +263,7 @@ if (curthread->unblock_sigcancel) { sigset_t set1; + curthread->unblock_sigcancel = 0; SIGEMPTYSET(set1); SIGADDSET(set1, SIGCANCEL); __sys_sigprocmask(SIG_UNBLOCK, &set1, NULL); Index: thread/thr_rtld.c =================================================================== --- thread/thr_rtld.c (revision 211861) +++ thread/thr_rtld.c (working copy) @@ -32,6 +32,7 @@ */ #include #include +#include #include "rtld_lock.h" #include "thr_private.h" @@ -132,7 +133,7 @@ SAVE_ERRNO(); l = (struct rtld_lock *)lock; - _thr_signal_block(curthread); + THR_CRITICAL_ENTER(curthread); while (_thr_rwlock_wrlock(&l->lock, NULL) != 0) ; RESTORE_ERRNO(); @@ -152,12 +153,9 @@ state = l->lock.rw_state; if (_thr_rwlock_unlock(&l->lock) == 0) { - if ((state & URWLOCK_WRITE_OWNER) == 0) { + if ((state & URWLOCK_WRITE_OWNER) == 0) curthread->rdlock_count--; - THR_CRITICAL_LEAVE(curthread); - } else { - _thr_signal_unblock(curthread); - } + THR_CRITICAL_LEAVE(curthread); } RESTORE_ERRNO(); } @@ -193,6 +191,9 @@ /* force to resolve errno() PLT */ __error(); + /* force to resolve memcpy PLT */ + memcpy(&dummy, &dummy, sizeof(dummy)); + li.lock_create = _thr_rtld_lock_create; li.lock_destroy = _thr_rtld_lock_destroy; li.rlock_acquire = _thr_rtld_rlock_acquire;