diff options
-rw-r--r-- | ChangeLog | 21 | ||||
-rw-r--r-- | elf/dl-open.c | 10 | ||||
-rw-r--r-- | elf/dl-support.c | 4 | ||||
-rw-r--r-- | elf/rtld.c | 4 | ||||
-rw-r--r-- | elf/tls-macros.h | 1 | ||||
-rw-r--r-- | include/link.h | 4 | ||||
-rw-r--r-- | linuxthreads/ChangeLog | 6 | ||||
-rw-r--r-- | linuxthreads/pthread.c | 42 | ||||
-rw-r--r-- | nptl/ChangeLog | 16 | ||||
-rw-r--r-- | nptl/Makefile | 8 | ||||
-rw-r--r-- | nptl/allocatestack.c | 38 | ||||
-rw-r--r-- | nptl/init.c | 2 | ||||
-rw-r--r-- | nptl/pthreadP.h | 2 | ||||
-rw-r--r-- | nptl/tst-tls4.c | 191 | ||||
-rw-r--r-- | nptl/tst-tls4moda.c | 56 | ||||
-rw-r--r-- | nptl/tst-tls4modb.c | 65 | ||||
-rw-r--r-- | sysdeps/generic/ldsodefs.h | 8 |
17 files changed, 472 insertions, 6 deletions
@@ -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. diff --git a/elf/dl-open.c b/elf/dl-open.c index aadd8f5..fcda376 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -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; diff --git a/elf/dl-support.c b/elf/dl-support.c index 52447f4..8c58b2b 100644 --- a/elf/dl-support.c +++ b/elf/dl-support.c @@ -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. */ @@ -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); diff --git a/elf/tls-macros.h b/elf/tls-macros.h index bb243d8..7c25424 100644 --- a/elf/tls-macros.h +++ b/elf/tls-macros.h @@ -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") diff --git a/include/link.h b/include/link.h index cd66222..5d10bd6 100644 --- a/include/link.h +++ b/include/link.h @@ -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; diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog index b151dc3..288d352 100644 --- a/linuxthreads/ChangeLog +++ b/linuxthreads/ChangeLog @@ -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 diff --git a/linuxthreads/pthread.c b/linuxthreads/pthread.c index 6211124..f708113 100644 --- a/linuxthreads/pthread.c +++ b/linuxthreads/pthread.c @@ -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) diff --git a/nptl/ChangeLog b/nptl/ChangeLog index 45037eb..d79e798 100644 --- a/nptl/ChangeLog +++ b/nptl/ChangeLog @@ -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 diff --git a/nptl/Makefile b/nptl/Makefile index 6beacdc..cfb82e9 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -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)) diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c index e042cf4..729f3b8 100644 --- a/nptl/allocatestack.c +++ b/nptl/allocatestack.c @@ -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); +} diff --git a/nptl/init.c b/nptl/init.c index 9c76773..dae24f1 100644 --- a/nptl/init.c +++ b/nptl/init.c @@ -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 = diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h index a8cefab..b07c6da 100644 --- a/nptl/pthreadP.h +++ b/nptl/pthreadP.h @@ -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, diff --git a/nptl/tst-tls4.c b/nptl/tst-tls4.c new file mode 100644 index 0000000..52775de --- /dev/null +++ b/nptl/tst-tls4.c @@ -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" diff --git a/nptl/tst-tls4moda.c b/nptl/tst-tls4moda.c new file mode 100644 index 0000000..ff7ee56 --- /dev/null +++ b/nptl/tst-tls4moda.c @@ -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 diff --git a/nptl/tst-tls4modb.c b/nptl/tst-tls4modb.c new file mode 100644 index 0000000..99f3b54 --- /dev/null +++ b/nptl/tst-tls4modb.c @@ -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 diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index 565edb3..b647ea4 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -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 */ |