From: Siva Chandra Reddy Date: Wed, 25 May 2022 21:07:23 +0000 (+0000) Subject: [libc] Add pthread_create and pthread_join functions. X-Git-Tag: upstream/15.0.7~6110 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=70c8d12b79a58cf350256bb0a366f0e91000d82e;p=platform%2Fupstream%2Fllvm.git [libc] Add pthread_create and pthread_join functions. They do not yet support all the feature/attributes in pthread_attr_t. Future changes will add such support. Reviewed By: lntue Differential Revision: https://reviews.llvm.org/D126718 --- diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td index f8ca3213..3ab2f3a 100644 --- a/libc/config/linux/api.td +++ b/libc/config/linux/api.td @@ -244,9 +244,11 @@ def ThreadsAPI : PublicAPI<"threads.h"> { def PThreadAPI : PublicAPI<"pthread.h"> { let Types = [ + "__pthread_start_t", "pthread_attr_t", "pthread_mutex_t", - "pthread_mutexattr_t" + "pthread_mutexattr_t", + "pthread_t", ]; } diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 28607d6..ed2e248 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -236,6 +236,8 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.pthread.pthread_attr_setstack libc.src.pthread.pthread_attr_setstacksize libc.src.pthread.pthread_attr_init + libc.src.pthread.pthread_create + libc.src.pthread.pthread_join libc.src.pthread.pthread_mutex_destroy libc.src.pthread.pthread_mutex_init libc.src.pthread.pthread_mutex_lock diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt index 5ffef44..afd4972 100644 --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -162,9 +162,11 @@ add_gen_header( GEN_HDR pthread.h DEPENDS .llvm_libc_common_h + .llvm-libc-types.__pthread_start_t .llvm-libc-types.pthread_attr_t .llvm-libc-types.pthread_mutex_t .llvm-libc-types.pthread_mutexattr_t + .llvm-libc-types.pthread_t ) # TODO: Not all platforms will have a include/sys directory. Add the sys diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt index 681f7aa..9ca82ad 100644 --- a/libc/include/llvm-libc-types/CMakeLists.txt +++ b/libc/include/llvm-libc-types/CMakeLists.txt @@ -1,9 +1,11 @@ add_header(__bsearchcompare_t HDR __bsearchcompare_t.h) add_header(__call_once_func_t HDR __call_once_func_t.h) add_header(__futex_word HDR __futex_word.h) -add_header(__mutex_type HDR __mutex_type.h) +add_header(__mutex_type HDR __mutex_type.h DEPENDS .__futex_word) +add_header(__pthread_start_t HDR __pthread_start_t.h) add_header(__qsortcompare_t HDR __qsortcompare_t.h) add_header(__sighandler_t HDR __sighandler_t.h) +add_header(__thread_type HDR __thread_type.h) add_header(cnd_t HDR cnd_t.h) add_header(cookie_io_functions_t HDR cookie_io_functions_t.h DEPENDS .off64_t) add_header(double_t HDR double_t.h) @@ -22,12 +24,13 @@ add_header(off64_t HDR off64_t.h) add_header(once_flag HDR once_flag.h DEPENDS .__futex_word) add_header(pthread_attr_t HDR pthread_attr_t.h DEPENDS .size_t) add_header(pthread_mutex_t HDR pthread_mutex_t.h DEPENDS .__futex_word .__mutex_type) +add_header(pthread_t HDR pthread_t.h DEPENDS .__thread_type) add_header(pthread_mutexattr_t HDR pthread_mutexattr_t.h) add_header(size_t HDR size_t.h) add_header(ssize_t HDR ssize_t.h) add_header(struct_sigaction HDR struct_sigaction.h) add_header(struct_tm HDR struct_tm.h) add_header(thrd_start_t HDR thrd_start_t.h) -add_header(thrd_t HDR thrd_t.h) +add_header(thrd_t HDR thrd_t.h DEPENDS .__thread_type) add_header(time_t HDR time_t.h) add_header(__atexithandler_t HDR __atexithandler_t.h) diff --git a/libc/include/llvm-libc-types/__pthread_start_t.h b/libc/include/llvm-libc-types/__pthread_start_t.h new file mode 100644 index 0000000..1e05f9b4 --- /dev/null +++ b/libc/include/llvm-libc-types/__pthread_start_t.h @@ -0,0 +1,14 @@ +//===-- Definition of __pthread_start_t type ------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef __LLVM_LIBC_TYPES_PTHREAD_START_T_H__ +#define __LLVM_LIBC_TYPES_PTHREAD_START_T_H__ + +typedef void *(*__pthread_start_t)(void *); + +#endif // __LLVM_LIBC_TYPES_PTHREAD_START_T_H__ diff --git a/libc/include/llvm-libc-types/__thread_type.h b/libc/include/llvm-libc-types/__thread_type.h new file mode 100644 index 0000000..1d64f90 --- /dev/null +++ b/libc/include/llvm-libc-types/__thread_type.h @@ -0,0 +1,17 @@ +//===-- Definition of thrd_t type -----------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef __LLVM_LIBC_TYPES_THREAD_TYPE_H__ +#define __LLVM_LIBC_TYPES_THREAD_TYPE_H__ + +typedef struct { + void *__attrib; + void *__platform_attrib; +} __thread_type; + +#endif // __LLVM_LIBC_TYPES_THREAD_TYPE_H__ diff --git a/libc/include/llvm-libc-types/pthread_t.h b/libc/include/llvm-libc-types/pthread_t.h new file mode 100644 index 0000000..8130491 --- /dev/null +++ b/libc/include/llvm-libc-types/pthread_t.h @@ -0,0 +1,16 @@ +//===-- Definition of pthread_t type --------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef __LLVM_LIBC_TYPES_PTHREAD_T_H__ +#define __LLVM_LIBC_TYPES_PTHREAD_T_H__ + +#include + +typedef __thread_type pthread_t; + +#endif // __LLVM_LIBC_TYPES_PTHREAD_T_H__ diff --git a/libc/include/llvm-libc-types/thrd_t.h b/libc/include/llvm-libc-types/thrd_t.h index 169f937..0743106 100644 --- a/libc/include/llvm-libc-types/thrd_t.h +++ b/libc/include/llvm-libc-types/thrd_t.h @@ -9,11 +9,8 @@ #ifndef __LLVM_LIBC_TYPES_THRD_T_H__ #define __LLVM_LIBC_TYPES_THRD_T_H__ -#include +#include -typedef struct { - void *__attribs; - void *__platform_attribs; -} thrd_t; +typedef __thread_type thrd_t; #endif // __LLVM_LIBC_TYPES_THRD_T_H__ diff --git a/libc/spec/posix.td b/libc/spec/posix.td index 2436d8e..e53942dd 100644 --- a/libc/spec/posix.td +++ b/libc/spec/posix.td @@ -10,6 +10,8 @@ def ConstStructSigactionPtr : ConstType; def RestrictedStructSigactionPtr : RestrictedPtrType; def ConstRestrictedStructSigactionPtr : ConstType; +def PThreadStartT : NamedType<"__pthread_start_t">; + def POSIX : StandardSpec<"POSIX"> { PtrType CharPtr = PtrType; RestrictedPtrType RestrictedCharPtr = RestrictedPtrType; @@ -39,6 +41,10 @@ def POSIX : StandardSpec<"POSIX"> { ConstType ConstPThreadMutexTPtr = ConstType; ConstType ConstRestrictedPThreadMutexTPtr = ConstType; + NamedType PThreadTType = NamedType<"pthread_t">; + PtrType PThreadTPtr = PtrType; + RestrictedPtrType RestrictedPThreadTPtr = RestrictedPtrType; + HeaderSpec Errno = HeaderSpec< "errno.h", [ @@ -392,7 +398,7 @@ def POSIX : StandardSpec<"POSIX"> { HeaderSpec PThread = HeaderSpec< "pthread.h", [], // Macros - [PThreadAttrTType, PThreadMutexAttrTType, PThreadMutexTType], // Types + [PThreadAttrTType, PThreadMutexAttrTType, PThreadMutexTType, PThreadStartT, PThreadTType], // Types [], // Enumerations [ FunctionSpec< @@ -446,6 +452,16 @@ def POSIX : StandardSpec<"POSIX"> { [ArgSpec, ArgSpec, ArgSpec] >, FunctionSpec< + "pthread_create", + RetValSpec, + [ArgSpec, ArgSpec, ArgSpec, ArgSpec] + >, + FunctionSpec< + "pthread_join", + RetValSpec, + [ArgSpec, ArgSpec] + >, + FunctionSpec< "pthread_mutexattr_init", RetValSpec, [ArgSpec] diff --git a/libc/src/pthread/CMakeLists.txt b/libc/src/pthread/CMakeLists.txt index ca5f0e0..828fee2 100644 --- a/libc/src/pthread/CMakeLists.txt +++ b/libc/src/pthread/CMakeLists.txt @@ -242,3 +242,26 @@ add_entrypoint_object( libc.include.pthread libc.src.__support.threads.mutex ) + +add_entrypoint_object( + pthread_create + SRCS + pthread_create.cpp + HDRS + pthread_create.h + DEPENDS + libc.include.errno + libc.include.pthread + libc.src.__support.threads.thread +) + +add_entrypoint_object( + pthread_join + SRCS + pthread_join.cpp + HDRS + pthread_join.h + DEPENDS + libc.include.pthread + libc.src.__support.threads.thread +) diff --git a/libc/src/pthread/pthread_create.cpp b/libc/src/pthread/pthread_create.cpp new file mode 100644 index 0000000..bc945a9 --- /dev/null +++ b/libc/src/pthread/pthread_create.cpp @@ -0,0 +1,33 @@ +//===-- Linux implementation of the pthread_create function ---------------===// +// +// 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 "pthread_create.h" + +#include "src/__support/common.h" +#include "src/__support/threads/thread.h" + +#include +#include // For pthread_* type definitions. + +namespace __llvm_libc { + +static_assert(sizeof(pthread_t) == sizeof(__llvm_libc::Thread), + "Mismatch between pthread_t and internal Thread."); + +LLVM_LIBC_FUNCTION(int, pthread_create, + (pthread_t *__restrict th, + const pthread_attr_t *__restrict attr, + __pthread_start_t func, void *arg)) { + auto *thread = reinterpret_cast<__llvm_libc::Thread *>(th); + int result = thread->run(func, arg, nullptr, 0); + if (result != 0 && result != EPERM) + return EAGAIN; + return result; +} + +} // namespace __llvm_libc diff --git a/libc/src/pthread/pthread_create.h b/libc/src/pthread/pthread_create.h new file mode 100644 index 0000000..500aa6c --- /dev/null +++ b/libc/src/pthread/pthread_create.h @@ -0,0 +1,22 @@ +//===-- Implementation header for pthread_create function -------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_THREADS_PTHREAD_CREATE_H +#define LLVM_LIBC_SRC_THREADS_PTHREAD_CREATE_H + +#include + +namespace __llvm_libc { + +int pthread_create(pthread_t *__restrict thread, + const pthread_attr_t *__restrict attr, + __pthread_start_t func, void *arg); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_THREADS_PTHREAD_CREATE_H diff --git a/libc/src/pthread/pthread_join.cpp b/libc/src/pthread/pthread_join.cpp new file mode 100644 index 0000000..c3bf4ad --- /dev/null +++ b/libc/src/pthread/pthread_join.cpp @@ -0,0 +1,27 @@ +//===-- Linux implementation of the pthread_join function -----------------===// +// +// 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 "pthread_join.h" + +#include "src/__support/common.h" +#include "src/__support/threads/thread.h" + +#include // For pthread_* type definitions. + +namespace __llvm_libc { + +static_assert(sizeof(pthread_t) == sizeof(__llvm_libc::Thread), + "Mismatch between pthread_t and internal Thread."); + +LLVM_LIBC_FUNCTION(int, pthread_join, (pthread_t th, void **retval)) { + auto *thread = reinterpret_cast *>(&th); + int result = thread->join(retval); + return result; +} + +} // namespace __llvm_libc diff --git a/libc/src/pthread/pthread_join.h b/libc/src/pthread/pthread_join.h new file mode 100644 index 0000000..d659897 --- /dev/null +++ b/libc/src/pthread/pthread_join.h @@ -0,0 +1,20 @@ +//===-- Implementation header for pthread_join function ---------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_THREADS_PTHREAD_JOIN_H +#define LLVM_LIBC_SRC_THREADS_PTHREAD_JOIN_H + +#include + +namespace __llvm_libc { + +int pthread_join(pthread_t thread, void **retval); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_THREADS_PTHREAD_JOIN_H diff --git a/libc/test/src/pthread/CMakeLists.txt b/libc/test/src/pthread/CMakeLists.txt index 5f3bbcb..f69c77f 100644 --- a/libc/test/src/pthread/CMakeLists.txt +++ b/libc/test/src/pthread/CMakeLists.txt @@ -41,7 +41,7 @@ add_libc_unittest( ) add_libc_unittest( - phtread_mutex_test + pthread_mutex_test SUITE libc_pthread_unittests SRCS @@ -53,6 +53,18 @@ add_libc_unittest( libc.src.pthread.pthread_mutex_init libc.src.pthread.pthread_mutex_lock libc.src.pthread.pthread_mutex_unlock - libc.src.threads.thrd_create - libc.src.threads.thrd_join + libc.src.pthread.pthread_create + libc.src.pthread.pthread_join +) + +add_libc_unittest( + pthread_test + SUITE + libc_pthread_unittests + SRCS + pthread_test.cpp + DEPENDS + libc.include.pthread + libc.src.pthread.pthread_create + libc.src.pthread.pthread_join ) diff --git a/libc/test/src/pthread/pthread_mutex_test.cpp b/libc/test/src/pthread/pthread_mutex_test.cpp index 8b06294..28c06b0 100644 --- a/libc/test/src/pthread/pthread_mutex_test.cpp +++ b/libc/test/src/pthread/pthread_mutex_test.cpp @@ -11,10 +11,8 @@ #include "src/pthread/pthread_mutex_lock.h" #include "src/pthread/pthread_mutex_unlock.h" -// TODO: When pthread_t type is available, use it to spawn threads instead of -// thrd_t. -#include "src/threads/thrd_create.h" -#include "src/threads/thrd_join.h" +#include "src/pthread/pthread_create.h" +#include "src/pthread/pthread_join.h" #include "utils/UnitTest/Test.h" @@ -26,7 +24,7 @@ constexpr int MAX = 10000; pthread_mutex_t mutex; static int shared_int = START; -int counter(void *arg) { +void *counter(void *arg) { int last_count = START; while (true) { __llvm_libc::pthread_mutex_lock(&mutex); @@ -38,7 +36,7 @@ int counter(void *arg) { if (last_count >= MAX) break; } - return 0; + return nullptr; } TEST(LlvmLibcMutexTest, RelayCounter) { @@ -46,8 +44,8 @@ TEST(LlvmLibcMutexTest, RelayCounter) { // The idea of this test is that two competing threads will update // a counter only if the other thread has updated it. - thrd_t thread; - __llvm_libc::thrd_create(&thread, counter, nullptr); + pthread_t thread; + __llvm_libc::pthread_create(&thread, nullptr, counter, nullptr); int last_count = START; while (true) { @@ -65,9 +63,9 @@ TEST(LlvmLibcMutexTest, RelayCounter) { break; } - int retval = 123; - __llvm_libc::thrd_join(&thread, &retval); - ASSERT_EQ(retval, 0); + void *retval = reinterpret_cast(123); + __llvm_libc::pthread_join(thread, &retval); + ASSERT_EQ(uintptr_t(retval), uintptr_t(nullptr)); __llvm_libc::pthread_mutex_destroy(&mutex); } @@ -75,7 +73,7 @@ TEST(LlvmLibcMutexTest, RelayCounter) { pthread_mutex_t start_lock, step_lock; bool started, step; -int stepper(void *arg) { +void *stepper(void *arg) { __llvm_libc::pthread_mutex_lock(&start_lock); started = true; __llvm_libc::pthread_mutex_unlock(&start_lock); @@ -83,7 +81,7 @@ int stepper(void *arg) { __llvm_libc::pthread_mutex_lock(&step_lock); step = true; __llvm_libc::pthread_mutex_unlock(&step_lock); - return 0; + return nullptr; } TEST(LlvmLibcMutexTest, WaitAndStep) { @@ -97,8 +95,8 @@ TEST(LlvmLibcMutexTest, WaitAndStep) { started = false; ASSERT_EQ(__llvm_libc::pthread_mutex_lock(&step_lock), 0); - thrd_t thread; - __llvm_libc::thrd_create(&thread, stepper, nullptr); + pthread_t thread; + __llvm_libc::pthread_create(&thread, nullptr, stepper, nullptr); while (true) { // Make sure the thread actually started. @@ -123,9 +121,9 @@ TEST(LlvmLibcMutexTest, WaitAndStep) { break; } - int retval = 123; - __llvm_libc::thrd_join(&thread, &retval); - ASSERT_EQ(retval, 0); + void *retval = reinterpret_cast(123); + __llvm_libc::pthread_join(thread, &retval); + ASSERT_EQ(uintptr_t(retval), uintptr_t(nullptr)); __llvm_libc::pthread_mutex_destroy(&start_lock); __llvm_libc::pthread_mutex_destroy(&step_lock); @@ -136,7 +134,7 @@ static pthread_mutex_t multiple_waiter_lock; static pthread_mutex_t counter_lock; static int wait_count = 0; -int waiter_func(void *) { +void *waiter_func(void *) { __llvm_libc::pthread_mutex_lock(&counter_lock); ++wait_count; __llvm_libc::pthread_mutex_unlock(&counter_lock); @@ -150,7 +148,7 @@ int waiter_func(void *) { --wait_count; __llvm_libc::pthread_mutex_unlock(&counter_lock); - return 0; + return nullptr; } TEST(LlvmLibcMutexTest, MultipleWaiters) { @@ -158,9 +156,9 @@ TEST(LlvmLibcMutexTest, MultipleWaiters) { __llvm_libc::pthread_mutex_init(&counter_lock, nullptr); __llvm_libc::pthread_mutex_lock(&multiple_waiter_lock); - thrd_t waiters[THREAD_COUNT]; + pthread_t waiters[THREAD_COUNT]; for (int i = 0; i < THREAD_COUNT; ++i) { - __llvm_libc::thrd_create(waiters + i, waiter_func, nullptr); + __llvm_libc::pthread_create(waiters + i, nullptr, waiter_func, nullptr); } // Spin until the counter is incremented to the desired @@ -176,9 +174,9 @@ TEST(LlvmLibcMutexTest, MultipleWaiters) { __llvm_libc::pthread_mutex_unlock(&multiple_waiter_lock); - int retval; + void *retval; for (int i = 0; i < THREAD_COUNT; ++i) { - __llvm_libc::thrd_join(waiters + i, &retval); + __llvm_libc::pthread_join(waiters[i], &retval); } ASSERT_EQ(wait_count, 0); diff --git a/libc/test/src/pthread/pthread_test.cpp b/libc/test/src/pthread/pthread_test.cpp new file mode 100644 index 0000000..3a3d587 --- /dev/null +++ b/libc/test/src/pthread/pthread_test.cpp @@ -0,0 +1,56 @@ +//===-- Unittests for pthread_t -------------------------------------------===// +// +// 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_join.h" +#include "utils/UnitTest/Test.h" + +#include + +static constexpr int thread_count = 1000; +static int counter = 0; +static void *thread_func(void *) { + ++counter; + return nullptr; +} + +TEST(LlvmLibcThreadTest, CreateAndJoin) { + for (counter = 0; counter <= thread_count;) { + pthread_t thread; + int old_counter_val = counter; + ASSERT_EQ( + __llvm_libc::pthread_create(&thread, nullptr, thread_func, nullptr), 0); + + // Start with a retval we dont expect. + void *retval = reinterpret_cast(thread_count + 1); + ASSERT_EQ(__llvm_libc::pthread_join(thread, &retval), 0); + ASSERT_EQ(uintptr_t(retval), uintptr_t(nullptr)); + ASSERT_EQ(counter, old_counter_val + 1); + } +} + +static void *return_arg(void *arg) { return arg; } + +TEST(LlvmLibcThreadTest, SpawnAndJoin) { + pthread_t thread_list[thread_count]; + int args[thread_count]; + + for (int i = 0; i < thread_count; ++i) { + args[i] = i; + ASSERT_EQ(__llvm_libc::pthread_create(thread_list + i, nullptr, return_arg, + args + i), + 0); + } + + for (int i = 0; i < thread_count; ++i) { + // Start with a retval we dont expect. + void *retval = reinterpret_cast(thread_count + 1); + ASSERT_EQ(__llvm_libc::pthread_join(thread_list[i], &retval), 0); + ASSERT_EQ(*reinterpret_cast(retval), i); + } +}