blob: c1ffd1c9c2a3c36780e4ef3a91654e2ce5da10d8 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <float.h>
#include <limits.h>
#include <sched.h>
#include <stdint.h>
#include <threads.h>
#include <unittest/unittest.h>
static thread_local bool u1 = true;
static thread_local uint8_t u8 = UINT8_MAX;
static thread_local uint16_t u16 = UINT16_MAX;
static thread_local uint32_t u32 = UINT32_MAX;
static thread_local uint64_t u64 = UINT64_MAX;
static thread_local uintptr_t uptr = UINTPTR_MAX;
static thread_local int8_t i8 = INT8_MAX;
static thread_local int16_t i16 = INT16_MAX;
static thread_local int32_t i32 = INT32_MAX;
static thread_local int64_t i64 = INT64_MAX;
static thread_local intptr_t iptr = INTPTR_MAX;
static thread_local float f32 = FLT_MAX;
static thread_local double f64 = DBL_MAX;
static thread_local void* ptr = &ptr;
static thread_local struct {
uint64_t bits0 : 9;
uint64_t bits1 : 9;
uint64_t bits2 : 9;
uint64_t bits3 : 9;
uint64_t bits4 : 9;
uint64_t bits5 : 9;
uint64_t bits6 : 9;
double f64;
uint64_t bits7 : 9;
uint64_t bits8 : 9;
uint64_t bits9 : 9;
uint64_t bits10 : 9;
uint64_t bits11 : 9;
uint64_t bits12 : 9;
uint64_t bits13 : 9;
} bits = {
0x1ffu,
0x1ffu,
0x1ffu,
0x1ffu,
0x1ffu,
0x1ffu,
0x1ffu,
DBL_MAX,
0x1ffu,
0x1ffu,
0x1ffu,
0x1ffu,
0x1ffu,
0x1ffu,
0x1ffu,
};
#define BYTES_4 0xffu, 0xffu, 0xffu, 0xffu,
#define BYTES_16 BYTES_4 BYTES_4 BYTES_4 BYTES_4
#define BYTES_64 BYTES_16 BYTES_16 BYTES_16 BYTES_16
#define BYTES_256 BYTES_64 BYTES_64 BYTES_64 BYTES_64
#define BYTES_1024 BYTES_256 BYTES_256 BYTES_256 BYTES_256
static thread_local uint8_t array[1024] = { BYTES_1024 };
static thread_local struct Ctor {
Ctor() : x_(UINT64_MAX) {}
uint64_t x_;
} ctor;
static thread_local uint8_t big_array[1 << 20];
__attribute__((aligned(0x1000))) thread_local int aligned_var = 123;
bool CheckInitializers() {
BEGIN_TEST;
ASSERT_EQ(u1, true, "unexpected initialized value");
ASSERT_EQ(u8, UINT8_MAX, "unexpected initialized value");
ASSERT_EQ(u16, UINT16_MAX, "unexpected initialized value");
ASSERT_EQ(u32, UINT32_MAX, "unexpected initialized value");
ASSERT_EQ(u64, UINT64_MAX, "unexpected initialized value");
ASSERT_EQ(uptr, UINTPTR_MAX, "unexpected initialized value");
ASSERT_EQ(i8, INT8_MAX, "unexpected initialized value");
ASSERT_EQ(i16, INT16_MAX, "unexpected initialized value");
ASSERT_EQ(i32, INT32_MAX, "unexpected initialized value");
ASSERT_EQ(i64, INT64_MAX, "unexpected initialized value");
ASSERT_EQ(iptr, INTPTR_MAX, "unexpected initialized value");
ASSERT_EQ(f32, FLT_MAX, "unexpected initialized value");
ASSERT_EQ(f64, DBL_MAX, "unexpected initialized value");
ASSERT_EQ(ptr, &ptr, "unexpected initialized value");
ASSERT_EQ(bits.bits0, 0x1ffu, "unexpected initialized value");
ASSERT_EQ(bits.bits1, 0x1ffu, "unexpected initialized value");
ASSERT_EQ(bits.bits2, 0x1ffu, "unexpected initialized value");
ASSERT_EQ(bits.bits3, 0x1ffu, "unexpected initialized value");
ASSERT_EQ(bits.bits4, 0x1ffu, "unexpected initialized value");
ASSERT_EQ(bits.bits5, 0x1ffu, "unexpected initialized value");
ASSERT_EQ(bits.bits6, 0x1ffu, "unexpected initialized value");
ASSERT_EQ(bits.f64, DBL_MAX, "unexpected initialized value");
ASSERT_EQ(bits.bits7, 0x1ffu, "unexpected initialized value");
ASSERT_EQ(bits.bits8, 0x1ffu, "unexpected initialized value");
ASSERT_EQ(bits.bits9, 0x1ffu, "unexpected initialized value");
ASSERT_EQ(bits.bits10, 0x1ffu, "unexpected initialized value");
ASSERT_EQ(bits.bits11, 0x1ffu, "unexpected initialized value");
ASSERT_EQ(bits.bits12, 0x1ffu, "unexpected initialized value");
ASSERT_EQ(bits.bits13, 0x1ffu, "unexpected initialized value");
for (auto& byte : array)
ASSERT_EQ(byte, UINT8_MAX, "unexpected initialized value");
ASSERT_EQ(ctor.x_, UINT64_MAX, "unexpected initialized value");
uint8_t sum = 0u;
for (auto& byte : big_array)
sum |= byte;
ASSERT_EQ(sum, 0u, "unexpected initialized value");
// TODO(ZX-1646): Make this work on ARM64.
EXPECT_EQ((uintptr_t)&aligned_var % 0x1000, 0);
EXPECT_EQ(aligned_var, 123);
END_TEST;
}
bool TestArraySpam(uintptr_t idx) {
BEGIN_TEST;
for (uintptr_t iteration = 0; iteration < 100; ++iteration) {
auto starting_value = static_cast<uint8_t>(idx + iteration);
auto value = starting_value;
for (auto& byte : array) {
byte = value;
++value;
}
sched_yield();
value = starting_value;
for (auto& byte : array) {
ASSERT_EQ(byte, value, "unexpected value read back!");
++value;
}
}
END_TEST;
}
int TestThread(void* arg) {
auto idx = reinterpret_cast<uintptr_t>(arg);
CheckInitializers();
TestArraySpam(idx);
return 0;
}
bool ExecutableTlsTest() {
BEGIN_TEST;
constexpr uintptr_t thread_count = 64u;
thrd_t threads[thread_count];
for (uintptr_t idx = 0u; idx < thread_count; ++idx) {
auto arg = reinterpret_cast<void*>(idx);
int ret = thrd_create_with_name(&threads[idx], &TestThread, arg, "elf tls test");
ASSERT_EQ(ret, thrd_success, "unable to create test thread");
}
for (uintptr_t idx = 0u; idx < thread_count; ++idx) {
int ret = thrd_join(threads[idx], nullptr);
ASSERT_EQ(ret, thrd_success, "unable to join test thread");
}
TestThread(nullptr);
END_TEST;
}
BEGIN_TEST_CASE(elf_tls_tests)
RUN_TEST(ExecutableTlsTest)
END_TEST_CASE(elf_tls_tests)