Skip to content

Commit 8e488c3

Browse files
author
Siva Chandra Reddy
committed
[libc] Add a multi-waiter mutex test.
A corresponding adjustment to mtx_lock has also been made.
1 parent 175139b commit 8e488c3

File tree

2 files changed

+60
-1
lines changed

2 files changed

+60
-1
lines changed

libc/src/threads/linux/mtx_lock.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,16 @@ namespace __llvm_libc {
2121
// The implementation currently handles only plain mutexes.
2222
LLVM_LIBC_FUNCTION(int, mtx_lock, (mtx_t * mutex)) {
2323
FutexData *futex_data = reinterpret_cast<FutexData *>(mutex->__internal_data);
24+
bool was_waiting = false;
2425
while (true) {
2526
uint32_t mutex_status = MS_Free;
2627
uint32_t locked_status = MS_Locked;
2728

28-
if (atomic_compare_exchange_strong(futex_data, &mutex_status, MS_Locked))
29+
if (atomic_compare_exchange_strong(futex_data, &mutex_status, MS_Locked)) {
30+
if (was_waiting)
31+
atomic_store(futex_data, MS_Waiting);
2932
return thrd_success;
33+
}
3034

3135
switch (mutex_status) {
3236
case MS_Waiting:
@@ -35,6 +39,7 @@ LLVM_LIBC_FUNCTION(int, mtx_lock, (mtx_t * mutex)) {
3539
// 4th argument to the syscall function below.)
3640
__llvm_libc::syscall(SYS_futex, futex_data, FUTEX_WAIT_PRIVATE,
3741
MS_Waiting, 0, 0, 0);
42+
was_waiting = true;
3843
// Once woken up/unblocked, try everything all over.
3944
continue;
4045
case MS_Locked:
@@ -47,6 +52,7 @@ LLVM_LIBC_FUNCTION(int, mtx_lock, (mtx_t * mutex)) {
4752
// syscall will block only if the futex data is still `MS_Waiting`.
4853
__llvm_libc::syscall(SYS_futex, futex_data, FUTEX_WAIT_PRIVATE,
4954
MS_Waiting, 0, 0, 0);
55+
was_waiting = true;
5056
}
5157
continue;
5258
case MS_Free:

libc/test/src/threads/mtx_test.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,56 @@ TEST(LlvmLibcMutexTest, WaitAndStep) {
127127
__llvm_libc::thrd_join(&thread, &retval);
128128
ASSERT_EQ(retval, 0);
129129
}
130+
131+
static constexpr int THREAD_COUNT = 10;
132+
static mtx_t multiple_waiter_lock;
133+
static mtx_t counter_lock;
134+
static int wait_count = 0;
135+
136+
int waiter_func(void *) {
137+
__llvm_libc::mtx_lock(&counter_lock);
138+
++wait_count;
139+
__llvm_libc::mtx_unlock(&counter_lock);
140+
141+
// Block on the waiter lock until the main
142+
// thread unblocks.
143+
__llvm_libc::mtx_lock(&multiple_waiter_lock);
144+
__llvm_libc::mtx_unlock(&multiple_waiter_lock);
145+
146+
__llvm_libc::mtx_lock(&counter_lock);
147+
--wait_count;
148+
__llvm_libc::mtx_unlock(&counter_lock);
149+
150+
return 0;
151+
}
152+
153+
TEST(LlvmLibcMutexTest, MultipleWaiters) {
154+
__llvm_libc::mtx_init(&multiple_waiter_lock, mtx_plain);
155+
__llvm_libc::mtx_init(&counter_lock, mtx_plain);
156+
157+
__llvm_libc::mtx_lock(&multiple_waiter_lock);
158+
thrd_t waiters[THREAD_COUNT];
159+
for (int i = 0; i < THREAD_COUNT; ++i) {
160+
__llvm_libc::thrd_create(waiters + i, waiter_func, nullptr);
161+
}
162+
163+
// Spin until the counter is incremented to the desired
164+
// value.
165+
while (true) {
166+
__llvm_libc::mtx_lock(&counter_lock);
167+
if (wait_count == THREAD_COUNT) {
168+
__llvm_libc::mtx_unlock(&counter_lock);
169+
break;
170+
}
171+
__llvm_libc::mtx_unlock(&counter_lock);
172+
}
173+
174+
__llvm_libc::mtx_unlock(&multiple_waiter_lock);
175+
176+
int retval;
177+
for (int i = 0; i < THREAD_COUNT; ++i) {
178+
__llvm_libc::thrd_join(waiters + i, &retval);
179+
}
180+
181+
ASSERT_EQ(wait_count, 0);
182+
}

0 commit comments

Comments
 (0)