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
13static thread_local bool u1 = true;
14static thread_local uint8_t u8 = UINT8_MAX;
15static thread_local uint16_t u16 = UINT16_MAX;
16static thread_local uint32_t u32 = UINT32_MAX;
17static thread_local uint64_t u64 = UINT64_MAX;
18static thread_local uintptr_t uptr = UINTPTR_MAX;
19static thread_local int8_t i8 = INT8_MAX;
20static thread_local int16_t i16 = INT16_MAX;
21static thread_local int32_t i32 = INT32_MAX;
22static thread_local int64_t i64 = INT64_MAX;
23static thread_local intptr_t iptr = INTPTR_MAX;
24static thread_local float f32 = FLT_MAX;
25static thread_local double f64 = DBL_MAX;
26static thread_local void* ptr = &ptr;
27static 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
65static thread_local uint8_t array[1024] = { BYTES_1024 };
66static thread_local struct Ctor {
67    Ctor() : x_(UINT64_MAX) {}
68    uint64_t x_;
69} ctor;
70static thread_local uint8_t big_array[1 << 20];
71
72__attribute__((aligned(0x1000))) thread_local int aligned_var = 123;
73
74bool check_initializers() {
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
125bool test_array_spam(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
146int test_thread(void* arg) {
147    auto idx = reinterpret_cast<uintptr_t>(arg);
148
149    check_initializers();
150    test_array_spam(idx);
151    return 0;
152}
153
154bool executable_tls_test() {
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], &test_thread, 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    test_thread(nullptr);
170
171    END_TEST;
172}
173
174BEGIN_TEST_CASE(elf_tls_tests)
175RUN_TEST(executable_tls_test)
176END_TEST_CASE(elf_tls_tests)
177
178#ifndef BUILD_COMBINED_TESTS
179int main(int argc, char** argv) {
180    return unittest_run_all_tests(argc, argv) ? 0 : -1;
181}
182#endif
183