nptl: Move stack list variables into _rtld_global

Now __thread_gscope_wait (the function behind THREAD_GSCOPE_WAIT,
formerly __wait_lookup_done) can be implemented directly in ld.so,
eliminating the unprotected GL (dl_wait_lookup_done) function
pointer.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
This commit is contained in:
Florian Weimer 2020-11-16 19:33:30 +01:00
parent aac0f62c47
commit 1daccf403b
37 changed files with 243 additions and 184 deletions

View File

@ -24,6 +24,7 @@
#include <stdio.h> #include <stdio.h>
#include <sys/param.h> #include <sys/param.h>
#include <array_length.h> #include <array_length.h>
#include <list.h>
#ifdef SHARED #ifdef SHARED
#error makefile bug, this file is for static only #error makefile bug, this file is for static only
@ -193,6 +194,12 @@ __libc_setup_tls (void)
if (__builtin_expect (lossage != NULL, 0)) if (__builtin_expect (lossage != NULL, 0))
_startup_fatal (lossage); _startup_fatal (lossage);
#if THREAD_GSCOPE_IN_TCB
INIT_LIST_HEAD (&_dl_stack_used);
INIT_LIST_HEAD (&_dl_stack_user);
list_add (&THREAD_SELF->list, &_dl_stack_user);
#endif
/* Update the executable's link map with enough information to make /* Update the executable's link map with enough information to make
the TLS routines happy. */ the TLS routines happy. */
main_map->l_tls_align = align; main_map->l_tls_align = align;

View File

@ -34,7 +34,8 @@ dl-routines = $(addprefix dl-,load lookup object reloc deps \
version profile tls origin scope \ version profile tls origin scope \
execstack open close trampoline \ execstack open close trampoline \
exception sort-maps lookup-direct \ exception sort-maps lookup-direct \
call-libc-early-init write) call-libc-early-init write \
thread_gscope_wait)
ifeq (yes,$(use-ldconfig)) ifeq (yes,$(use-ldconfig))
dl-routines += dl-cache dl-routines += dl-cache
endif endif
@ -54,7 +55,8 @@ endif
all-dl-routines = $(dl-routines) $(sysdep-dl-routines) all-dl-routines = $(dl-routines) $(sysdep-dl-routines)
# But they are absent from the shared libc, because that code is in ld.so. # But they are absent from the shared libc, because that code is in ld.so.
elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin \ elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin \
dl-sysdep dl-exception dl-reloc-static-pie dl-sysdep dl-exception dl-reloc-static-pie \
thread_gscope_wait
# ld.so uses those routines, plus some special stuff for being the program # ld.so uses those routines, plus some special stuff for being the program
# interpreter and operating independent of libc. # interpreter and operating independent of libc.

View File

@ -183,10 +183,11 @@ ElfW(Word) _dl_stack_flags = DEFAULT_STACK_PERMS;
int (*_dl_make_stack_executable_hook) (void **) = _dl_make_stack_executable; int (*_dl_make_stack_executable_hook) (void **) = _dl_make_stack_executable;
/* Function in libpthread to wait for termination of lookups. */ #if THREAD_GSCOPE_IN_TCB
void (*_dl_wait_lookup_done) (void); list_t _dl_stack_used;
list_t _dl_stack_user;
#if !THREAD_GSCOPE_IN_TCB int _dl_stack_cache_lock;
#else
int _dl_thread_gscope_count; int _dl_thread_gscope_count;
#endif #endif
struct dl_scope_free_list *_dl_scope_free_list; struct dl_scope_free_list *_dl_scope_free_list;

View File

@ -0,0 +1,2 @@
/* By default, the dynamic linker does not use an out-of-line
__thread_gscope_wait function. */

View File

@ -48,6 +48,7 @@
#include <array_length.h> #include <array_length.h>
#include <libc-early-init.h> #include <libc-early-init.h>
#include <dl-main.h> #include <dl-main.h>
#include <list.h>
#include <assert.h> #include <assert.h>
@ -799,6 +800,9 @@ cannot allocate TLS data structures for initial thread\n");
const char *lossage = TLS_INIT_TP (tcbp); const char *lossage = TLS_INIT_TP (tcbp);
if (__glibc_unlikely (lossage != NULL)) if (__glibc_unlikely (lossage != NULL))
_dl_fatal_printf ("cannot set up thread-local storage: %s\n", lossage); _dl_fatal_printf ("cannot set up thread-local storage: %s\n", lossage);
#if THREAD_GSCOPE_IN_TCB
list_add (&THREAD_SELF->list, &GL (dl_stack_user));
#endif
tls_init_tp_called = true; tls_init_tp_called = true;
return tcbp; return tcbp;
@ -1139,6 +1143,11 @@ dl_main (const ElfW(Phdr) *phdr,
GL(dl_rtld_unlock_recursive) = rtld_lock_default_unlock_recursive; GL(dl_rtld_unlock_recursive) = rtld_lock_default_unlock_recursive;
#endif #endif
#if THREAD_GSCOPE_IN_TCB
INIT_LIST_HEAD (&GL (dl_stack_used));
INIT_LIST_HEAD (&GL (dl_stack_user));
#endif
/* The explicit initialization here is cheaper than processing the reloc /* The explicit initialization here is cheaper than processing the reloc
in the _rtld_local definition's initializer. */ in the _rtld_local definition's initializer. */
GL(dl_make_stack_executable_hook) = &_dl_make_stack_executable; GL(dl_make_stack_executable_hook) = &_dl_make_stack_executable;
@ -2383,6 +2392,9 @@ dl_main (const ElfW(Phdr) *phdr,
if (__glibc_unlikely (lossage != NULL)) if (__glibc_unlikely (lossage != NULL))
_dl_fatal_printf ("cannot set up thread-local storage: %s\n", _dl_fatal_printf ("cannot set up thread-local storage: %s\n",
lossage); lossage);
#if THREAD_GSCOPE_IN_TCB
list_add (&THREAD_SELF->list, &GL (dl_stack_user));
#endif
} }
/* Make sure no new search directories have been added. */ /* Make sure no new search directories have been added. */

