[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