2003-07-30  Jakub Jelinek  <jakub@redhat.com>

	* elf/dl-reloc.c (_dl_allocate_static_tls): Don't return any value,
	call dl_signal_error directly.  If already relocated, call
	GL(dl_init_static_tls) directly, otherwise queue it for later.
	(CHECK_STATIC_TLS): Undo 2003-07-24 change.
	* elf/rtld.c (dl_main): Initialize GL(dl_init_static_tls).
	* elf/dl-open.c (dl_open_worker): Call GL_dl_init_static_tls
	for all static TLS initializations delayed in _dl_allocate_static_tls.
	* elf/dl-support.c (_dl_init_static_tls): New variable.
	* include/link.h (struct link_map): Add l_need_tls_init.
	* sysdeps/generic/ldsodefs.h (_rtld_global): Add _dl_init_static_tls.
	(_dl_nothread_init_static_tls): New prototype.
	(_dl_allocate_static_tls): Adjust prototype.

	* elf/tls-macros.h (VAR_INT_DEF): Add alignment directive.

	elf_machine_rela_relative): Adjust.
	(CHECK_STATIC_TLS): _dl_allocate_static_tls can fail now.
This commit is contained in:
Ulrich Drepper 2003-07-31 07:42:20 +00:00
parent 9722e6f3e2
commit adc12574e5
17 changed files with 472 additions and 6 deletions

View file

@ -1,3 +1,20 @@
2003-07-30 Jakub Jelinek <jakub@redhat.com>
* elf/dl-reloc.c (_dl_allocate_static_tls): Don't return any value,
call dl_signal_error directly. If already relocated, call
GL(dl_init_static_tls) directly, otherwise queue it for later.
(CHECK_STATIC_TLS): Undo 2003-07-24 change.
* elf/rtld.c (dl_main): Initialize GL(dl_init_static_tls).
* elf/dl-open.c (dl_open_worker): Call GL_dl_init_static_tls
for all static TLS initializations delayed in _dl_allocate_static_tls.
* elf/dl-support.c (_dl_init_static_tls): New variable.
* include/link.h (struct link_map): Add l_need_tls_init.
* sysdeps/generic/ldsodefs.h (_rtld_global): Add _dl_init_static_tls.
(_dl_nothread_init_static_tls): New prototype.
(_dl_allocate_static_tls): Adjust prototype.
* elf/tls-macros.h (VAR_INT_DEF): Add alignment directive.
2003-07-31 Alexandre Oliva <aoliva@redhat.com>
* elf/dynamic-link.h (elf_machine_rel, elf_machine_rela,
@ -26,7 +43,7 @@
* sysdeps/s390/s390-32/dl-machine.h (elf_machine_rela,
elf_machine_rela_relative): Adjust.
* sysdeps/s390/s390-64/dl-machine.h (elf_machine_rela,
elf_machine_rela_relative):
elf_machine_rela_relative): Adjust.
* sysdeps/sh/dl-machine.h (elf_machine_rela,
elf_machine_rela_relative): Adjust.
* sysdeps/sparc/sparc32/dl-machine.h (elf_machine_rela,
@ -123,7 +140,7 @@
* elf/rtld.c (_dl_start_final, _dl_start, dl_main): Likewise.
* elf/dl-reloc.c (_dl_allocate_static_tls): Change return type to int.
Take l_tls_firstbyte_offset information into account.
(CHECK_STATIS_TLS): _dl_allocate_static_tls can fail now.
(CHECK_STATIC_TLS): _dl_allocate_static_tls can fail now.
* sysdeps/generic/ldsodefs.h: Adjust _dl_allocate_static_tls prototype.
* elf/Makefile: Add rules to build and run tst-tls14.
* elf/tst-tls14.c: New file.

View file

@ -303,6 +303,16 @@ dl_open_worker (void *a)
}
#ifdef USE_TLS
/* Do static TLS initialization now if it has been delayed because
the TLS template might not be fully relocated at _dl_allocate_static_tls
time. */
for (l = new; l; l = l->l_next)
if (l->l_need_tls_init)
{
l->l_need_tls_init = 0;
GL(dl_init_static_tls) (l);
}
/* We normally don't bump the TLS generation counter. There must be
actually a need to do this. */
any_tls = false;

View file

@ -98,6 +98,10 @@ int _dl_starting_up = 1;
hp_timing_t _dl_cpuclock_offset;
#endif
#ifdef USE_TLS
void (*_dl_init_static_tls) (struct link_map *) = &_dl_nothread_init_static_tls;
#endif
/* This is zero at program start to signal that the global scope map is
allocated by rtld. Later it keeps the size of the map. It might be
reset if in _dl_close if the last global object is removed. */