View File

@ -106,26 +106,14 @@
static size_t stack_cache_maxsize = 40 * 1024 * 1024; /* 40MiBi by default. */ static size_t stack_cache_maxsize = 40 * 1024 * 1024; /* 40MiBi by default. */
static size_t stack_cache_actsize; static size_t stack_cache_actsize;
/* Mutex protecting this variable. */
static int stack_cache_lock = LLL_LOCK_INITIALIZER;
/* List of queued stack frames. */ /* List of queued stack frames. */
static LIST_HEAD (stack_cache); static LIST_HEAD (stack_cache);
/* List of the stacks in use. */
static LIST_HEAD (stack_used);
/* We need to record what list operations we are going to do so that, /* We need to record what list operations we are going to do so that,
in case of an asynchronous interruption due to a fork() call, we in case of an asynchronous interruption due to a fork() call, we
can correct for the work. */ can correct for the work. */
static uintptr_t in_flight_stack; static uintptr_t in_flight_stack;
/* List of the threads with user provided stacks in use. No need to
initialize this, since it's done in __pthread_initialize_minimal. */
list_t __stack_user __attribute__ ((nocommon));
hidden_data_def (__stack_user)
/* Check whether the stack is still used or not. */ /* Check whether the stack is still used or not. */
#define FREE_P(descr) ((descr)->tid <= 0) #define FREE_P(descr) ((descr)->tid <= 0)
@ -173,7 +161,7 @@ get_cached_stack (size_t *sizep, void **memp)
struct pthread *result = NULL; struct pthread *result = NULL;
list_t *entry; list_t *entry;
lll_lock (stack_cache_lock, LLL_PRIVATE); lll_lock (GL (dl_stack_cache_lock), LLL_PRIVATE);
/* Search the cache for a matching entry. We search for the /* Search the cache for a matching entry. We search for the
smallest stack which has at least the required size. Note that smallest stack which has at least the required size. Note that
@ -206,7 +194,7 @@ get_cached_stack (size_t *sizep, void **memp)
|| __builtin_expect (result->stackblock_size > 4 * size, 0)) || __builtin_expect (result->stackblock_size > 4 * size, 0))
{ {
/* Release the lock. */ /* Release the lock. */
lll_unlock (stack_cache_lock, LLL_PRIVATE); lll_unlock (GL (dl_stack_cache_lock), LLL_PRIVATE);
return NULL; return NULL;
} }
@ -218,13 +206,13 @@ get_cached_stack (size_t *sizep, void **memp)
stack_list_del (&result->list); stack_list_del (&result->list);
/* And add to the list of stacks in use. */ /* And add to the list of stacks in use. */
stack_list_add (&result->list, &stack_used); stack_list_add (&result->list, &GL (dl_stack_used));
/* And decrease the cache size. */ /* And decrease the cache size. */
stack_cache_actsize -= result->stackblock_size; stack_cache_actsize -= result->stackblock_size;
/* Release the lock early. */ /* Release the lock early. */
lll_unlock (stack_cache_lock, LLL_PRIVATE); lll_unlock (GL (dl_stack_cache_lock), LLL_PRIVATE);
/* Report size and location of the stack to the caller. */ /* Report size and location of the stack to the caller. */
*sizep = result->stackblock_size; *sizep = result->stackblock_size;
@ -510,12 +498,12 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
/* Prepare to modify global data. */ /* Prepare to modify global data. */
lll_lock (stack_cache_lock, LLL_PRIVATE); lll_lock (GL (dl_stack_cache_lock), LLL_PRIVATE);
/* And add to the list of stacks in use. */ /* And add to the list of stacks in use. */
list_add (&pd->list, &__stack_user); list_add (&pd->list, &GL (dl_stack_user));
lll_unlock (stack_cache_lock, LLL_PRIVATE); lll_unlock (GL (dl_stack_cache_lock), LLL_PRIVATE);
} }
else else
{ {
@ -644,12 +632,12 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
/* Prepare to modify global data. */ /* Prepare to modify global data. */
lll_lock (stack_cache_lock, LLL_PRIVATE); lll_lock (GL (dl_stack_cache_lock), LLL_PRIVATE);
/* And add to the list of stacks in use. */ /* And add to the list of stacks in use. */
stack_list_add (&pd->list, &stack_used); stack_list_add (&pd->list, &GL (dl_stack_used));
lll_unlock (stack_cache_lock, LLL_PRIVATE); lll_unlock (GL (dl_stack_cache_lock), LLL_PRIVATE);
/* There might have been a race. Another thread might have /* There might have been a race. Another thread might have
@ -690,12 +678,12 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
if (__mprotect (guard, guardsize, PROT_NONE) != 0) if (__mprotect (guard, guardsize, PROT_NONE) != 0)
{ {
mprot_error: mprot_error:
lll_lock (stack_cache_lock, LLL_PRIVATE); lll_lock (GL (dl_stack_cache_lock), LLL_PRIVATE);
/* Remove the thread from the list. */ /* Remove the thread from the list. */
stack_list_del (&pd->list); stack_list_del (&pd->list);
lll_unlock (stack_cache_lock, LLL_PRIVATE); lll_unlock (GL (dl_stack_cache_lock), LLL_PRIVATE);
/* Get rid of the TLS block we allocated. */ /* Get rid of the TLS block we allocated. */
_dl_deallocate_tls (TLS_TPADJ (pd), false); _dl_deallocate_tls (TLS_TPADJ (pd), false);
@ -799,7 +787,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
void void
__deallocate_stack (struct pthread *pd) __deallocate_stack (struct pthread *pd)
{ {
lll_lock (stack_cache_lock, LLL_PRIVATE); lll_lock (GL (dl_stack_cache_lock), LLL_PRIVATE);
/* Remove the thread from the list of threads with user defined /* Remove the thread from the list of threads with user defined
stacks. */ stacks. */
@ -815,7 +803,7 @@ __deallocate_stack (struct pthread *pd)
/* Free the memory associated with the ELF TLS. */ /* Free the memory associated with the ELF TLS. */
_dl_deallocate_tls (TLS_TPADJ (pd), false); _dl_deallocate_tls (TLS_TPADJ (pd), false);
lll_unlock (stack_cache_lock, LLL_PRIVATE); lll_unlock (GL (dl_stack_cache_lock), LLL_PRIVATE);
} }
@ -831,10 +819,10 @@ __make_stacks_executable (void **stack_endp)
const size_t pagemask = ~(__getpagesize () - 1); const size_t pagemask = ~(__getpagesize () - 1);
#endif #endif
lll_lock (stack_cache_lock, LLL_PRIVATE); lll_lock (GL (dl_stack_cache_lock), LLL_PRIVATE);
list_t *runp; list_t *runp;
list_for_each (runp, &stack_used) list_for_each (runp, &GL (dl_stack_used))
{ {
err = change_stack_perm (list_entry (runp, struct pthread, list) err = change_stack_perm (list_entry (runp, struct pthread, list)
#ifdef NEED_SEPARATE_REGISTER_STACK #ifdef NEED_SEPARATE_REGISTER_STACK
@ -860,7 +848,7 @@ __make_stacks_executable (void **stack_endp)
break; break;
} }
lll_unlock (stack_cache_lock, LLL_PRIVATE); lll_unlock (GL (dl_stack_cache_lock), LLL_PRIVATE);
return err; return err;
} }
@ -891,8 +879,8 @@ __reclaim_stacks (void)
pointers at the head of the list are inconsistent. */ pointers at the head of the list are inconsistent. */
list_t *l = NULL; list_t *l = NULL;
if (stack_used.next->prev != &stack_used) if (GL (dl_stack_used).next->prev != &GL (dl_stack_used))
l = &stack_used; l = &GL (dl_stack_used);
else if (stack_cache.next->prev != &stack_cache) else if (stack_cache.next->prev != &stack_cache)
l = &stack_cache; l = &stack_cache;
@ -914,7 +902,7 @@ __reclaim_stacks (void)
/* Mark all stacks except the still running one as free. */ /* Mark all stacks except the still running one as free. */
list_t *runp; list_t *runp;
list_for_each (runp, &stack_used) list_for_each (runp, &GL (dl_stack_used))
{ {
struct pthread *curp = list_entry (runp, struct pthread, list); struct pthread *curp = list_entry (runp, struct pthread, list);
if (curp != self) if (curp != self)
@ -948,7 +936,7 @@ __reclaim_stacks (void)
} }
/* Add the stack of all running threads to the cache. */ /* Add the stack of all running threads to the cache. */
list_splice (&stack_used, &stack_cache); list_splice (&GL (dl_stack_used), &stack_cache);
/* Remove the entry for the current thread to from the cache list /* Remove the entry for the current thread to from the cache list
and add it to the list of running threads. Which of the two and add it to the list of running threads. Which of the two
@ -956,13 +944,13 @@ __reclaim_stacks (void)
stack_list_del (&self->list); stack_list_del (&self->list);
/* Re-initialize the lists for all the threads. */ /* Re-initialize the lists for all the threads. */
INIT_LIST_HEAD (&stack_used); INIT_LIST_HEAD (&GL (dl_stack_used));
INIT_LIST_HEAD (&__stack_user); INIT_LIST_HEAD (&GL (dl_stack_user));
if (__glibc_unlikely (THREAD_GETMEM (self, user_stack))) if (__glibc_unlikely (THREAD_GETMEM (self, user_stack)))
list_add (&self->list, &__stack_user); list_add (&self->list, &GL (dl_stack_user));
else else
list_add (&self->list, &stack_used); list_add (&self->list, &GL (dl_stack_used));
/* There is one thread running. */ /* There is one thread running. */
__nptl_nthreads = 1; __nptl_nthreads = 1;
@ -970,7 +958,7 @@ __reclaim_stacks (void)
in_flight_stack = 0; in_flight_stack = 0;
/* Initialize locks. */ /* Initialize locks. */
stack_cache_lock = LLL_LOCK_INITIALIZER; GL (dl_stack_cache_lock) = LLL_LOCK_INITIALIZER;
__default_pthread_attr_lock = LLL_LOCK_INITIALIZER; __default_pthread_attr_lock = LLL_LOCK_INITIALIZER;
} }
@ -1083,7 +1071,7 @@ __nptl_setxid (struct xid_command *cmdp)
{ {
int signalled; int signalled;
int result; int result;
lll_lock (stack_cache_lock, LLL_PRIVATE); lll_lock (GL (dl_stack_cache_lock), LLL_PRIVATE);
__xidcmd = cmdp; __xidcmd = cmdp;
cmdp->cntr = 0; cmdp->cntr = 0;
@ -1093,7 +1081,7 @@ __nptl_setxid (struct xid_command *cmdp)
/* Iterate over the list with system-allocated threads first. */ /* Iterate over the list with system-allocated threads first. */
list_t *runp; list_t *runp;
list_for_each (runp, &stack_used) list_for_each (runp, &GL (dl_stack_used))
{ {
struct pthread *t = list_entry (runp, struct pthread, list); struct pthread *t = list_entry (runp, struct pthread, list);
if (t == self) if (t == self)
@ -1103,7 +1091,7 @@ __nptl_setxid (struct xid_command *cmdp)
} }
/* Now the list with threads using user-allocated stacks. */ /* Now the list with threads using user-allocated stacks. */
list_for_each (runp, &__stack_user) list_for_each (runp, &GL (dl_stack_user))
{ {
struct pthread *t = list_entry (runp, struct pthread, list); struct pthread *t = list_entry (runp, struct pthread, list);
if (t == self) if (t == self)
@ -1119,7 +1107,7 @@ __nptl_setxid (struct xid_command *cmdp)
{ {
signalled = 0; signalled = 0;
list_for_each (runp, &stack_used) list_for_each (runp, &GL (dl_stack_used))
{ {
struct pthread *t = list_entry (runp, struct pthread, list); struct pthread *t = list_entry (runp, struct pthread, list);
if (t == self) if (t == self)
@ -1128,7 +1116,7 @@ __nptl_setxid (struct xid_command *cmdp)
signalled += setxid_signal_thread (cmdp, t); signalled += setxid_signal_thread (cmdp, t);
} }
list_for_each (runp, &__stack_user) list_for_each (runp, &GL (dl_stack_user))
{ {
struct pthread *t = list_entry (runp, struct pthread, list); struct pthread *t = list_entry (runp, struct pthread, list);
if (t == self) if (t == self)
@ -1149,7 +1137,7 @@ __nptl_setxid (struct xid_command *cmdp)
/* Clean up flags, so that no thread blocks during exit waiting /* Clean up flags, so that no thread blocks during exit waiting
for a signal which will never come. */ for a signal which will never come. */
list_for_each (runp, &stack_used) list_for_each (runp, &GL (dl_stack_used))
{ {
struct pthread *t = list_entry (runp, struct pthread, list); struct pthread *t = list_entry (runp, struct pthread, list);
if (t == self) if (t == self)
@ -1158,7 +1146,7 @@ __nptl_setxid (struct xid_command *cmdp)
setxid_unmark_thread (cmdp, t); setxid_unmark_thread (cmdp, t);
} }
list_for_each (runp, &__stack_user) list_for_each (runp, &GL (dl_stack_user))
{ {
struct pthread *t = list_entry (runp, struct pthread, list); struct pthread *t = list_entry (runp, struct pthread, list);
if (t == self) if (t == self)
@ -1180,7 +1168,7 @@ __nptl_setxid (struct xid_command *cmdp)
} }
__nptl_setxid_error (cmdp, error); __nptl_setxid_error (cmdp, error);
lll_unlock (stack_cache_lock, LLL_PRIVATE); lll_unlock (GL (dl_stack_cache_lock), LLL_PRIVATE);
return result; return result;
} }
@ -1204,75 +1192,16 @@ void
attribute_hidden attribute_hidden
__pthread_init_static_tls (struct link_map *map) __pthread_init_static_tls (struct link_map *map)
{ {
lll_lock (stack_cache_lock, LLL_PRIVATE); lll_lock (GL (dl_stack_cache_lock), LLL_PRIVATE);
/* Iterate over the list with system-allocated threads first. */ /* Iterate over the list with system-allocated threads first. */
list_t *runp; list_t *runp;
list_for_each (runp, &stack_used) list_for_each (runp, &GL (dl_stack_used))
init_one_static_tls (list_entry (runp, struct pthread, list), map); init_one_static_tls (list_entry (runp, struct pthread, list), map);
/* Now the list with threads using user-allocated stacks. */ /* Now the list with threads using user-allocated stacks. */
list_for_each (runp, &__stack_user) list_for_each (runp, &GL (dl_stack_user))
init_one_static_tls (list_entry (runp, struct pthread, list), map); init_one_static_tls (list_entry (runp, struct pthread, list), map);
lll_unlock (stack_cache_lock, LLL_PRIVATE); lll_unlock (GL (dl_stack_cache_lock), LLL_PRIVATE);
}
void
attribute_hidden
__wait_lookup_done (void)
{
lll_lock (stack_cache_lock, LLL_PRIVATE);
struct pthread *self = THREAD_SELF;
/* Iterate over the list with system-allocated threads first. */
list_t *runp;
list_for_each (runp, &stack_used)
{
struct pthread *t = list_entry (runp, struct pthread, list);
if (t == self || t->header.gscope_flag == THREAD_GSCOPE_FLAG_UNUSED)
continue;
int *const gscope_flagp = &t->header.gscope_flag;
/* We have to wait until this thread is done with the global
scope. First tell the thread that we are waiting and
possibly have to be woken. */
if (atomic_compare_and_exchange_bool_acq (gscope_flagp,
THREAD_GSCOPE_FLAG_WAIT,
THREAD_GSCOPE_FLAG_USED))
continue;
do
futex_wait_simple ((unsigned int *) gscope_flagp,
THREAD_GSCOPE_FLAG_WAIT, FUTEX_PRIVATE);
while (*gscope_flagp == THREAD_GSCOPE_FLAG_WAIT);
}
/* Now the list with threads using user-allocated stacks. */
list_for_each (runp, &__stack_user)
{
struct pthread *t = list_entry (runp, struct pthread, list);
if (t == self || t->header.gscope_flag == THREAD_GSCOPE_FLAG_UNUSED)
continue;
int *const gscope_flagp = &t->header.gscope_flag;
/* We have to wait until this thread is done with the global
scope. First tell the thread that we are waiting and
possibly have to be woken. */
if (atomic_compare_and_exchange_bool_acq (gscope_flagp,
THREAD_GSCOPE_FLAG_WAIT,
THREAD_GSCOPE_FLAG_USED))
continue;
do
futex_wait_simple ((unsigned int *) gscope_flagp,
THREAD_GSCOPE_FLAG_WAIT, FUTEX_PRIVATE);
while (*gscope_flagp == THREAD_GSCOPE_FLAG_WAIT);
}
lll_unlock (stack_cache_lock, LLL_PRIVATE);
} }

View File

@ -162,7 +162,8 @@ struct pthread
void *__padding[24]; void *__padding[24];
}; };
/* This descriptor's link on the `stack_used' or `__stack_user' list. */ /* This descriptor's link on the GL (dl_stack_used) or
GL (dl_stack_user) list. */
list_t list; list_t list;
/* Thread ID - which is also a 'is this thread descriptor (and /* Thread ID - which is also a 'is this thread descriptor (and

View File

@ -251,12 +251,9 @@ __pthread_initialize_minimal_internal (void)
purposes this is good enough. */ purposes this is good enough. */
THREAD_SETMEM (pd, stackblock_size, (size_t) __libc_stack_end); THREAD_SETMEM (pd, stackblock_size, (size_t) __libc_stack_end);
/* Initialize the list of all running threads with the main thread. */ /* Before initializing GL (dl_stack_user), the debugger could not
INIT_LIST_HEAD (&__stack_user); find us and had to set __nptl_initial_report_events. Propagate
list_add (&pd->list, &__stack_user); its setting. */
/* Before initializing __stack_user, the debugger could not find us and
had to set __nptl_initial_report_events. Propagate its setting. */
THREAD_SETMEM (pd, report_events, __nptl_initial_report_events); THREAD_SETMEM (pd, report_events, __nptl_initial_report_events);
struct sigaction sa; struct sigaction sa;
@ -336,8 +333,6 @@ __pthread_initialize_minimal_internal (void)
GL(dl_init_static_tls) = &__pthread_init_static_tls; GL(dl_init_static_tls) = &__pthread_init_static_tls;
GL(dl_wait_lookup_done) = &__wait_lookup_done;
/* Register the fork generation counter with the libc. */ /* Register the fork generation counter with the libc. */
#ifndef TLS_MULTIPLE_THREADS_IN_TCB #ifndef TLS_MULTIPLE_THREADS_IN_TCB
__libc_multiple_threads_ptr = __libc_multiple_threads_ptr =

View File

@ -208,10 +208,6 @@ extern void __default_pthread_attr_freeres (void) attribute_hidden;
extern size_t __static_tls_size attribute_hidden; extern size_t __static_tls_size attribute_hidden;
extern size_t __static_tls_align_m1 attribute_hidden; extern size_t __static_tls_align_m1 attribute_hidden;
/* Thread descriptor handling. */
extern list_t __stack_user;
hidden_proto (__stack_user)
/* Attribute handling. */ /* Attribute handling. */
extern struct pthread_attr *__attr_list attribute_hidden; extern struct pthread_attr *__attr_list attribute_hidden;
extern int __attr_list_lock attribute_hidden; extern int __attr_list_lock attribute_hidden;

View File

@ -213,9 +213,9 @@ __find_in_stack_list (struct pthread *pd)
list_t *entry; list_t *entry;
struct pthread *result = NULL; struct pthread *result = NULL;
lll_lock (stack_cache_lock, LLL_PRIVATE); lll_lock (GL (dl_stack_cache_lock), LLL_PRIVATE);
list_for_each (entry, &stack_used) list_for_each (entry, &GL (dl_stack_used))
{ {
struct pthread *curp; struct pthread *curp;
@ -228,7 +228,7 @@ __find_in_stack_list (struct pthread *pd)
} }
if (result == NULL) if (result == NULL)
list_for_each (entry, &__stack_user) list_for_each (entry, &GL (dl_stack_user))
{ {
struct pthread *curp; struct pthread *curp;
@ -240,7 +240,7 @@ __find_in_stack_list (struct pthread *pd)
} }
} }
lll_unlock (stack_cache_lock, LLL_PRIVATE); lll_unlock (GL (dl_stack_cache_lock), LLL_PRIVATE);
return result; return result;
} }

