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
init_functions(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 (soname, sizeof (soname), "tst-tls-manydynamic%02dmod.so", i);
51         handles[i] = dlopen (soname, RTLD_LAZY);
52         if (handles[i] == NULL)
53           {
54             printf ("error: dlopen failed: %s\n", dlerror ());
55             exit (1);
56           }
57       }
58 
59       /* Obtain the setter function.  */
60       {
61         char fname[100];
62         snprintf (fname, sizeof (fname), "set_value_%02d", i);
63         void *func = dlsym (handles[i], fname);
64         if (func == NULL)
65           {
66             printf ("error: dlsym: %s\n", dlerror ());
67             exit (1);
68           }
69         set_value_funcs[i] = func;
70       }
71 
72       /* Obtain the getter function.  */
73       {
74         char fname[100];
75         snprintf (fname, sizeof (fname), "get_value_%02d", i);
76         void *func = dlsym (handles[i], fname);
77         if (func == NULL)
78           {
79             printf ("error: dlsym: %s\n", dlerror ());
80             exit (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 *
blocked_thread_func(void * closure)91 blocked_thread_func (void *closure)
92 {
93   xpthread_barrier_wait (&barrier);
94 
95   /* TLS test runs here in the main thread.  */
96 
97   xpthread_barrier_wait (&barrier);
98   return NULL;
99 }
100 
101 static int
do_test(void)102 do_test (void)
103 {
104   {
105     int ret = pthread_barrier_init (&barrier, NULL, 2);
106     if (ret != 0)
107       {
108         errno = ret;
109         printf ("error: pthread_barrier_init: %m\n");
110         exit (1);
111       }
112   }
113 
114   pthread_t blocked_thread = xpthread_create (NULL, blocked_thread_func, NULL);
115   xpthread_barrier_wait (&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 ("error: mismatch at variable %d/%d: %d != %d\n",
138                   i, j, actual.num[j], values[i].num[j]);
139           exit (1);
140         }
141     }
142 
143   xpthread_barrier_wait (&barrier);
144   xpthread_join (blocked_thread);
145 
146   /* Close the modules.  */
147   for (int i = 0; i < COUNT; ++i)
148     dlclose (handles[i]);
149 
150   return 0;
151 }
152