[PATCH v2 1/2] Add the __libc_single_threaded variable

DJ Delorie dj@redhat.com
Tue Jun 30 00:52:35 GMT 2020


Nits noted below:

* comment in test about multi vs single threaded
* copyright dates still say 2019 throughout
* suggested comment change in single_threaded.h
* __libc_single_threaded_local ?
* _dl_single_threaded_update ?

Florian Weimer via Libc-alpha <libc-alpha@sourceware.org> writes:
> The variable is placed in libc.so, and it can be true only in
> an outer libc, not libcs loaded via dlmopen or static dlopen.
> Since thread creation from inner namespaces does not work,
> pthread_create can update __libc_single_threaded directly.

So we have a One True Variable in the outer glibc that starts at "1" and
gets set to "0" on thread creation; if you dlopen another glibc, the
variable therein can't be trusted but you can't use that glibc for
thread creation anyway.

Ok :-)

> diff --git a/NEWS b/NEWS
> +* The GNU C Library now provides the header file <sys/single_threaded.h>
> +  which declares the variable __libc_single_threaded.  Applications are
> +  encouraged to use this variable for single-thread optimizations,
> +  instead of weak references to symbols historically defined in
> +  libpthread.

Ok.

> diff --git a/elf/Makefile b/elf/Makefile
> -	       tst-linkall-static tst-env-setuid tst-env-setuid-tunables
> +	       tst-linkall-static tst-env-setuid tst-env-setuid-tunables \
> +	       tst-single_threaded-static tst-single_threaded-pthread-static
> +

Adds two tests.  Ok.

> -tests-static += tst-tls9-static
> -tst-tls9-static-ENV = \
> -       LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)dlfcn
> +tests-static += tst-tls9-static tst-single_threaded-static-dlopen
> +static-dlopen-environment = \
> +  LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)dlfcn
> +tst-tls9-static-ENV = $(static-dlopen-environment)
> +tst-single_threaded-static-dlopen-ENV = $(static-dlopen-environment)

New test.  Breaking out common definitions; ok.

> @@ -204,7 +208,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
>  	 tst-dlopen-self tst-auditmany tst-initfinilazyfail tst-dlopenfail \
>  	 tst-dlopenfail-2 \
>  	 tst-filterobj tst-filterobj-dlopen tst-auxobj tst-auxobj-dlopen \
> -	 tst-audit14 tst-audit15 tst-audit16
> +	 tst-audit14 tst-audit15 tst-audit16 \
> +	 tst-single_threaded tst-single_threaded-pthread

Adds two new test.  Ok. 

> @@ -317,7 +322,9 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
>  		tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 \
>  		tst-dlopenfailmod3 tst-ldconfig-ld-mod \
>  		tst-filterobj-flt tst-filterobj-aux tst-filterobj-filtee \
> -		tst-auditlogmod-1 tst-auditlogmod-2 tst-auditlogmod-3
> +		tst-auditlogmod-1 tst-auditlogmod-2 tst-auditlogmod-3 \
> +		tst-single_threaded-mod1 tst-single_threaded-mod2 \
> +		tst-single_threaded-mod3 tst-single_threaded-mod4

Adds four more modules.  Ok.

> +
> +$(objpfx)tst-single_threaded: $(objpfx)tst-single_threaded-mod1.so $(libdl)
> +$(objpfx)tst-single_threaded.out: \
> +  $(objpfx)tst-single_threaded-mod2.so $(objpfx)tst-single_threaded-mod3.so
> +$(objpfx)tst-single_threaded-static-dlopen: \
> +  $(objpfx)tst-single_threaded-mod1.o $(common-objpfx)dlfcn/libdl.a
> +$(objpfx)tst-single_threaded-static-dlopen.out: \
> +  $(objpfx)tst-single_threaded-mod2.so
> +$(objpfx)tst-single_threaded-pthread: \
> +  $(objpfx)tst-single_threaded-mod1.so $(libdl) $(shared-thread-library)
> +$(objpfx)tst-single_threaded-pthread.out: \
> +  $(objpfx)tst-single_threaded-mod2.so $(objpfx)tst-single_threaded-mod3.so \
> +  $(objpfx)tst-single_threaded-mod4.so
> +$(objpfx)tst-single_threaded-pthread-static: $(static-thread-library)

four test deps, three .out deps; ok.  Static .out doesn't need deps on
dlopen'd objects ;-)

