From patchwork Wed May 12 16:58:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 43407 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 55C83399C034; Wed, 12 May 2021 16:58:34 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 55C83399C034 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1620838714; bh=BD550Pu1zb5hmhAvBpoU9xGOXXSkgFyYcAJRU1Pg4V4=; h=To:Subject:In-Reply-To:References:Date:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=NoqmnzWQSjdvd48prrfFlXDKzDonLTmP9j+8q8doDvRqj4ps48A6X/tlSxoODUFX8 HAk90wu39jeKJtc/jmiBnIndGQScA4bYTGBOMWDu2c8ZjhmQimtNmwYKBIfTAryO0z Abx5mV4fVGVTIqb3NOVmeZpepkuRoy0Hvy1TUgEk= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by sourceware.org (Postfix) with ESMTP id 9B1473990834 for ; Wed, 12 May 2021 16:58:30 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 9B1473990834 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-557-TqvpVpAeNaSWB1GoRf5zaQ-1; Wed, 12 May 2021 12:58:28 -0400 X-MC-Unique: TqvpVpAeNaSWB1GoRf5zaQ-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id B87B2800D55 for ; Wed, 12 May 2021 16:58:27 +0000 (UTC) Received: from oldenburg.str.redhat.com (ovpn-112-137.ams2.redhat.com [10.36.112.137]) by smtp.corp.redhat.com (Postfix) with ESMTPS id ADCE860CE6 for ; Wed, 12 May 2021 16:58:26 +0000 (UTC) To: libc-alpha@sourceware.org Subject: [PATCH 12/23] nptl: Introduce __nptl_deferred_init In-Reply-To: References: X-From-Line: 303f46939bafa347bae62f9740837955ebbf43e9 Mon Sep 17 00:00:00 2001 Message-Id: <303f46939bafa347bae62f9740837955ebbf43e9.1620838411.git.fweimer@redhat.com> Date: Wed, 12 May 2021 18:58:24 +0200 User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-12.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Florian Weimer via Libc-alpha From: Florian Weimer Reply-To: Florian Weimer Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" This function is called once by pthread_create, before spawning the first thread, and also within pthread_cancel. Since it sets up cancellation handlers, place it along with the pthread_cancel implementation within libc. It is necessary to drop the weak attribute for the unwinding function because otherwise, the implementation is no longer being pulled in. This increases ldconfig size by about 1200 bytes, despite the updated static stubs. --- elf/static-stubs.c | 14 ++++ nptl/Versions | 5 +- nptl/nptl-init.c | 75 ------------------ nptl/pthreadP.h | 17 ++--- nptl/pthread_cancel.c | 84 +++++++++++++++++++++ nptl/pthread_create.c | 8 +- sysdeps/unix/sysv/linux/ia64/static-stubs.c | 26 +++++++ 7 files changed, 140 insertions(+), 89 deletions(-) create mode 100644 sysdeps/unix/sysv/linux/ia64/static-stubs.c diff --git a/elf/static-stubs.c b/elf/static-stubs.c index a8f24b9028..1752bc7372 100644 --- a/elf/static-stubs.c +++ b/elf/static-stubs.c @@ -33,6 +33,20 @@ _Unwind_Resume (struct _Unwind_Exception *exc __attribute__ ((unused))) abort (); } +_Unwind_Word +_Unwind_GetCFA (struct _Unwind_Context *ctx __attribute__ ((unused))) +{ + abort (); +} + +_Unwind_Reason_Code +_Unwind_ForcedUnwind (struct _Unwind_Exception *exc __attribute__ ((unused)), + _Unwind_Stop_Fn fn __attribute__ ((unused)), + void *ptr __attribute__ ((unused))) +{ + abort (); +} + _Unwind_Reason_Code __gcc_personality_v0 (int version __attribute__ ((unused)), _Unwind_Action actions __attribute__ ((unused)), diff --git a/nptl/Versions b/nptl/Versions index 6e2def1b4c..200055cffa 100644 --- a/nptl/Versions +++ b/nptl/Versions @@ -351,8 +351,6 @@ libc { tss_set; } GLIBC_PRIVATE { - __nptl_create_event; - __nptl_death_event; __default_pthread_attr; __default_pthread_attr_lock; __futex_abstimed_wait64; @@ -370,8 +368,11 @@ libc { __lll_trylock_elision; __lll_unlock_elision; __mutex_aconf; + __nptl_create_event; __nptl_deallocate_stack; __nptl_deallocate_tsd; + __nptl_death_event; + __nptl_deferred_init; __nptl_free_tcb; __nptl_nthreads; __nptl_setxid_sighandler; diff --git a/nptl/nptl-init.c b/nptl/nptl-init.c index f4b86fbfaf..bc4831ac89 100644 --- a/nptl/nptl-init.c +++ b/nptl/nptl-init.c @@ -44,84 +44,9 @@ size_t __static_tls_align_m1; /* Version of the library, used in libthread_db to detect mismatches. */ static const char nptl_version[] __attribute_used__ = VERSION; -/* For asynchronous cancellation we use a signal. This is the handler. */ -static void -sigcancel_handler (int sig, siginfo_t *si, void *ctx) -{ - /* Safety check. It would be possible to call this function for - other signals and send a signal from another process. This is not - correct and might even be a security problem. Try to catch as - many incorrect invocations as possible. */ - if (sig != SIGCANCEL - || si->si_pid != __getpid() - || si->si_code != SI_TKILL) - return; - - struct pthread *self = THREAD_SELF; - - int oldval = THREAD_GETMEM (self, cancelhandling); - while (1) - { - /* We are canceled now. When canceled by another thread this flag - is already set but if the signal is directly send (internally or - from another process) is has to be done here. */ - int newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK; - - if (oldval == newval || (oldval & EXITING_BITMASK) != 0) - /* Already canceled or exiting. */ - break; - - int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, - oldval); - if (curval == oldval) - { - /* Set the return value. */ - THREAD_SETMEM (self, result, PTHREAD_CANCELED); - - /* Make sure asynchronous cancellation is still enabled. */ - if ((newval & CANCELTYPE_BITMASK) != 0) - /* Run the registered destructors and terminate the thread. */ - __do_cancel (); - - break; - } - - oldval = curval; - } -} - - -/* When using __thread for this, we do it in libc so as not - to give libpthread its own TLS segment just for this. */ -extern void **__libc_dl_error_tsd (void) __attribute__ ((const)); - - void __pthread_initialize_minimal_internal (void) { - struct sigaction sa; - __sigemptyset (&sa.sa_mask); - - /* Install the cancellation signal handler. 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. */ - sa.sa_sigaction = 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); - /* Get the size of the static and alignment requirements for the TLS block. */ size_t static_tls_align; diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h index a4a87cb549..e33b071a4d 100644 --- a/nptl/pthreadP.h +++ b/nptl/pthreadP.h @@ -262,18 +262,10 @@ libc_hidden_proto (__pthread_current_priority) extern void __pthread_unwind (__pthread_unwind_buf_t *__buf) - __cleanup_fct_attribute __attribute ((__noreturn__)) -#if !defined SHARED && !IS_IN (libpthread) - weak_function -#endif - ; + __cleanup_fct_attribute __attribute ((__noreturn__)); libc_hidden_proto (__pthread_unwind) extern void __pthread_unwind_next (__pthread_unwind_buf_t *__buf) - __cleanup_fct_attribute __attribute ((__noreturn__)) -#ifndef SHARED - weak_function -#endif - ; + __cleanup_fct_attribute __attribute ((__noreturn__)); /* NB: No hidden proto for __pthread_unwind_next: inside glibc, the legacy unwinding mechanism is used. */ @@ -301,6 +293,11 @@ __do_cancel (void) /* Internal prototypes. */ +/* One-time initialization activities before pthread_create spawns a + new thread. */ +void __nptl_deferred_init (void); +libc_hidden_proto (__nptl_deferred_init) + /* Deallocate a thread's stack after optionally making sure the thread descriptor is still valid. */ extern void __nptl_free_tcb (struct pthread *pd); diff --git a/nptl/pthread_cancel.c b/nptl/pthread_cancel.c index e4ad602900..76daa791ea 100644 --- a/nptl/pthread_cancel.c +++ b/nptl/pthread_cancel.c @@ -26,6 +26,81 @@ #include #include #include +#include + +/* For asynchronous cancellation we use a signal. This is the handler. */ +static void +sigcancel_handler (int sig, siginfo_t *si, void *ctx) +{ + /* Safety check. It would be possible to call this function for + other signals and send a signal from another process. This is not + correct and might even be a security problem. Try to catch as + many incorrect invocations as possible. */ + if (sig != SIGCANCEL + || si->si_pid != __getpid() + || si->si_code != SI_TKILL) + return; + + struct pthread *self = THREAD_SELF; + + int oldval = THREAD_GETMEM (self, cancelhandling); + while (1) + { + /* We are canceled now. When canceled by another thread this flag + is already set but if the signal is directly send (internally or + from another process) is has to be done here. */ + int newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK; + + if (oldval == newval || (oldval & EXITING_BITMASK) != 0) + /* Already canceled or exiting. */ + break; + + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, + oldval); + if (curval == oldval) + { + /* Set the return value. */ + THREAD_SETMEM (self, result, PTHREAD_CANCELED); + + /* Make sure asynchronous cancellation is still enabled. */ + if ((newval & CANCELTYPE_BITMASK) != 0) + /* Run the registered destructors and terminate the thread. */ + __do_cancel (); + + break; + } + + oldval = curval; + } +} + +void +__nptl_deferred_init (void) +{ + struct sigaction sa; + __sigemptyset (&sa.sa_mask); + + /* Install the cancellation signal handler. 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. */ + sa.sa_sigaction = 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); +} +libc_hidden_def (__nptl_deferred_init) int __pthread_cancel (pthread_t th) @@ -46,6 +121,15 @@ __pthread_cancel (pthread_t th) " must be installed for pthread_cancel to work\n"); } #endif + + /* Perform the deferred initialization if necessary, to install the + signal handler for a potential self-cancellation below. */ + if (__libc_single_threaded) + { + __nptl_deferred_init (); + __libc_single_threaded = 0; + } + int result = 0; int oldval; int newval; diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c index 770656453d..43f3722f57 100644 --- a/nptl/pthread_create.c +++ b/nptl/pthread_create.c @@ -459,9 +459,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; + { + __nptl_deferred_init (); + __libc_single_threaded = 0; + } const struct pthread_attr *iattr = (struct pthread_attr *) attr; union pthread_attr_transparent default_attr; diff --git a/sysdeps/unix/sysv/linux/ia64/static-stubs.c b/sysdeps/unix/sysv/linux/ia64/static-stubs.c new file mode 100644 index 0000000000..8bd594c2f1 --- /dev/null +++ b/sysdeps/unix/sysv/linux/ia64/static-stubs.c @@ -0,0 +1,26 @@ +/* Stub implementations of functions to link into statically linked + programs without needing libgcc_eh. ia64 version. + Copyright (C) 2021 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +_Unwind_Word +_Unwind_GetBSP (struct _Unwind_Context *ctx) +{ + abort (); +}