View File

@ -69,8 +69,6 @@ DB_STRUCT (td_eventbuf_t)
DB_STRUCT_FIELD (td_eventbuf_t, eventnum) DB_STRUCT_FIELD (td_eventbuf_t, eventnum)
DB_STRUCT_FIELD (td_eventbuf_t, eventdata) DB_STRUCT_FIELD (td_eventbuf_t, eventdata)
DB_SYMBOL (stack_used)
DB_SYMBOL (__stack_user)
DB_SYMBOL (nptl_version) DB_SYMBOL (nptl_version)
DB_FUNCTION (__nptl_create_event) DB_FUNCTION (__nptl_create_event)
DB_FUNCTION (__nptl_death_event) DB_FUNCTION (__nptl_death_event)
@ -106,6 +104,8 @@ DB_STRUCT (rtld_global)
DB_RTLD_VARIABLE (_rtld_global) DB_RTLD_VARIABLE (_rtld_global)
#endif #endif
DB_RTLD_GLOBAL_FIELD (dl_tls_dtv_slotinfo_list) DB_RTLD_GLOBAL_FIELD (dl_tls_dtv_slotinfo_list)
DB_RTLD_GLOBAL_FIELD (dl_stack_user)
DB_RTLD_GLOBAL_FIELD (dl_stack_used)
DB_STRUCT (dtv_slotinfo_list) DB_STRUCT (dtv_slotinfo_list)
DB_STRUCT_FIELD (dtv_slotinfo_list, len) DB_STRUCT_FIELD (dtv_slotinfo_list, len)

