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 | |
34 | static int do_test (void); |
35 | #include <support/xthread.h> |
36 | #include <support/test-driver.c> |
37 | |
38 | void *handles[COUNT]; |
39 | set_value_func set_value_funcs[COUNT]; |
40 | get_value_func get_value_funcs[COUNT]; |
41 | |
42 | static void |
43 | init_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 | |
87 | static pthread_barrier_t barrier; |
88 | |
89 | /* Running thread which forces real TLS initialization. */ |
90 | static void * |
91 | blocked_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 | |
101 | static int |
102 | do_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 | |