1*8d67ca89SAndroid Build Coastguard Worker /*
2*8d67ca89SAndroid Build Coastguard Worker * Copyright (C) 2015 The Android Open Source Project
3*8d67ca89SAndroid Build Coastguard Worker *
4*8d67ca89SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*8d67ca89SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*8d67ca89SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*8d67ca89SAndroid Build Coastguard Worker *
8*8d67ca89SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*8d67ca89SAndroid Build Coastguard Worker *
10*8d67ca89SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*8d67ca89SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*8d67ca89SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*8d67ca89SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*8d67ca89SAndroid Build Coastguard Worker * limitations under the License.
15*8d67ca89SAndroid Build Coastguard Worker */
16*8d67ca89SAndroid Build Coastguard Worker
17*8d67ca89SAndroid Build Coastguard Worker #include <gtest/gtest.h>
18*8d67ca89SAndroid Build Coastguard Worker #include <stdint.h>
19*8d67ca89SAndroid Build Coastguard Worker #include <string.h>
20*8d67ca89SAndroid Build Coastguard Worker
21*8d67ca89SAndroid Build Coastguard Worker __thread int local_var = 100;
22*8d67ca89SAndroid Build Coastguard Worker int shared_var = 200;
23*8d67ca89SAndroid Build Coastguard Worker
reset_vars()24*8d67ca89SAndroid Build Coastguard Worker static void reset_vars() {
25*8d67ca89SAndroid Build Coastguard Worker local_var = 1000;
26*8d67ca89SAndroid Build Coastguard Worker shared_var = 2000;
27*8d67ca89SAndroid Build Coastguard Worker // local_var should be reset by threads
28*8d67ca89SAndroid Build Coastguard Worker }
29*8d67ca89SAndroid Build Coastguard Worker
30*8d67ca89SAndroid Build Coastguard Worker typedef void* (*MyThread)(void*);
31*8d67ca89SAndroid Build Coastguard Worker
inc_shared_var(void * p)32*8d67ca89SAndroid Build Coastguard Worker static void* inc_shared_var(void* p) {
33*8d67ca89SAndroid Build Coastguard Worker int *data = reinterpret_cast<int*>(p);
34*8d67ca89SAndroid Build Coastguard Worker shared_var++;
35*8d67ca89SAndroid Build Coastguard Worker *data = shared_var;
36*8d67ca89SAndroid Build Coastguard Worker return nullptr;
37*8d67ca89SAndroid Build Coastguard Worker }
38*8d67ca89SAndroid Build Coastguard Worker
inc_local_var(void * p)39*8d67ca89SAndroid Build Coastguard Worker static void* inc_local_var(void* p) {
40*8d67ca89SAndroid Build Coastguard Worker int *data = reinterpret_cast<int*>(p);
41*8d67ca89SAndroid Build Coastguard Worker local_var++;
42*8d67ca89SAndroid Build Coastguard Worker *data = local_var;
43*8d67ca89SAndroid Build Coastguard Worker return nullptr;
44*8d67ca89SAndroid Build Coastguard Worker }
45*8d67ca89SAndroid Build Coastguard Worker
run_one_thread(MyThread foo)46*8d67ca89SAndroid Build Coastguard Worker static int run_one_thread(MyThread foo) {
47*8d67ca89SAndroid Build Coastguard Worker pthread_t t;
48*8d67ca89SAndroid Build Coastguard Worker int data;
49*8d67ca89SAndroid Build Coastguard Worker int error = pthread_create(&t, nullptr, foo, &data);
50*8d67ca89SAndroid Build Coastguard Worker if (!error)
51*8d67ca89SAndroid Build Coastguard Worker error = pthread_join(t, nullptr);
52*8d67ca89SAndroid Build Coastguard Worker return error ? error : data;
53*8d67ca89SAndroid Build Coastguard Worker }
54*8d67ca89SAndroid Build Coastguard Worker
TEST(thread_local_storage,shared)55*8d67ca89SAndroid Build Coastguard Worker TEST(thread_local_storage, shared) {
56*8d67ca89SAndroid Build Coastguard Worker reset_vars();
57*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(local_var, 1000);
58*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(shared_var, 2000);
59*8d67ca89SAndroid Build Coastguard Worker
60*8d67ca89SAndroid Build Coastguard Worker // Update shared_var, local_var remains 1000.
61*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(run_one_thread(inc_shared_var), 2001);
62*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(local_var, 1000);
63*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(shared_var, 2001);
64*8d67ca89SAndroid Build Coastguard Worker
65*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(run_one_thread(inc_shared_var), 2002);
66*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(local_var, 1000);
67*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(shared_var, 2002);
68*8d67ca89SAndroid Build Coastguard Worker
69*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(run_one_thread(inc_shared_var), 2003);
70*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(local_var, 1000);
71*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(shared_var, 2003);
72*8d67ca89SAndroid Build Coastguard Worker }
73*8d67ca89SAndroid Build Coastguard Worker
TEST(thread_local_storage,local)74*8d67ca89SAndroid Build Coastguard Worker TEST(thread_local_storage, local) {
75*8d67ca89SAndroid Build Coastguard Worker reset_vars();
76*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(local_var, 1000);
77*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(shared_var, 2000);
78*8d67ca89SAndroid Build Coastguard Worker
79*8d67ca89SAndroid Build Coastguard Worker // When a child thread updates its own TLS variable,
80*8d67ca89SAndroid Build Coastguard Worker // this thread's local_var and shared_var are not changed.
81*8d67ca89SAndroid Build Coastguard Worker // TLS local_var is initialized to 100 in a thread.
82*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(run_one_thread(inc_local_var), 101);
83*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(local_var, 1000);
84*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(shared_var, 2000);
85*8d67ca89SAndroid Build Coastguard Worker
86*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(run_one_thread(inc_local_var), 101);
87*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(local_var, 1000);
88*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(shared_var, 2000);
89*8d67ca89SAndroid Build Coastguard Worker
90*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(run_one_thread(inc_local_var), 101);
91*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(local_var, 1000);
92*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(shared_var, 2000);
93*8d67ca89SAndroid Build Coastguard Worker }
94*8d67ca89SAndroid Build Coastguard Worker
95*8d67ca89SAndroid Build Coastguard Worker // Test TLS initialization of more complicated type, array of struct.
96*8d67ca89SAndroid Build Coastguard Worker struct Point {
97*8d67ca89SAndroid Build Coastguard Worker int x, y;
98*8d67ca89SAndroid Build Coastguard Worker };
99*8d67ca89SAndroid Build Coastguard Worker
100*8d67ca89SAndroid Build Coastguard Worker typedef Point Triangle[3];
101*8d67ca89SAndroid Build Coastguard Worker
102*8d67ca89SAndroid Build Coastguard Worker __thread Triangle local_triangle = {{10,10}, {20,20}, {30,30}};
103*8d67ca89SAndroid Build Coastguard Worker Triangle shared_triangle = {{1,1}, {2,2}, {3,3}};
104*8d67ca89SAndroid Build Coastguard Worker
reset_triangle()105*8d67ca89SAndroid Build Coastguard Worker static void reset_triangle() {
106*8d67ca89SAndroid Build Coastguard Worker static const Triangle t1 = {{3,3}, {4,4}, {5,5}};
107*8d67ca89SAndroid Build Coastguard Worker static const Triangle t2 = {{2,2}, {3,3}, {4,4}};
108*8d67ca89SAndroid Build Coastguard Worker memcpy(local_triangle, t1, sizeof(local_triangle));
109*8d67ca89SAndroid Build Coastguard Worker memcpy(shared_triangle, t2, sizeof(shared_triangle));
110*8d67ca89SAndroid Build Coastguard Worker }
111*8d67ca89SAndroid Build Coastguard Worker
move_shared_triangle(void * p)112*8d67ca89SAndroid Build Coastguard Worker static void* move_shared_triangle(void* p) {
113*8d67ca89SAndroid Build Coastguard Worker int *data = reinterpret_cast<int*>(p);
114*8d67ca89SAndroid Build Coastguard Worker shared_triangle[1].y++;
115*8d67ca89SAndroid Build Coastguard Worker *data = shared_triangle[1].y;
116*8d67ca89SAndroid Build Coastguard Worker return nullptr;
117*8d67ca89SAndroid Build Coastguard Worker }
118*8d67ca89SAndroid Build Coastguard Worker
move_local_triangle(void * p)119*8d67ca89SAndroid Build Coastguard Worker static void* move_local_triangle(void* p) {
120*8d67ca89SAndroid Build Coastguard Worker int *data = reinterpret_cast<int*>(p);
121*8d67ca89SAndroid Build Coastguard Worker local_triangle[1].y++;
122*8d67ca89SAndroid Build Coastguard Worker *data = local_triangle[1].y;
123*8d67ca89SAndroid Build Coastguard Worker return nullptr;
124*8d67ca89SAndroid Build Coastguard Worker }
125*8d67ca89SAndroid Build Coastguard Worker
TEST(thread_local_storage,shared_triangle)126*8d67ca89SAndroid Build Coastguard Worker TEST(thread_local_storage, shared_triangle) {
127*8d67ca89SAndroid Build Coastguard Worker reset_triangle();
128*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(local_triangle[1].y, 4);
129*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(shared_triangle[1].y, 3);
130*8d67ca89SAndroid Build Coastguard Worker
131*8d67ca89SAndroid Build Coastguard Worker // Update shared_triangle, local_triangle remains 1000.
132*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(run_one_thread(move_shared_triangle), 4);
133*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(local_triangle[1].y, 4);
134*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(shared_triangle[1].y, 4);
135*8d67ca89SAndroid Build Coastguard Worker
136*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(run_one_thread(move_shared_triangle), 5);
137*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(local_triangle[1].y, 4);
138*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(shared_triangle[1].y, 5);
139*8d67ca89SAndroid Build Coastguard Worker
140*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(run_one_thread(move_shared_triangle), 6);
141*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(local_triangle[1].y, 4);
142*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(shared_triangle[1].y, 6);
143*8d67ca89SAndroid Build Coastguard Worker }
144*8d67ca89SAndroid Build Coastguard Worker
TEST(thread_local_storage,local_triangle)145*8d67ca89SAndroid Build Coastguard Worker TEST(thread_local_storage, local_triangle) {
146*8d67ca89SAndroid Build Coastguard Worker reset_triangle();
147*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(local_triangle[1].y, 4);
148*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(shared_triangle[1].y, 3);
149*8d67ca89SAndroid Build Coastguard Worker
150*8d67ca89SAndroid Build Coastguard Worker // Update local_triangle, parent thread's
151*8d67ca89SAndroid Build Coastguard Worker // shared_triangle and local_triangle are unchanged.
152*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(run_one_thread(move_local_triangle), 21);
153*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(local_triangle[1].y, 4);
154*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(shared_triangle[1].y, 3);
155*8d67ca89SAndroid Build Coastguard Worker
156*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(run_one_thread(move_local_triangle), 21);
157*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(local_triangle[1].y, 4);
158*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(shared_triangle[1].y, 3);
159*8d67ca89SAndroid Build Coastguard Worker
160*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(run_one_thread(move_local_triangle), 21);
161*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(local_triangle[1].y, 4);
162*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(shared_triangle[1].y, 3);
163*8d67ca89SAndroid Build Coastguard Worker }
164*8d67ca89SAndroid Build Coastguard Worker
165*8d67ca89SAndroid Build Coastguard Worker // Test emutls runtime data structures and __emutls_get_address function.
166*8d67ca89SAndroid Build Coastguard Worker typedef unsigned int gcc_word __attribute__((mode(word)));
167*8d67ca89SAndroid Build Coastguard Worker typedef unsigned int gcc_pointer __attribute__((mode(pointer)));
168*8d67ca89SAndroid Build Coastguard Worker struct gcc_emutls_object { // for libgcc
169*8d67ca89SAndroid Build Coastguard Worker gcc_word size;
170*8d67ca89SAndroid Build Coastguard Worker gcc_word align;
171*8d67ca89SAndroid Build Coastguard Worker union {
172*8d67ca89SAndroid Build Coastguard Worker gcc_pointer offset;
173*8d67ca89SAndroid Build Coastguard Worker void* ptr;
174*8d67ca89SAndroid Build Coastguard Worker } loc;
175*8d67ca89SAndroid Build Coastguard Worker void* templ;
176*8d67ca89SAndroid Build Coastguard Worker };
177*8d67ca89SAndroid Build Coastguard Worker
178*8d67ca89SAndroid Build Coastguard Worker typedef struct __emutls_control { // for clang/llvm
179*8d67ca89SAndroid Build Coastguard Worker size_t size;
180*8d67ca89SAndroid Build Coastguard Worker size_t align;
181*8d67ca89SAndroid Build Coastguard Worker union {
182*8d67ca89SAndroid Build Coastguard Worker uintptr_t index;
183*8d67ca89SAndroid Build Coastguard Worker void* address;
184*8d67ca89SAndroid Build Coastguard Worker } object;
185*8d67ca89SAndroid Build Coastguard Worker void* value;
186*8d67ca89SAndroid Build Coastguard Worker } __emutls_control;
187*8d67ca89SAndroid Build Coastguard Worker
TEST(thread_local_storage,type_size)188*8d67ca89SAndroid Build Coastguard Worker TEST(thread_local_storage, type_size) {
189*8d67ca89SAndroid Build Coastguard Worker static_assert(sizeof(size_t) == sizeof(gcc_word),
190*8d67ca89SAndroid Build Coastguard Worker "size_t != gcc_word");
191*8d67ca89SAndroid Build Coastguard Worker static_assert(sizeof(uintptr_t) == sizeof(gcc_pointer),
192*8d67ca89SAndroid Build Coastguard Worker "uintptr_t != gcc_pointer");
193*8d67ca89SAndroid Build Coastguard Worker static_assert(sizeof(uintptr_t) == sizeof(void*),
194*8d67ca89SAndroid Build Coastguard Worker "sizoeof(uintptr_t) != sizeof(void*)");
195*8d67ca89SAndroid Build Coastguard Worker static_assert(sizeof(__emutls_control) == sizeof(struct gcc_emutls_object),
196*8d67ca89SAndroid Build Coastguard Worker "sizeof(__emutls_control) != sizeof(struct gcc_emutls_object)");
197*8d67ca89SAndroid Build Coastguard Worker }
198*8d67ca89SAndroid Build Coastguard Worker
199*8d67ca89SAndroid Build Coastguard Worker extern "C" void* __emutls_get_address(__emutls_control*);
200*8d67ca89SAndroid Build Coastguard Worker
TEST(thread_local_storage,init_value)201*8d67ca89SAndroid Build Coastguard Worker TEST(thread_local_storage, init_value) {
202*8d67ca89SAndroid Build Coastguard Worker char tls_value1[] = "123456789";
203*8d67ca89SAndroid Build Coastguard Worker char tls_value2[] = "abcdefghi";
204*8d67ca89SAndroid Build Coastguard Worker constexpr size_t num_saved_values = 10;
205*8d67ca89SAndroid Build Coastguard Worker __emutls_control tls_var[num_saved_values];
206*8d67ca89SAndroid Build Coastguard Worker size_t prev_index = 0;
207*8d67ca89SAndroid Build Coastguard Worker void* saved_gap[num_saved_values];
208*8d67ca89SAndroid Build Coastguard Worker void* saved_p[num_saved_values];
209*8d67ca89SAndroid Build Coastguard Worker ASSERT_TRUE(strlen(tls_value2) <= strlen(tls_value1));
210*8d67ca89SAndroid Build Coastguard Worker __emutls_control c =
211*8d67ca89SAndroid Build Coastguard Worker {strlen(tls_value1) + 1, 1, {0}, tls_value1};
212*8d67ca89SAndroid Build Coastguard Worker for (size_t n = 0; n < num_saved_values; n++) {
213*8d67ca89SAndroid Build Coastguard Worker memcpy(&tls_var[n], &c, sizeof(c));
214*8d67ca89SAndroid Build Coastguard Worker tls_var[n].align = (1 << n);
215*8d67ca89SAndroid Build Coastguard Worker }
216*8d67ca89SAndroid Build Coastguard Worker for (size_t n = 0; n < num_saved_values; n++) {
217*8d67ca89SAndroid Build Coastguard Worker // Try to mess up malloc space so that the next malloc will not have the
218*8d67ca89SAndroid Build Coastguard Worker // required alignment, but __emutls_get_address should still return an
219*8d67ca89SAndroid Build Coastguard Worker // aligned address.
220*8d67ca89SAndroid Build Coastguard Worker saved_gap[n] = malloc(1);
221*8d67ca89SAndroid Build Coastguard Worker void* p = __emutls_get_address(&tls_var[n]);
222*8d67ca89SAndroid Build Coastguard Worker saved_p[n] = p;
223*8d67ca89SAndroid Build Coastguard Worker ASSERT_TRUE(p != nullptr);
224*8d67ca89SAndroid Build Coastguard Worker ASSERT_TRUE(tls_var[n].object.index != 0);
225*8d67ca89SAndroid Build Coastguard Worker // check if p is a new object.
226*8d67ca89SAndroid Build Coastguard Worker if (n > 0) {
227*8d67ca89SAndroid Build Coastguard Worker // In single-thread environment, object.address == p.
228*8d67ca89SAndroid Build Coastguard Worker // In multi-threads environment, object.index is increased.
229*8d67ca89SAndroid Build Coastguard Worker ASSERT_TRUE(prev_index + 1 == tls_var[n].object.index ||
230*8d67ca89SAndroid Build Coastguard Worker p == tls_var[n].object.address);
231*8d67ca89SAndroid Build Coastguard Worker ASSERT_TRUE(p != saved_p[n - 1]);
232*8d67ca89SAndroid Build Coastguard Worker }
233*8d67ca89SAndroid Build Coastguard Worker prev_index = tls_var[n].object.index;
234*8d67ca89SAndroid Build Coastguard Worker // check if p is aligned
235*8d67ca89SAndroid Build Coastguard Worker uintptr_t align = (1 << n);
236*8d67ca89SAndroid Build Coastguard Worker uintptr_t address= reinterpret_cast<uintptr_t>(p);
237*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ((address & ~(align - 1)), address);
238*8d67ca89SAndroid Build Coastguard Worker // check if *p is initialized
239*8d67ca89SAndroid Build Coastguard Worker ASSERT_STREQ(tls_value1, static_cast<char*>(p));
240*8d67ca89SAndroid Build Coastguard Worker // change value in *p
241*8d67ca89SAndroid Build Coastguard Worker memcpy(p, tls_value2, strlen(tls_value2) + 1);
242*8d67ca89SAndroid Build Coastguard Worker }
243*8d67ca89SAndroid Build Coastguard Worker for (size_t n = 0; n < num_saved_values; n++) {
244*8d67ca89SAndroid Build Coastguard Worker free(saved_gap[n]);
245*8d67ca89SAndroid Build Coastguard Worker }
246*8d67ca89SAndroid Build Coastguard Worker for (size_t n = 0; n < num_saved_values; n++) {
247*8d67ca89SAndroid Build Coastguard Worker void* p = __emutls_get_address(&tls_var[n]);
248*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(p, saved_p[n]);
249*8d67ca89SAndroid Build Coastguard Worker // check if *p has the new value
250*8d67ca89SAndroid Build Coastguard Worker ASSERT_STREQ(tls_value2, static_cast<char*>(p));
251*8d67ca89SAndroid Build Coastguard Worker }
252*8d67ca89SAndroid Build Coastguard Worker }
253