> +#include <sys/single_threaded.h>
>  
>  void
>  __libc_early_init (_Bool initial)
>  {
>    /* Initialize ctype data.  */
>    __ctype_init ();
> +
> +  /* Only the outer namespace is marked as single-threaded.  */
> +  __libc_single_threaded = initial;
>  }

"initial" is only set if it's the outermost glibc; thus
__libc_single_threaded is TRUE for that case, and FALSE otherwise.

Ok.

> diff --git a/elf/tst-single_threaded-mod1.c b/elf/tst-single_threaded-mod1.c
> +#include <sys/single_threaded.h>
> +
> +_Bool
> +single_threaded_1 (void)
> +{
> +  return __libc_single_threaded;
> +}

Ok.

> diff --git a/elf/tst-single_threaded-mod2.c b/elf/tst-single_threaded-mod2.c
> +#include <sys/single_threaded.h>
> +
> +_Bool
> +single_threaded_2 (void)
> +{
> +  return __libc_single_threaded;
> +}

Ok.

> diff --git a/elf/tst-single_threaded-mod3.c b/elf/tst-single_threaded-mod3.c
> +#include <sys/single_threaded.h>
> +
> +_Bool
> +single_threaded_3 (void)
> +{
> +  return __libc_single_threaded;
> +}

Ok.

> diff --git a/elf/tst-single_threaded-mod4.c b/elf/tst-single_threaded-mod4.c
> +#include <sys/single_threaded.h>
> +
> +_Bool
> +single_threaded_4 (void)
> +{
> +  return __libc_single_threaded;
> +}

Ok.  Starting to see a pattern here...   ;-)