View file

@ -622,6 +622,10 @@ dl_main (const ElfW(Phdr) *phdr,
GL(dl_error_catch_tsd) = &_dl_initial_error_catch_tsd;
#endif
#ifdef USE_TLS
GL(dl_init_static_tls) = &_dl_nothread_init_static_tls;
#endif
/* Process the environment variable which control the behaviour. */
process_envvars (&mode);

View file

@ -9,6 +9,7 @@
#define VAR_INT_DEF(x) \
asm (".section .tdata\n\t" \
".globl " #x "\n" \
".balign 4\n" \
#x ":\t.long 0\n\t" \
".size " #x ",4\n\t" \
".previous")

View file

@ -186,7 +186,9 @@ struct link_map
the l_libname list. */
unsigned int l_faked:1; /* Nonzero if this is a faked descriptor
without associated file. */
unsigned int l_need_tls_init:1; /* Nonzero if GL(dl_init_static_tls)
should be called on this link map
when relocation finishes. */
/* Array with version names. */
unsigned int l_nversions;
struct r_found_version *l_versions;

View file

@ -1,3 +1,9 @@
2003-07-30 Jakub Jelinek <jakub@redhat.com>
* pthread.c (init_one_static_tls, __pthread_init_static_tls): New
functions.
(pthread_initialize): Initialize GL(dl_init_static_tls).
2003-06-19 Daniel Jacobowitz <drow@mvista.com>
* sysdeps/pthread/timer_create.c (timer_create): Call timer_delref

View file

@ -462,6 +462,44 @@ __libc_dl_error_tsd (void)
# endif
#endif
#ifdef USE_TLS
static inline void __attribute__((always_inline))
init_one_static_tls (pthread_descr descr, struct link_map *map)
{
# if TLS_TCB_AT_TP
dtv_t *dtv = GET_DTV (descr);
void *dest = (char *) descr - map->l_tls_offset;
# elif TLS_DTV_AT_TP
dtv_t *dtv = GET_DTV ((pthread_descr) ((char *) descr + TLS_PRE_TCB_SIZE));
void *dest = (char *) descr + map->l_tls_offset + TLS_PRE_TCB_SIZE;
# else
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
# endif
/* Fill in the DTV slot so that a later LD/GD access will find it. */
dtv[map->l_tls_modid].pointer = dest;
/* Initialize the memory. */
memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
'\0', map->l_tls_blocksize - map->l_tls_initimage_size);
}
static void
__pthread_init_static_tls (struct link_map *map)
{
size_t i;
for (i = 0; i < PTHREAD_THREADS_MAX; ++i)
if (__pthread_handles[i].h_descr != NULL && i != 1)
{
__pthread_lock (&__pthread_handles[i].h_lock, NULL);
if (__pthread_handles[i].h_descr != NULL)
init_one_static_tls (__pthread_handles[i].h_descr, map);
__pthread_unlock (&__pthread_handles[i].h_lock);
}
}
#endif
static void pthread_initialize(void)
{
struct sigaction sa;
@ -551,6 +589,10 @@ static void pthread_initialize(void)
*__libc_dl_error_tsd () = *(*GL(dl_error_catch_tsd)) ();
GL(dl_error_catch_tsd) = &__libc_dl_error_tsd;
#endif
#ifdef USE_TLS
GL(dl_init_static_tls) = &__pthread_init_static_tls;
#endif
}
void __pthread_initialize(void)

View file

@ -1,3 +1,19 @@
2003-07-30 Jakub Jelinek <jakub@redhat.com>
* init.c (__pthread_initialize_minimal_internal): Initialize
GL(dl_init_static_tls).
* pthreadP.h (__pthread_init_static_tls): New prototype.
* allocatestack.c (init_one_static_tls, __pthread_init_static_tls):
New functions.
* Makefile (tests): Add tst-tls4.
(modules-names): Add tst-tls4moda and tst-tls4modb.
($(objpfx)tst-tls4): Link against libdl and libpthread.
($(objpfx)tst-tls4.out): Depend on tst-tls4moda.so and
tst-tls4modb.so.
* tst-tls4.c: New file.
* tst-tls4moda.c: New file.
* tst-tls4modb.c: New file.
2003-06-19 Daniel Jacobowitz <drow@mvista.com>
* sysdeps/pthread/timer_create.c (timer_create): Call timer_delref

View file

