htl: Move thread table to ld.so

The next commit is going to introduce a new implementation of
THREAD_GSCOPE_WAIT which needs to access the list of threads.
Since it must be usable from the dynamic laoder, we have to move
the symbols for the list of threads into the loader.

Signed-off-by: Sergey Bugaev <bugaevc@gmail.com>
Message-Id: <20210915171110.226187-2-bugaevc@gmail.com>
Reviewed-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
This commit is contained in:
Sergey Bugaev 2021-09-15 20:11:08 +03:00 committed by Samuel Thibault
parent 4b6574a6f6
commit 166bb3eac3
13 changed files with 83 additions and 63 deletions

View File

@ -168,8 +168,6 @@ libpthread {
GLIBC_PRIVATE {
__pthread_initialize_minimal;
__pthread_threads;
__cthread_detach;
__cthread_fork;
__pthread_detach;

View File

@ -28,19 +28,9 @@
of the threads functions "shall fail" if "No thread could be found
corresponding to that specified by the given thread ID." */
/* Thread ID lookup table. */
struct __pthread **__pthread_threads;
/* The size of the thread ID lookup table. */
int __pthread_max_threads;
/* The total number of thread IDs currently in use, or on the list of
available thread IDs. */
int __pthread_num_threads;
/* A lock for the table, and the other variables above. */
pthread_rwlock_t __pthread_threads_lock;
/* List of thread structures corresponding to free thread IDs. */
struct __pthread *__pthread_free_threads;
pthread_mutex_t __pthread_free_threads_lock;
@ -132,25 +122,25 @@ __pthread_alloc (struct __pthread **pthread)
}
retry:
__pthread_rwlock_wrlock (&__pthread_threads_lock);
__libc_rwlock_wrlock (GL (dl_pthread_threads_lock));
if (__pthread_num_threads < __pthread_max_threads)
if (GL (dl_pthread_num_threads) < __pthread_max_threads)
{
/* We have a free slot. Use the slot number plus one as the
thread ID for the new thread. */
new->thread = 1 + __pthread_num_threads++;
__pthread_threads[new->thread - 1] = NULL;
new->thread = 1 + GL (dl_pthread_num_threads)++;
GL (dl_pthread_threads)[new->thread - 1] = NULL;
__pthread_rwlock_unlock (&__pthread_threads_lock);
__libc_rwlock_unlock (GL (dl_pthread_threads_lock));
*pthread = new;
return 0;
}
#ifdef PTHREAD_THREADS_MAX
else if (__pthread_num_threads >= PTHREAD_THREADS_MAX)
else if (GL (dl_pthread_num_threads) >= PTHREAD_THREADS_MAX)
{
/* We have reached the limit on the number of threads per process. */
__pthread_rwlock_unlock (&__pthread_threads_lock);
__libc_rwlock_unlock (GL (dl_pthread_threads_lock));
free (new);
return EAGAIN;
@ -162,7 +152,7 @@ retry:
memory allocation, since that's a potentially blocking operation. */
max_threads = __pthread_max_threads;
__pthread_rwlock_unlock (&__pthread_threads_lock);
__libc_rwlock_unlock (GL (dl_pthread_threads_lock));
/* Allocate a new lookup table that's twice as large. */
new_max_threads
@ -174,13 +164,13 @@ retry:
return ENOMEM;
}
__pthread_rwlock_wrlock (&__pthread_threads_lock);
__libc_rwlock_wrlock (GL (dl_pthread_threads_lock));
/* Check if nobody else has already enlarged the table. */
if (max_threads != __pthread_max_threads)
{
/* Yep, they did. */
__pthread_rwlock_unlock (&__pthread_threads_lock);
__libc_rwlock_unlock (GL (dl_pthread_threads_lock));
/* Free the newly allocated table and try again to allocate a slot. */
free (threads);
@ -188,22 +178,22 @@ retry:
}
/* Copy over the contents of the old table. */
memcpy (threads, __pthread_threads,
memcpy (threads, GL (dl_pthread_threads),
__pthread_max_threads * sizeof (struct __pthread *));
/* Save the location of the old table. We want to deallocate its
storage after we released the lock. */
old_threads = __pthread_threads;
old_threads = GL (dl_pthread_threads);
/* Replace the table with the new one. */
__pthread_max_threads = new_max_threads;
__pthread_threads = threads;
GL (dl_pthread_threads) = threads;
/* And allocate ourselves one of the newly created slots. */
new->thread = 1 + __pthread_num_threads++;
__pthread_threads[new->thread - 1] = NULL;
new->thread = 1 + GL (dl_pthread_num_threads)++;
GL (dl_pthread_threads)[new->thread - 1] = NULL;
__pthread_rwlock_unlock (&__pthread_threads_lock);
__libc_rwlock_unlock (GL (dl_pthread_threads_lock));
free (old_threads);
@ -217,10 +207,10 @@ __pthread_init_static_tls (struct link_map *map)
{
int i;
__pthread_rwlock_wrlock (&__pthread_threads_lock);
for (i = 0; i < __pthread_num_threads; ++i)
__libc_rwlock_wrlock (GL (dl_pthread_threads_lock));
for (i = 0; i < GL (dl_pthread_num_threads); ++i)
{
struct __pthread *t = __pthread_threads[i];
struct __pthread *t = GL (dl_pthread_threads)[i];
if (t == NULL)
continue;
@ -237,5 +227,5 @@ __pthread_init_static_tls (struct link_map *map)
memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
'\0', map->l_tls_blocksize - map->l_tls_initimage_size);
}
__pthread_rwlock_unlock (&__pthread_threads_lock);
__libc_rwlock_unlock (GL (dl_pthread_threads_lock));
}

View File

@ -207,7 +207,7 @@ __pthread_create_internal (struct __pthread **thread,
creating thread. The set of signals pending for the new thread
shall be empty." If the currnet thread is not a pthread then we
just inherit the process' sigmask. */
if (__pthread_num_threads == 1)
if (GL (dl_pthread_num_threads) == 1)
err = __sigprocmask (0, 0, &pthread->init_sigset);
else
err = __pthread_sigstate (_pthread_self (), 0, 0, &pthread->init_sigset, 0);
@ -231,9 +231,9 @@ __pthread_create_internal (struct __pthread **thread,
could use __thread_setid, however, we only lock for reading as no
other thread should be using this entry (we also assume that the
store is atomic). */
__pthread_rwlock_rdlock (&__pthread_threads_lock);
__pthread_threads[pthread->thread - 1] = pthread;
__pthread_rwlock_unlock (&__pthread_threads_lock);
__libc_rwlock_rdlock (GL (dl_pthread_threads_lock));
GL (dl_pthread_threads)[pthread->thread - 1] = pthread;
__libc_rwlock_unlock (GL (dl_pthread_threads_lock));
/* At this point it is possible to guess our pthread ID. We have to
make sure that all functions taking a pthread_t argument can

View File

@ -166,33 +166,24 @@ __pthread_dequeue (struct __pthread *thread)
/* The total number of threads currently active. */
extern unsigned int __pthread_total;
/* The total number of thread IDs currently in use, or on the list of
available thread IDs. */
extern int __pthread_num_threads;
/* Concurrency hint. */
extern int __pthread_concurrency;
/* Array of __pthread structures and its lock. Indexed by the pthread
id minus one. (Why not just use the pthread id? Because some
brain-dead users of the pthread interface incorrectly assume that 0
is an invalid pthread id.) */
extern struct __pthread **__pthread_threads;
/* The size of the thread ID lookup table. */
extern int __pthread_max_threads;
extern pthread_rwlock_t __pthread_threads_lock;
#define __pthread_getid(thread) \
({ struct __pthread *__t = NULL; \
__pthread_rwlock_rdlock (&__pthread_threads_lock); \
__libc_rwlock_rdlock (GL (dl_pthread_threads_lock)); \
if (thread <= __pthread_max_threads) \
__t = __pthread_threads[thread - 1]; \
__pthread_rwlock_unlock (&__pthread_threads_lock); \
__t = GL (dl_pthread_threads)[thread - 1]; \
__libc_rwlock_unlock (GL (dl_pthread_threads_lock)); \
__t; })
#define __pthread_setid(thread, pthread) \
__pthread_rwlock_wrlock (&__pthread_threads_lock); \
__pthread_threads[thread - 1] = pthread; \
__pthread_rwlock_unlock (&__pthread_threads_lock);
__libc_rwlock_wrlock (GL (dl_pthread_threads_lock)); \
GL (dl_pthread_threads)[thread - 1] = pthread; \
__libc_rwlock_unlock (GL (dl_pthread_threads_lock));
/* Similar to pthread_self, but returns the thread descriptor instead
of the thread ID. */

View File

@ -486,7 +486,16 @@ struct rtld_global
/* Mutex protecting the stack lists. */
EXTERN int _dl_stack_cache_lock;
#else
/* The total number of thread IDs currently in use, or on the list of
available thread IDs. */
EXTERN int _dl_pthread_num_threads;
/* Array of __pthread structures and its lock. */
EXTERN struct __pthread **_dl_pthread_threads;
__libc_rwlock_define (EXTERN, _dl_pthread_threads_lock)
#endif
#if !THREAD_GSCOPE_IN_TCB
EXTERN int _dl_thread_gscope_count;
#endif

23
sysdeps/htl/dl-support.c Normal file
View File

@ -0,0 +1,23 @@
/* Support for dynamic linking code in static libc.
Copyright (C) 2007-2021 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <elf/dl-support.c>
int _dl_pthread_num_threads;
struct __pthread **_dl_pthread_threads;
__libc_rwlock_define_initialized (, _dl_pthread_threads_lock)

View File

@ -39,12 +39,12 @@ __pthread_key_delete (pthread_key_t key)
__pthread_key_destructors[key] = PTHREAD_KEY_INVALID;
__pthread_key_invalid_count++;
__pthread_rwlock_rdlock (&__pthread_threads_lock);
for (i = 0; i < __pthread_num_threads; ++i)
__libc_rwlock_rdlock (GL (dl_pthread_threads_lock));
for (i = 0; i < GL (dl_pthread_num_threads); ++i)
{
struct __pthread *t;
t = __pthread_threads[i];
t = GL (dl_pthread_threads)[i];
if (t == NULL)
continue;
@ -54,7 +54,7 @@ __pthread_key_delete (pthread_key_t key)
if (key < t->thread_specifics_size)
t->thread_specifics[key] = 0;
}
__pthread_rwlock_unlock (&__pthread_threads_lock);
__libc_rwlock_unlock (GL (dl_pthread_threads_lock));
}
__pthread_mutex_unlock (&__pthread_key_lock);

View File

@ -31,8 +31,6 @@ extern void __pthread_init_static_tls (struct link_map *) attribute_hidden;
/* These represent the interface used by glibc itself. */
extern struct __pthread **__pthread_threads;
extern int __pthread_mutex_init (pthread_mutex_t *__mutex, const pthread_mutexattr_t *__attr);
extern int __pthread_mutex_destroy (pthread_mutex_t *__mutex);
extern int __pthread_mutex_lock (pthread_mutex_t *__mutex);

View File

@ -17,6 +17,7 @@
License along with this program. If not, see
<https://www.gnu.org/licenses/>. */
#include <ldsodefs.h>
#include <pthreadP.h>
#include <signal.h>
#include <unistd.h>
@ -24,6 +25,11 @@
#pragma weak __pthread_kill
#pragma weak __pthread_self
#pragma weak __pthread_threads
#ifndef SHARED
#pragma weak _dl_pthread_threads
#endif
int
raise (int signo)
{
@ -31,7 +37,7 @@ raise (int signo)
"the effect of the raise() function shall be equivalent to
calling: pthread_kill(pthread_self(), sig);" */
if (__pthread_kill != NULL && __pthread_threads != NULL)
if (__pthread_kill != NULL && GL (dl_pthread_threads) != NULL)
{
int err;
err = __pthread_kill (__pthread_self (), signo);

View File

@ -17,14 +17,19 @@
<https://www.gnu.org/licenses/>. */
#include "thrd_priv.h"
#include <ldsodefs.h>
#pragma weak __pthread_self
#pragma weak __pthread_threads
#ifndef SHARED
#pragma weak _dl_pthread_threads
#endif
thrd_t
thrd_current (void)
{
if (__pthread_threads)
if (GL (dl_pthread_threads))
return (thrd_t) __pthread_self ();
return (thrd_t) 0;

View File

@ -37,7 +37,7 @@ __pthread_sigstate_init (struct __pthread *thread)
struct hurd_sigstate *ss = _hurd_thread_sigstate (thread->kernel_thread);
_hurd_sigstate_set_global_rcv (ss);
}
else if (__pthread_num_threads >= 2)
else if (GL (dl_pthread_num_threads) >= 2)
do_init_global = 1;
return 0;

View File

@ -45,7 +45,7 @@ _init_routine (void *stack)
int err;
pthread_attr_t attr, *attrp = 0;
if (__pthread_threads != NULL)
if (GL (dl_pthread_threads) != NULL)
/* Already initialized */
return;

View File

@ -37,7 +37,7 @@ extern __thread struct __pthread *___pthread_self;
({ \
struct __pthread *thread; \
\
assert (__pthread_threads); \
assert (GL (dl_pthread_threads)); \
thread = ___pthread_self; \
\
assert (thread); \