From 01b23a30b42a90b1ebd882a0d81110a1542e504a Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Fri, 2 Dec 2016 17:09:19 +0100 Subject: [PATCH] elf/tst-tls-manydynamic: New test This test adds coverage for creating many dynamic TLS variables which exhaust the static TLS allocation. --- ChangeLog | 14 ++++ elf/Makefile | 17 +++- elf/tst-tls-manydynamic.c | 150 +++++++++++++++++++++++++++++++++++ elf/tst-tls-manydynamic.h | 44 ++++++++++ elf/tst-tls-manydynamicmod.c | 36 +++++++++ 5 files changed, 259 insertions(+), 2 deletions(-) create mode 100644 elf/tst-tls-manydynamic.c create mode 100644 elf/tst-tls-manydynamic.h create mode 100644 elf/tst-tls-manydynamicmod.c diff --git a/ChangeLog b/ChangeLog index f75137bbea..95b5c7eb1a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2016-12-02 Florian Weimer + + * elf/Makefile [build-shared] (tests): Add tst-latepthread. + (one-hundred, tst-tls-many-dynamic-modules): Define. + (modules-names): Add $(tst-tls-many-dynamic-modules). + (tst-tls-manydynamic%mod.os): Build with special preprocessor + macros. + (tst-tls-manydynamic): Link against libdl, libpthread. + (tst-tls-manydynamic.out): The test needs the test modules at run + time. + * elf/tst-tls-manydynamic.c: New file. + * elf/tst-tls-manydynamic.h: Likewise. + * elf/tst-tls-manydynamicmod.c: Likewise. + 2016-12-02 Florian Weimer * sysdeps/aarch64/tlsdesc.sym (TCBHEAD_DTV, DTV_COUNTER) diff --git a/elf/Makefile b/elf/Makefile index 18b3e2a95d..ebdcbc6ff4 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -152,7 +152,7 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \ tst-initorder tst-initorder2 tst-relsort1 tst-null-argv \ tst-ptrguard1 tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \ tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \ - tst-latepthread + tst-latepthread tst-tls-manydynamic # reldep9 ifeq ($(build-hardcoded-path-in-tests),yes) tests += tst-dlopen-aout @@ -173,6 +173,10 @@ tlsmod17a-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 tlsmod18a-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 tlsmod17a-modules = $(addprefix tst-tlsmod17a, $(tlsmod17a-suffixes)) tlsmod18a-modules = $(addprefix tst-tlsmod18a, $(tlsmod17a-suffixes)) +one-hundred = $(foreach x,0 1 2 3 4 5 6 7 8 9, \ + 0$x 1$x 2$x 3$x 4$x 5$x 6$x 7$x 8$x 9$x) +tst-tls-many-dynamic-modules := \ + $(foreach n,$(one-hundred),tst-tls-manydynamic$(n)mod) extra-test-objs += $(tlsmod17a-modules:=.os) $(tlsmod18a-modules:=.os) \ tst-tlsalign-vars.o test-extras += tst-tlsmod17a tst-tlsmod18a tst-tlsalign-vars @@ -227,7 +231,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ tst-tlsalign-lib tst-nodelete-opened-lib tst-nodelete2mod \ tst-audit11mod1 tst-audit11mod2 tst-auditmod11 \ tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12 \ - tst-latepthreadmod + tst-latepthreadmod $(tst-tls-many-dynamic-modules) ifeq (yes,$(have-mtls-dialect-gnu2)) tests += tst-gnu2-tls1 modules-names += tst-gnu2-tls1mod @@ -1278,6 +1282,15 @@ $(objpfx)tst-latepthreadmod.so: $(shared-thread-library) $(objpfx)tst-latepthread: $(libdl) $(objpfx)tst-latepthread.out: $(objpfx)tst-latepthreadmod.so +# The test modules are parameterized by preprocessor macros. +$(patsubst %,$(objpfx)%.os,$(tst-tls-many-dynamic-modules)): \ + $(objpfx)tst-tls-manydynamic%mod.os : tst-tls-manydynamicmod.c + $(compile-command.c) \ + -DNAME=tls_global_$* -DSETTER=set_value_$* -DGETTER=get_value_$* +$(objpfx)tst-tls-manydynamic: $(libdl) $(shared-thread-library) +$(objpfx)tst-tls-manydynamic.out: \ + $(patsubst %,$(objpfx)%.so,$(tst-tls-many-dynamic-modules)) + tst-prelink-ENV = LD_TRACE_PRELINKING=1 $(objpfx)tst-prelink-conflict.out: $(objpfx)tst-prelink.out diff --git a/elf/tst-tls-manydynamic.c b/elf/tst-tls-manydynamic.c new file mode 100644 index 0000000000..29bf1394d8 --- /dev/null +++ b/elf/tst-tls-manydynamic.c @@ -0,0 +1,150 @@ +/* Test with many dynamic TLS variables. + Copyright (C) 2016 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 + . */ + +/* This test intends to exercise dynamic TLS variable allocation. It + achieves this by combining dlopen (to avoid static TLS allocation + after static TLS resizing), many DSOs with a large variable (to + exceed the static TLS reserve), and an already-running thread (to + force full dynamic TLS initialization). */ + +#include "tst-tls-manydynamic.h" + +#include +#include +#include +#include +#include + +static int do_test (void); +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + +void *handles[COUNT]; +set_value_func set_value_funcs[COUNT]; +get_value_func get_value_funcs[COUNT]; + +static void +init_functions (void) +{ + for (int i = 0; i < COUNT; ++i) + { + /* Open the module. */ + { + char soname[100]; + snprintf (soname, sizeof (soname), "tst-tls-manydynamic%02dmod.so", i); + handles[i] = dlopen (soname, RTLD_LAZY); + if (handles[i] == NULL) + { + printf ("error: dlopen failed: %s\n", dlerror ()); + exit (1); + } + } + + /* Obtain the setter function. */ + { + char fname[100]; + snprintf (fname, sizeof (fname), "set_value_%02d", i); + void *func = dlsym (handles[i], fname); + if (func == NULL) + { + printf ("error: dlsym: %s\n", dlerror ()); + exit (1); + } + set_value_funcs[i] = func; + } + + /* Obtain the getter function. */ + { + char fname[100]; + snprintf (fname, sizeof (fname), "get_value_%02d", i); + void *func = dlsym (handles[i], fname); + if (func == NULL) + { + printf ("error: dlsym: %s\n", dlerror ()); + exit (1); + } + get_value_funcs[i] = func; + } + } +} + +static pthread_barrier_t barrier; + +/* Running thread which forces real TLS initialization. */ +static void * +blocked_thread_func (void *closure) +{ + xpthread_barrier_wait (&barrier); + + /* TLS test runs here in the main thread. */ + + xpthread_barrier_wait (&barrier); + return NULL; +} + +static int +do_test (void) +{ + { + int ret = pthread_barrier_init (&barrier, NULL, 2); + if (ret != 0) + { + errno = ret; + printf ("error: pthread_barrier_init: %m\n"); + exit (1); + } + } + + pthread_t blocked_thread = xpthread_create (NULL, blocked_thread_func, NULL); + xpthread_barrier_wait (&barrier); + + init_functions (); + + struct value values[COUNT]; + /* Initialze the TLS variables. */ + for (int i = 0; i < COUNT; ++i) + { + for (int j = 0; j < PER_VALUE_COUNT; ++j) + values[i].num[j] = rand (); + set_value_funcs[i] (&values[i]); + } + + /* Read back their values to check that they do not overlap. */ + for (int i = 0; i < COUNT; ++i) + { + struct value actual; + get_value_funcs[i] (&actual); + + for (int j = 0; j < PER_VALUE_COUNT; ++j) + if (actual.num[j] != values[i].num[j]) + { + printf ("error: mismatch at variable %d/%d: %d != %d\n", + i, j, actual.num[j], values[i].num[j]); + exit (1); + } + } + + xpthread_barrier_wait (&barrier); + xpthread_join (blocked_thread); + + /* Close the modules. */ + for (int i = 0; i < COUNT; ++i) + dlclose (handles[i]); + + return 0; +} diff --git a/elf/tst-tls-manydynamic.h b/elf/tst-tls-manydynamic.h new file mode 100644 index 0000000000..4756ece5dd --- /dev/null +++ b/elf/tst-tls-manydynamic.h @@ -0,0 +1,44 @@ +/* Interfaces for test with many dynamic TLS variables. + Copyright (C) 2016 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 + . */ + +#ifndef TST_TLS_MANYDYNAMIC_H +#define TST_TLS_MANYDYNAMIC_H + +enum + { + /* This many TLS variables (and modules) are defined. */ + COUNT = 100, + + /* Number of elements in the TLS variable. */ + PER_VALUE_COUNT = 1, + }; + +/* The TLS variables are of this type. We use a larger type to ensure + that we can reach the static TLS limit with COUNT variables. */ +struct value +{ + int num[PER_VALUE_COUNT]; +}; + +/* Set the TLS variable defined in the module. */ +typedef void (*set_value_func) (const struct value *); + +/* Read the TLS variable defined in the module. */ +typedef void (*get_value_func) (struct value *); + +#endif /* TST_TLS_MANYDYNAMICMOD_H */ diff --git a/elf/tst-tls-manydynamicmod.c b/elf/tst-tls-manydynamicmod.c new file mode 100644 index 0000000000..578f11b857 --- /dev/null +++ b/elf/tst-tls-manydynamicmod.c @@ -0,0 +1,36 @@ +/* Module for test with many dynamic TLS variables. + Copyright (C) 2016 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 + . */ + +/* This file is parameterized by macros NAME, SETTER, GETTER, which + are set form the Makefile. */ + +#include "tst-tls-manydynamic.h" + +__thread struct value NAME; + +void +SETTER (const struct value *value) +{ + NAME = *value; +} + +void +GETTER (struct value *value) +{ + *value = NAME; +}