@ -251,10 +251,11 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx4 tst-cancelx5 \
tst-oncex3 tst-oncex4
endif
ifeq ($(build-shared),yes)
tests += tst-atfork2 tst-tls3 tst-_res1
tests += tst-atfork2 tst-tls3 tst-tls4 tst-_res1
endif
modules-names = tst-atfork2mod tst-tls3mod tst-_res1mod1 tst-_res1mod2
modules-names = tst-atfork2mod tst-tls3mod tst-tls4moda tst-tls4modb \
tst-_res1mod1 tst-_res1mod2
extra-objs += $(addsuffix .os,$(strip $(modules-names)))
test-extras += $(modules-names)
test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names)))
@ -395,6 +396,9 @@ LDFLAGS-tst-tls3 = -rdynamic
$(objpfx)tst-tls3.out: $(objpfx)tst-tls3mod.so
$(objpfx)tst-tls3mod.so: $(shared-thread-library)
$(objpfx)tst-tls4: $(libdl) $(shared-thread-library)
$(objpfx)tst-tls4.out: $(objpfx)tst-tls4moda.so $(objpfx)tst-tls4modb.so
$(objpfx)tst-dlsym1: $(libdl) $(shared-thread-library)
ifeq (yes,$(build-shared))

View file

@ -710,3 +710,41 @@ __find_thread_by_id (pid_t tid)
return result;
}
#endif
static inline void __attribute__((always_inline))
init_one_static_tls (struct pthread *curp, struct link_map *map)
{
dtv_t *dtv = GET_DTV (TLS_TPADJ (curp));
# if TLS_TCB_AT_TP
void *dest = (char *) curp - map->l_tls_offset;
# elif TLS_DTV_AT_TP
void *dest = (char *) curp + map->l_tls_offset + TLS_PRE_TCB_SIZE;
# else
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
# endif
/* Fill in the DTV slot so that a later LD/GD access will find it. */
dtv[map->l_tls_modid].pointer = dest;
/* Initialize the memory. */
memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
'\0', map->l_tls_blocksize - map->l_tls_initimage_size);
}
void
attribute_hidden
__pthread_init_static_tls (struct link_map *map)
{
lll_lock (stack_cache_lock);
/* Iterate over the list with system-allocated threads first. */
list_t *runp;
list_for_each (runp, &stack_used)
init_one_static_tls (list_entry (runp, struct pthread, list), map);
/* Now the list with threads using user-allocated stacks. */
list_for_each (runp, &__stack_user)
init_one_static_tls (list_entry (runp, struct pthread, list), map);
lll_unlock (stack_cache_lock);
}

View file

@ -272,6 +272,8 @@ __pthread_initialize_minimal_internal (void)
GL(dl_error_catch_tsd) = &__libc_dl_error_tsd;
#endif
GL(dl_init_static_tls) = &__pthread_init_static_tls;
/* Register the fork generation counter with the libc. */
#ifndef TLS_MULTIPLE_THREADS_IN_TCB
__libc_multiple_threads_ptr =

View file

