]> git.ipfire.org Git - thirdparty/glibc.git/blob - nptl/tst-thread_local1.cc
Prefer https to http for gnu.org and fsf.org URLs
[thirdparty/glibc.git] / nptl / tst-thread_local1.cc
1 /* Test basic thread_local support.
2 Copyright (C) 2015-2019 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 #include <errno.h>
20 #include <pthread.h>
21 #include <stdio.h>
22 #include <string.h>
23
24 #include <functional>
25 #include <string>
26 #include <thread>
27
28 struct counter
29 {
30 int constructed {};
31 int destructed {};
32
33 void reset ();
34 };
35
36 void
37 counter::reset ()
38 {
39 constructed = 0;
40 destructed = 0;
41 }
42
43 static std::string
44 to_string (const counter &c)
45 {
46 char buf[128];
47 snprintf (buf, sizeof (buf), "%d/%d",
48 c.constructed, c.destructed);
49 return buf;
50 }
51
52 template <counter *Counter>
53 struct counting
54 {
55 counting () __attribute__ ((noinline, noclone));
56 ~counting () __attribute__ ((noinline, noclone));
57 void operation () __attribute__ ((noinline, noclone));
58 };
59
60 template<counter *Counter>
61 __attribute__ ((noinline, noclone))
62 counting<Counter>::counting ()
63 {
64 ++Counter->constructed;
65 }
66
67 template<counter *Counter>
68 __attribute__ ((noinline, noclone))
69 counting<Counter>::~counting ()
70 {
71 ++Counter->destructed;
72 }
73
74 template<counter *Counter>
75 void __attribute__ ((noinline, noclone))
76 counting<Counter>::operation ()
77 {
78 // Optimization barrier.
79 asm ("");
80 }
81
82 static counter counter_static;
83 static counter counter_anonymous_namespace;
84 static counter counter_extern;
85 static counter counter_function_local;
86 static bool errors (false);
87
88 static std::string
89 all_counters ()
90 {
91 return to_string (counter_static)
92 + ' ' + to_string (counter_anonymous_namespace)
93 + ' ' + to_string (counter_extern)
94 + ' ' + to_string (counter_function_local);
95 }
96
97 static void
98 check_counters (const char *name, const char *expected)
99 {
100 std::string actual{all_counters ()};
101 if (actual != expected)
102 {
103 printf ("error: %s: (%s) != (%s)\n",
104 name, actual.c_str (), expected);
105 errors = true;
106 }
107 }
108
109 static void
110 reset_all ()
111 {
112 counter_static.reset ();
113 counter_anonymous_namespace.reset ();
114 counter_extern.reset ();
115 counter_function_local.reset ();
116 }
117
118 static thread_local counting<&counter_static> counting_static;
119 namespace {
120 thread_local counting<&counter_anonymous_namespace>
121 counting_anonymous_namespace;
122 }
123 extern thread_local counting<&counter_extern> counting_extern;
124 thread_local counting<&counter_extern> counting_extern;
125
126 static void *
127 thread_without_access (void *)
128 {
129 return nullptr;
130 }
131
132 static void *
133 thread_with_access (void *)
134 {
135 thread_local counting<&counter_function_local> counting_function_local;
136 counting_function_local.operation ();
137 check_counters ("early in thread_with_access", "0/0 0/0 0/0 1/0");
138 counting_static.operation ();
139 counting_anonymous_namespace.operation ();
140 counting_extern.operation ();
141 check_counters ("in thread_with_access", "1/0 1/0 1/0 1/0");
142 return nullptr;
143 }
144
145 static int
146 do_test (void)
147 {
148 std::function<void (void *(void *))> do_pthread =
149 [](void *(func) (void *))
150 {
151 pthread_t thr;
152 int ret = pthread_create (&thr, nullptr, func, nullptr);
153 if (ret != 0)
154 {
155 errno = ret;
156 printf ("error: pthread_create: %m\n");
157 errors = true;
158 return;
159 }
160 ret = pthread_join (thr, nullptr);
161 if (ret != 0)
162 {
163 errno = ret;
164 printf ("error: pthread_join: %m\n");
165 errors = true;
166 return;
167 }
168 };
169 std::function<void (void *(void *))> do_std_thread =
170 [](void *(func) (void *))
171 {
172 std::thread thr{[func] {func (nullptr);}};
173 thr.join ();
174 };
175
176 std::array<std::pair<const char *, std::function<void (void *(void *))>>, 2>
177 do_thread_X
178 {{
179 {"pthread_create", do_pthread},
180 {"std::thread", do_std_thread},
181 }};
182
183 for (auto do_thread : do_thread_X)
184 {
185 printf ("info: testing %s\n", do_thread.first);
186 check_counters ("initial", "0/0 0/0 0/0 0/0");
187 do_thread.second (thread_without_access);
188 check_counters ("after thread_without_access", "0/0 0/0 0/0 0/0");
189 reset_all ();
190 do_thread.second (thread_with_access);
191 check_counters ("after thread_with_access", "1/1 1/1 1/1 1/1");
192 reset_all ();
193 }
194
195 return errors;
196 }
197
198 #define TEST_FUNCTION do_test ()
199 #include "../test-skeleton.c"