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