1/* Test with many dynamic TLS variables.
2 Copyright (C) 2016-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19/* This test intends to exercise dynamic TLS variable allocation. It
20 achieves this by combining dlopen (to avoid static TLS allocation
21 after static TLS resizing), many DSOs with a large variable (to
22 exceed the static TLS reserve), and an already-running thread (to
23 force full dynamic TLS initialization). */
24
25#include "tst-tls-manydynamic.h"
26
27#include <errno.h>
28#include <dlfcn.h>
29#include <pthread.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33
34static int do_test (void);
35#include <support/xthread.h>
36#include <support/test-driver.c>
37
38void *handles[COUNT];
39set_value_func set_value_funcs[COUNT];
40get_value_func get_value_funcs[COUNT];
41
42static void
43init_functions (void)
44{
45 for (int i = 0; i < COUNT; ++i)
46 {
47 /* Open the module. */
48 {
49 char soname[100];
50 snprintf (s: soname, maxlen: sizeof (soname), format: "tst-tls-manydynamic%02dmod.so", i);
51 handles[i] = dlopen (file: soname, RTLD_LAZY);
52 if (handles[i] == NULL)
53 {
54 printf (format: "error: dlopen failed: %s\n", dlerror ());
55 exit (status: 1);
56 }
57 }
58
59 /* Obtain the setter function. */
60 {
61 char fname[100];
62 snprintf (s: fname, maxlen: sizeof (fname), format: "set_value_%02d", i);
63 void *func = dlsym (handle: handles[i], name: fname);
64 if (func == NULL)
65 {
66 printf (format: "error: dlsym: %s\n", dlerror ());
67 exit (status: 1);
68 }
69 set_value_funcs[i] = func;
70 }
71
72 /* Obtain the getter function. */
73 {
74 char fname[100];
75 snprintf (s: fname, maxlen: sizeof (fname), format: "get_value_%02d", i);
76 void *func = dlsym (handle: handles[i], name: fname);
77 if (func == NULL)
78 {
79 printf (format: "error: dlsym: %s\n", dlerror ());
80 exit (status: 1);
81 }
82 get_value_funcs[i] = func;
83 }
84 }
85}
86
87static pthread_barrier_t barrier;
88
89/* Running thread which forces real TLS initialization. */
90static void *
91blocked_thread_func (void *closure)
92{
93 xpthread_barrier_wait (barrier: &barrier);
94
95 /* TLS test runs here in the main thread. */
96
97 xpthread_barrier_wait (barrier: &barrier);
98 return NULL;
99}
100
101static int
102do_test (void)
103{
104 {
105 int ret = pthread_barrier_init (barrier: &barrier, NULL, count: 2);
106 if (ret != 0)
107 {
108 errno = ret;
109 printf (format: "error: pthread_barrier_init: %m\n");
110 exit (status: 1);
111 }
112 }
113
114 pthread_t blocked_thread = xpthread_create (NULL, thread_func: blocked_thread_func, NULL);
115 xpthread_barrier_wait (barrier: &barrier);
116
117 init_functions ();
118
119 struct value values[COUNT];
120 /* Initialze the TLS variables. */
121 for (int i = 0; i < COUNT; ++i)
122 {
123 for (int j = 0; j < PER_VALUE_COUNT; ++j)
124 values[i].num[j] = rand ();
125 set_value_funcs[i] (&values[i]);
126 }
127
128 /* Read back their values to check that they do not overlap. */
129 for (int i = 0; i < COUNT; ++i)
130 {
131 struct value actual;
132 get_value_funcs[i] (&actual);
133
134 for (int j = 0; j < PER_VALUE_COUNT; ++j)
135 if (actual.num[j] != values[i].num[j])
136 {
137 printf (format: "error: mismatch at variable %d/%d: %d != %d\n",
138 i, j, actual.num[j], values[i].num[j]);
139 exit (status: 1);
140 }
141 }
142
143 xpthread_barrier_wait (barrier: &barrier);
144 xpthread_join (thr: blocked_thread);
145
146 /* Close the modules. */
147 for (int i = 0; i < COUNT; ++i)
148 dlclose (handle: handles[i]);
149
150 return 0;
151}
152

source code of glibc/elf/tst-tls-manydynamic.c