blob: 8a9398c96b20ab0951d3dd48028cf874cfcdda51 [file]
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Test handling of overly aligned thread local data.
///
//===----------------------------------------------------------------------===//
#include "hdr/stdint_proxy.h"
#include "src/pthread/pthread_create.h"
#include "src/pthread/pthread_join.h"
#include "test/IntegrationTest/test.h"
#include <pthread.h>
constexpr size_t ALIGN1 = 64;
constexpr size_t ALIGN2 = 128;
constexpr size_t ALIGN3 = 256;
alignas(ALIGN1) static thread_local int aligned_var1 = 123;
alignas(ALIGN2) static thread_local int aligned_var2 = 456;
alignas(ALIGN3) static thread_local int aligned_bss_var;
struct ThreadTlsPointers {
void *ptr1 = nullptr;
void *ptr2 = nullptr;
void *ptr3 = nullptr;
};
static void *thread_func(void *arg) {
auto *ptrs = static_cast<ThreadTlsPointers *>(arg);
ASSERT_EQ(reinterpret_cast<uintptr_t>(&aligned_var1) % ALIGN1,
static_cast<uintptr_t>(0));
ASSERT_EQ(reinterpret_cast<uintptr_t>(&aligned_var2) % ALIGN2,
static_cast<uintptr_t>(0));
ASSERT_EQ(reinterpret_cast<uintptr_t>(&aligned_bss_var) % ALIGN3,
static_cast<uintptr_t>(0));
ASSERT_EQ(aligned_var1, 123);
ASSERT_EQ(aligned_var2, 456);
ASSERT_EQ(aligned_bss_var, 0);
ptrs->ptr1 = &aligned_var1;
ptrs->ptr2 = &aligned_var2;
ptrs->ptr3 = &aligned_bss_var;
aligned_var1 = 789;
aligned_var2 = 101112;
aligned_bss_var = 131415;
ASSERT_EQ(aligned_var1, 789);
ASSERT_EQ(aligned_var2, 101112);
ASSERT_EQ(aligned_bss_var, 131415);
return nullptr;
}
TEST_MAIN() {
ASSERT_EQ(reinterpret_cast<uintptr_t>(&aligned_var1) % ALIGN1,
static_cast<uintptr_t>(0));
ASSERT_EQ(reinterpret_cast<uintptr_t>(&aligned_var2) % ALIGN2,
static_cast<uintptr_t>(0));
ASSERT_EQ(reinterpret_cast<uintptr_t>(&aligned_bss_var) % ALIGN3,
static_cast<uintptr_t>(0));
ASSERT_EQ(aligned_var1, 123);
ASSERT_EQ(aligned_var2, 456);
ASSERT_EQ(aligned_bss_var, 0);
pthread_t th1;
pthread_t th2;
ThreadTlsPointers th1_ptrs;
ThreadTlsPointers th2_ptrs;
void *retval = nullptr;
ASSERT_EQ(
LIBC_NAMESPACE::pthread_create(&th1, nullptr, thread_func, &th1_ptrs), 0);
ASSERT_EQ(
LIBC_NAMESPACE::pthread_create(&th2, nullptr, thread_func, &th2_ptrs), 0);
ASSERT_EQ(LIBC_NAMESPACE::pthread_join(th1, &retval), 0);
ASSERT_EQ(retval, nullptr);
ASSERT_EQ(LIBC_NAMESPACE::pthread_join(th2, &retval), 0);
ASSERT_EQ(retval, nullptr);
// Child thread pointers must not match main thread.
ASSERT_NE(th1_ptrs.ptr1, static_cast<void *>(&aligned_var1));
ASSERT_NE(th1_ptrs.ptr2, static_cast<void *>(&aligned_var2));
ASSERT_NE(th1_ptrs.ptr3, static_cast<void *>(&aligned_bss_var));
ASSERT_NE(th2_ptrs.ptr1, static_cast<void *>(&aligned_var1));
ASSERT_NE(th2_ptrs.ptr2, static_cast<void *>(&aligned_var2));
ASSERT_NE(th2_ptrs.ptr3, static_cast<void *>(&aligned_bss_var));
// Child thread pointers must not match each other.
ASSERT_NE(th1_ptrs.ptr1, th2_ptrs.ptr1);
ASSERT_NE(th1_ptrs.ptr2, th2_ptrs.ptr2);
ASSERT_NE(th1_ptrs.ptr3, th2_ptrs.ptr3);
// Child thread modifications must not affect main thread.
ASSERT_EQ(aligned_var1, 123);
ASSERT_EQ(aligned_var2, 456);
ASSERT_EQ(aligned_bss_var, 0);
return 0;
}