View File

@ -29,3 +29,17 @@ td_init (void)
LOG ("td_init"); LOG ("td_init");
return TD_OK; return TD_OK;
} }
bool
__td_ta_rtld_global (td_thragent_t *ta)
{
if (ta->ta_addr__rtld_global == 0
&& td_mod_lookup (ta->ph, LD_SO, SYM__rtld_global,
&ta->ta_addr__rtld_global) != PS_OK)
{
ta->ta_addr__rtld_global = (void*)-1;
return false;
}
else
return ta->ta_addr__rtld_global != (void*)-1;
}

View File

@ -187,7 +187,7 @@ td_ta_map_lwp2thr (const td_thragent_t *ta_arg,
fake a special descriptor for the initial thread. */ fake a special descriptor for the initial thread. */
psaddr_t list; psaddr_t list;
td_err_e err = DB_GET_SYMBOL (list, ta, __stack_user); td_err_e err = __td_ta_stack_user (ta, &list);
if (err != TD_OK) if (err != TD_OK)
return err; return err;

View File

@ -133,14 +133,14 @@ td_ta_thr_iter (const td_thragent_t *ta_arg, td_thr_iter_f *callback,
have to iterate over both lists separately. We start with the have to iterate over both lists separately. We start with the
list of threads with user-defined stacks. */ list of threads with user-defined stacks. */
err = DB_GET_SYMBOL (list, ta, __stack_user); err = __td_ta_stack_user (ta, &list);
if (err == TD_OK) if (err == TD_OK)
err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri, err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri,
list, true); list, true);
/* And the threads with stacks allocated by the implementation. */ /* And the threads with stacks allocated by the implementation. */
if (err == TD_OK) if (err == TD_OK)
err = DB_GET_SYMBOL (list, ta, stack_used); err = __td_ta_stack_used (ta, &list);
if (err == TD_OK) if (err == TD_OK)
err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri, err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri,
list, false); list, false);

