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