xref: /llvm-project/libc/test/integration/src/pthread/pthread_mutex_test.cpp (revision b6bc9d72f65a5086f310f321e969d96e9a559e75)
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