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,4 @@ -//===-- 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,15 +6,105 @@ // //===----------------------------------------------------------------------===// +#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 +struct TestThreadArgs { + pthread_t Tid; + int Detached; + volatile int Done; + size_t SpinCnt; + void *Ret; +}; +static __llvm_libc::AllocChecker AC; + +static void *func(void *Arg) { + TestThreadArgs *ThArg = reinterpret_cast(Arg); + volatile size_t SpinCnt = ThArg->SpinCnt; + + while (SpinCnt) { + --SpinCnt; + } + + ThArg->Done = 1; + return ThArg->Ret; +} + static void *simpleFunc(void *) { return nullptr; } + +static TestThreadArgs *initializeTestThreadArgs(size_t NumThreads, + unsigned detached_percent) { + TestThreadArgs *ThArgs = new (AC) TestThreadArgs[NumThreads]; + for (size_t I = 0; I < NumThreads; ++I) { + unsigned RandVal = __llvm_libc::rand(); + uintptr_t RandRet = __llvm_libc::rand(); + RandRet *= __llvm_libc::rand(); + RandVal %= 100; + ThArgs[I].Detached = detached_percent > RandVal; + ThArgs[I].Done = 0; + ThArgs[I].SpinCnt = RandVal % (1000 * 1000); + ThArgs[I].Ret = reinterpret_cast(RandRet); + } + + pthread_attr_t Attr; + ASSERT_EQ(__llvm_libc::pthread_attr_init(&Attr), 0); + for (size_t I = 0; I < NumThreads; ++I) { + ASSERT_EQ(__llvm_libc::pthread_attr_setdetachstate( + &Attr, ThArgs[I].Detached ? PTHREAD_CREATE_DETACHED + : PTHREAD_CREATE_JOINABLE), + 0); + + ASSERT_EQ(__llvm_libc::pthread_create(&ThArgs[I].Tid, &Attr, func, + reinterpret_cast(ThArgs + I)), + 0); + } + return ThArgs; +} + +static void runJoinTests(size_t NumThreads, bool JoinAsCompleted) { + TestThreadArgs *ThArgs = initializeTestThreadArgs(NumThreads, 0); + for (size_t JoinCnt = 0; JoinCnt < NumThreads;) { + for (size_t I = 0; I < NumThreads; ++I) { + if (ThArgs[I].Detached) { + if (ThArgs[I].Done == 1) { + ThArgs[I].Done = 2; + ++JoinCnt; + } + } else { + if (!JoinAsCompleted || ThArgs[I].Done == 1) { + void *ThRet; + ASSERT_EQ(__llvm_libc::pthread_join(ThArgs[I].Tid, &ThRet), 0); + ASSERT_EQ(libc_errno, 0); + + ASSERT_EQ(ThArgs[I].Done, 1); + ASSERT_EQ(ThRet, ThArgs[I].Ret); + + ThArgs[I].Done = 2; + ++JoinCnt; + } + } + } + } + delete ThArgs; +} + static void nullJoinTest() { pthread_t Tid; ASSERT_EQ(__llvm_libc::pthread_create(&Tid, nullptr, simpleFunc, nullptr), 0); @@ -25,6 +115,14 @@ TEST_MAIN() { libc_errno = 0; + __llvm_libc::srand(123); + nullJoinTest(); + + for (size_t NumThreads = 1; NumThreads < 8; ++NumThreads) { + runJoinTests(NumThreads, /*JoinAsCompleted*/ true); + runJoinTests(NumThreads, /*JoinAsCompleted*/ false); + } + return 0; }