46 changes: 22 additions & 24 deletions libc/test/src/pthread/pthread_mutex_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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);
Expand All @@ -38,16 +36,16 @@ int counter(void *arg) {
if (last_count >= MAX)
break;
}
return 0;
return nullptr;
}

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);
pthread_t thread;
__llvm_libc::pthread_create(&thread, nullptr, counter, nullptr);

int last_count = START;
while (true) {
Expand All @@ -65,25 +63,25 @@ TEST(LlvmLibcMutexTest, RelayCounter) {
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) {
Expand All @@ -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.
Expand All @@ -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<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);
Expand All @@ -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);
Expand All @@ -150,17 +148,17 @@ int waiter_func(void *) {
--wait_count;
__llvm_libc::pthread_mutex_unlock(&counter_lock);

return 0;
return nullptr;
}

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];
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
Expand All @@ -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);
Expand Down
56 changes: 56 additions & 0 deletions libc/test/src/pthread/pthread_test.cpp
Original file line number Diff line number Diff line change
@@ -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 <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);
}
}