[libc-commits] [libc] 8e488c3 - [libc] Add a multi-waiter mutex test.
Siva Chandra Reddy via libc-commits
libc-commits at lists.llvm.org
Sun Aug 22 23:01:15 PDT 2021
Author: Siva Chandra Reddy
Date: 2021-08-23T05:47:30Z
New Revision: 8e488c3cc0da71afbe75963033e86bf32ee56c11
URL: https://github.com/llvm/llvm-project/commit/8e488c3cc0da71afbe75963033e86bf32ee56c11
DIFF: https://github.com/llvm/llvm-project/commit/8e488c3cc0da71afbe75963033e86bf32ee56c11.diff
LOG: [libc] Add a multi-waiter mutex test.
A corresponding adjustment to mtx_lock has also been made.
Added:
Modified:
libc/src/threads/linux/mtx_lock.cpp
libc/test/src/threads/mtx_test.cpp
Removed:
################################################################################
diff --git a/libc/src/threads/linux/mtx_lock.cpp b/libc/src/threads/linux/mtx_lock.cpp
index 7ae30a78ba81f..39bd329e9e9a9 100644
--- a/libc/src/threads/linux/mtx_lock.cpp
+++ b/libc/src/threads/linux/mtx_lock.cpp
@@ -21,12 +21,16 @@ namespace __llvm_libc {
// The implementation currently handles only plain mutexes.
LLVM_LIBC_FUNCTION(int, mtx_lock, (mtx_t * mutex)) {
FutexData *futex_data = reinterpret_cast<FutexData *>(mutex->__internal_data);
+ bool was_waiting = false;
while (true) {
uint32_t mutex_status = MS_Free;
uint32_t locked_status = MS_Locked;
- if (atomic_compare_exchange_strong(futex_data, &mutex_status, MS_Locked))
+ if (atomic_compare_exchange_strong(futex_data, &mutex_status, MS_Locked)) {
+ if (was_waiting)
+ atomic_store(futex_data, MS_Waiting);
return thrd_success;
+ }
switch (mutex_status) {
case MS_Waiting:
@@ -35,6 +39,7 @@ LLVM_LIBC_FUNCTION(int, mtx_lock, (mtx_t * mutex)) {
// 4th argument to the syscall function below.)
__llvm_libc::syscall(SYS_futex, futex_data, FUTEX_WAIT_PRIVATE,
MS_Waiting, 0, 0, 0);
+ was_waiting = true;
// Once woken up/unblocked, try everything all over.
continue;
case MS_Locked:
@@ -47,6 +52,7 @@ LLVM_LIBC_FUNCTION(int, mtx_lock, (mtx_t * mutex)) {
// syscall will block only if the futex data is still `MS_Waiting`.
__llvm_libc::syscall(SYS_futex, futex_data, FUTEX_WAIT_PRIVATE,
MS_Waiting, 0, 0, 0);
+ was_waiting = true;
}
continue;
case MS_Free:
diff --git a/libc/test/src/threads/mtx_test.cpp b/libc/test/src/threads/mtx_test.cpp
index 0f3df0ee03849..536ff520c6018 100644
--- a/libc/test/src/threads/mtx_test.cpp
+++ b/libc/test/src/threads/mtx_test.cpp
@@ -127,3 +127,56 @@ TEST(LlvmLibcMutexTest, WaitAndStep) {
__llvm_libc::thrd_join(&thread, &retval);
ASSERT_EQ(retval, 0);
}
+
+static constexpr int THREAD_COUNT = 10;
+static mtx_t multiple_waiter_lock;
+static mtx_t counter_lock;
+static int wait_count = 0;
+
+int waiter_func(void *) {
+ __llvm_libc::mtx_lock(&counter_lock);
+ ++wait_count;
+ __llvm_libc::mtx_unlock(&counter_lock);
+
+ // Block on the waiter lock until the main
+ // thread unblocks.
+ __llvm_libc::mtx_lock(&multiple_waiter_lock);
+ __llvm_libc::mtx_unlock(&multiple_waiter_lock);
+
+ __llvm_libc::mtx_lock(&counter_lock);
+ --wait_count;
+ __llvm_libc::mtx_unlock(&counter_lock);
+
+ return 0;
+}
+
+TEST(LlvmLibcMutexTest, MultipleWaiters) {
+ __llvm_libc::mtx_init(&multiple_waiter_lock, mtx_plain);
+ __llvm_libc::mtx_init(&counter_lock, mtx_plain);
+
+ __llvm_libc::mtx_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::mtx_lock(&counter_lock);
+ if (wait_count == THREAD_COUNT) {
+ __llvm_libc::mtx_unlock(&counter_lock);
+ break;
+ }
+ __llvm_libc::mtx_unlock(&counter_lock);
+ }
+
+ __llvm_libc::mtx_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);
+}
More information about the libc-commits
mailing list