diff --git a/libc/test/integration/src/pthread/CMakeLists.txt b/libc/test/integration/src/pthread/CMakeLists.txt --- a/libc/test/integration/src/pthread/CMakeLists.txt +++ b/libc/test/integration/src/pthread/CMakeLists.txt @@ -129,6 +129,13 @@ libc.include.stdio libc.src.pthread.pthread_create libc.src.pthread.pthread_join + libc.src.pthread.pthread_attr_setdetachstate + libc.src.pthread.pthread_attr_init + libc.src.pthread.pthread_attr_destroy + libc.src.stdlib.srand + libc.src.stdlib.rand + libc.src.__support.CPP.atomic + libc.src.__support.CPP.new ) add_integration_test( diff --git a/libc/test/integration/src/pthread/pthread_join_test.cpp b/libc/test/integration/src/pthread/pthread_join_test.cpp --- a/libc/test/integration/src/pthread/pthread_join_test.cpp +++ b/libc/test/integration/src/pthread/pthread_join_test.cpp @@ -1,4 +1,5 @@ -//===-- Tests for pthread_join-- ------------------------------------------===// +//===-- Tests for pthread_join +//--------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,25 +7,126 @@ // //===----------------------------------------------------------------------===// +#include "src/pthread/pthread_attr_destroy.h" +#include "src/pthread/pthread_attr_init.h" +#include "src/pthread/pthread_attr_setdetachstate.h" #include "src/pthread/pthread_create.h" #include "src/pthread/pthread_join.h" +#include "src/stdlib/rand.h" +#include "src/stdlib/srand.h" + +#include "src/__support/CPP/atomic.h" +#include "src/__support/CPP/new.h" + +#include "src/__support/threads/thread.h" #include "src/errno/libc_errno.h" #include "test/IntegrationTest/test.h" + +#include // For EXEC_PAGESIZE. #include -static void *simpleFunc(void *) { return nullptr; } -static void nullJoinTest() { - pthread_t Tid; - ASSERT_EQ(__llvm_libc::pthread_create(&Tid, nullptr, simpleFunc, nullptr), 0); +struct TestThreadArgs { + pthread_t tid; + int detached; + volatile int done; + size_t spin_cnt; + void *ret; +}; + +static __llvm_libc::AllocChecker global_ac; + +static void *func(void *arg) { + TestThreadArgs *th_arg = reinterpret_cast(arg); + volatile size_t spin_cnt = th_arg->spin_cnt; + + while (spin_cnt) { + --spin_cnt; + } + + th_arg->done = 1; + return th_arg->ret; +} + +static void *simple_func(void *) { return nullptr; } + +static TestThreadArgs *initialize_test_thread_args(size_t num_threads, + unsigned detached_percent) { + TestThreadArgs *th_args = new (global_ac) TestThreadArgs[num_threads]; + for (size_t i = 0; i < num_threads; ++i) { + unsigned rand_val = __llvm_libc::rand(); + uintptr_t rand_ret = __llvm_libc::rand(); + rand_ret *= __llvm_libc::rand(); + rand_val %= 100; + th_args[i].detached = detached_percent > rand_val; + th_args[i].done = 0; + th_args[i].spin_cnt = rand_val % (1000 * 1000); + th_args[i].ret = reinterpret_cast(rand_ret); + } + + pthread_attr_t attr; + ASSERT_EQ(__llvm_libc::pthread_attr_init(&attr), 0); + for (size_t i = 0; i < num_threads; ++i) { + ASSERT_EQ(__llvm_libc::pthread_attr_setdetachstate( + &attr, th_args[i].detached ? PTHREAD_CREATE_DETACHED + : PTHREAD_CREATE_JOINABLE), + 0); + + ASSERT_EQ( + __llvm_libc::pthread_create(&th_args[i].tid, &attr, func, + reinterpret_cast(th_args + i)), + 0); + } + return th_args; +} + +static void run_join_tests(size_t num_threads, bool join_as_completed) { + TestThreadArgs *th_args = initialize_test_thread_args(num_threads, 0); + for (size_t join_cnt = 0; join_cnt < num_threads;) { + for (size_t i = 0; i < num_threads; ++i) { + if (th_args[i].detached) { + if (th_args[i].done == 1) { + th_args[i].done = 2; + ++join_cnt; + } + } else { + if (!join_as_completed || th_args[i].done == 1) { + void *th_ret; + ASSERT_EQ(__llvm_libc::pthread_join(th_args[i].tid, &th_ret), 0); + ASSERT_EQ(libc_errno, 0); + + ASSERT_EQ(th_args[i].done, 1); + ASSERT_EQ(th_ret, th_args[i].ret); + + th_args[i].done = 2; + ++join_cnt; + } + } + } + } + delete th_args; +} + +static void null_join_test() { + pthread_t tid; + ASSERT_EQ(__llvm_libc::pthread_create(&tid, nullptr, simple_func, nullptr), + 0); ASSERT_EQ(libc_errno, 0); - ASSERT_EQ(__llvm_libc::pthread_join(Tid, nullptr), 0); + ASSERT_EQ(__llvm_libc::pthread_join(tid, nullptr), 0); ASSERT_EQ(libc_errno, 0); } TEST_MAIN() { libc_errno = 0; - nullJoinTest(); + __llvm_libc::srand(123); + + null_join_test(); + + for (size_t num_threads = 1; num_threads < 8; ++num_threads) { + run_join_tests(num_threads, /*join_as_completed*/ true); + run_join_tests(num_threads, /*join_as_completed*/ false); + } + return 0; }