#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"
#include "src/pthread/pthread_create.h"
#include "src/pthread/pthread_join.h"
#include "test/IntegrationTest/test.h"
#include <pthread.h>
#include <stdint.h>
constexpr int START = 0;
constexpr int MAX = 10000;
pthread_mutex_t mutex;
static int shared_int = START;
void *counter(void *arg) {
int last_count = START;
while (true) {
LIBC_NAMESPACE::pthread_mutex_lock(&mutex);
if (shared_int == last_count + 1) {
shared_int++;
last_count = shared_int;
}
LIBC_NAMESPACE::pthread_mutex_unlock(&mutex);
if (last_count >= MAX)
break;
}
return nullptr;
}
void relay_counter() {
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_init(&mutex, nullptr), 0);
pthread_t thread;
LIBC_NAMESPACE::pthread_create(&thread, nullptr, counter, nullptr);
int last_count = START;
while (true) {
ASSERT_EQ(LIBC_NAMESPACE::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(LIBC_NAMESPACE::pthread_mutex_unlock(&mutex), 0);
if (last_count > MAX)
break;
}
void *retval = reinterpret_cast<void *>(123);
LIBC_NAMESPACE::pthread_join(thread, &retval);
ASSERT_EQ(uintptr_t(retval), uintptr_t(nullptr));
LIBC_NAMESPACE::pthread_mutex_destroy(&mutex);
}
pthread_mutex_t start_lock, step_lock;
bool started, step;
void *stepper(void *arg) {
LIBC_NAMESPACE::pthread_mutex_lock(&start_lock);
started = true;
LIBC_NAMESPACE::pthread_mutex_unlock(&start_lock);
LIBC_NAMESPACE::pthread_mutex_lock(&step_lock);
step = true;
LIBC_NAMESPACE::pthread_mutex_unlock(&step_lock);
return nullptr;
}
void wait_and_step() {
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_init(&start_lock, nullptr), 0);
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_init(&step_lock, nullptr), 0);
step = false;
started = false;
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&step_lock), 0);
pthread_t thread;
LIBC_NAMESPACE::pthread_create(&thread, nullptr, stepper, nullptr);
while (true) {
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&start_lock), 0);
bool s = started;
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&start_lock), 0);
if (s)
break;
}
ASSERT_FALSE(step);
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&step_lock), 0);
while (true) {
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&step_lock), 0);
bool current_step_value = step;
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&step_lock), 0);
if (current_step_value)
break;
}
void *retval = reinterpret_cast<void *>(123);
LIBC_NAMESPACE::pthread_join(thread, &retval);
ASSERT_EQ(uintptr_t(retval), uintptr_t(nullptr));
LIBC_NAMESPACE::pthread_mutex_destroy(&start_lock);
LIBC_NAMESPACE::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;
void *waiter_func(void *) {
LIBC_NAMESPACE::pthread_mutex_lock(&counter_lock);
++wait_count;
LIBC_NAMESPACE::pthread_mutex_unlock(&counter_lock);
LIBC_NAMESPACE::pthread_mutex_lock(&multiple_waiter_lock);
LIBC_NAMESPACE::pthread_mutex_unlock(&multiple_waiter_lock);
LIBC_NAMESPACE::pthread_mutex_lock(&counter_lock);
--wait_count;
LIBC_NAMESPACE::pthread_mutex_unlock(&counter_lock);
return nullptr;
}
void multiple_waiters() {
LIBC_NAMESPACE::pthread_mutex_init(&multiple_waiter_lock, nullptr);
LIBC_NAMESPACE::pthread_mutex_init(&counter_lock, nullptr);
LIBC_NAMESPACE::pthread_mutex_lock(&multiple_waiter_lock);
pthread_t waiters[THREAD_COUNT];
for (int i = 0; i < THREAD_COUNT; ++i) {
LIBC_NAMESPACE::pthread_create(waiters + i, nullptr, waiter_func, nullptr);
}
while (true) {
LIBC_NAMESPACE::pthread_mutex_lock(&counter_lock);
if (wait_count == THREAD_COUNT) {
LIBC_NAMESPACE::pthread_mutex_unlock(&counter_lock);
break;
}
LIBC_NAMESPACE::pthread_mutex_unlock(&counter_lock);
}
LIBC_NAMESPACE::pthread_mutex_unlock(&multiple_waiter_lock);
void *retval;
for (int i = 0; i < THREAD_COUNT; ++i) {
LIBC_NAMESPACE::pthread_join(waiters[i], &retval);
}
ASSERT_EQ(wait_count, 0);
LIBC_NAMESPACE::pthread_mutex_destroy(&multiple_waiter_lock);
LIBC_NAMESPACE::pthread_mutex_destroy(&counter_lock);
}
TEST_MAIN() {
relay_counter();
wait_and_step();
multiple_waiters();
return 0;
}