This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [PATCH] Linux: Implement per-thread file system attributes
- From: Carlos O'Donell <carlos at redhat dot com>
- To: Florian Weimer <fweimer at redhat dot com>, libc-alpha at sourceware dot org
- Date: Fri, 28 Jun 2019 08:59:08 -0400
- Subject: Re: [PATCH] Linux: Implement per-thread file system attributes
- References: <87d0jpfius.fsf@oldenburg2.str.redhat.com>
On 6/7/19 12:41 PM, Florian Weimer wrote:
> [Compared to the previous version, this fixes the hppa build by updating
> its own copy of pthread.h. It also addresses the rebase conflicts due
> to other new functions. This is still the version with the “sticky”
> behavior.]
>
> This commit adds the functions pthread_attr_setperthreadfs_np and
> pthread_attr_getperthreadfs_np.
>
> The implementation is based on suppressing the CLONE_FS clone flag when
> creating the new thread. The new flag is sticky and is applied to
> all threads created from a thread with the PTHREAD_PER_THREAD_NP
> attribute.
>
Please post v2 with a new test case to cover the inherited flag check.
- pthread_attr_getperthreadfs_np.c code change.
- comments added to test case.
- New test.
I would like to see a new test which does:
- From main start a thread.
- In the new thread set per-thread fs, which is now sticky.
- Create an attr with per-process fs, and then start a new thread with that.
- In thread 2 use pthread_getattr_np and verify the resulting attr shows
that per-thread fs as indeed sticky and the value seen is per-thread fs.
This test shows things get copied properly from thread-to-thread and are
visible to pthread_getattr_np properly.
> 2019-06-07 Florian Weimer <fweimer@redhat.com>
>
> Linux: Implement per-thread file system attributes.
> * manual/threads.texi (Enabling Per-Thread Properties): New
> section.
> (Non-POSIX Extensions): Reference it.
> * nptl/Makefile (routines): Add pthread_attr_setperthreadfs_np,
> pthread_attr_getperthreadfs_np.
> (tests): Add tst-pthread-perthreadfs,
> tst-pthread-perthreadfs-chroot.
> * nptl/Versions (GLIBC_2.30): Export
> pthread_attr_setperthreadfs_np, pthread_attr_getperthreadfs_np.
> * nptl/pthread_attr_setperthreadfs_np.c: New file
> * nptl/pthread_attr_getperthreadfs_np.c: Likewise.
> * nptl/pthread_create.c (__pthread_create_2_1): Use
> ATTR_FLAGS_IGNORED_ATTR and ATTR_FLAGS_INHERITED to compute the
> flags for the new thread.
> * nptl/tst-pthread-perthreadfs.c: Likewise.
> * nptl/tst-pthread-perthreadfs-chroot.c: Likewise.
> * sysdeps/nptl/internaltypes.h (ATTR_FLAG_PERTHREADFS)
> (ATTR_FLAGS_IGNORED_ATTR, ATTR_FLAGS_INHERITED): Define.
> * sysdeps/unix/sysv/linux/createthread.c (create_thread): Use it.
> * sysdeps/nptl/pthread.h
> (PTHREAD_PER_PROCESS_NP, PTHREAD_PER_THREAD_NP): Define.
> (pthread_attr_setperthreadfs_np, pthread_attr_getperthreadfs_np):
> Declare.
> * sysdeps/unix/sysv/linux/hppa/pthread.h
> (PTHREAD_PER_PROCESS_NP, PTHREAD_PER_THREAD_NP): Define.
> (pthread_attr_setperthreadfs_np, pthread_attr_getperthreadfs_np):
> Declare.
> * support/Makefile (libsupport-routines): Add xchdir, xfchdir.
> * support/xunistd.h (xchdir, xfchdir): Declare.
> * support/xchdir.c: New file.
> * support/xfchdir.c: Likewise.
> * sysdeps/unix/sysv/linux/aarch64/libc.abilist (GLIBC_2.30): Add
> pthread_attr_setperthreadfs_np, pthread_attr_getperthreadfs_np.
> * sysdeps/unix/sysv/linux/alpha/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/arm/libc.abilist (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/csky/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/hppa/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/i386/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/ia64/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/microblaze/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/nios2/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/sh/libc.abilist (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/x86_64/64/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist (GLIBC_2.30):
> Likewise.
>
> diff --git a/NEWS b/NEWS
> index 00f9e855a2..f320675f7c 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -34,6 +34,11 @@ Major new features:
> pointer subtraction within the allocated object, where results might
> overflow the ptrdiff_t type.
>
> +* On Linux, it is now possible to create threads with per-thread current
> + directory, umask, and file system root. The functions
> + pthread_attr_setperthreadfs_np and pthread_attr_getperthreadfs_np have
> + been added in support of that.
OK.
> +
> Deprecated and removed features, and other changes affecting compatibility:
>
> * The functions clock_gettime, clock_getres, clock_settime,
> diff --git a/manual/threads.texi b/manual/threads.texi
> index 87fda7d8e7..60c15a8d15 100644
> --- a/manual/threads.texi
> +++ b/manual/threads.texi
> @@ -625,6 +625,7 @@ the standard.
> @menu
> * Default Thread Attributes:: Setting default attributes for
> threads in a process.
> +* Enabling Per-Thread Properties:: Additional per-thread properties.
OK.
> @end menu
>
> @node Default Thread Attributes
> @@ -669,6 +670,100 @@ The system does not have sufficient memory.
> @end table
> @end deftypefun
>
> +@node Enabling Per-Thread Properties
> +@subsubsection Enabling Additional Per-Thread Properties
> +
> +POSIX mandates that the current directory, file system root, umask
> +value, and the current user and group IDs are process-global
> +properties. For example, if a thread calls the @code{chdir} function
> +to change to a different directory, all threads are eventually
> +affected by this change. @Theglibc{} implements an extension which
> +allows threads to be created which do not share these properties with
> +the rest of the process.
OK.
> +
> +The desired behavior is specified at the time the thread is created,
> +using the thread attribute. The following constants are used to
> +update the attribute:
OK.
> +
> +@vtable @code
> +@item PTHREAD_PER_PROCESS_NP
> +@standards{GNU, pthread.h}
> +This property in question is globally shared across the entire process.
> +This is the default.
OK.
> +
> +@item PTHREAD_PER_THREAD_NP
> +@standards{GNU, pthread.h}
> +This property in question is thread-specific.
OK.
> +@end vtable
> +
> +The @code{PTHREAD_PER_THREAD_NP} flag is sticky, in the sense that all
> +threads created by a thread created with this flag have per-thread
> +properties, even if they are created with the matching thread
> +attribute set to the @code{PTHREAD_PER_PROCESS_NP} flag. If an
> +application wants to create new threads sharing properties with the
> +main thread, it should create a service thread early (perhaps from an
> +ELF constructor) and create these threads using this service thread.
> +
OK
> +Per-thread properties can be set and examined for an attribute using
> +the functions below.
> +
> +@deftypefun int pthread_attr_setperthreadfs_np (pthread_attr_t *@var{attr}, int @var{scope})
> +@standards{GNU, pthread.h}
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +Change whether the following properties related to file system access
> +are made thread-specific when a new thread is created using the
> +attribute @var{attr}:
> +
> +@itemize @bullet
> +@item
> +@cindex current directiry as a per-thread property
> +@cindex per-thread current directory
> +@cindex thread-specific current directory
> +current directory (as changed by @code{chdir} and related functions)
> +
> +@item
> +@cindex @code{chroot} as a per-thread property
> +@cindex per-thread @code{chroot}
> +@cindex thread-specific @code{chroot}
> +file system root (as changed by @code{chroot})
> +
> +@item
> +@cindex umask as a per-thread property
> +@cindex per-thread @code{umask}
> +@cindex thread-specific @code{umask}
> +umask value (as changed by the function of the same name)
> +@end itemize
> +
> +This function returns zero on success. @var{scope} must be one of the
> +constants @code{PTHREAD_PER_PROCESS_NP} or
> +@code{PTHREAD_PER_THREAD_NP}, otherwise the function returns
> +@code{EINVAL}.
OK.
> +
> +If @var{scope} is @code{PTHREAD_PER_THREAD_NP}, the attribute will
> +cause the properties listed above to be specific to the thread. The
> +initial values of these properties are copied from the creating
> +thread, at thread creation time.
> +
OK.
> +If a thread that has been created with the
> +@code{PTHREAD_PER_THREAD_NP} flag creates further threads, these
> +threads are implicitly created with the @code{PTHREAD_PER_THREAD_NP}
> +flag, ignoring the value of this thread creation attribute.
> +(If this behavior is not desirable, it is possible to call
> +@samp{unshare (CLONE_FS)} from the new thread instead of creating it
> +with the @code{PTHREAD_PER_THREAD_NP} flag.)
> +
OK.
> +This function is a GNU extension and specific to Linux.
> +@end deftypefun
> +
> +@deftypefun int pthread_attr_getperthreadfs_np (pthread_attr_t *restrict @var{attr}, int *restrict @var{scope})
> +@standards{GNU, pthread.h}
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +Obtain the per-thread status of the file system properties in
> +@var{attr} and store it in the location @var{scope}.
> +
OK.
> +This function is a GNU extension and specific to Linux.
> +@end deftypefun
OK.
> +
> @c FIXME these are undocumented:
> @c pthread_atfork
> @c pthread_attr_destroy
> diff --git a/nptl/Makefile b/nptl/Makefile
> index de312b3477..1374838339 100644
> --- a/nptl/Makefile
> +++ b/nptl/Makefile
> @@ -30,7 +30,8 @@ extra-libs-others := $(extra-libs)
> routines = alloca_cutoff forward libc-lowlevellock libc-cancellation \
> libc-cleanup libc_pthread_init libc_multiple_threads \
> register-atfork pthread_atfork pthread_self thrd_current \
> - thrd_equal thrd_sleep thrd_yield
> + thrd_equal thrd_sleep thrd_yield \
> + pthread_attr_setperthreadfs_np pthread_attr_getperthreadfs_np
OK. Two new functions.
> shared-only-routines = forward
> static-only-routines = pthread_atfork
>
> @@ -321,7 +322,8 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
> tst-mtx-recursive tst-tss-basic tst-call-once tst-mtx-timedlock \
> tst-rwlock-pwn \
> tst-rwlock-tryrdlock-stall tst-rwlock-trywrlock-stall \
> - tst-unwind-thread
> + tst-unwind-thread \
> + tst-pthread-perthreadfs tst-pthread-perthreadfs-chroot
OK. Two new tests.
>
> tests-internal := tst-rwlock19 tst-rwlock20 \
> tst-sem11 tst-sem12 tst-sem13 \
> diff --git a/nptl/Versions b/nptl/Versions
> index e7f691da7a..817fec04f3 100644
> --- a/nptl/Versions
> +++ b/nptl/Versions
> @@ -32,6 +32,10 @@ libc {
> GLIBC_2.28 {
> thrd_current; thrd_equal; thrd_sleep; thrd_yield;
> }
> + GLIBC_2.30 {
> + pthread_attr_setperthreadfs_np;
> + pthread_attr_getperthreadfs_np;
OK.
> + }
> GLIBC_PRIVATE {
> __libc_alloca_cutoff;
> # Internal libc interface to libpthread
> diff --git a/nptl/pthread_attr_getperthreadfs_np.c b/nptl/pthread_attr_getperthreadfs_np.c
> new file mode 100644
> index 0000000000..6670939101
> --- /dev/null
> +++ b/nptl/pthread_attr_getperthreadfs_np.c
> @@ -0,0 +1,29 @@
> +/* Read the private file system flag in thread attributes.
> + Copyright (C) 2019 Free Software Foundation, Inc.
OK.
> + 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
> + <http://www.gnu.org/licenses/>. */
> +
> +#include <pthread.h>
> +#include <internaltypes.h>
> +
> +int
> +pthread_attr_getperthreadfs_np (const pthread_attr_t *__restrict attr,
> + int *__restrict scope)
> +{
> + struct pthread_attr *iattr = (struct pthread_attr *) attr;
> + *scope = (iattr->flags & ATTR_FLAG_PERTHREADFS) != 0;
The '!= 0' is a bit mystical, I would rather see someting like this:
if (iattr->flags & ATTR_FLAG_PERTHREADFS == 0)
*scope = PTHREAD_PER_PROCESS_NP;
else
*socpe = PTHREAD_PER_THREAD_NP;
Which makes it similar to the code in pthread_attr_setperthreadfs_np.
The compiler should optimize this to the same thing.
> + return 0;
OK.
> +}
> diff --git a/nptl/pthread_attr_setperthreadfs_np.c b/nptl/pthread_attr_setperthreadfs_np.c
> new file mode 100644
> index 0000000000..2d274cb144
> --- /dev/null
> +++ b/nptl/pthread_attr_setperthreadfs_np.c
> @@ -0,0 +1,39 @@
> +/* Change the private file system flag in thread attributes.
> + Copyright (C) 2019 Free Software Foundation, Inc.
OK.
> + 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
> + <http://www.gnu.org/licenses/>. */
> +
> +#include <pthread.h>
> +#include <internaltypes.h>
> +#include <errno.h>
> +
> +int
> +pthread_attr_setperthreadfs_np (pthread_attr_t *attr, int scope)
> +{
> + struct pthread_attr *iattr = (struct pthread_attr *) attr;
> + switch (scope)
> + {
> + case PTHREAD_PER_PROCESS_NP:
> + iattr->flags &= ~ATTR_FLAG_PERTHREADFS;
OK.
> + return 0;
> + break;
> + case PTHREAD_PER_THREAD_NP:
> + iattr->flags |= ATTR_FLAG_PERTHREADFS;
OK.
> + return 0;
> + default:
> + return EINVAL;
> + }
> +}
OK.
> diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
> index 18b7bbe765..0002fa7299 100644
> --- a/nptl/pthread_create.c
> +++ b/nptl/pthread_create.c
> @@ -693,8 +693,8 @@ __pthread_create_2_1 (pthread_t *newthread, const pthread_attr_t *attr,
>
> /* Copy the thread attribute flags. */
> struct pthread *self = THREAD_SELF;
> - pd->flags = ((iattr->flags & ~(ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET))
> - | (self->flags & (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET)));
> + pd->flags = ((iattr->flags & ~ATTR_FLAGS_IGNORED_ATTR)
> + | (self->flags & ATTR_FLAGS_INHERITED));
OK. Simplifies handling of flags we ignore using ATTR_FLAGS_IGNORED_ATTR, and that looks good.
>
> /* Initialize the field for the ID of the thread which is waiting
> for us. This is a self-reference in case the thread is created
> diff --git a/nptl/tst-pthread-perthreadfs-chroot.c b/nptl/tst-pthread-perthreadfs-chroot.c
> new file mode 100644
> index 0000000000..094c291baa
> --- /dev/null
> +++ b/nptl/tst-pthread-perthreadfs-chroot.c
> @@ -0,0 +1,255 @@
> +/* Test per-thread file system attributes, chroot version.
> + Copyright (C) 2019 Free Software Foundation, Inc.
OK.
> + 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
> + <http://www.gnu.org/licenses/>. */
> +
> +/* This thread is separate from tst-pthread-perthreadfs because it
> + requires chroot support. */
> +
> +#include <fcntl.h>
> +#include <pthread.h>
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +#include <support/namespace.h>
> +#include <support/support.h>
> +#include <support/temp_file.h>
> +#include <support/xthread.h>
> +#include <support/xunistd.h>
> +#include <sys/stat.h>
> +#include <unistd.h>
> +
> +/* Paths for chroot operations. */
> +static char *chroot_1;
> +static char *chroot_2;
> +static char *chroot_3;
> +
> +/* These paths are used for recognizing chroots. */
> +static const char *const chroot_1_marker = "/chroot-1-marker";
> +static const char *const chroot_2_marker = "/chroot-2-marker";
> +
> +/* Directory available in the chroot for a second chroot call. */
> +static const char *const next_chroot = "/next_chroot";
> +
> +/* Return 0 for no chroot, 1 for first chroot, 2 for second chroot, or
> + -1 for error. */
> +static int
> +which_chroot (void)
> +{
> + /* If the full (out-of-chroot) path is present, we are not in a
> + chroot. */
> + if (access (chroot_1, F_OK) == 0)
> + return 0;
> + if (access (chroot_1_marker, F_OK) == 0)
> + return 1;
> + if (access (chroot_2_marker, F_OK) == 0)
> + return 2;
> + return -1;
> +}
> +
> +/* Thread attribute requesting per-thread file system attributes. */
> +pthread_attr_t attr_perthreadfs;
> +
> +/* Used to synchronize operations among the threads. This is needed
> + so that the chroot changes happen in the expected order. */
> +static pthread_barrier_t barrier;
> +
> +static void *
> +thread_which_chroot_helper (void *closure)
> +{
> + int *result = closure;
> + *result = which_chroot ();
> + return NULL;
> +}
> +
> +static void *
> +thread_which_chroot_helper_perthread (void *closure)
> +{
> + int *result = closure;
> + *result = which_chroot ();
> + if (*result == 0)
> + /* No /next-chroot available without a first chroot. */
> + xchroot (chroot_3);
> + else
> + xchroot (next_chroot);
> + return NULL;
> +}
> +
> +/* Determine the current chroot on another thread. */
> +static int
> +thread_which_chroot (void)
> +{
> + int result1;
> + pthread_t thr = xpthread_create (NULL, thread_which_chroot_helper, &result1);
> + xpthread_join (thr);
> + /* Same using per-thread attributes. They are supposed to be equal.
> + Also change the chroot to check isolation. */
> + int result2;
> + thr = xpthread_create (&attr_perthreadfs,
> + thread_which_chroot_helper_perthread, &result2);
> + xpthread_join (thr);
> + TEST_COMPARE (result1, result2);
> + return result1;
> +}
> +
> +/* Verify that the file system attributes for the current thread are
> + as expected. */
> +static void
> +check_attributes (const char *where, int expected_chroot)
> +{
> + printf ("info: reading file attributes in %s\n", where);
> + TEST_COMPARE (which_chroot (), expected_chroot);
> + TEST_COMPARE (thread_which_chroot (), expected_chroot);
> +}
> +
> +/* Thread function launched with per-thread file system
> + attributes. */
> +static void *
> +thread_perthreadfs (void *closure)
> +{
> + puts ("info: changing file attributes in thread_perthreadfs");
> + xchroot (chroot_1);
> + check_attributes ("thread_perthreadfs", 1);
> +
> + pthread_barrier_wait (&barrier);
> + /* File attributes read in thread_sharedfs here. */
> + pthread_barrier_wait (&barrier);
> + /* File attributes read in main thread here. */
> + pthread_barrier_wait (&barrier);
> + /* File attributes changed in thread_sharedfs here. */
> + pthread_barrier_wait (&barrier);
> +
> + check_attributes ("thread_perthreadfs", 1);
> +
> + pthread_barrier_wait (&barrier);
> + /* File attributes read in main thread here. */
> + pthread_barrier_wait (&barrier);
> + return NULL;
> +}
> +
> +/* Thread function launched with shared file system attributes. */
> +static void *
> +thread_sharedfs (void *closure)
> +{
> + /* Wait for thread_perthreadfs to update chroot. */
> + pthread_barrier_wait (&barrier);
> +
> + check_attributes ("thread_sharedfs", 0);
> +
> + pthread_barrier_wait (&barrier);
> + /* File attributes read in main thread here. */
> + pthread_barrier_wait (&barrier);
> +
> + puts ("info: changing file attributes in thread_sharedfs");
> + xchroot (chroot_2);
> + check_attributes ("thread_sharedfs", 2);
> +
> + pthread_barrier_wait (&barrier);
> + /* File attributes read in thread_perthreadfs here. */
> + pthread_barrier_wait (&barrier);
> + /* File attributes read in main thread here. */
> + pthread_barrier_wait (&barrier);
> + return NULL;
> +}
> +
> +static int
> +do_test (void)
> +{
> + support_become_root ();
> + if (!support_can_chroot ())
> + FAIL_UNSUPPORTED ("chroot not supported");
> +
> + /* Used to revert the effect of chroot. */
> + int original_chroot_fd = xopen ("/", O_DIRECTORY | O_RDONLY, 0);
OK.
> +
> + TEST_COMPARE (access (chroot_1_marker, F_OK), -1);
> + TEST_COMPARE (access (chroot_2_marker, F_OK), -1);
> + TEST_COMPARE (access (next_chroot, F_OK), -1);
> +
> + chroot_1 = support_create_temp_directory
> + ("tst-pthread-perthreadfs-chroot-1-");
> + chroot_2 = support_create_temp_directory
> + ("tst-pthread-perthreadfs-chroot-2-");
> + chroot_3 = support_create_temp_directory
> + ("tst-pthread-perthreadfs-chroot-3-");
> + {
> + char *path = xasprintf ("%s%s", chroot_1, chroot_1_marker);
> + xmkdir (path, 0777);
> + add_temp_file (path);
> + free (path);
> +
> + path = xasprintf ("%s%s", chroot_1, next_chroot);
> + xmkdir (path, 0777);
> + add_temp_file (path);
> + free (path);
> +
> + path = xasprintf ("%s%s", chroot_2, chroot_2_marker);
> + xmkdir (path, 0777);
> + add_temp_file (path);
> + free (path);
> +
> + path = xasprintf ("%s%s", chroot_2, next_chroot);
> + xmkdir (path, 0777);
> + add_temp_file (path);
> + free (path);
> + }
> + TEST_COMPARE (which_chroot (), 0);
> +
> + xpthread_barrier_init (&barrier, NULL, 3);
> + xpthread_attr_init (&attr_perthreadfs);
> + TEST_COMPARE (pthread_attr_setperthreadfs_np (&attr_perthreadfs,
> + PTHREAD_PER_THREAD_NP), 0);
OK.
> +
> + pthread_t thr1 = xpthread_create (&attr_perthreadfs,
> + thread_perthreadfs, NULL);
> + pthread_t thr2 = xpthread_create (NULL, thread_sharedfs, NULL);
> +
> + /* Wait for thread_perthreadfs to update chroot. */
> + xpthread_barrier_wait (&barrier);
> + /* File attributes read thread_sharedfs here. */
> + xpthread_barrier_wait (&barrier);
> +
> + check_attributes ("main thread", 0);
OK.
> +
> + xpthread_barrier_wait (&barrier);
> + /* File attributes changed thread_sharedfs here. */
> + xpthread_barrier_wait (&barrier);
> + /* File attributes read in thread_perthreadfs here. */
> + xpthread_barrier_wait (&barrier);
> +
> + check_attributes ("main thread", 2);
> +
OK.
> + xpthread_barrier_wait (&barrier);
> +
> + xpthread_join (thr2);
> + xpthread_join (thr1);
OK.
> +
> + xpthread_attr_destroy (&attr_perthreadfs);
> + xpthread_barrier_destroy (&barrier);
> +
> + free (chroot_3);
> + free (chroot_2);
> + free (chroot_1);
> +
> + xfchdir (original_chroot_fd);
> + xclose (original_chroot_fd);
> + xchroot (".");
> +
> + return 0;
> +}
OK.
> +
> +#include <support/test-driver.c>
> diff --git a/nptl/tst-pthread-perthreadfs.c b/nptl/tst-pthread-perthreadfs.c
> new file mode 100644
> index 0000000000..81cf315c97
> --- /dev/null
> +++ b/nptl/tst-pthread-perthreadfs.c
> @@ -0,0 +1,280 @@
> +/* Test per-thread file system attributes.
> + Copyright (C) 2019 Free Software Foundation, Inc.
OK.
> + 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
> + <http://www.gnu.org/licenses/>. */
> +
> +#include <errno.h>
> +#include <pthread.h>
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +#include <support/temp_file.h>
> +#include <support/xthread.h>
> +#include <support/xunistd.h>
> +#include <sys/stat.h>
> +#include <unistd.h>
> +
> +/* Original values in the parent process. */
> +static char *original_cwd;
> +static mode_t original_umask;
> +
> +/* New values for the attributes, distinct from the old. */
> +static char *new_cwd_1;
> +static char *new_cwd_2;
> +static mode_t new_umask_1;
> +static mode_t new_umask_2;
> +
> +/* Thread attribute requesting per-thread file system attributes. */
> +pthread_attr_t attr_perthreadfs;
> +
> +/* Used to synchronize operations among the threads. This is needed
> + so that the attribute changes happen in the expected order, and
> + that get_umask_unlocked can be used safely. */
> +static pthread_barrier_t barrier;
> +
> +/* Linux does not have getumask, so use synchronization and the umask
> + system call to read the value. */
> +static mode_t
> +get_umask_unlocked (void)
> +{
> + mode_t mask = umask (0);
> + TEST_COMPARE (umask (mask), 0);
> + return mask;
> +}
> +
> +static void *
> +thread_get_pwd_helper (void *closure)
> +{
> + char *result = get_current_dir_name ();
> + if (closure != NULL)
> + xchdir (closure);
> + return result;
> +}
> +
> +/* Obtain the current directory on another thread. */
> +static char *
> +thread_get_pwd (void)
> +{
> + pthread_t thr = xpthread_create (NULL, thread_get_pwd_helper, NULL);
> + char *path1 = xpthread_join (thr);
> + /* Same using per-thread attributes. They are supposed to be equal.
> + Also change the current directory to check isolation. */
> + thr = xpthread_create (&attr_perthreadfs,
> + thread_get_pwd_helper, (char *) "/");
> + char *path2 = xpthread_join (thr);
> + TEST_COMPARE_STRING (path1, path2);
> + free (path2);
> + return path1;
> +}
> +
> +static void *
> +thread_get_umask_helper (void *closure)
> +{
> + mode_t *pmask = closure;
> + *pmask = get_umask_unlocked ();
> + return NULL;
> +}
> +
> +static void *
> +thread_get_umask_helper_perthread (void *closure)
> +{
> + mode_t *pmask = closure;
> + *pmask = get_umask_unlocked ();
> + /* Check isolation. This bit pattern is not used anywhere else. */
> + TEST_COMPARE (umask (*pmask ^ 0101), *pmask);
> + return NULL;
> +}
> +
> +/* Obtain the current umask on another thread. */
> +static mode_t
> +thread_get_umask_unlocked (void)
> +{
> + mode_t mask1;
> + pthread_t thr = xpthread_create (NULL, thread_get_umask_helper, &mask1);
> + xpthread_join (thr);
> + mode_t mask2;
> + thr = xpthread_create (&attr_perthreadfs,
> + thread_get_umask_helper_perthread, &mask2);
> + xpthread_join (thr);
> + TEST_COMPARE (mask1, mask2);
> + return mask1;
> +}
> +
> +/* Verify that the file system attributes for the current thread are
> + as expected. */
> +static void
> +check_attributes (const char *where, mode_t expected_umask,
> + const char *expected_cwd)
> +{
> + printf ("info: reading file attributes in %s\n", where);
> + TEST_COMPARE (get_umask_unlocked (), expected_umask);
> + TEST_COMPARE (thread_get_umask_unlocked (), expected_umask);
> + char *cwd = get_current_dir_name ();
> + TEST_COMPARE_STRING (cwd, expected_cwd);
> + free (cwd);
> + cwd = thread_get_pwd ();
> + TEST_COMPARE_STRING (cwd, expected_cwd);
> + free (cwd);
> +}
> +
> +/* Thread function launched with per-thread file system
> + attributes. */
> +static void *
> +thread_perthreadfs (void *closure)
> +{
> + puts ("info: changing file attributes in thread_perthreadfs");
> + xchdir (new_cwd_1);
> + TEST_COMPARE (umask (new_umask_1), original_umask);
> + check_attributes ("thread_perthreadfs", new_umask_1, new_cwd_1);
> +
> + pthread_barrier_wait (&barrier);
> + /* File attributes read in thread_sharedfs here. */
> + pthread_barrier_wait (&barrier);
> + /* File attributes read in main thread here. */
> + pthread_barrier_wait (&barrier);
> + /* File attributes changed in thread_sharedfs here. */
> + pthread_barrier_wait (&barrier);
> +
> + check_attributes ("thread_perthreadfs", new_umask_1, new_cwd_1);
> +
> + pthread_barrier_wait (&barrier);
> + /* File attributes read in main thread here. */
> + pthread_barrier_wait (&barrier);
> + return NULL;
> +}
> +
> +/* Launched with te PTHREAD_PER_THREAD_NP, but runs the actual test on
> + a PTHREAD_PER_PROCESS_NP thread. */
> +static void *
> +thread_perthreadfs_indirect (void *closure)
> +{
> + return xpthread_join (xpthread_create (NULL, thread_perthreadfs, closure));
> +}
> +
> +/* Thread function launched with shared file system attributes. */
> +static void *
> +thread_sharedfs (void *closure)
> +{
> + /* Wait for thread_perthreadfs to update current directory and
> + umask. */
> + pthread_barrier_wait (&barrier);
> +
> + check_attributes ("thread_sharedfs", original_umask, original_cwd);
> +
> + pthread_barrier_wait (&barrier);
> + /* File attributes read in main thread here. */
> + pthread_barrier_wait (&barrier);
> +
> + puts ("info: changing file attributes in thread_sharedfs");
> + TEST_COMPARE (umask (new_umask_2), original_umask);
> + xchdir (new_cwd_2);
> + check_attributes ("thread_sharedfs", new_umask_2, new_cwd_2);
> +
> + pthread_barrier_wait (&barrier);
> + /* File attributes read in thread_perthreadfs here. */
> + pthread_barrier_wait (&barrier);
> + /* File attributes read in main thread here. */
> + pthread_barrier_wait (&barrier);
> + return NULL;
> +}
> +
> +static int
> +do_test (void)
> +{
> + original_cwd = get_current_dir_name ();
> + TEST_VERIFY_EXIT (original_cwd != NULL);
> + original_umask = get_umask_unlocked ();
> +
> + new_cwd_1 = support_create_temp_directory ("tst-pthread-perthreadfs-1-");
> + new_cwd_2 = support_create_temp_directory ("tst-pthread-perthreadfs-2-");
> + /* Arbitrary bit pattern change to obtain distinct values, so that
> + it is possible to check for actual changes. */
> + new_umask_1 = original_umask ^ 0111;
> + new_umask_2 = original_umask ^ 0222;
> +
> + xpthread_barrier_init (&barrier, NULL, 3);
> + xpthread_attr_init (&attr_perthreadfs);
> + {
Each of these tests should havea 1 comment explaining intent.
/* Test: Default is PTHREAD_PER_PROCESS_NP. */
> + int scope = -1;
> + TEST_COMPARE (pthread_attr_getperthreadfs_np (&attr_perthreadfs, &scope),
> + 0);
> + TEST_COMPARE (scope, PTHREAD_PER_PROCESS_NP);
/* Test: Set and get compares the same. */
> + TEST_COMPARE (pthread_attr_setperthreadfs_np (&attr_perthreadfs,
> + PTHREAD_PER_THREAD_NP), 0);
> + scope = -1;
> + TEST_COMPARE (pthread_attr_getperthreadfs_np (&attr_perthreadfs, &scope),
> + 0);
> + TEST_COMPARE (scope, PTHREAD_PER_THREAD_NP);
/* Test: Invalid scope returns EINVAL. */
> +
> + TEST_COMPARE (pthread_attr_setperthreadfs_np (&attr_perthreadfs, 2),
> + EINVAL);
> + scope = -1;
> + TEST_COMPARE (pthread_attr_getperthreadfs_np (&attr_perthreadfs, &scope),
> + 0);
> + TEST_COMPARE (scope, PTHREAD_PER_THREAD_NP);
OK.
> + }
> +
> + /* Two test runs, once with perthreadsfs set to
> + PTHREAD_PER_THREAD_NP directly, once indirectly via inheritance
> + from the current (overriding the PTHREAD_PER_PROCESS_NP
> + default). */
OK.
> + for (int do_indirect = 0; do_indirect < 2; ++do_indirect)
> + {
> + printf ("info: test iteration with do_indirect == %d\n", do_indirect);
> + pthread_t thr1;
> + if (do_indirect)
> + thr1 = xpthread_create (&attr_perthreadfs,
> + thread_perthreadfs_indirect, NULL);
> + else
> + thr1 = xpthread_create (&attr_perthreadfs, thread_perthreadfs, NULL);
> + pthread_t thr2 = xpthread_create (NULL, thread_sharedfs, NULL);
> +
> + /* Wait for thread_perthreadfs to update current directory and
> + umask. */
> + xpthread_barrier_wait (&barrier);
> + /* File attributes read thread_sharedfs here. */
> + xpthread_barrier_wait (&barrier);
> +
> + check_attributes ("main thread", original_umask, original_cwd);
> +
> + xpthread_barrier_wait (&barrier);
> + /* File attributes changed thread_sharedfs here. */
> + xpthread_barrier_wait (&barrier);
> + /* File attributes read in thread_perthreadfs here. */
> + xpthread_barrier_wait (&barrier);
> +
> + check_attributes ("main thread", new_umask_2, new_cwd_2);
> +
> + xpthread_barrier_wait (&barrier);
> +
> + xpthread_join (thr2);
> + xpthread_join (thr1);
> +
> + xchdir (original_cwd);
> + umask (original_umask);
> + }
> +
> + xpthread_attr_destroy (&attr_perthreadfs);
> + xpthread_barrier_destroy (&barrier);
> +
> + free (new_cwd_2);
> + free (new_cwd_1);
> + free (original_cwd);
> + return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/support/Makefile b/support/Makefile
> index 56c1ed43bb..774b0a692a 100644
> --- a/support/Makefile
> +++ b/support/Makefile
> @@ -80,6 +80,7 @@ libsupport-routines = \
> xasprintf \
> xbind \
> xcalloc \
> + xchdir \
OK.
> xchroot \
> xclock_gettime \
> xclose \
> @@ -88,6 +89,7 @@ libsupport-routines = \
> xdlfcn \
> xdlmopen \
> xdup2 \
> + xfchdir \
OK.
> xfclose \
> xfopen \
> xfork \
> diff --git a/support/xchdir.c b/support/xchdir.c
> new file mode 100644
> index 0000000000..a2f728f5df
> --- /dev/null
> +++ b/support/xchdir.c
> @@ -0,0 +1,28 @@
> +/* chdir with error checking.
> + Copyright (C) 2017-2019 Free Software Foundation, Inc.
New file? Copyright 2019.
> + 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
> + <http://www.gnu.org/licenses/>. */
> +
> +#include <support/check.h>
> +#include <support/xunistd.h>
> +#include <sys/stat.h>
> +
> +void
> +xchdir (const char *path)
> +{
> + if (chdir (path) != 0)
> + FAIL_EXIT1 ("chdir (\"%s\"): %m", path);
OK.
> +}
> diff --git a/support/xfchdir.c b/support/xfchdir.c
> new file mode 100644
> index 0000000000..76c5f655bb
> --- /dev/null
> +++ b/support/xfchdir.c
> @@ -0,0 +1,28 @@
> +/* fchdir with error checking.
> + Copyright (C) 2017-2019 Free Software Foundation, Inc.
New file? Copyright 2019.
> + 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
> + <http://www.gnu.org/licenses/>. */
> +
> +#include <support/check.h>
> +#include <support/xunistd.h>
> +#include <sys/stat.h>
> +
> +void
> +xfchdir (int fd)
> +{
> + if (fchdir (fd) != 0)
> + FAIL_EXIT1 ("fchdir (%d): %m", fd);
OK.
> +}
> diff --git a/support/xunistd.h b/support/xunistd.h
> index 338eb86a1b..b470d99be1 100644
> --- a/support/xunistd.h
> +++ b/support/xunistd.h
> @@ -38,6 +38,8 @@ int xopen (const char *path, int flags, mode_t);
> void xstat (const char *path, struct stat64 *);
> void xfstat (int fd, struct stat64 *);
> void xmkdir (const char *path, mode_t);
> +void xchdir (const char *path);
> +void xfchdir (int);
OK.
> void xchroot (const char *path);
> void xunlink (const char *path);
> long xsysconf (int name);
> diff --git a/sysdeps/nptl/internaltypes.h b/sysdeps/nptl/internaltypes.h
> index 53d037e0f1..5ad56908b5 100644
> --- a/sysdeps/nptl/internaltypes.h
> +++ b/sysdeps/nptl/internaltypes.h
> @@ -48,6 +48,18 @@ struct pthread_attr
> #define ATTR_FLAG_OLDATTR 0x0010
> #define ATTR_FLAG_SCHED_SET 0x0020
> #define ATTR_FLAG_POLICY_SET 0x0040
> +#define ATTR_FLAG_PERTHREADFS 0x0080
OK.
> +
> +/* These flags are not copied from the thread attribute at
> + pthread_create time. */
> +#define ATTR_FLAGS_IGNORED_ATTR \
> + (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET)
OK.
> +
> +/* These flags are inherited from the current thread during
> + pthread_create even if they are not specified in the thread
> + attribute. */
> +#define ATTR_FLAGS_INHERITED \
> + ATTR_FLAG_PERTHREADFS
OK.
>
>
> /* Mutex attribute data structure. */
> diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
> index 704a3c48d6..37073e3ce7 100644
> --- a/sysdeps/nptl/pthread.h
> +++ b/sysdeps/nptl/pthread.h
> @@ -181,7 +181,16 @@ enum
> #define PTHREAD_PROCESS_SHARED PTHREAD_PROCESS_SHARED
> };
>
> -
> +#ifdef __USE_GNU
> +/* Thread-private or process-global flag. */
> +enum
> +{
> + PTHREAD_PER_PROCESS_NP,
> +# define PTHREAD_PER_PROCESS_NP PTHREAD_PER_PROCESS_NP
> + PTHREAD_PER_THREAD_NP
> +# define PTHREAD_PER_THREAD_NP PTHREAD_PER_THREAD_NP
> +};
> +#endif /* __USE_GNU */
>
> /* Conditional variable handling. */
> #define PTHREAD_COND_INITIALIZER { { {0}, {0}, {0, 0}, {0, 0}, 0, 0, {0, 0} } }
> @@ -406,6 +415,21 @@ extern int pthread_attr_getaffinity_np (const pthread_attr_t *__attr,
> cpu_set_t *__cpuset)
> __THROW __nonnull ((1, 3));
>
> +
> +/* Control the flag in ATTR whether the thread has its own current
> + directory, file system root, and umask attribute. SCOPE must be
> + PTHREAD_PER_PROCESS_NP or PTHREAD_PER_THREAD_NP. By default, new
> + threads share these attributes with their creating thread
> + (PTHREAD_PER_PROCESS_NP). */
> +int pthread_attr_setperthreadfs_np (pthread_attr_t *__attr, int __scope)
> + __THROW __nonnull ((1));
> +
> +/* Set *SCOPE to PTHREAD_PER_PROCESS_NP or PTHREAD_PER_THREAD_NP,
> + depending on the state of *ATTR. */
> +int pthread_attr_getperthreadfs_np (const pthread_attr_t *__restrict __attr,
> + int *__restrict __scope)
> + __THROW __nonnull ((1, 2));
> +
> /* Get the default attributes used by pthread_create in this process. */
> extern int pthread_getattr_default_np (pthread_attr_t *__attr)
> __THROW __nonnull ((1));
> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> index a4c31932cb..2635e16f5e 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> @@ -2143,5 +2143,7 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> index fe85a35620..12227b9800 100644
> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> @@ -2218,6 +2218,8 @@ GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
> index bc3df8dcea..6d09148e1d 100644
> --- a/sysdeps/unix/sysv/linux/arm/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
> @@ -128,6 +128,8 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 _Exit F
> diff --git a/sysdeps/unix/sysv/linux/createthread.c b/sysdeps/unix/sysv/linux/createthread.c
> index 579bd94743..177e14e9ae 100644
> --- a/sysdeps/unix/sysv/linux/createthread.c
> +++ b/sysdeps/unix/sysv/linux/createthread.c
> @@ -66,7 +66,9 @@ create_thread (struct pthread *pd, const struct pthread_attr *attr,
>
> CLONE_VM, CLONE_FS, CLONE_FILES
> These flags select semantics with shared address space and
> - file descriptors according to what POSIX requires.
> + file descriptors according to what POSIX requires. CLONE_FS
> + is optional; it can be controlled using the function
> + pthread_attr_setperthreadfs_np.
OK.
>
> CLONE_SIGHAND, CLONE_THREAD
> This flag selects the POSIX signal semantics and various
> @@ -90,11 +92,13 @@ create_thread (struct pthread *pd, const struct pthread_attr *attr,
>
> The termination signal is chosen to be zero which means no signal
> is sent. */
> - const int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SYSVSEM
> - | CLONE_SIGHAND | CLONE_THREAD
> - | CLONE_SETTLS | CLONE_PARENT_SETTID
> - | CLONE_CHILD_CLEARTID
> - | 0);
> + int clone_flags = (CLONE_VM | CLONE_FILES | CLONE_SYSVSEM
> + | CLONE_SIGHAND | CLONE_THREAD
> + | CLONE_SETTLS | CLONE_PARENT_SETTID
> + | CLONE_CHILD_CLEARTID
> + | 0);
> + if ((attr->flags & ATTR_FLAG_PERTHREADFS) == 0)
> + clone_flags |= CLONE_FS;
OK.
>
> TLS_DEFINE_INIT_TP (tp, pd);
>
> diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
> index 9b3cee65bb..5ee091972b 100644
> --- a/sysdeps/unix/sysv/linux/csky/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
> @@ -2087,5 +2087,7 @@ GLIBC_2.29 xprt_register F
> GLIBC_2.29 xprt_unregister F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> index 75edece94a..844eaf539b 100644
> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> @@ -2039,6 +2039,8 @@ GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/hppa/pthread.h b/sysdeps/unix/sysv/linux/hppa/pthread.h
> index 45e706c037..b80c84c0b7 100644
> --- a/sysdeps/unix/sysv/linux/hppa/pthread.h
> +++ b/sysdeps/unix/sysv/linux/hppa/pthread.h
> @@ -158,6 +158,16 @@ enum
> #define PTHREAD_PROCESS_SHARED PTHREAD_PROCESS_SHARED
> };
>
> +#ifdef __USE_GNU
> +/* Thread-private or process-global flag. */
> +enum
> +{
> + PTHREAD_PER_PROCESS_NP,
> +# define PTHREAD_PER_PROCESS_NP PTHREAD_PER_PROCESS_NP
> + PTHREAD_PER_THREAD_NP
> +# define PTHREAD_PER_THREAD_NP PTHREAD_PER_THREAD_NP
> +};
> +#endif /* __USE_GNU */
>
> /* Conditional variable handling. */
> #define PTHREAD_COND_INITIALIZER { { {0}, {0}, {0, 0}, {0, 0}, 0, 0, {0, 0} } }
> @@ -382,6 +392,21 @@ extern int pthread_attr_getaffinity_np (const pthread_attr_t *__attr,
> cpu_set_t *__cpuset)
> __THROW __nonnull ((1, 3));
>
> +
> +/* Control the flag in ATTR whether the thread has its own current
> + directory, file system root, and umask attribute. SCOPE must be
> + PTHREAD_PER_PROCESS_NP or PTHREAD_PER_THREAD_NP. By default, new
> + threads share these attributes with their creating thread
> + (PTHREAD_PER_PROCESS_NP). */
> +int pthread_attr_setperthreadfs_np (pthread_attr_t *__attr, int __scope)
> + __THROW __nonnull ((1));
OK.
> +
> +/* Set *SCOPE to PTHREAD_PER_PROCESS_NP or PTHREAD_PER_THREAD_NP,
> + depending on the state of *ATTR. */
> +int pthread_attr_getperthreadfs_np (const pthread_attr_t *__restrict __attr,
> + int *__restrict __scope)
> + __THROW __nonnull ((1, 2));
OK.
> +
> /* Get the default attributes used by pthread_create in this process. */
> extern int pthread_getattr_default_np (pthread_attr_t *__attr)
> __THROW __nonnull ((1));
> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
> index edeaf8e722..efd8cb1685 100644
> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
> @@ -2205,6 +2205,8 @@ GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> index b5d460eeb2..7f34f4d1e6 100644
> --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> @@ -2071,6 +2071,8 @@ GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> index 05633b3cb8..34d5f6c91a 100644
> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> @@ -129,6 +129,8 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 _Exit F
> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> index 47eb7b4608..71882c6e23 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> @@ -2148,6 +2148,8 @@ GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> index f7ced487f7..4f605fa67a 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> @@ -2135,5 +2135,7 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> index e49dc4272e..62790b0a64 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> @@ -2122,6 +2122,8 @@ GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> index daa3b60c5b..eb2ae61601 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> @@ -2120,6 +2120,8 @@ GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> index 457ce0b6f2..9cf1462270 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> @@ -2128,6 +2128,8 @@ GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> index 63d5c03bfb..d116e7180e 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> @@ -2122,6 +2122,8 @@ GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> index 7fec0c9670..0e8d5bfcc7 100644
> --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> @@ -2176,5 +2176,7 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> index 9200a54309..16e66c2fa4 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> @@ -2178,6 +2178,8 @@ GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> index ef7779905f..fff0295a63 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> @@ -2211,6 +2211,8 @@ GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> index 2860df8ebc..808f021335 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> @@ -2041,6 +2041,8 @@ GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> index 2229a1dcc0..a894bc49be 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> @@ -2245,5 +2245,7 @@ GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> index 31010e6cf7..e220b0fd0c 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> @@ -2105,5 +2105,7 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> index 576295deff..1567d2ff1d 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> @@ -2173,6 +2173,8 @@ GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> index abf0473683..f9d88d588e 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> @@ -2077,6 +2077,8 @@ GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
> index 41977f6e9c..affd74df4c 100644
> --- a/sysdeps/unix/sysv/linux/sh/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
> @@ -2043,6 +2043,8 @@ GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> index 3d2f00ca52..c12cc83bb2 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> @@ -2167,6 +2167,8 @@ GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> index 2f20643e8e..37c9dff44c 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> @@ -2094,6 +2094,8 @@ GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> index 59f85d9373..71b7cc4ff9 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> @@ -2052,6 +2052,8 @@ GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> index 67a4e238d6..573fc2e01c 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> @@ -2151,5 +2151,7 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadfs_np F
OK.
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
>
--
Cheers,
Carlos.