[libc-commits] [libc] 2a5d507 - [libc] Add the pthread_mutex_t type.
Siva Chandra Reddy via libc-commits
libc-commits at lists.llvm.org
Tue May 24 15:48:35 PDT 2022
Author: Siva Chandra Reddy
Date: 2022-05-24T22:48:14Z
New Revision: 2a5d5078d5dadb1aaa4487c89a92c91a98e2ed12
URL: https://github.com/llvm/llvm-project/commit/2a5d5078d5dadb1aaa4487c89a92c91a98e2ed12
DIFF: https://github.com/llvm/llvm-project/commit/2a5d5078d5dadb1aaa4487c89a92c91a98e2ed12.diff
LOG: [libc] Add the pthread_mutex_t type.
Simple implementations of the functions pthread_mutex_init,
pthread_mutex_destroy, pthread_mutex_lock and pthread_mutex_unlock have
have also been added. Future patches will extend these functions to add
features required by the POSIX specification.
Reviewed By: lntue
Differential Revision: https://reviews.llvm.org/D126235
Added:
libc/include/llvm-libc-types/pthread_mutex_t.h
libc/src/pthread/pthread_mutex_destroy.cpp
libc/src/pthread/pthread_mutex_destroy.h
libc/src/pthread/pthread_mutex_init.cpp
libc/src/pthread/pthread_mutex_init.h
libc/src/pthread/pthread_mutex_lock.cpp
libc/src/pthread/pthread_mutex_lock.h
libc/src/pthread/pthread_mutex_unlock.cpp
libc/src/pthread/pthread_mutex_unlock.h
libc/test/src/pthread/pthread_mutex_test.cpp
Modified:
libc/config/linux/api.td
libc/config/linux/x86_64/entrypoints.txt
libc/include/CMakeLists.txt
libc/include/llvm-libc-types/CMakeLists.txt
libc/include/llvm-libc-types/__mutex_type.h
libc/spec/posix.td
libc/src/pthread/CMakeLists.txt
libc/src/pthread/pthread_mutexattr.h
libc/test/src/pthread/CMakeLists.txt
Removed:
################################################################################
diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index c99e35e5f2f28..6862139d66c31 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -241,6 +241,7 @@ def ThreadsAPI : PublicAPI<"threads.h"> {
def PThreadAPI : PublicAPI<"pthread.h"> {
let Types = [
"pthread_attr_t",
+ "pthread_mutex_t",
"pthread_mutexattr_t"
];
}
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index a0b7a6b5af225..99937c7ebe592 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -236,6 +236,10 @@ 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_mutex_destroy
+ libc.src.pthread.pthread_mutex_init
+ libc.src.pthread.pthread_mutex_lock
+ libc.src.pthread.pthread_mutex_unlock
libc.src.pthread.pthread_mutexattr_destroy
libc.src.pthread.pthread_mutexattr_init
libc.src.pthread.pthread_mutexattr_getpshared
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index d011d6d6f59be..5ffef44cbc62e 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -163,6 +163,7 @@ add_gen_header(
DEPENDS
.llvm_libc_common_h
.llvm-libc-types.pthread_attr_t
+ .llvm-libc-types.pthread_mutex_t
.llvm-libc-types.pthread_mutexattr_t
)
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index 3a5c17f4e29c1..681f7aa63fd28 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -20,7 +20,8 @@ add_header(mtx_t HDR mtx_t.h DEPENDS .__futex_word .__mutex_type)
add_header(off_t HDR off_t.h)
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)
+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_mutexattr_t HDR pthread_mutexattr_t.h)
add_header(size_t HDR size_t.h)
add_header(ssize_t HDR ssize_t.h)
diff --git a/libc/include/llvm-libc-types/__mutex_type.h b/libc/include/llvm-libc-types/__mutex_type.h
index 37cb856fd58b8..ffd67e7c7bc33 100644
--- a/libc/include/llvm-libc-types/__mutex_type.h
+++ b/libc/include/llvm-libc-types/__mutex_type.h
@@ -6,6 +6,9 @@
//
//===----------------------------------------------------------------------===//
+#ifndef __LLVM_LIBC_TYPES___MUTEX_T_H
+#define __LLVM_LIBC_TYPES___MUTEX_T_H
+
#include <llvm-libc-types/__futex_word.h>
typedef struct {
@@ -22,3 +25,5 @@ typedef struct {
#error "Mutex type not defined for the target platform."
#endif
} __mutex_type;
+
+#endif // __LLVM_LIBC_TYPES___MUTEX_T_H
diff --git a/libc/include/llvm-libc-types/pthread_mutex_t.h b/libc/include/llvm-libc-types/pthread_mutex_t.h
new file mode 100644
index 0000000000000..65e43538cd27d
--- /dev/null
+++ b/libc/include/llvm-libc-types/pthread_mutex_t.h
@@ -0,0 +1,16 @@
+//===-- Definition of pthread_mutex_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_MUTEX_T_H
+#define __LLVM_LIBC_TYPES_PTHREAD_MUTEX_T_H
+
+#include <llvm-libc-types/__mutex_type.h>
+
+typedef __mutex_type pthread_mutex_t;
+
+#endif // __LLVM_LIBC_TYPES_PTHREAD_MUTEX_T_H
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index fbb6a78225dd8..2436d8eea4b1c 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -33,6 +33,12 @@ def POSIX : StandardSpec<"POSIX"> {
ConstType ConstPThreadMutexAttrTPtr = ConstType<PThreadMutexAttrTPtr>;
ConstType ConstRestrictedPThreadMutexAttrTPtr = ConstType<RestrictedPThreadMutexAttrTPtr>;
+ NamedType PThreadMutexTType = NamedType<"pthread_mutex_t">;
+ PtrType PThreadMutexTPtr = PtrType<PThreadMutexTType>;
+ RestrictedPtrType RestrictedPThreadMutexTPtr = RestrictedPtrType<PThreadMutexTType>;
+ ConstType ConstPThreadMutexTPtr = ConstType<PThreadMutexTPtr>;
+ ConstType ConstRestrictedPThreadMutexTPtr = ConstType<RestrictedPThreadMutexTPtr>;
+
HeaderSpec Errno = HeaderSpec<
"errno.h",
[
@@ -386,7 +392,7 @@ def POSIX : StandardSpec<"POSIX"> {
HeaderSpec PThread = HeaderSpec<
"pthread.h",
[], // Macros
- [PThreadAttrTType, PThreadMutexAttrTType], // Types
+ [PThreadAttrTType, PThreadMutexAttrTType, PThreadMutexTType], // Types
[], // Enumerations
[
FunctionSpec<
@@ -499,6 +505,26 @@ def POSIX : StandardSpec<"POSIX"> {
RetValSpec<IntType>,
[ArgSpec<RestrictedPThreadMutexAttrTPtr>, ArgSpec<IntType>]
>,
+ FunctionSpec<
+ "pthread_mutex_init",
+ RetValSpec<IntType>,
+ [ArgSpec<RestrictedPThreadMutexTPtr>, ArgSpec<ConstRestrictedPThreadMutexAttrTPtr>]
+ >,
+ FunctionSpec<
+ "pthread_mutex_destroy",
+ RetValSpec<IntType>,
+ [ArgSpec<PThreadMutexTPtr>]
+ >,
+ FunctionSpec<
+ "pthread_mutex_lock",
+ RetValSpec<IntType>,
+ [ArgSpec<PThreadMutexTPtr>]
+ >,
+ FunctionSpec<
+ "pthread_mutex_unlock",
+ RetValSpec<IntType>,
+ [ArgSpec<PThreadMutexTPtr>]
+ >,
]
>;
diff --git a/libc/src/pthread/CMakeLists.txt b/libc/src/pthread/CMakeLists.txt
index 5d447baef08a6..ca5f0e0433cb5 100644
--- a/libc/src/pthread/CMakeLists.txt
+++ b/libc/src/pthread/CMakeLists.txt
@@ -196,3 +196,49 @@ add_entrypoint_object(
libc.include.errno
libc.include.pthread
)
+
+add_entrypoint_object(
+ pthread_mutex_init
+ SRCS
+ pthread_mutex_init.cpp
+ HDRS
+ pthread_mutex_init.h
+ DEPENDS
+ .pthread_mutexattr
+ libc.include.errno
+ libc.include.pthread
+ libc.src.__support.threads.mutex
+)
+
+add_entrypoint_object(
+ pthread_mutex_destroy
+ SRCS
+ pthread_mutex_destroy.cpp
+ HDRS
+ pthread_mutex_destroy.h
+ DEPENDS
+ libc.include.pthread
+ libc.src.__support.threads.mutex
+)
+
+add_entrypoint_object(
+ pthread_mutex_lock
+ SRCS
+ pthread_mutex_lock.cpp
+ HDRS
+ pthread_mutex_lock.h
+ DEPENDS
+ libc.include.pthread
+ libc.src.__support.threads.mutex
+)
+
+add_entrypoint_object(
+ pthread_mutex_unlock
+ SRCS
+ pthread_mutex_unlock.cpp
+ HDRS
+ pthread_mutex_unlock.h
+ DEPENDS
+ libc.include.pthread
+ libc.src.__support.threads.mutex
+)
diff --git a/libc/src/pthread/pthread_mutex_destroy.cpp b/libc/src/pthread/pthread_mutex_destroy.cpp
new file mode 100644
index 0000000000000..acb344bbea52f
--- /dev/null
+++ b/libc/src/pthread/pthread_mutex_destroy.cpp
@@ -0,0 +1,26 @@
+//===-- Linux implementation of the pthread_mutex_destroy 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_mutex_destroy.h"
+
+#include "src/__support/common.h"
+#include "src/__support/threads/mutex.h"
+
+#include <pthread.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, pthread_mutex_destroy, (pthread_mutex_t * mutex)) {
+ auto *m = reinterpret_cast<Mutex *>(mutex);
+ Mutex::destroy(m);
+ // TODO: When the Mutex class supports all the possible error conditions
+ // return the appropriate error value here.
+ return 0;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/pthread/pthread_mutex_destroy.h b/libc/src/pthread/pthread_mutex_destroy.h
new file mode 100644
index 0000000000000..bd6ea1932c1b6
--- /dev/null
+++ b/libc/src/pthread/pthread_mutex_destroy.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for pthread_mutex_destroy ---------*- 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_PTHREAD_PTHREAD_MUTEX__DESTROY_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX__DESTROY_H
+
+#include <pthread.h>
+
+namespace __llvm_libc {
+
+int pthread_mutex_destroy(pthread_mutex_t *mutex);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_DESTROY_H
diff --git a/libc/src/pthread/pthread_mutex_init.cpp b/libc/src/pthread/pthread_mutex_init.cpp
new file mode 100644
index 0000000000000..5038ee0887593
--- /dev/null
+++ b/libc/src/pthread/pthread_mutex_init.cpp
@@ -0,0 +1,35 @@
+//===-- Linux implementation of the pthread_mutex_init 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_mutex_init.h"
+#include "pthread_mutexattr.h"
+
+#include "src/__support/common.h"
+#include "src/__support/threads/mutex.h"
+
+#include <errno.h>
+#include <pthread.h>
+
+namespace __llvm_libc {
+
+static_assert(sizeof(Mutex) <= sizeof(pthread_mutex_t),
+ "The public pthread_mutex_t type cannot accommodate the internal "
+ "mutex type.");
+
+LLVM_LIBC_FUNCTION(int, pthread_mutex_init,
+ (pthread_mutex_t * m,
+ const pthread_mutexattr_t *__restrict attr)) {
+ auto mutexattr = attr == nullptr ? DEFAULT_MUTEXATTR : *attr;
+ auto err =
+ Mutex::init(reinterpret_cast<Mutex *>(m), false,
+ get_mutexattr_type(mutexattr) & PTHREAD_MUTEX_RECURSIVE,
+ get_mutexattr_robust(mutexattr) & PTHREAD_MUTEX_ROBUST);
+ return err == MutexError::NONE ? 0 : EAGAIN;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/pthread/pthread_mutex_init.h b/libc/src/pthread/pthread_mutex_init.h
new file mode 100644
index 0000000000000..d25fe8968cd63
--- /dev/null
+++ b/libc/src/pthread/pthread_mutex_init.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for pthread_mutex_init 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_PTHREAD_PTHREAD_MUTEX_INIT_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_INIT_H
+
+#include "include/pthread.h"
+
+namespace __llvm_libc {
+
+int pthread_mutex_init(pthread_mutex_t *mutex,
+ const pthread_mutexattr_t *__restrict attr);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_PTHREAD_pthread_mutex_INIT_H
diff --git a/libc/src/pthread/pthread_mutex_lock.cpp b/libc/src/pthread/pthread_mutex_lock.cpp
new file mode 100644
index 0000000000000..9daffafff942f
--- /dev/null
+++ b/libc/src/pthread/pthread_mutex_lock.cpp
@@ -0,0 +1,26 @@
+//===-- Linux implementation of the pthread_mutex_lock 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_mutex_lock.h"
+
+#include "src/__support/common.h"
+#include "src/__support/threads/mutex.h"
+
+#include <pthread.h>
+
+namespace __llvm_libc {
+
+// The implementation currently handles only plain mutexes.
+LLVM_LIBC_FUNCTION(int, pthread_mutex_lock, (pthread_mutex_t * mutex)) {
+ reinterpret_cast<Mutex *>(mutex)->lock();
+ // TODO: When the Mutex class supports all the possible error conditions
+ // return the appropriate error value here.
+ return 0;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/pthread/pthread_mutex_lock.h b/libc/src/pthread/pthread_mutex_lock.h
new file mode 100644
index 0000000000000..bb47e59809698
--- /dev/null
+++ b/libc/src/pthread/pthread_mutex_lock.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for pthread_mutex_lock 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_PTHREAD_PTHREAD_MUTEX_LOCK_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_LOCK_H
+
+#include <pthread.h>
+
+namespace __llvm_libc {
+
+int pthread_mutex_lock(pthread_mutex_t *mutex);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_LOCK_H
diff --git a/libc/src/pthread/pthread_mutex_unlock.cpp b/libc/src/pthread/pthread_mutex_unlock.cpp
new file mode 100644
index 0000000000000..3cc8c7cdac09b
--- /dev/null
+++ b/libc/src/pthread/pthread_mutex_unlock.cpp
@@ -0,0 +1,26 @@
+//===-- Linux implementation of the pthread_mutex_unlock 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_mutex_unlock.h"
+
+#include "src/__support/common.h"
+#include "src/__support/threads/mutex.h"
+
+#include <pthread.h>
+
+namespace __llvm_libc {
+
+// The implementation currently handles only plain mutexes.
+LLVM_LIBC_FUNCTION(int, pthread_mutex_unlock, (pthread_mutex_t * mutex)) {
+ reinterpret_cast<Mutex *>(mutex)->unlock();
+ // TODO: When the Mutex class supports all the possible error conditions
+ // return the appropriate error value here.
+ return 0;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/pthread/pthread_mutex_unlock.h b/libc/src/pthread/pthread_mutex_unlock.h
new file mode 100644
index 0000000000000..4653841244eb7
--- /dev/null
+++ b/libc/src/pthread/pthread_mutex_unlock.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for pthread_mutex_unlock 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_PTHREAD_PTHREAD_MUTEX_UNLOCK_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_UNLOCK_H
+
+#include <pthread.h>
+
+namespace __llvm_libc {
+
+int pthread_mutex_unlock(pthread_mutex_t *mutex);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_UNLOCK_H
diff --git a/libc/src/pthread/pthread_mutexattr.h b/libc/src/pthread/pthread_mutexattr.h
index 4f969e288c881..98f9ff9067e44 100644
--- a/libc/src/pthread/pthread_mutexattr.h
+++ b/libc/src/pthread/pthread_mutexattr.h
@@ -31,6 +31,16 @@ constexpr pthread_mutexattr_t DEFAULT_MUTEXATTR =
PTHREAD_MUTEX_STALLED << unsigned(PThreadMutexAttrPos::ROBUST_SHIFT) |
PTHREAD_PROCESS_PRIVATE << unsigned(PThreadMutexAttrPos::PSHARED_SHIFT);
+static inline int get_mutexattr_type(pthread_mutexattr_t attr) {
+ return (attr & unsigned(PThreadMutexAttrPos::TYPE_MASK)) >>
+ unsigned(PThreadMutexAttrPos::TYPE_SHIFT);
+}
+
+static inline int get_mutexattr_robust(pthread_mutexattr_t attr) {
+ return (attr & unsigned(PThreadMutexAttrPos::ROBUST_MASK)) >>
+ unsigned(PThreadMutexAttrPos::ROBUST_SHIFT);
+}
+
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEXATTR_H
diff --git a/libc/test/src/pthread/CMakeLists.txt b/libc/test/src/pthread/CMakeLists.txt
index db0516cecc4fd..5f3bbcbdd9a36 100644
--- a/libc/test/src/pthread/CMakeLists.txt
+++ b/libc/test/src/pthread/CMakeLists.txt
@@ -39,3 +39,20 @@ add_libc_unittest(
libc.src.pthread.pthread_mutexattr_setrobust
libc.src.pthread.pthread_mutexattr_settype
)
+
+add_libc_unittest(
+ phtread_mutex_test
+ SUITE
+ libc_pthread_unittests
+ SRCS
+ pthread_mutex_test.cpp
+ DEPENDS
+ libc.include.pthread
+ libc.src.errno.errno
+ libc.src.pthread.pthread_mutex_destroy
+ 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
+)
diff --git a/libc/test/src/pthread/pthread_mutex_test.cpp b/libc/test/src/pthread/pthread_mutex_test.cpp
new file mode 100644
index 0000000000000..8b06294169ed6
--- /dev/null
+++ b/libc/test/src/pthread/pthread_mutex_test.cpp
@@ -0,0 +1,188 @@
+//===-- Unittests for pthread_mutex_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_mutex_destroy.h"
+#include "src/pthread/pthread_mutex_init.h"
+#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 "utils/UnitTest/Test.h"
+
+#include <pthread.h>
+
+constexpr int START = 0;
+constexpr int MAX = 10000;
+
+pthread_mutex_t mutex;
+static int shared_int = START;
+
+int counter(void *arg) {
+ int last_count = START;
+ while (true) {
+ __llvm_libc::pthread_mutex_lock(&mutex);
+ if (shared_int == last_count + 1) {
+ shared_int++;
+ last_count = shared_int;
+ }
+ __llvm_libc::pthread_mutex_unlock(&mutex);
+ if (last_count >= MAX)
+ break;
+ }
+ return 0;
+}
+
+TEST(LlvmLibcMutexTest, RelayCounter) {
+ ASSERT_EQ(__llvm_libc::pthread_mutex_init(&mutex, nullptr), 0);
+
+ // 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);
+
+ int last_count = START;
+ while (true) {
+ ASSERT_EQ(__llvm_libc::pthread_mutex_lock(&mutex), 0);
+ if (shared_int == START) {
+ ++shared_int;
+ last_count = shared_int;
+ } else if (shared_int != last_count) {
+ ASSERT_EQ(shared_int, last_count + 1);
+ ++shared_int;
+ last_count = shared_int;
+ }
+ ASSERT_EQ(__llvm_libc::pthread_mutex_unlock(&mutex), 0);
+ if (last_count > MAX)
+ break;
+ }
+
+ int retval = 123;
+ __llvm_libc::thrd_join(&thread, &retval);
+ ASSERT_EQ(retval, 0);
+
+ __llvm_libc::pthread_mutex_destroy(&mutex);
+}
+
+pthread_mutex_t start_lock, step_lock;
+bool started, step;
+
+int 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;
+}
+
+TEST(LlvmLibcMutexTest, WaitAndStep) {
+ ASSERT_EQ(__llvm_libc::pthread_mutex_init(&start_lock, nullptr), 0);
+ ASSERT_EQ(__llvm_libc::pthread_mutex_init(&step_lock, nullptr), 0);
+
+ // In this test, we start a new thread but block it before it can make a
+ // step. Once we ensure that the thread is blocked, we unblock it.
+ // After unblocking, we then verify that the thread was indeed unblocked.
+ step = false;
+ started = false;
+ ASSERT_EQ(__llvm_libc::pthread_mutex_lock(&step_lock), 0);
+
+ thrd_t thread;
+ __llvm_libc::thrd_create(&thread, stepper, nullptr);
+
+ while (true) {
+ // Make sure the thread actually started.
+ ASSERT_EQ(__llvm_libc::pthread_mutex_lock(&start_lock), 0);
+ bool s = started;
+ ASSERT_EQ(__llvm_libc::pthread_mutex_unlock(&start_lock), 0);
+ if (s)
+ break;
+ }
+
+ // Since |step_lock| is still locked, |step| should be false.
+ ASSERT_FALSE(step);
+
+ // Unlock the step lock and wait until the step is made.
+ ASSERT_EQ(__llvm_libc::pthread_mutex_unlock(&step_lock), 0);
+
+ while (true) {
+ ASSERT_EQ(__llvm_libc::pthread_mutex_lock(&step_lock), 0);
+ bool current_step_value = step;
+ ASSERT_EQ(__llvm_libc::pthread_mutex_unlock(&step_lock), 0);
+ if (current_step_value)
+ break;
+ }
+
+ int retval = 123;
+ __llvm_libc::thrd_join(&thread, &retval);
+ ASSERT_EQ(retval, 0);
+
+ __llvm_libc::pthread_mutex_destroy(&start_lock);
+ __llvm_libc::pthread_mutex_destroy(&step_lock);
+}
+
+static constexpr int THREAD_COUNT = 10;
+static pthread_mutex_t multiple_waiter_lock;
+static pthread_mutex_t counter_lock;
+static int wait_count = 0;
+
+int waiter_func(void *) {
+ __llvm_libc::pthread_mutex_lock(&counter_lock);
+ ++wait_count;
+ __llvm_libc::pthread_mutex_unlock(&counter_lock);
+
+ // Block on the waiter lock until the main
+ // thread unblocks.
+ __llvm_libc::pthread_mutex_lock(&multiple_waiter_lock);
+ __llvm_libc::pthread_mutex_unlock(&multiple_waiter_lock);
+
+ __llvm_libc::pthread_mutex_lock(&counter_lock);
+ --wait_count;
+ __llvm_libc::pthread_mutex_unlock(&counter_lock);
+
+ return 0;
+}
+
+TEST(LlvmLibcMutexTest, MultipleWaiters) {
+ __llvm_libc::pthread_mutex_init(&multiple_waiter_lock, nullptr);
+ __llvm_libc::pthread_mutex_init(&counter_lock, nullptr);
+
+ __llvm_libc::pthread_mutex_lock(&multiple_waiter_lock);
+ thrd_t waiters[THREAD_COUNT];
+ for (int i = 0; i < THREAD_COUNT; ++i) {
+ __llvm_libc::thrd_create(waiters + i, waiter_func, nullptr);
+ }
+
+ // Spin until the counter is incremented to the desired
+ // value.
+ while (true) {
+ __llvm_libc::pthread_mutex_lock(&counter_lock);
+ if (wait_count == THREAD_COUNT) {
+ __llvm_libc::pthread_mutex_unlock(&counter_lock);
+ break;
+ }
+ __llvm_libc::pthread_mutex_unlock(&counter_lock);
+ }
+
+ __llvm_libc::pthread_mutex_unlock(&multiple_waiter_lock);
+
+ int retval;
+ for (int i = 0; i < THREAD_COUNT; ++i) {
+ __llvm_libc::thrd_join(waiters + i, &retval);
+ }
+
+ ASSERT_EQ(wait_count, 0);
+
+ __llvm_libc::pthread_mutex_destroy(&multiple_waiter_lock);
+ __llvm_libc::pthread_mutex_destroy(&counter_lock);
+}
More information about the libc-commits
mailing list