View File

@ -28,12 +28,7 @@ dtv_slotinfo_list (td_thragent_t *ta,
td_err_e err; td_err_e err;
psaddr_t head; psaddr_t head;
if (ta->ta_addr__rtld_global == 0 if (__td_ta_rtld_global (ta))
&& td_mod_lookup (ta->ph, LD_SO, SYM__rtld_global,
&ta->ta_addr__rtld_global) != PS_OK)
ta->ta_addr__rtld_global = (void*)-1;
if (ta->ta_addr__rtld_global != (void*)-1)
{ {
err = DB_GET_FIELD (head, ta, ta->ta_addr__rtld_global, err = DB_GET_FIELD (head, ta, ta->ta_addr__rtld_global,
rtld_global, _dl_tls_dtv_slotinfo_list, 0); rtld_global, _dl_tls_dtv_slotinfo_list, 0);

View File

@ -20,6 +20,41 @@
#include "thread_dbP.h" #include "thread_dbP.h"
#include <stdbool.h> #include <stdbool.h>
td_err_e
__td_ta_stack_user (td_thragent_t *ta, psaddr_t *plist)
{
if (__td_ta_rtld_global (ta))
return DB_GET_FIELD_ADDRESS (*plist, ta, ta->ta_addr__rtld_global,
rtld_global, _dl_stack_user, 0);
else
{
if (ta->ta_addr__dl_stack_user == 0
&& td_mod_lookup (ta->ph, NULL, SYM__dl_stack_user,
&ta->ta_addr__dl_stack_user) != PS_OK)
return TD_ERR;
*plist = ta->ta_addr__dl_stack_user;
return TD_OK;
}
}
td_err_e
__td_ta_stack_used (td_thragent_t *ta, psaddr_t *plist)
{
if (__td_ta_rtld_global (ta))
return DB_GET_FIELD_ADDRESS (*plist, ta, ta->ta_addr__rtld_global,
rtld_global, _dl_stack_used, 0);
else
{
if (ta->ta_addr__dl_stack_used == 0
&& td_mod_lookup (ta->ph, NULL, SYM__dl_stack_used,
&ta->ta_addr__dl_stack_used) != PS_OK)
return TD_ERR;
*plist = ta->ta_addr__dl_stack_used;
return TD_OK;
}
}
static td_err_e static td_err_e
check_thread_list (const td_thrhandle_t *th, psaddr_t head, bool *uninit) check_thread_list (const td_thrhandle_t *th, psaddr_t head, bool *uninit)
{ {
@ -62,7 +97,7 @@ td_thr_validate (const td_thrhandle_t *th)
/* First check the list with threads using user allocated stacks. */ /* First check the list with threads using user allocated stacks. */
bool uninit = false; bool uninit = false;
err = DB_GET_SYMBOL (list, th->th_ta_p, __stack_user); err = __td_ta_stack_user (th->th_ta_p, &list);
if (err == TD_OK) if (err == TD_OK)
err = check_thread_list (th, list, &uninit); err = check_thread_list (th, list, &uninit);
@ -70,7 +105,7 @@ td_thr_validate (const td_thrhandle_t *th)
using implementation allocated stacks. */ using implementation allocated stacks. */
if (err == TD_NOTHR) if (err == TD_NOTHR)
{ {
err = DB_GET_SYMBOL (list, th->th_ta_p, stack_used); err = __td_ta_stack_used (th->th_ta_p, &list);
if (err == TD_OK) if (err == TD_OK)
err = check_thread_list (th, list, &uninit); err = check_thread_list (th, list, &uninit);

View File

@ -269,4 +269,17 @@ extern td_err_e _td_check_sizeof (td_thragent_t *ta, uint32_t *sizep,
extern td_err_e __td_ta_lookup_th_unique (const td_thragent_t *ta, extern td_err_e __td_ta_lookup_th_unique (const td_thragent_t *ta,
lwpid_t lwpid, td_thrhandle_t *th); lwpid_t lwpid, td_thrhandle_t *th);
/* Try to initialize TA->ta_addr__rtld_global. Return true on
success, false on failure (which may be cached). */
bool __td_ta_rtld_global (td_thragent_t *ta) attribute_hidden;
/* Obtain the address of the list_t fields _dl_stack_user and
_dl_stack_used in _rtld_global, or fall back to the global
variables of the same name (to support statically linked
programs). */
td_err_e __td_ta_stack_user (td_thragent_t *ta, psaddr_t *plist)
attribute_hidden;
td_err_e __td_ta_stack_used (td_thragent_t *ta, psaddr_t *plist)
attribute_hidden;
#endif /* thread_dbP.h */ #endif /* thread_dbP.h */

View File

@ -129,8 +129,6 @@ typedef struct
atomic_write_barrier (); \ atomic_write_barrier (); \
} \ } \
while (0) while (0)
# define THREAD_GSCOPE_WAIT() \
GL(dl_wait_lookup_done) ()
# endif /* __ASSEMBLER__ */ # endif /* __ASSEMBLER__ */

View File

@ -123,8 +123,6 @@ typedef struct
atomic_write_barrier (); \ atomic_write_barrier (); \
} \ } \
while (0) while (0)
#define THREAD_GSCOPE_WAIT() \
GL(dl_wait_lookup_done) ()
#else /* __ASSEMBLER__ */ #else /* __ASSEMBLER__ */
# include <tcb-offsets.h> # include <tcb-offsets.h>

View File

@ -131,8 +131,6 @@ typedef struct
atomic_write_barrier (); \ atomic_write_barrier (); \
} \ } \
while (0) while (0)
#define THREAD_GSCOPE_WAIT() \
GL(dl_wait_lookup_done) ()
#endif /* !__ASSEMBLER__ */ #endif /* !__ASSEMBLER__ */

View File

@ -120,8 +120,6 @@ typedef struct
atomic_write_barrier (); \ atomic_write_barrier (); \
} \ } \
while (0) while (0)
#define THREAD_GSCOPE_WAIT() \
GL(dl_wait_lookup_done) ()
#endif /* __ASSEMBLER__ */ #endif /* __ASSEMBLER__ */