> diff --git a/elf/tst-single_threaded-pthread-static.c b/elf/tst-single_threaded-pthread-static.c
> +/* This test is a stripped-down version of
> +   tst-single_threaded-pthread.c, without any loading of dynamic
> +   objects.  */
> +
> +#include <stdio.h>
> +#include <support/check.h>
> +#include <support/xthread.h>
> +#include <sys/single_threaded.h>
> +
> +/* First barrier synchronizes main thread, thread 1, thread 2.  */
> +static pthread_barrier_t barrier1;
> +
> +/* Second barrier synchronizes main thread, thread 2.  */
> +static pthread_barrier_t barrier2;
> +
> +static void *
> +threadfunc (void *closure)
> +{
> +  TEST_VERIFY (!__libc_single_threaded);
> +
> +  /* Wait for the main thread and the other thread.  */
> +  xpthread_barrier_wait (&barrier1);
> +  TEST_VERIFY (!__libc_single_threaded);
> +
> +  /* Second thread waits on second barrier, too.  */
> +  if (closure != NULL)
> +    xpthread_barrier_wait (&barrier2);
> +  TEST_VERIFY (!__libc_single_threaded);
> +
> +  return NULL;
> +}
> +
> +static int
> +do_test (void)
> +{
> +  TEST_VERIFY (__libc_single_threaded);
> +
> +  /* Two threads plus main thread.  */
> +  xpthread_barrier_init (&barrier1, NULL, 3);
> +
> +  /* Main thread and second thread.  */
> +  xpthread_barrier_init (&barrier2, NULL, 2);
> +
> +  pthread_t thr1 = xpthread_create (NULL, threadfunc, NULL);
> +  TEST_VERIFY (!__libc_single_threaded);
> +
> +  pthread_t thr2 = xpthread_create (NULL, threadfunc, &thr2);
> +  TEST_VERIFY (!__libc_single_threaded);
> +
> +  xpthread_barrier_wait (&barrier1);
> +  TEST_VERIFY (!__libc_single_threaded);
> +
> +  /* Join first thread.  This should not bring us back into
> +     single-threaded mode.  */
> +  xpthread_join (thr1);
> +  TEST_VERIFY (!__libc_single_threaded);
> +
> +  /* We may be back in single-threaded mode after joining both
> +     threads, but this is not guaranteed.  */
> +  xpthread_barrier_wait (&barrier2);
> +  xpthread_join (thr2);
> +  printf ("info: __libc_single_threaded after joining all threads: %d\n",
> +          __libc_single_threaded);
> +
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>

Verfies __libc_single_threaded until first pthread_create, then
everything should be !__libc_single_threaded as long as any threads
remain unjoined.  Ok.

> diff --git a/elf/tst-single_threaded-pthread.c b/elf/tst-single_threaded-pthread.c
> new file mode 100644
> index 0000000000..c02f4047d1
> --- /dev/null
> +++ b/elf/tst-single_threaded-pthread.c
> @@ -0,0 +1,174 @@
> +/* Test support for single-thread optimizations.  With threads.
> +   Copyright (C) 2019 Free Software Foundation, Inc.

It's 2020 now.  Same throughout.

> +   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 <stddef.h>
> +#include <stdio.h>
> +#include <support/check.h>
> +#include <support/namespace.h>
> +#include <support/xdlfcn.h>
> +#include <support/xthread.h>
> +#include <sys/single_threaded.h>
> +
> +/* First barrier synchronizes main thread, thread 1, thread 2.  */
> +static pthread_barrier_t barrier1;
> +
> +/* Second barrier synchronizes main thread, thread 2.  */
> +static pthread_barrier_t barrier2;
> +
> +/* Defined in tst-single-threaded-mod1.so.  */
> +_Bool single_threaded_1 (void);
> +
> +/* Initialized via dlsym.  */
> +static _Bool (*single_threaded_2) (void);
> +static _Bool (*single_threaded_3) (void);
> +static _Bool (*single_threaded_4) (void);
> +
> +static void *
> +threadfunc (void *closure)
> +{
> +  TEST_VERIFY (!__libc_single_threaded);
> +  TEST_VERIFY (!single_threaded_1 ());
> +  TEST_VERIFY (!single_threaded_2 ());
> +
> +  /* Wait until the main thread loads more functions.  */
> +  xpthread_barrier_wait (&barrier1);
> +
> +  TEST_VERIFY (!__libc_single_threaded);
> +  TEST_VERIFY (!single_threaded_1 ());
> +  TEST_VERIFY (!single_threaded_2 ());
> +  TEST_VERIFY (!single_threaded_3 ());
> +  TEST_VERIFY (!single_threaded_4 ());
> +
> +  /* Second thread waits on second barrier, too.  */
> +  if (closure != NULL)
> +    xpthread_barrier_wait (&barrier2);
> +  TEST_VERIFY (!__libc_single_threaded);
> +  TEST_VERIFY (!single_threaded_1 ());
> +  TEST_VERIFY (!single_threaded_2 ());
> +  TEST_VERIFY (!single_threaded_3 ());
> +  TEST_VERIFY (!single_threaded_4 ());
> +
> +  return NULL;
> +}

All check for signalling multi-threaded.  Ok.

> +/* Used for closure arguments to the subprocess function.  */
> +static char expected_false = 0;
> +static char expected_true = 1;
> +
> +/* A subprocess inherits currently inherits the single-threaded state
> +   of the parent process.  */
> +static void
> +subprocess (void *closure)
> +{
> +  const char *expected = closure;
> +  TEST_COMPARE (__libc_single_threaded, *expected);
> +  TEST_COMPARE (single_threaded_1 (), *expected);
> +  if (single_threaded_2 != NULL)
> +    TEST_COMPARE (single_threaded_2 (), *expected);
> +  if (single_threaded_3 != NULL)
> +    TEST_COMPARE (single_threaded_3 (), *expected);
> +  if (single_threaded_4 != NULL)
> +    TEST_VERIFY (!single_threaded_4 ());
> +}

Ok.

> +static int
> +do_test (void)
> +{
> +  printf ("info: main __libc_single_threaded address: %p\n",
> +          &__libc_single_threaded);
> +  TEST_VERIFY (__libc_single_threaded);
> +  TEST_VERIFY (single_threaded_1 ());
> +  support_isolate_in_subprocess (subprocess, &expected_true);

Test for signalling single threaded.  Ok.

> +  void *handle_mod2 = xdlopen ("tst-single_threaded-mod2.so", RTLD_LAZY);
> +  single_threaded_2 = xdlsym (handle_mod2, "single_threaded_2");
> +  TEST_VERIFY (single_threaded_2 ());

Loading an SO doesn't make it multi threaded.  Ok.

> +  /* Two threads plus main thread.  */
> +  xpthread_barrier_init (&barrier1, NULL, 3);
> +
> +  /* Main thread and second thread.  */
> +  xpthread_barrier_init (&barrier2, NULL, 2);
> +
> +  pthread_t thr1 = xpthread_create (NULL, threadfunc, NULL);
> +  TEST_VERIFY (!__libc_single_threaded);
> +  TEST_VERIFY (!single_threaded_1 ());
> +  TEST_VERIFY (!single_threaded_2 ());
> +  support_isolate_in_subprocess (subprocess, &expected_false);

Now we expect signalling multi-threaded.  Ok.

> +  pthread_t thr2 = xpthread_create (NULL, threadfunc, &thr2);
> +  TEST_VERIFY (!__libc_single_threaded);
> +  TEST_VERIFY (!single_threaded_1 ());
> +  TEST_VERIFY (!single_threaded_2 ());
> +  support_isolate_in_subprocess (subprocess, &expected_false);
> +
> +  /* Delayed library load, while already multi-threaded.  */
> +  void *handle_mod3 = xdlopen ("tst-single_threaded-mod3.so", RTLD_LAZY);
> +  single_threaded_3 = xdlsym (handle_mod3, "single_threaded_3");
> +  TEST_VERIFY (!__libc_single_threaded);
> +  TEST_VERIFY (!single_threaded_1 ());
> +  TEST_VERIFY (!single_threaded_2 ());
> +  TEST_VERIFY (!single_threaded_3 ());
> +  support_isolate_in_subprocess (subprocess, &expected_false);
> +
> +  /* Same with dlmopen.  */
> +  void *handle_mod4 = dlmopen (LM_ID_NEWLM, "tst-single_threaded-mod4.so",
> +                               RTLD_LAZY);
> +  single_threaded_4 = xdlsym (handle_mod4, "single_threaded_4");
> +  TEST_VERIFY (!__libc_single_threaded);
> +  TEST_VERIFY (!single_threaded_1 ());
> +  TEST_VERIFY (!single_threaded_2 ());
> +  TEST_VERIFY (!single_threaded_3 ());
> +  TEST_VERIFY (!single_threaded_4 ());
> +  support_isolate_in_subprocess (subprocess, &expected_false);
> +
> +  /* Run the newly loaded functions from the other threads as
> +     well.  */
> +  xpthread_barrier_wait (&barrier1);
> +  TEST_VERIFY (!__libc_single_threaded);
> +  TEST_VERIFY (!single_threaded_1 ());
> +  TEST_VERIFY (!single_threaded_2 ());
> +  TEST_VERIFY (!single_threaded_3 ());
> +  TEST_VERIFY (!single_threaded_4 ());
> +  support_isolate_in_subprocess (subprocess, &expected_false);
> +
> +  /* Join first thread.  This should not bring us back into
> +     single-threaded mode.  */
> +  xpthread_join (thr1);
> +  TEST_VERIFY (!__libc_single_threaded);
> +  TEST_VERIFY (!single_threaded_1 ());
> +  TEST_VERIFY (!single_threaded_2 ());
> +  TEST_VERIFY (!single_threaded_3 ());
> +  TEST_VERIFY (!single_threaded_4 ());
> +  support_isolate_in_subprocess (subprocess, &expected_false);

Likewise for all these.  Ok.

> +  /* We may be back in single-threaded mode after joining both
> +     threads, but this is not guaranteed.  */
> +  xpthread_barrier_wait (&barrier2);
> +  xpthread_join (thr2);
> +  printf ("info: __libc_single_threaded after joining all threads: %d\n",
> +          __libc_single_threaded);
> +
> +  xdlclose (handle_mod4);
> +  xdlclose (handle_mod3);
> +  xdlclose (handle_mod2);
> +
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>

Ok.

> diff --git a/elf/tst-single_threaded-static-dlopen.c b/elf/tst-single_threaded-static-dlopen.c
> new file mode 100644
> index 0000000000..f270cf452e
> --- /dev/null
> +++ b/elf/tst-single_threaded-static-dlopen.c
> @@ -0,0 +1,56 @@
> +/* Test support for single-thread optimizations.  No threads, static dlopen.
> +   Copyright (C) 2019 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
> +   <http://www.gnu.org/licenses/>.  */
> +
> +/* In a static dlopen scenario, the single-threaded optimization is
> +   not possible because their is no globally shared dynamic linker
> +   across all namespaces.  */
> +
> +#include <stddef.h>
> +#include <support/check.h>
> +#include <support/xdlfcn.h>
> +#include <sys/single_threaded.h>
> +
> +static int
> +do_test (void)
> +{
> +  TEST_VERIFY (__libc_single_threaded);
> +
> +  /* Defined in tst-single-threaded-mod1.o.  */
> +  extern _Bool single_threaded_1 (void);
> +  TEST_VERIFY (single_threaded_1 ());
> +
> +  /* Even after a failed dlopen, assume multi-threaded mode.  */
> +  TEST_VERIFY (dlopen ("tst-single_threaded-does-not-exist.so", RTLD_LAZY)
> +               == NULL);
> +  TEST_VERIFY (__libc_single_threaded);
> +  TEST_VERIFY (single_threaded_1 ());

You say "assume multi-threaded" but you test for signalling single
threaded.

> +  void *handle_mod2 = xdlopen ("tst-single_threaded-mod2.so", RTLD_LAZY);
> +  _Bool (*single_threaded_2) (void)
> +    = xdlsym (handle_mod2, "single_threaded_2");
> +  TEST_VERIFY (__libc_single_threaded);
> +  TEST_VERIFY (single_threaded_1 ());
> +  /* The inner libc always assumes multi-threaded use.  */
> +  TEST_VERIFY (!single_threaded_2 ());

Ok.

> diff --git a/elf/tst-single_threaded-static.c b/elf/tst-single_threaded-static.c
> +#include <support/check.h>
> +#include <sys/single_threaded.h>
> +
> +static int
> +do_test (void)
> +{
> +  TEST_VERIFY (__libc_single_threaded);
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>

Ok.

> diff --git a/elf/tst-single_threaded.c b/elf/tst-single_threaded.c
> +#include <stddef.h>
> +#include <stdio.h>
> +#include <support/check.h>
> +#include <support/namespace.h>
> +#include <support/xdlfcn.h>
> +#include <sys/single_threaded.h>
> +
> +/* Defined in tst-single-threaded-mod1.so.  */
> +extern _Bool single_threaded_1 (void);
> +
> +/* Initialized via dlsym.  */
> +_Bool (*single_threaded_2) (void);
> +_Bool (*single_threaded_3) (void);
> +
> +static void
> +subprocess (void *closure)
> +{
> +  TEST_VERIFY (__libc_single_threaded);
> +  TEST_VERIFY (single_threaded_1 ());
> +  if (single_threaded_2 != NULL)
> +    TEST_VERIFY (single_threaded_2 ());
> +  if (single_threaded_3 != NULL)
> +    TEST_VERIFY (!single_threaded_3 ());
> +}

Ok.

> +static int
> +do_test (void)
> +{
> +  TEST_VERIFY (__libc_single_threaded);
> +  TEST_VERIFY (single_threaded_1 ());
> +  support_isolate_in_subprocess (subprocess, NULL);
> +
> +  void *handle_mod2 = xdlopen ("tst-single_threaded-mod2.so", RTLD_LAZY);
> +  single_threaded_2 = xdlsym (handle_mod2, "single_threaded_2");
> +  TEST_VERIFY (single_threaded_2 ());
> +  support_isolate_in_subprocess (subprocess, NULL);
> +
> +  /* The current implementation treats the inner namespace as
> +     multi-threaded.  */
> +  void *handle_mod3 = dlmopen (LM_ID_NEWLM, "tst-single_threaded-mod3.so",
> +                               RTLD_LAZY);
> +  single_threaded_3 = xdlsym (handle_mod3, "single_threaded_3");
> +  TEST_VERIFY (!single_threaded_3 ());
> +  support_isolate_in_subprocess (subprocess, NULL);
> +
> +  xdlclose (handle_mod3);
> +  xdlclose (handle_mod2);
> +
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>

Ok.

> diff --git a/htl/pt-create.c b/htl/pt-create.c
> index f501a12017..7ac875cbf7 100644
> --- a/htl/pt-create.c
> +++ b/htl/pt-create.c
> @@ -24,6 +24,7 @@
>  
>  #include <atomic.h>
>  #include <hurd/resource.h>
> +#include <sys/single_threaded.h>
>  
>  #include <pt-internal.h>
>  #include <pthreadP.h>
> @@ -104,6 +105,10 @@ __pthread_create_internal (struct __pthread **thread,
>    sigset_t sigset;
>    size_t stacksize;
>  
> +  /* Avoid a data race in the multi-threaded case.  */
> +  if (__libc_single_threaded)
> +    __libc_single_threaded = 0;

The only time you don't set __libc_single_threaded to zero is if it's
already zero, so the test isn't needed.  Just setting
__libc_single_threaded to zero does the same thing, but faster.  Even if
we're multi-threaded, it doesn't matter if other cpus get the old value
(zero) or the new one (zero).

The comment doesn't really enlighten the reader, IMHO.

> diff --git a/include/sys/single_threaded.h b/include/sys/single_threaded.h
> +#include <misc/sys/single_threaded.h>

Ok.

> diff --git a/misc/Makefile b/misc/Makefile
> index 67c5237f97..58959f6913 100644
> --- a/misc/Makefile
> +++ b/misc/Makefile
> @@ -37,7 +37,8 @@ headers	:= sys/uio.h bits/uio-ext.h bits/uio_lim.h \
>  	   bits/syslog.h bits/syslog-ldbl.h bits/syslog-path.h bits/error.h \
>  	   bits/select2.h bits/hwcap.h sys/auxv.h \
>  	   sys/sysmacros.h bits/sysmacros.h bits/types/struct_iovec.h \
> -	   bits/err-ldbl.h bits/error-ldbl.h
> +	   bits/err-ldbl.h bits/error-ldbl.h \
> +	   sys/single_threaded.h
>  
>  routines := brk sbrk sstk ioctl \
>  	    readv writev preadv preadv64 pwritev pwritev64 \
> @@ -72,7 +73,7 @@ routines := brk sbrk sstk ioctl \
>  	    fgetxattr flistxattr fremovexattr fsetxattr getxattr \
>  	    listxattr lgetxattr llistxattr lremovexattr lsetxattr \
>  	    removexattr setxattr getauxval ifunc-impl-list makedev \
> -	    allocate_once fd_to_filename
> +	    allocate_once fd_to_filename single_threaded

Ok.

> diff --git a/misc/Versions b/misc/Versions
> +  GLIBC_2.32 {
> +    __libc_single_threaded;
> +  }

Ok.

> diff --git a/misc/single_threaded.c b/misc/single_threaded.c
> +#include <sys/single_threaded.h>
> +
> +/* In dynamically linked programs, this variable is initialized in
> +   __libc_early_init (as false for inner libcs).  */
> +#ifdef SHARED
> +char __libc_single_threaded;
> +#else
> +char __libc_single_threaded = 1;
> +#endif

Ok.  Default for SHARED is assume multi-threaded unless properly
initialized.

> diff --git a/misc/sys/single_threaded.h b/misc/sys/single_threaded.h
> +#ifndef _SYS_SINGLE_THREADED_H
> +#define _SYS_SINGLE_THREADED_H
> +
> +#include <features.h>
> +
> +__BEGIN_DECLS
> +
> +/* If this variable is non-zero, then the current thread is the only
> +   thread in the process image.  If it is zero, the process can be
> +   multi-threaded.  */
> +extern char __libc_single_threaded;
> +
> +__END_DECLS
> +
> +#endif /* _SYS_SINGLE_THREADED_H */

Ok.  Suggest s/can be/might be/.  "Can" implies we're giving the user
permission to do something, "might" indicates a condition to be
expected.  Or "the process must act as if multiple threads are running." ?

> diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
> +#include <sys/single_threaded.h>
>  
>  #include <shlib-compat.h>
>  
> @@ -611,6 +612,10 @@ __pthread_create_2_1 (pthread_t *newthread, const pthread_attr_t *attr,
>  {
>    STACK_VARIABLES;
>  
> +  /* Avoid a data race in the multi-threaded case.  */
> +  if (__libc_single_threaded)
> +    __libc_single_threaded = 0;

Same comment as last time.

> diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
>  extern struct rtld_global _rtld_local __rtld_local_attribute__;
> +extern char __libc_single_threaded_local __rtld_local_attribute__;

This isn't mentioned anywhere else...

>  #  undef __rtld_local_attribute__
>  # endif
>  extern struct rtld_global _rtld_global __rtld_global_attribute__;
> +extern char __libc_single_threaded __rtld_global_attribute__;

Ok.

> @@ -1119,6 +1121,9 @@ extern struct link_map * _dl_get_dl_main_map (void)
>     If libpthread is not linked in, this is an empty function.  */
>  void __pthread_initialize_minimal (void) weak_function;
>  
> +/* Update both copies of __libc_single_threaded.  */
> +void _dl_single_threaded_update (char value);
> +

Nor is this mentioned elsewhere.

> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1
> +GLIBC_2.32 __libc_single_threaded D 0x1

Ok.



More information about the Libc-alpha mailing list