15 changes: 15 additions & 0 deletions libc/test/integration/src/pthread/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,18 @@ add_integration_test(
libc.src.pthread.pthread_self
libc.src.pthread.pthread_setname_np
)

add_integration_test(
pthread_exit_test
SUITE
libc-pthread-integration-tests
SRCS
pthread_exit_test.cpp
LOADER
libc.loader.linux.crt1
DEPENDS
libc.include.pthread
libc.src.pthread.pthread_create
libc.src.pthread.pthread_exit
libc.src.pthread.pthread_join
)
65 changes: 65 additions & 0 deletions libc/test/integration/src/pthread/pthread_exit_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//===-- Tests for pthread_exit --------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#include "src/pthread/pthread_create.h"
#include "src/pthread/pthread_exit.h"
#include "src/pthread/pthread_join.h"
#include "utils/IntegrationTest/test.h"

#include <pthread.h>

bool dtor_called = false;

class A {
int val;

public:
A(int i) { val = i; }

void set(int i) { val = i; }

~A() {
val = 0;
dtor_called = true;
}
};

thread_local A thread_local_a(123);

void *func(void *) {
// Touch the thread local variable so that it gets initialized and a callback
// for its destructor gets registered with __cxa_thread_atexit.
thread_local_a.set(321);
__llvm_libc::pthread_exit(nullptr);
return nullptr;
}

TEST_MAIN() {
pthread_t th;
void *retval;

ASSERT_EQ(__llvm_libc::pthread_create(&th, nullptr, func, nullptr), 0);
ASSERT_EQ(__llvm_libc::pthread_join(th, &retval), 0);

ASSERT_TRUE(dtor_called);
__llvm_libc::pthread_exit(nullptr);
return 0;
}

extern "C" {

using Destructor = void(void *);

int __cxa_thread_atexit_impl(Destructor *, void *, void *);

// We do not link integration tests to C++ runtime pieces like the libcxxabi.
// So, we provide our own simple __cxa_thread_atexit implementation.
int __cxa_thread_atexit(Destructor *dtor, void *obj, void *) {
return __cxa_thread_atexit_impl(dtor, obj, nullptr);
}
}
15 changes: 15 additions & 0 deletions libc/test/integration/src/threads/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,21 @@ add_integration_test(
libc.src.threads.thrd_join
)

add_integration_test(
thrd_exit_test
SUITE
libc-threads-integration-tests
SRCS
thrd_exit_test.cpp
LOADER
libc.loader.linux.crt1
DEPENDS
libc.include.threads
libc.src.threads.thrd_create
libc.src.threads.thrd_exit
libc.src.threads.thrd_join
)

add_integration_test(
call_once_test
SUITE
Expand Down
63 changes: 63 additions & 0 deletions libc/test/integration/src/threads/thrd_exit_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//===-- Tests for thrd_exit -----------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#include "src/threads/thrd_create.h"
#include "src/threads/thrd_exit.h"
#include "src/threads/thrd_join.h"
#include "utils/IntegrationTest/test.h"

#include <threads.h>

bool dtor_called = false;

class A {
int val;

public:
A(int i) { val = i; }

void set(int i) { val = i; }

~A() {
val = 0;
dtor_called = true;
}
};

thread_local A thread_local_a(123);

int func(void *) {
thread_local_a.set(321);
__llvm_libc::thrd_exit(0);
return 0;
}

TEST_MAIN() {
thrd_t th;
int retval;

ASSERT_EQ(__llvm_libc::thrd_create(&th, func, nullptr), thrd_success);
ASSERT_EQ(__llvm_libc::thrd_join(&th, &retval), thrd_success);

ASSERT_TRUE(dtor_called);
__llvm_libc::thrd_exit(0);
return 0;
}

extern "C" {

using Destructor = void(void *);

int __cxa_thread_atexit_impl(Destructor *, void *, void *);

// We do not link integration tests to C++ runtime pieces like the libcxxabi.
// So, we provide our own simple __cxa_thread_atexit implementation.
int __cxa_thread_atexit(Destructor *dtor, void *obj, void *) {
return __cxa_thread_atexit_impl(dtor, obj, nullptr);
}
}