View File

@ -147,8 +147,6 @@ typedef struct
atomic_write_barrier (); \ atomic_write_barrier (); \
} \ } \
while (0) while (0)
# define THREAD_GSCOPE_WAIT() \
GL(dl_wait_lookup_done) ()
#endif /* __ASSEMBLER__ */ #endif /* __ASSEMBLER__ */

View File

@ -38,6 +38,7 @@
#include <libc-lock.h> #include <libc-lock.h>
#include <hp-timing.h> #include <hp-timing.h>
#include <tls.h> #include <tls.h>
#include <list_t.h>
__BEGIN_DECLS __BEGIN_DECLS
@ -461,15 +462,22 @@ struct rtld_global
EXTERN void (*_dl_init_static_tls) (struct link_map *); EXTERN void (*_dl_init_static_tls) (struct link_map *);
EXTERN void (*_dl_wait_lookup_done) (void);
/* Scopes to free after next THREAD_GSCOPE_WAIT (). */ /* Scopes to free after next THREAD_GSCOPE_WAIT (). */
EXTERN struct dl_scope_free_list EXTERN struct dl_scope_free_list
{ {
size_t count; size_t count;
void *list[50]; void *list[50];
} *_dl_scope_free_list; } *_dl_scope_free_list;
#if !THREAD_GSCOPE_IN_TCB #if THREAD_GSCOPE_IN_TCB
/* List of active thread stacks, with memory managed by glibc. */
EXTERN list_t _dl_stack_used;
/* List of thread stacks that were allocated by the application. */
EXTERN list_t _dl_stack_user;
/* Mutex protecting the stack lists. */
EXTERN int _dl_stack_cache_lock;
#else
EXTERN int _dl_thread_gscope_count; EXTERN int _dl_thread_gscope_count;
#endif #endif
#ifdef SHARED #ifdef SHARED
@ -1252,6 +1260,11 @@ link_map_audit_state (struct link_map *l, size_t index)
} }
#endif /* SHARED */ #endif /* SHARED */
#if THREAD_GSCOPE_IN_TCB
void __thread_gscope_wait (void) attribute_hidden;
# define THREAD_GSCOPE_WAIT() __thread_gscope_wait ()
#endif
__END_DECLS __END_DECLS
#endif /* ldsodefs.h */ #endif /* ldsodefs.h */

