10a537a12SSiva Chandra Reddy //===-- Tests for pthread_mutex_t -----------------------------------------===//
20a537a12SSiva Chandra Reddy //
30a537a12SSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40a537a12SSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information.
50a537a12SSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60a537a12SSiva Chandra Reddy //
70a537a12SSiva Chandra Reddy //===----------------------------------------------------------------------===//
80a537a12SSiva Chandra Reddy
90a537a12SSiva Chandra Reddy #include "src/pthread/pthread_mutex_destroy.h"
100a537a12SSiva Chandra Reddy #include "src/pthread/pthread_mutex_init.h"
110a537a12SSiva Chandra Reddy #include "src/pthread/pthread_mutex_lock.h"
120a537a12SSiva Chandra Reddy #include "src/pthread/pthread_mutex_unlock.h"
130a537a12SSiva Chandra Reddy
140a537a12SSiva Chandra Reddy #include "src/pthread/pthread_create.h"
150a537a12SSiva Chandra Reddy #include "src/pthread/pthread_join.h"
160a537a12SSiva Chandra Reddy
17af1315c2SSiva Chandra Reddy #include "test/IntegrationTest/test.h"
180a537a12SSiva Chandra Reddy
190a537a12SSiva Chandra Reddy #include <pthread.h>
20d9c135cfSGuillaume Chatelet #include <stdint.h> // uintptr_t
210a537a12SSiva Chandra Reddy
220a537a12SSiva Chandra Reddy constexpr int START = 0;
230a537a12SSiva Chandra Reddy constexpr int MAX = 10000;
240a537a12SSiva Chandra Reddy
250a537a12SSiva Chandra Reddy pthread_mutex_t mutex;
260a537a12SSiva Chandra Reddy static int shared_int = START;
270a537a12SSiva Chandra Reddy
counter(void * arg)280a537a12SSiva Chandra Reddy void *counter(void *arg) {
290a537a12SSiva Chandra Reddy int last_count = START;
300a537a12SSiva Chandra Reddy while (true) {
31*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_lock(&mutex);
320a537a12SSiva Chandra Reddy if (shared_int == last_count + 1) {
330a537a12SSiva Chandra Reddy shared_int++;
340a537a12SSiva Chandra Reddy last_count = shared_int;
350a537a12SSiva Chandra Reddy }
36*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_unlock(&mutex);
370a537a12SSiva Chandra Reddy if (last_count >= MAX)
380a537a12SSiva Chandra Reddy break;
390a537a12SSiva Chandra Reddy }
400a537a12SSiva Chandra Reddy return nullptr;
410a537a12SSiva Chandra Reddy }
420a537a12SSiva Chandra Reddy
relay_counter()430a537a12SSiva Chandra Reddy void relay_counter() {
44*b6bc9d72SGuillaume Chatelet ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_init(&mutex, nullptr), 0);
450a537a12SSiva Chandra Reddy
460a537a12SSiva Chandra Reddy // The idea of this test is that two competing threads will update
470a537a12SSiva Chandra Reddy // a counter only if the other thread has updated it.
480a537a12SSiva Chandra Reddy pthread_t thread;
49*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_create(&thread, nullptr, counter, nullptr);
500a537a12SSiva Chandra Reddy
510a537a12SSiva Chandra Reddy int last_count = START;
520a537a12SSiva Chandra Reddy while (true) {
53*b6bc9d72SGuillaume Chatelet ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&mutex), 0);
540a537a12SSiva Chandra Reddy if (shared_int == START) {
550a537a12SSiva Chandra Reddy ++shared_int;
560a537a12SSiva Chandra Reddy last_count = shared_int;
570a537a12SSiva Chandra Reddy } else if (shared_int != last_count) {
580a537a12SSiva Chandra Reddy ASSERT_EQ(shared_int, last_count + 1);
590a537a12SSiva Chandra Reddy ++shared_int;
600a537a12SSiva Chandra Reddy last_count = shared_int;
610a537a12SSiva Chandra Reddy }
62*b6bc9d72SGuillaume Chatelet ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&mutex), 0);
630a537a12SSiva Chandra Reddy if (last_count > MAX)
640a537a12SSiva Chandra Reddy break;
650a537a12SSiva Chandra Reddy }
660a537a12SSiva Chandra Reddy
670a537a12SSiva Chandra Reddy void *retval = reinterpret_cast<void *>(123);
68*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_join(thread, &retval);
690a537a12SSiva Chandra Reddy ASSERT_EQ(uintptr_t(retval), uintptr_t(nullptr));
700a537a12SSiva Chandra Reddy
71*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_destroy(&mutex);
720a537a12SSiva Chandra Reddy }
730a537a12SSiva Chandra Reddy
740a537a12SSiva Chandra Reddy pthread_mutex_t start_lock, step_lock;
750a537a12SSiva Chandra Reddy bool started, step;
760a537a12SSiva Chandra Reddy
stepper(void * arg)770a537a12SSiva Chandra Reddy void *stepper(void *arg) {
78*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_lock(&start_lock);
790a537a12SSiva Chandra Reddy started = true;
80*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_unlock(&start_lock);
810a537a12SSiva Chandra Reddy
82*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_lock(&step_lock);
830a537a12SSiva Chandra Reddy step = true;
84*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_unlock(&step_lock);
850a537a12SSiva Chandra Reddy return nullptr;
860a537a12SSiva Chandra Reddy }
870a537a12SSiva Chandra Reddy
wait_and_step()880a537a12SSiva Chandra Reddy void wait_and_step() {
89*b6bc9d72SGuillaume Chatelet ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_init(&start_lock, nullptr), 0);
90*b6bc9d72SGuillaume Chatelet ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_init(&step_lock, nullptr), 0);
910a537a12SSiva Chandra Reddy
920a537a12SSiva Chandra Reddy // In this test, we start a new thread but block it before it can make a
930a537a12SSiva Chandra Reddy // step. Once we ensure that the thread is blocked, we unblock it.
940a537a12SSiva Chandra Reddy // After unblocking, we then verify that the thread was indeed unblocked.
950a537a12SSiva Chandra Reddy step = false;
960a537a12SSiva Chandra Reddy started = false;
97*b6bc9d72SGuillaume Chatelet ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&step_lock), 0);
980a537a12SSiva Chandra Reddy
990a537a12SSiva Chandra Reddy pthread_t thread;
100*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_create(&thread, nullptr, stepper, nullptr);
1010a537a12SSiva Chandra Reddy
1020a537a12SSiva Chandra Reddy while (true) {
1030a537a12SSiva Chandra Reddy // Make sure the thread actually started.
104*b6bc9d72SGuillaume Chatelet ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&start_lock), 0);
1050a537a12SSiva Chandra Reddy bool s = started;
106*b6bc9d72SGuillaume Chatelet ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&start_lock), 0);
1070a537a12SSiva Chandra Reddy if (s)
1080a537a12SSiva Chandra Reddy break;
1090a537a12SSiva Chandra Reddy }
1100a537a12SSiva Chandra Reddy
1110a537a12SSiva Chandra Reddy // Since |step_lock| is still locked, |step| should be false.
1120a537a12SSiva Chandra Reddy ASSERT_FALSE(step);
1130a537a12SSiva Chandra Reddy
1140a537a12SSiva Chandra Reddy // Unlock the step lock and wait until the step is made.
115*b6bc9d72SGuillaume Chatelet ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&step_lock), 0);
1160a537a12SSiva Chandra Reddy
1170a537a12SSiva Chandra Reddy while (true) {
118*b6bc9d72SGuillaume Chatelet ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&step_lock), 0);
1190a537a12SSiva Chandra Reddy bool current_step_value = step;
120*b6bc9d72SGuillaume Chatelet ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&step_lock), 0);
1210a537a12SSiva Chandra Reddy if (current_step_value)
1220a537a12SSiva Chandra Reddy break;
1230a537a12SSiva Chandra Reddy }
1240a537a12SSiva Chandra Reddy
1250a537a12SSiva Chandra Reddy void *retval = reinterpret_cast<void *>(123);
126*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_join(thread, &retval);
1270a537a12SSiva Chandra Reddy ASSERT_EQ(uintptr_t(retval), uintptr_t(nullptr));
1280a537a12SSiva Chandra Reddy
129*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_destroy(&start_lock);
130*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_destroy(&step_lock);
1310a537a12SSiva Chandra Reddy }
1320a537a12SSiva Chandra Reddy
1330a537a12SSiva Chandra Reddy static constexpr int THREAD_COUNT = 10;
1340a537a12SSiva Chandra Reddy static pthread_mutex_t multiple_waiter_lock;
1350a537a12SSiva Chandra Reddy static pthread_mutex_t counter_lock;
1360a537a12SSiva Chandra Reddy static int wait_count = 0;
1370a537a12SSiva Chandra Reddy
waiter_func(void *)1380a537a12SSiva Chandra Reddy void *waiter_func(void *) {
139*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_lock(&counter_lock);
1400a537a12SSiva Chandra Reddy ++wait_count;
141*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_unlock(&counter_lock);
1420a537a12SSiva Chandra Reddy
1430a537a12SSiva Chandra Reddy // Block on the waiter lock until the main
1440a537a12SSiva Chandra Reddy // thread unblocks.
145*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_lock(&multiple_waiter_lock);
146*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_unlock(&multiple_waiter_lock);
1470a537a12SSiva Chandra Reddy
148*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_lock(&counter_lock);
1490a537a12SSiva Chandra Reddy --wait_count;
150*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_unlock(&counter_lock);
1510a537a12SSiva Chandra Reddy
1520a537a12SSiva Chandra Reddy return nullptr;
1530a537a12SSiva Chandra Reddy }
1540a537a12SSiva Chandra Reddy
multiple_waiters()1550a537a12SSiva Chandra Reddy void multiple_waiters() {
156*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_init(&multiple_waiter_lock, nullptr);
157*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_init(&counter_lock, nullptr);
1580a537a12SSiva Chandra Reddy
159*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_lock(&multiple_waiter_lock);
1600a537a12SSiva Chandra Reddy pthread_t waiters[THREAD_COUNT];
1610a537a12SSiva Chandra Reddy for (int i = 0; i < THREAD_COUNT; ++i) {
162*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_create(waiters + i, nullptr, waiter_func, nullptr);
1630a537a12SSiva Chandra Reddy }
1640a537a12SSiva Chandra Reddy
1650a537a12SSiva Chandra Reddy // Spin until the counter is incremented to the desired
1660a537a12SSiva Chandra Reddy // value.
1670a537a12SSiva Chandra Reddy while (true) {
168*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_lock(&counter_lock);
1690a537a12SSiva Chandra Reddy if (wait_count == THREAD_COUNT) {
170*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_unlock(&counter_lock);
1710a537a12SSiva Chandra Reddy break;
1720a537a12SSiva Chandra Reddy }
173*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_unlock(&counter_lock);
1740a537a12SSiva Chandra Reddy }
1750a537a12SSiva Chandra Reddy
176*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_unlock(&multiple_waiter_lock);
1770a537a12SSiva Chandra Reddy
1780a537a12SSiva Chandra Reddy void *retval;
1790a537a12SSiva Chandra Reddy for (int i = 0; i < THREAD_COUNT; ++i) {
180*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_join(waiters[i], &retval);
1810a537a12SSiva Chandra Reddy }
1820a537a12SSiva Chandra Reddy
1830a537a12SSiva Chandra Reddy ASSERT_EQ(wait_count, 0);
1840a537a12SSiva Chandra Reddy
185*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_destroy(&multiple_waiter_lock);
186*b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::pthread_mutex_destroy(&counter_lock);
1870a537a12SSiva Chandra Reddy }
1880a537a12SSiva Chandra Reddy
TEST_MAIN()18912df3080SSiva Chandra Reddy TEST_MAIN() {
1900a537a12SSiva Chandra Reddy relay_counter();
1910a537a12SSiva Chandra Reddy wait_and_step();
1920a537a12SSiva Chandra Reddy multiple_waiters();
1930a537a12SSiva Chandra Reddy return 0;
1940a537a12SSiva Chandra Reddy }
195