diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2014-11-28 07:54:07 -0800 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2014-11-28 07:57:40 -0800 |
commit | d8dd00805b8f3a011735d7a407097fb1c408d867 (patch) | |
tree | cc2f23b98c40684fa76e86a6230066d876b5e61b /elf/dl-tls.c | |
parent | 167da422b30b35c9eb9fc819ce5d3b3b0d65c6f4 (diff) | |
download | glibc-d8dd00805b8f3a011735d7a407097fb1c408d867.tar glibc-d8dd00805b8f3a011735d7a407097fb1c408d867.tar.gz glibc-d8dd00805b8f3a011735d7a407097fb1c408d867.tar.bz2 glibc-d8dd00805b8f3a011735d7a407097fb1c408d867.zip |
Resize DTV if the current DTV isn't big enough
This patch changes _dl_allocate_tls_init to resize DTV if the current DTV
isn't big enough. Tested on X86-64, x32 and ia32.
[BZ #13862]
* elf/dl-tls.c: Include <atomic.h>.
(oom): Remove #ifdef SHARED/#endif.
(_dl_static_dtv, _dl_initial_dtv): Moved before ...
(_dl_resize_dtv): This. Extracted from _dl_update_slotinfo.
(_dl_allocate_tls_init): Resize DTV if the current DTV isn't
big enough.
(_dl_update_slotinfo): Call _dl_resize_dtv to resize DTV.
* nptl/Makefile (tests): Add tst-stack4.
(modules-names): Add tst-stack4mod.
($(objpfx)tst-stack4): New.
(tst-stack4mod.sos): Likewise.
($(objpfx)tst-stack4.out): Likewise.
($(tst-stack4mod.sos)): Likewise.
(clean): Likewise.
* nptl/tst-stack4.c: New file.
* nptl/tst-stack4mod.c: Likewise.
Diffstat (limited to 'elf/dl-tls.c')
-rw-r--r-- | elf/dl-tls.c | 102 |
1 files changed, 61 insertions, 41 deletions
diff --git a/elf/dl-tls.c b/elf/dl-tls.c index 5204fdaac0..76b8b368d1 100644 --- a/elf/dl-tls.c +++ b/elf/dl-tls.c @@ -23,6 +23,7 @@ #include <stdlib.h> #include <unistd.h> #include <sys/param.h> +#include <atomic.h> #include <tls.h> #include <dl-tls.h> @@ -34,14 +35,12 @@ /* Out-of-memory handler. */ -#ifdef SHARED static void __attribute__ ((__noreturn__)) oom (void) { _dl_fatal_printf ("cannot allocate memory for thread-local data: ABORT\n"); } -#endif size_t @@ -397,6 +396,53 @@ _dl_allocate_tls_storage (void) } +#ifndef SHARED +extern dtv_t _dl_static_dtv[]; +# define _dl_initial_dtv (&_dl_static_dtv[1]) +#endif + +static dtv_t * +_dl_resize_dtv (dtv_t *dtv) +{ + /* Resize the dtv. */ + dtv_t *newp; + /* Load GL(dl_tls_max_dtv_idx) atomically since it may be written to by + other threads concurrently. */ + size_t newsize + = atomic_load_acquire (&GL(dl_tls_max_dtv_idx)) + DTV_SURPLUS; + size_t oldsize = dtv[-1].counter; + + if (dtv == GL(dl_initial_dtv)) + { + /* This is the initial dtv that was either statically allocated in + __libc_setup_tls or allocated during rtld startup using the + dl-minimal.c malloc instead of the real malloc. We can't free + it, we have to abandon the old storage. */ + + newp = malloc ((2 + newsize) * sizeof (dtv_t)); + if (newp == NULL) + oom (); + memcpy (newp, &dtv[-1], (2 + oldsize) * sizeof (dtv_t)); + } + else + { + newp = realloc (&dtv[-1], + (2 + newsize) * sizeof (dtv_t)); + if (newp == NULL) + oom (); + } + + newp[0].counter = newsize; + + /* Clear the newly allocated part. */ + memset (newp + 2 + oldsize, '\0', + (newsize - oldsize) * sizeof (dtv_t)); + + /* Return the generation counter. */ + return &newp[1]; +} + + void * internal_function _dl_allocate_tls_init (void *result) @@ -410,6 +456,16 @@ _dl_allocate_tls_init (void *result) size_t total = 0; size_t maxgen = 0; + /* Check if the current dtv is big enough. */ + if (dtv[-1].counter < GL(dl_tls_max_dtv_idx)) + { + /* Resize the dtv. */ + dtv = _dl_resize_dtv (dtv); + + /* Install this new dtv in the thread data structures. */ + INSTALL_DTV (result, &dtv[-1]); + } + /* We have to prepare the dtv for all currently loaded modules using TLS. For those which are dynamically loaded we add the values indicating deferred allocation. */ @@ -492,11 +548,6 @@ _dl_allocate_tls (void *mem) rtld_hidden_def (_dl_allocate_tls) -#ifndef SHARED -extern dtv_t _dl_static_dtv[]; -# define _dl_initial_dtv (&_dl_static_dtv[1]) -#endif - void internal_function _dl_deallocate_tls (void *tcb, bool dealloc_tcb) @@ -645,41 +696,10 @@ _dl_update_slotinfo (unsigned long int req_modid) assert (total + cnt == modid); if (dtv[-1].counter < modid) { - /* Reallocate the dtv. */ - dtv_t *newp; - size_t newsize = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS; - size_t oldsize = dtv[-1].counter; - - assert (map->l_tls_modid <= newsize); - - if (dtv == GL(dl_initial_dtv)) - { - /* This is the initial dtv that was allocated - during rtld startup using the dl-minimal.c - malloc instead of the real malloc. We can't - free it, we have to abandon the old storage. */ - - newp = malloc ((2 + newsize) * sizeof (dtv_t)); - if (newp == NULL) - oom (); - memcpy (newp, &dtv[-1], (2 + oldsize) * sizeof (dtv_t)); - } - else - { - newp = realloc (&dtv[-1], - (2 + newsize) * sizeof (dtv_t)); - if (newp == NULL) - oom (); - } - - newp[0].counter = newsize; - - /* Clear the newly allocated part. */ - memset (newp + 2 + oldsize, '\0', - (newsize - oldsize) * sizeof (dtv_t)); + /* Resize the dtv. */ + dtv = _dl_resize_dtv (dtv); - /* Point dtv to the generation counter. */ - dtv = &newp[1]; + assert (modid <= dtv[-1].counter); /* Install this new dtv in the thread data structures. */ |