1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <float.h>
6 #include <limits.h>
7 #include <sched.h>
8 #include <stdint.h>
9 #include <threads.h>
10
11 #include <unittest/unittest.h>
12
13 static thread_local bool u1 = true;
14 static thread_local uint8_t u8 = UINT8_MAX;
15 static thread_local uint16_t u16 = UINT16_MAX;
16 static thread_local uint32_t u32 = UINT32_MAX;
17 static thread_local uint64_t u64 = UINT64_MAX;
18 static thread_local uintptr_t uptr = UINTPTR_MAX;
19 static thread_local int8_t i8 = INT8_MAX;
20 static thread_local int16_t i16 = INT16_MAX;
21 static thread_local int32_t i32 = INT32_MAX;
22 static thread_local int64_t i64 = INT64_MAX;
23 static thread_local intptr_t iptr = INTPTR_MAX;
24 static thread_local float f32 = FLT_MAX;
25 static thread_local double f64 = DBL_MAX;
26 static thread_local void* ptr = &ptr;
27 static thread_local struct {
28 uint64_t bits0 : 9;
29 uint64_t bits1 : 9;
30 uint64_t bits2 : 9;
31 uint64_t bits3 : 9;
32 uint64_t bits4 : 9;
33 uint64_t bits5 : 9;
34 uint64_t bits6 : 9;
35 double f64;
36 uint64_t bits7 : 9;
37 uint64_t bits8 : 9;
38 uint64_t bits9 : 9;
39 uint64_t bits10 : 9;
40 uint64_t bits11 : 9;
41 uint64_t bits12 : 9;
42 uint64_t bits13 : 9;
43 } bits = {
44 0x1ffu,
45 0x1ffu,
46 0x1ffu,
47 0x1ffu,
48 0x1ffu,
49 0x1ffu,
50 0x1ffu,
51 DBL_MAX,
52 0x1ffu,
53 0x1ffu,
54 0x1ffu,
55 0x1ffu,
56 0x1ffu,
57 0x1ffu,
58 0x1ffu,
59 };
60 #define BYTES_4 0xffu, 0xffu, 0xffu, 0xffu,
61 #define BYTES_16 BYTES_4 BYTES_4 BYTES_4 BYTES_4
62 #define BYTES_64 BYTES_16 BYTES_16 BYTES_16 BYTES_16
63 #define BYTES_256 BYTES_64 BYTES_64 BYTES_64 BYTES_64
64 #define BYTES_1024 BYTES_256 BYTES_256 BYTES_256 BYTES_256
65 static thread_local uint8_t array[1024] = { BYTES_1024 };
66 static thread_local struct Ctor {
CtorCtor67 Ctor() : x_(UINT64_MAX) {}
68 uint64_t x_;
69 } ctor;
70 static thread_local uint8_t big_array[1 << 20];
71
72 __attribute__((aligned(0x1000))) thread_local int aligned_var = 123;
73
CheckInitializers()74 bool CheckInitializers() {
75 BEGIN_TEST;
76
77 ASSERT_EQ(u1, true, "unexpected initialized value");
78 ASSERT_EQ(u8, UINT8_MAX, "unexpected initialized value");
79 ASSERT_EQ(u16, UINT16_MAX, "unexpected initialized value");
80 ASSERT_EQ(u32, UINT32_MAX, "unexpected initialized value");
81 ASSERT_EQ(u64, UINT64_MAX, "unexpected initialized value");
82 ASSERT_EQ(uptr, UINTPTR_MAX, "unexpected initialized value");
83 ASSERT_EQ(i8, INT8_MAX, "unexpected initialized value");
84 ASSERT_EQ(i16, INT16_MAX, "unexpected initialized value");
85 ASSERT_EQ(i32, INT32_MAX, "unexpected initialized value");
86 ASSERT_EQ(i64, INT64_MAX, "unexpected initialized value");
87 ASSERT_EQ(iptr, INTPTR_MAX, "unexpected initialized value");
88 ASSERT_EQ(f32, FLT_MAX, "unexpected initialized value");
89 ASSERT_EQ(f64, DBL_MAX, "unexpected initialized value");
90 ASSERT_EQ(ptr, &ptr, "unexpected initialized value");
91
92 ASSERT_EQ(bits.bits0, 0x1ffu, "unexpected initialized value");
93 ASSERT_EQ(bits.bits1, 0x1ffu, "unexpected initialized value");
94 ASSERT_EQ(bits.bits2, 0x1ffu, "unexpected initialized value");
95 ASSERT_EQ(bits.bits3, 0x1ffu, "unexpected initialized value");
96 ASSERT_EQ(bits.bits4, 0x1ffu, "unexpected initialized value");
97 ASSERT_EQ(bits.bits5, 0x1ffu, "unexpected initialized value");
98 ASSERT_EQ(bits.bits6, 0x1ffu, "unexpected initialized value");
99 ASSERT_EQ(bits.f64, DBL_MAX, "unexpected initialized value");
100 ASSERT_EQ(bits.bits7, 0x1ffu, "unexpected initialized value");
101 ASSERT_EQ(bits.bits8, 0x1ffu, "unexpected initialized value");
102 ASSERT_EQ(bits.bits9, 0x1ffu, "unexpected initialized value");
103 ASSERT_EQ(bits.bits10, 0x1ffu, "unexpected initialized value");
104 ASSERT_EQ(bits.bits11, 0x1ffu, "unexpected initialized value");
105 ASSERT_EQ(bits.bits12, 0x1ffu, "unexpected initialized value");
106 ASSERT_EQ(bits.bits13, 0x1ffu, "unexpected initialized value");
107
108 for (auto& byte : array)
109 ASSERT_EQ(byte, UINT8_MAX, "unexpected initialized value");
110
111 ASSERT_EQ(ctor.x_, UINT64_MAX, "unexpected initialized value");
112
113 uint8_t sum = 0u;
114 for (auto& byte : big_array)
115 sum |= byte;
116 ASSERT_EQ(sum, 0u, "unexpected initialized value");
117
118 // TODO(ZX-1646): Make this work on ARM64.
119 EXPECT_EQ((uintptr_t)&aligned_var % 0x1000, 0);
120 EXPECT_EQ(aligned_var, 123);
121
122 END_TEST;
123 }
124
TestArraySpam(uintptr_t idx)125 bool TestArraySpam(uintptr_t idx) {
126 BEGIN_TEST;
127
128 for (uintptr_t iteration = 0; iteration < 100; ++iteration) {
129 auto starting_value = static_cast<uint8_t>(idx + iteration);
130 auto value = starting_value;
131 for (auto& byte : array) {
132 byte = value;
133 ++value;
134 }
135 sched_yield();
136 value = starting_value;
137 for (auto& byte : array) {
138 ASSERT_EQ(byte, value, "unexpected value read back!");
139 ++value;
140 }
141 }
142
143 END_TEST;
144 }
145
TestThread(void * arg)146 int TestThread(void* arg) {
147 auto idx = reinterpret_cast<uintptr_t>(arg);
148
149 CheckInitializers();
150 TestArraySpam(idx);
151 return 0;
152 }
153
ExecutableTlsTest()154 bool ExecutableTlsTest() {
155 BEGIN_TEST;
156
157 constexpr uintptr_t thread_count = 64u;
158 thrd_t threads[thread_count];
159 for (uintptr_t idx = 0u; idx < thread_count; ++idx) {
160 auto arg = reinterpret_cast<void*>(idx);
161 int ret = thrd_create_with_name(&threads[idx], &TestThread, arg, "elf tls test");
162 ASSERT_EQ(ret, thrd_success, "unable to create test thread");
163 }
164 for (uintptr_t idx = 0u; idx < thread_count; ++idx) {
165 int ret = thrd_join(threads[idx], nullptr);
166 ASSERT_EQ(ret, thrd_success, "unable to join test thread");
167 }
168
169 TestThread(nullptr);
170
171 END_TEST;
172 }
173
174 BEGIN_TEST_CASE(elf_tls_tests)
RUN_TEST(ExecutableTlsTest)175 RUN_TEST(ExecutableTlsTest)
176 END_TEST_CASE(elf_tls_tests)
177
178 #ifndef BUILD_COMBINED_TESTS
179 int main(int argc, char** argv) {
180 return unittest_run_all_tests(argc, argv) ? 0 : -1;
181 }
182 #endif
183