View File

@ -154,8 +154,6 @@ static inline void __set_cr27(struct pthread *cr27)
atomic_write_barrier (); \ atomic_write_barrier (); \
} \ } \
while (0) while (0)
#define THREAD_GSCOPE_WAIT() \
GL(dl_wait_lookup_done) ()
#endif /* !__ASSEMBLER__ */ #endif /* !__ASSEMBLER__ */

View File

@ -387,8 +387,6 @@ tls_fill_user_desc (union user_desc_init *desc,
while (0) while (0)
#define THREAD_GSCOPE_SET_FLAG() \ #define THREAD_GSCOPE_SET_FLAG() \
THREAD_SETMEM (THREAD_SELF, header.gscope_flag, THREAD_GSCOPE_FLAG_USED) THREAD_SETMEM (THREAD_SELF, header.gscope_flag, THREAD_GSCOPE_FLAG_USED)
#define THREAD_GSCOPE_WAIT() \
GL(dl_wait_lookup_done) ()
#endif /* __ASSEMBLER__ */ #endif /* __ASSEMBLER__ */

View File

@ -175,8 +175,6 @@ register struct pthread *__thread_self __asm__("r13");
atomic_write_barrier (); \ atomic_write_barrier (); \
} \ } \
while (0) while (0)
#define THREAD_GSCOPE_WAIT() \
GL(dl_wait_lookup_done) ()
#endif /* __ASSEMBLER__ */ #endif /* __ASSEMBLER__ */

View File

@ -153,8 +153,6 @@ extern void * __m68k_read_tp (void);
atomic_write_barrier (); \ atomic_write_barrier (); \
} \ } \
while (0) while (0)
#define THREAD_GSCOPE_WAIT() \
GL(dl_wait_lookup_done) ()
#endif /* __ASSEMBLER__ */ #endif /* __ASSEMBLER__ */

View File

@ -136,8 +136,6 @@ typedef struct
atomic_write_barrier (); \ atomic_write_barrier (); \
} \ } \
while (0) while (0)
# define THREAD_GSCOPE_WAIT() \
GL (dl_wait_lookup_done) ()
#endif /* __ASSEMBLER__ */ #endif /* __ASSEMBLER__ */