@ -257,6 +257,8 @@ extern int *__libc_multiple_threads_ptr attribute_hidden;
/* Find a thread given its TID. */
extern struct pthread *__find_thread_by_id (pid_t tid) attribute_hidden;
extern void __pthread_init_static_tls (struct link_map *) attribute_hidden;
/* Namespace save aliases. */
extern int __pthread_getschedparam (pthread_t thread_id, int *policy,

191
nptl/tst-tls4.c Normal file
View file

@ -0,0 +1,191 @@
/* Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
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, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <dlfcn.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <tls.h>
#if HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE
#define N 3
void (*test1) (void), (*test2) (void);
pthread_barrier_t b2, b3;
static void *
tf (void *arg)
{
int i;
for (i = 0; i <= (uintptr_t) arg; ++i)
{
int r = pthread_barrier_wait (&b3);
if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
{
puts ("tf: barrier_wait failed");
exit (1);
}
}
test1 ();
for (i = 0; i < 3; ++i)
{
int r = pthread_barrier_wait (&b3);
if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
{
puts ("tf: barrier_wait failed");
exit (1);
}
}
test2 ();
for (i = 0; i < 3 - (uintptr_t) arg; ++i)
{
int r = pthread_barrier_wait (&b3);
if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
{
puts ("tf: barrier_wait failed");
exit (1);
}
}
return NULL;
}
static void *
tf2 (void *arg)
{
int r = pthread_barrier_wait (&b2);
if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
{
puts ("tf2: barrier_wait failed");
exit (1);
}
int i;
for (i = 0; i < N; ++i)
tf (arg);
return NULL;
}
int
do_test (void)
{
pthread_t th[2];
const char *modules[N]
= { "tst-tls4moda.so", "tst-tls4moda.so", "tst-tls4modb.so" };
if (pthread_barrier_init (&b2, NULL, 2) != 0)
{
puts ("barrier_init failed");
return 1;
}
if (pthread_barrier_init (&b3, NULL, 3) != 0)
{
puts ("barrier_init failed");
return 1;
}
if (pthread_create (&th[0], NULL, tf2, (void *) (uintptr_t) 1))
{
puts ("pthread_create failed");
return 1;
}
int r = pthread_barrier_wait (&b2);
if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
{
puts ("barrier_wait failed");
return 1;
}
int i;
for (i = 0; i < N; ++i)
{
void *h = dlopen (modules[i], RTLD_LAZY);
if (h == NULL)
{
printf ("dlopen failed %s\n", dlerror ());
return 1;
}
test1 = dlsym (h, "test1");
if (test1 == NULL)
{
printf ("dlsym for test1 failed %s\n", dlerror ());
return 1;
}
test2 = dlsym (h, "test2");
if (test2 == NULL)
{
printf ("dlsym for test2 failed %s\n", dlerror ());
return 1;
}
if (pthread_create (&th[1], NULL, tf, (void *) (uintptr_t) 2))
{
puts ("pthread_create failed");
return 1;
}
tf ((void *) (uintptr_t) 0);
if (pthread_join (th[1], NULL) != 0)
{
puts ("join failed");
return 1;
}
if (dlclose (h))
{
puts ("dlclose failed");
return 1;
}
printf ("test %d with %s succeeded\n", i, modules[i]);
}
if (pthread_join (th[0], NULL) != 0)
{
puts ("join failed");
return 1;
}
return 0;
}
#define TIMEOUT 5
#define TEST_FUNCTION do_test ()
#else
#define TEST_FUNCTION 0
#endif
#include "../test-skeleton.c"

56
nptl/tst-tls4moda.c Normal file
View file

@ -0,0 +1,56 @@
/* Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
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, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <tls.h>
#if HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE
static __thread unsigned char foo [32]
__attribute__ ((tls_model ("initial-exec"), aligned (sizeof (void *))));
void
test1 (void)
{
size_t s;
for (s = 0; s < sizeof (foo); ++s)
{
if (foo [s])
abort ();
foo [s] = s;
}
}
void
test2 (void)
{
size_t s;
for (s = 0; s < sizeof (foo); ++s)
{
if (foo [s] != s)
abort ();
foo [s] = sizeof (foo) - s;
}
}
#endif

65
nptl/tst-tls4modb.c Normal file
View file

@ -0,0 +1,65 @@
/* Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
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, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <tls.h>
#if HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE
static int i;
int bar;
static __thread void *foo [32 / sizeof (void *)]
__attribute__ ((tls_model ("initial-exec"), aligned (sizeof (void *))))
= { &i, &bar };
void
test1 (void)
{
size_t s;
if (foo [0] != &i || foo [1] != &bar)
abort ();
foo [0] = NULL;
foo [1] = NULL;
for (s = 0; s < sizeof (foo) / sizeof (void *); ++s)
{
if (foo [s])
abort ();
foo [s] = &foo[s];
}
}
void
test2 (void)
{
size_t s;
for (s = 0; s < sizeof (foo) / sizeof (void *); ++s)
{
if (foo [s] != &foo [s])
abort ();
foo [s] = &foo [s ^ 1];
}
}
#endif

View file

@ -390,6 +390,8 @@ struct rtld_global
EXTERN void *_dl_initial_dtv;
/* Generation counter for the dtv. */
EXTERN size_t _dl_tls_generation;
EXTERN void (*_dl_init_static_tls) (struct link_map *);
#endif
#ifdef NEED_DL_SYSINFO
@ -797,7 +799,7 @@ rtld_hidden_proto (_dl_allocate_tls)
extern void _dl_get_tls_static_info (size_t *sizep, size_t *alignp)
internal_function;
extern int _dl_allocate_static_tls (struct link_map *map)
extern void _dl_allocate_static_tls (struct link_map *map)
internal_function attribute_hidden;
/* These are internal entry points to the two halves of _dl_allocate_tls,
@ -816,6 +818,10 @@ rtld_hidden_proto (_dl_deallocate_tls)
extern void *_dl_tls_symaddr (struct link_map *map, const ElfW(Sym) *ref)
internal_function;
#if defined USE_TLS
extern void _dl_nothread_init_static_tls (struct link_map *) attribute_hidden;
#endif
__END_DECLS
#endif /* ldsodefs.h */