diff options
author | Florian Weimer <fweimer@redhat.com> | 2021-05-21 22:35:00 +0200 |
---|---|---|
committer | Florian Weimer <fweimer@redhat.com> | 2021-05-21 22:35:00 +0200 |
commit | 2f69522d460611b1018e15df6c238dda2d8d6609 (patch) | |
tree | 1e7a59afe9de337ad58dfdebab4502794db51732 /nptl/pthread_create.c | |
parent | 06a36b70f946548d7bc5bc1b163d1ecf877da071 (diff) | |
download | glibc-2f69522d460611b1018e15df6c238dda2d8d6609.tar.gz glibc-2f69522d460611b1018e15df6c238dda2d8d6609.tar.xz glibc-2f69522d460611b1018e15df6c238dda2d8d6609.zip |
nptl: Perform signal initialization upon pthread_create
Install signal handlers and unblock signals before pthread_create creates the first thread. create_thread in sysdeps/unix/sysv/linux/createthread.c can send SIGCANCEL to the current thread, so the SIGCANCEL handler is currently needed even if pthread_cancel is never called. (The way timer_create uses SIGCANCEL does not need a signal handler; both SIG_DFL and SIG_IGN dispositions should work.) Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Diffstat (limited to 'nptl/pthread_create.c')
-rw-r--r-- | nptl/pthread_create.c | 45 |
1 files changed, 43 insertions, 2 deletions
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c index 770656453d..772b5efcc6 100644 --- a/nptl/pthread_create.c +++ b/nptl/pthread_create.c @@ -56,6 +56,43 @@ static struct rtld_global *__nptl_rtld_global __attribute_used__ = &_rtld_global; #endif +/* This performs the initialization necessary when going from + single-threaded to multi-threaded mode for the first time. */ +static void +late_init (void) +{ + struct sigaction sa; + __sigemptyset (&sa.sa_mask); + + /* Install the cancellation signal handler (in static builds only if + pthread_cancel has been linked in). If for some reason we cannot + install the handler we do not abort. Maybe we should, but it is + only asynchronous cancellation which is affected. */ +#ifndef SHARED + extern __typeof (__nptl_sigcancel_handler) __nptl_sigcancel_handler + __attribute__ ((weak)); + if (__nptl_sigcancel_handler != NULL) +#endif + { + sa.sa_sigaction = __nptl_sigcancel_handler; + sa.sa_flags = SA_SIGINFO; + (void) __libc_sigaction (SIGCANCEL, &sa, NULL); + } + + /* Install the handle to change the threads' uid/gid. */ + sa.sa_sigaction = __nptl_setxid_sighandler; + sa.sa_flags = SA_SIGINFO | SA_RESTART; + (void) __libc_sigaction (SIGSETXID, &sa, NULL); + + /* The parent process might have left the signals blocked. Just in + case, unblock it. We reuse the signal mask in the sigaction + structure. It is already cleared. */ + __sigaddset (&sa.sa_mask, SIGCANCEL); + __sigaddset (&sa.sa_mask, SIGSETXID); + INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_UNBLOCK, &sa.sa_mask, + NULL, __NSIG_BYTES); +} + /* Code to allocate and deallocate a stack. */ #include "allocatestack.c" @@ -459,9 +496,13 @@ __pthread_create_2_1 (pthread_t *newthread, const pthread_attr_t *attr, { STACK_VARIABLES; - /* Avoid a data race in the multi-threaded case. */ + /* Avoid a data race in the multi-threaded case, and call the + deferred initialization only once. */ if (__libc_single_threaded) - __libc_single_threaded = 0; + { + late_init (); + __libc_single_threaded = 0; + } const struct pthread_attr *iattr = (struct pthread_attr *) attr; union pthread_attr_transparent default_attr; |