View File

@ -178,8 +178,6 @@ typedef struct
atomic_write_barrier (); \ atomic_write_barrier (); \
} \ } \
while (0) while (0)
#define THREAD_GSCOPE_WAIT() \
GL(dl_wait_lookup_done) ()
#endif /* __ASSEMBLER__ */ #endif /* __ASSEMBLER__ */

View File

@ -157,8 +157,6 @@ register struct pthread *__thread_self __asm__("r23");
atomic_write_barrier (); \ atomic_write_barrier (); \
} \ } \
while (0) while (0)
#define THREAD_GSCOPE_WAIT() \
GL(dl_wait_lookup_done) ()
#endif /* __ASSEMBLER__ */ #endif /* __ASSEMBLER__ */

View File

@ -0,0 +1,80 @@
/* Out-of-line notification function for the GSCOPE locking mechanism.
Copyright (C) 2007-2020 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
<https://www.gnu.org/licenses/>. */
#include <nptl/descr.h>
#include <futex-internal.h>
#include <ldsodefs.h>
#include <list.h>
#include <lowlevellock.h>
void
__thread_gscope_wait (void)
{
lll_lock (GL (dl_stack_cache_lock), LLL_PRIVATE);
struct pthread *self = THREAD_SELF;
/* Iterate over the list with system-allocated threads first. */
list_t *runp;
list_for_each (runp, &GL (dl_stack_used))
{
struct pthread *t = list_entry (runp, struct pthread, list);
if (t == self || t->header.gscope_flag == THREAD_GSCOPE_FLAG_UNUSED)
continue;
int *const gscope_flagp = &t->header.gscope_flag;
/* We have to wait until this thread is done with the global
scope. First tell the thread that we are waiting and
possibly have to be woken. */
if (atomic_compare_and_exchange_bool_acq (gscope_flagp,
THREAD_GSCOPE_FLAG_WAIT,
THREAD_GSCOPE_FLAG_USED))
continue;
do
futex_wait_simple ((unsigned int *) gscope_flagp,
THREAD_GSCOPE_FLAG_WAIT, FUTEX_PRIVATE);
while (*gscope_flagp == THREAD_GSCOPE_FLAG_WAIT);
}
/* Now the list with threads using user-allocated stacks. */
list_for_each (runp, &GL (dl_stack_user))
{
struct pthread *t = list_entry (runp, struct pthread, list);
if (t == self || t->header.gscope_flag == THREAD_GSCOPE_FLAG_UNUSED)
continue;
int *const gscope_flagp = &t->header.gscope_flag;
/* We have to wait until this thread is done with the global
scope. First tell the thread that we are waiting and
possibly have to be woken. */
if (atomic_compare_and_exchange_bool_acq (gscope_flagp,
THREAD_GSCOPE_FLAG_WAIT,
THREAD_GSCOPE_FLAG_USED))
continue;
do
futex_wait_simple ((unsigned int *) gscope_flagp,
THREAD_GSCOPE_FLAG_WAIT, FUTEX_PRIVATE);
while (*gscope_flagp == THREAD_GSCOPE_FLAG_WAIT);
}
lll_unlock (GL (dl_stack_cache_lock), LLL_PRIVATE);
}

View File

@ -245,8 +245,6 @@ register void *__thread_register __asm__ ("r13");
atomic_write_barrier (); \ atomic_write_barrier (); \
} \ } \
while (0) while (0)
#define THREAD_GSCOPE_WAIT() \
GL(dl_wait_lookup_done) ()
#endif /* __ASSEMBLER__ */ #endif /* __ASSEMBLER__ */

View File

@ -139,8 +139,6 @@ typedef struct
atomic_write_barrier (); \ atomic_write_barrier (); \
} \ } \
while (0) while (0)
# define THREAD_GSCOPE_WAIT() \
GL(dl_wait_lookup_done) ()
#endif /* __ASSEMBLER__ */ #endif /* __ASSEMBLER__ */

View File

@ -185,8 +185,6 @@ typedef struct
atomic_write_barrier (); \ atomic_write_barrier (); \
} \ } \
while (0) while (0)
#define THREAD_GSCOPE_WAIT() \
GL(dl_wait_lookup_done) ()
#endif /* __ASSEMBLER__ */ #endif /* __ASSEMBLER__ */

View File

@ -161,8 +161,6 @@ typedef struct
atomic_write_barrier (); \ atomic_write_barrier (); \
} \ } \
while (0) while (0)
#define THREAD_GSCOPE_WAIT() \
GL(dl_wait_lookup_done) ()
#endif /* __ASSEMBLER__ */ #endif /* __ASSEMBLER__ */

View File

@ -158,8 +158,6 @@ register struct pthread *__thread_self __asm__("%g7");
atomic_write_barrier (); \ atomic_write_barrier (); \
} \ } \
while (0) while (0)
#define THREAD_GSCOPE_WAIT() \
GL(dl_wait_lookup_done) ()
#endif /* !ASSEMBLER */ #endif /* !ASSEMBLER */

View File

@ -332,8 +332,6 @@ _Static_assert (offsetof (tcbhead_t, __glibc_unused2) == 0x80,
while (0) while (0)
# define THREAD_GSCOPE_SET_FLAG() \ # define THREAD_GSCOPE_SET_FLAG() \
THREAD_SETMEM (THREAD_SELF, header.gscope_flag, THREAD_GSCOPE_FLAG_USED) THREAD_SETMEM (THREAD_SELF, header.gscope_flag, THREAD_GSCOPE_FLAG_USED)
# define THREAD_GSCOPE_WAIT() \
GL(dl_wait_lookup_done) ()
#endif /* __ASSEMBLER__ */ #endif /* __ASSEMBLER__ */