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
def PThreadAPI : PublicAPI<"pthread.h"> {
let Types = [
+ "__pthread_start_t",
"pthread_attr_t",
"pthread_mutex_t",
- "pthread_mutexattr_t"
+ "pthread_mutexattr_t",
+ "pthread_t",
];
}
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
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
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)
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)
--- /dev/null
+//===-- 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__
--- /dev/null
+//===-- 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__
--- /dev/null
+//===-- 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 <llvm-libc-types/__thread_type.h>
+
+typedef __thread_type pthread_t;
+
+#endif // __LLVM_LIBC_TYPES_PTHREAD_T_H__
#ifndef __LLVM_LIBC_TYPES_THRD_T_H__
#define __LLVM_LIBC_TYPES_THRD_T_H__
-#include <llvm-libc-types/__futex_word.h>
+#include <llvm-libc-types/__thread_type.h>
-typedef struct {
- void *__attribs;
- void *__platform_attribs;
-} thrd_t;
+typedef __thread_type thrd_t;
#endif // __LLVM_LIBC_TYPES_THRD_T_H__
def RestrictedStructSigactionPtr : RestrictedPtrType<StructSigaction>;
def ConstRestrictedStructSigactionPtr : ConstType<RestrictedStructSigactionPtr>;
+def PThreadStartT : NamedType<"__pthread_start_t">;
+
def POSIX : StandardSpec<"POSIX"> {
PtrType CharPtr = PtrType<CharType>;
RestrictedPtrType RestrictedCharPtr = RestrictedPtrType<CharType>;
ConstType ConstPThreadMutexTPtr = ConstType<PThreadMutexTPtr>;
ConstType ConstRestrictedPThreadMutexTPtr = ConstType<RestrictedPThreadMutexTPtr>;
+ NamedType PThreadTType = NamedType<"pthread_t">;
+ PtrType PThreadTPtr = PtrType<PThreadTType>;
+ RestrictedPtrType RestrictedPThreadTPtr = RestrictedPtrType<PThreadTType>;
+
HeaderSpec Errno = HeaderSpec<
"errno.h",
[
HeaderSpec PThread = HeaderSpec<
"pthread.h",
[], // Macros
- [PThreadAttrTType, PThreadMutexAttrTType, PThreadMutexTType], // Types
+ [PThreadAttrTType, PThreadMutexAttrTType, PThreadMutexTType, PThreadStartT, PThreadTType], // Types
[], // Enumerations
[
FunctionSpec<
[ArgSpec<PThreadAttrTPtr>, ArgSpec<VoidPtr>, ArgSpec<SizeTType>]
>,
FunctionSpec<
+ "pthread_create",
+ RetValSpec<IntType>,
+ [ArgSpec<RestrictedPThreadTPtr>, ArgSpec<ConstRestrictedPThreadAttrTPtr>, ArgSpec<PThreadStartT>, ArgSpec<VoidPtr>]
+ >,
+ FunctionSpec<
+ "pthread_join",
+ RetValSpec<IntType>,
+ [ArgSpec<PThreadTType>, ArgSpec<VoidPtrPtr>]
+ >,
+ FunctionSpec<
"pthread_mutexattr_init",
RetValSpec<IntType>,
[ArgSpec<PThreadMutexAttrTPtr>]
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
+)
--- /dev/null
+//===-- 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 <errno.h>
+#include <pthread.h> // For pthread_* type definitions.
+
+namespace __llvm_libc {
+
+static_assert(sizeof(pthread_t) == sizeof(__llvm_libc::Thread<int>),
+ "Mismatch between pthread_t and internal Thread<int>.");
+
+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<void *> *>(th);
+ int result = thread->run(func, arg, nullptr, 0);
+ if (result != 0 && result != EPERM)
+ return EAGAIN;
+ return result;
+}
+
+} // namespace __llvm_libc
--- /dev/null
+//===-- 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 <pthread.h>
+
+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
--- /dev/null
+//===-- 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 <pthread.h> // For pthread_* type definitions.
+
+namespace __llvm_libc {
+
+static_assert(sizeof(pthread_t) == sizeof(__llvm_libc::Thread<int>),
+ "Mismatch between pthread_t and internal Thread<int>.");
+
+LLVM_LIBC_FUNCTION(int, pthread_join, (pthread_t th, void **retval)) {
+ auto *thread = reinterpret_cast<Thread<void *> *>(&th);
+ int result = thread->join(retval);
+ return result;
+}
+
+} // namespace __llvm_libc
--- /dev/null
+//===-- 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 <pthread.h>
+
+namespace __llvm_libc {
+
+int pthread_join(pthread_t thread, void **retval);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_THREADS_PTHREAD_JOIN_H
)
add_libc_unittest(
- phtread_mutex_test
+ pthread_mutex_test
SUITE
libc_pthread_unittests
SRCS
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
)
#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"
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);
if (last_count >= MAX)
break;
}
- return 0;
+ return nullptr;
}
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) {
break;
}
- int retval = 123;
- __llvm_libc::thrd_join(&thread, &retval);
- ASSERT_EQ(retval, 0);
+ void *retval = reinterpret_cast<void *>(123);
+ __llvm_libc::pthread_join(thread, &retval);
+ ASSERT_EQ(uintptr_t(retval), uintptr_t(nullptr));
__llvm_libc::pthread_mutex_destroy(&mutex);
}
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);
__llvm_libc::pthread_mutex_lock(&step_lock);
step = true;
__llvm_libc::pthread_mutex_unlock(&step_lock);
- return 0;
+ return nullptr;
}
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.
break;
}
- int retval = 123;
- __llvm_libc::thrd_join(&thread, &retval);
- ASSERT_EQ(retval, 0);
+ void *retval = reinterpret_cast<void *>(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);
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);
--wait_count;
__llvm_libc::pthread_mutex_unlock(&counter_lock);
- return 0;
+ return nullptr;
}
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
__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);
--- /dev/null
+//===-- 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 <pthread.h>
+
+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<void *>(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<void *>(thread_count + 1);
+ ASSERT_EQ(__llvm_libc::pthread_join(thread_list[i], &retval), 0);
+ ASSERT_EQ(*reinterpret_cast<int *>(retval), i);
+ }
+}