| //===----------------------------------------------------------------------===// |
| // |
| // 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 |
| /// This file consists of an integration test written to the functionality |
| /// of __cxa_thread_atexit_impl() function while an exit of a pthread |
| /// |
| //===----------------------------------------------------------------------===// |
| |
| #include "src/pthread/pthread_create.h" |
| #include "src/pthread/pthread_exit.h" |
| #include "src/pthread/pthread_join.h" |
| #include "src/stdlib/__cxa_thread_atexit_impl.h" |
| #include "test/IntegrationTest/test.h" |
| |
| #include "hdr/types/pthread_t.h" |
| |
| namespace { |
| |
| int dtor_order[3]; |
| int dtor_count = 0; |
| |
| struct Obj { |
| int id; |
| Obj(int i) : id(i) {} |
| ~Obj() { dtor_order[dtor_count++] = id; } |
| }; |
| |
| thread_local Obj tl_first(1); |
| thread_local Obj tl_second(2); |
| thread_local Obj tl_third(3); |
| |
| void touch_all() { |
| // touch is in definition order so the destruction order becomes well defined. |
| (void)tl_first.id; |
| (void)tl_second.id; |
| (void)tl_third.id; |
| } |
| |
| void *return_func(void *) { |
| touch_all(); |
| return nullptr; |
| } |
| |
| void *exit_func(void *) { |
| touch_all(); |
| LIBC_NAMESPACE::pthread_exit(nullptr); |
| return nullptr; |
| } |
| |
| void run_thread(void *(*fn)(void *)) { |
| dtor_count = 0; |
| |
| pthread_t th; |
| void *retval; |
| ASSERT_EQ(LIBC_NAMESPACE::pthread_create(&th, nullptr, fn, nullptr), 0); |
| ASSERT_EQ(LIBC_NAMESPACE::pthread_join(th, &retval), 0); |
| |
| ASSERT_EQ(dtor_count, 3); |
| ASSERT_EQ(dtor_order[0], 3); |
| ASSERT_EQ(dtor_order[1], 2); |
| ASSERT_EQ(dtor_order[2], 1); |
| } |
| |
| } // namespace |
| |
| extern "C" { |
| // Integration tests are not linked to the C++ runtime, so provide a minimal |
| // __cxa_thread_atexit for the compiler-emitted calls. |
| int __cxa_thread_atexit(void (*dtor)(void *), void *obj, void *) { |
| return LIBC_NAMESPACE::__cxa_thread_atexit_impl(dtor, obj, nullptr); |
| } |
| } |
| |
| TEST_MAIN() { |
| run_thread(return_func); |
| run_thread(exit_func); |
| return 0; |
| } |