1*0a537a12SSiva Chandra Reddy //===-- Tests for pthread_mutex_t -----------------------------------------===//
2*0a537a12SSiva Chandra Reddy //
3*0a537a12SSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0a537a12SSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information.
5*0a537a12SSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0a537a12SSiva Chandra Reddy //
7*0a537a12SSiva Chandra Reddy //===----------------------------------------------------------------------===//
8*0a537a12SSiva Chandra Reddy 
9*0a537a12SSiva Chandra Reddy #include "src/pthread/pthread_mutex_destroy.h"
10*0a537a12SSiva Chandra Reddy #include "src/pthread/pthread_mutex_init.h"
11*0a537a12SSiva Chandra Reddy #include "src/pthread/pthread_mutex_lock.h"
12*0a537a12SSiva Chandra Reddy #include "src/pthread/pthread_mutex_unlock.h"
13*0a537a12SSiva Chandra Reddy 
14*0a537a12SSiva Chandra Reddy #include "src/pthread/pthread_create.h"
15*0a537a12SSiva Chandra Reddy #include "src/pthread/pthread_join.h"
16*0a537a12SSiva Chandra Reddy 
17*0a537a12SSiva Chandra Reddy #include "utils/IntegrationTest/test.h"
18*0a537a12SSiva Chandra Reddy 
19*0a537a12SSiva Chandra Reddy #include <pthread.h>
20*0a537a12SSiva Chandra Reddy 
21*0a537a12SSiva Chandra Reddy constexpr int START = 0;
22*0a537a12SSiva Chandra Reddy constexpr int MAX = 10000;
23*0a537a12SSiva Chandra Reddy 
24*0a537a12SSiva Chandra Reddy pthread_mutex_t mutex;
25*0a537a12SSiva Chandra Reddy static int shared_int = START;
26*0a537a12SSiva Chandra Reddy 
counter(void * arg)27*0a537a12SSiva Chandra Reddy void *counter(void *arg) {
28*0a537a12SSiva Chandra Reddy   int last_count = START;
29*0a537a12SSiva Chandra Reddy   while (true) {
30*0a537a12SSiva Chandra Reddy     __llvm_libc::pthread_mutex_lock(&mutex);
31*0a537a12SSiva Chandra Reddy     if (shared_int == last_count + 1) {
32*0a537a12SSiva Chandra Reddy       shared_int++;
33*0a537a12SSiva Chandra Reddy       last_count = shared_int;
34*0a537a12SSiva Chandra Reddy     }
35*0a537a12SSiva Chandra Reddy     __llvm_libc::pthread_mutex_unlock(&mutex);
36*0a537a12SSiva Chandra Reddy     if (last_count >= MAX)
37*0a537a12SSiva Chandra Reddy       break;
38*0a537a12SSiva Chandra Reddy   }
39*0a537a12SSiva Chandra Reddy   return nullptr;
40*0a537a12SSiva Chandra Reddy }
41*0a537a12SSiva Chandra Reddy 
relay_counter()42*0a537a12SSiva Chandra Reddy void relay_counter() {
43*0a537a12SSiva Chandra Reddy   ASSERT_EQ(__llvm_libc::pthread_mutex_init(&mutex, nullptr), 0);
44*0a537a12SSiva Chandra Reddy 
45*0a537a12SSiva Chandra Reddy   // The idea of this test is that two competing threads will update
46*0a537a12SSiva Chandra Reddy   // a counter only if the other thread has updated it.
47*0a537a12SSiva Chandra Reddy   pthread_t thread;
48*0a537a12SSiva Chandra Reddy   __llvm_libc::pthread_create(&thread, nullptr, counter, nullptr);
49*0a537a12SSiva Chandra Reddy 
50*0a537a12SSiva Chandra Reddy   int last_count = START;
51*0a537a12SSiva Chandra Reddy   while (true) {
52*0a537a12SSiva Chandra Reddy     ASSERT_EQ(__llvm_libc::pthread_mutex_lock(&mutex), 0);
53*0a537a12SSiva Chandra Reddy     if (shared_int == START) {
54*0a537a12SSiva Chandra Reddy       ++shared_int;
55*0a537a12SSiva Chandra Reddy       last_count = shared_int;
56*0a537a12SSiva Chandra Reddy     } else if (shared_int != last_count) {
57*0a537a12SSiva Chandra Reddy       ASSERT_EQ(shared_int, last_count + 1);
58*0a537a12SSiva Chandra Reddy       ++shared_int;
59*0a537a12SSiva Chandra Reddy       last_count = shared_int;
60*0a537a12SSiva Chandra Reddy     }
61*0a537a12SSiva Chandra Reddy     ASSERT_EQ(__llvm_libc::pthread_mutex_unlock(&mutex), 0);
62*0a537a12SSiva Chandra Reddy     if (last_count > MAX)
63*0a537a12SSiva Chandra Reddy       break;
64*0a537a12SSiva Chandra Reddy   }
65*0a537a12SSiva Chandra Reddy 
66*0a537a12SSiva Chandra Reddy   void *retval = reinterpret_cast<void *>(123);
67*0a537a12SSiva Chandra Reddy   __llvm_libc::pthread_join(thread, &retval);
68*0a537a12SSiva Chandra Reddy   ASSERT_EQ(uintptr_t(retval), uintptr_t(nullptr));
69*0a537a12SSiva Chandra Reddy 
70*0a537a12SSiva Chandra Reddy   __llvm_libc::pthread_mutex_destroy(&mutex);
71*0a537a12SSiva Chandra Reddy }
72*0a537a12SSiva Chandra Reddy 
73*0a537a12SSiva Chandra Reddy pthread_mutex_t start_lock, step_lock;
74*0a537a12SSiva Chandra Reddy bool started, step;
75*0a537a12SSiva Chandra Reddy 
stepper(void * arg)76*0a537a12SSiva Chandra Reddy void *stepper(void *arg) {
77*0a537a12SSiva Chandra Reddy   __llvm_libc::pthread_mutex_lock(&start_lock);
78*0a537a12SSiva Chandra Reddy   started = true;
79*0a537a12SSiva Chandra Reddy   __llvm_libc::pthread_mutex_unlock(&start_lock);
80*0a537a12SSiva Chandra Reddy 
81*0a537a12SSiva Chandra Reddy   __llvm_libc::pthread_mutex_lock(&step_lock);
82*0a537a12SSiva Chandra Reddy   step = true;
83*0a537a12SSiva Chandra Reddy   __llvm_libc::pthread_mutex_unlock(&step_lock);
84*0a537a12SSiva Chandra Reddy   return nullptr;
85*0a537a12SSiva Chandra Reddy }
86*0a537a12SSiva Chandra Reddy 
wait_and_step()87*0a537a12SSiva Chandra Reddy void wait_and_step() {
88*0a537a12SSiva Chandra Reddy   ASSERT_EQ(__llvm_libc::pthread_mutex_init(&start_lock, nullptr), 0);
89*0a537a12SSiva Chandra Reddy   ASSERT_EQ(__llvm_libc::pthread_mutex_init(&step_lock, nullptr), 0);
90*0a537a12SSiva Chandra Reddy 
91*0a537a12SSiva Chandra Reddy   // In this test, we start a new thread but block it before it can make a
92*0a537a12SSiva Chandra Reddy   // step. Once we ensure that the thread is blocked, we unblock it.
93*0a537a12SSiva Chandra Reddy   // After unblocking, we then verify that the thread was indeed unblocked.
94*0a537a12SSiva Chandra Reddy   step = false;
95*0a537a12SSiva Chandra Reddy   started = false;
96*0a537a12SSiva Chandra Reddy   ASSERT_EQ(__llvm_libc::pthread_mutex_lock(&step_lock), 0);
97*0a537a12SSiva Chandra Reddy 
98*0a537a12SSiva Chandra Reddy   pthread_t thread;
99*0a537a12SSiva Chandra Reddy   __llvm_libc::pthread_create(&thread, nullptr, stepper, nullptr);
100*0a537a12SSiva Chandra Reddy 
101*0a537a12SSiva Chandra Reddy   while (true) {
102*0a537a12SSiva Chandra Reddy     // Make sure the thread actually started.
103*0a537a12SSiva Chandra Reddy     ASSERT_EQ(__llvm_libc::pthread_mutex_lock(&start_lock), 0);
104*0a537a12SSiva Chandra Reddy     bool s = started;
105*0a537a12SSiva Chandra Reddy     ASSERT_EQ(__llvm_libc::pthread_mutex_unlock(&start_lock), 0);
106*0a537a12SSiva Chandra Reddy     if (s)
107*0a537a12SSiva Chandra Reddy       break;
108*0a537a12SSiva Chandra Reddy   }
109*0a537a12SSiva Chandra Reddy 
110*0a537a12SSiva Chandra Reddy   // Since |step_lock| is still locked, |step| should be false.
111*0a537a12SSiva Chandra Reddy   ASSERT_FALSE(step);
112*0a537a12SSiva Chandra Reddy 
113*0a537a12SSiva Chandra Reddy   // Unlock the step lock and wait until the step is made.
114*0a537a12SSiva Chandra Reddy   ASSERT_EQ(__llvm_libc::pthread_mutex_unlock(&step_lock), 0);
115*0a537a12SSiva Chandra Reddy 
116*0a537a12SSiva Chandra Reddy   while (true) {
117*0a537a12SSiva Chandra Reddy     ASSERT_EQ(__llvm_libc::pthread_mutex_lock(&step_lock), 0);
118*0a537a12SSiva Chandra Reddy     bool current_step_value = step;
119*0a537a12SSiva Chandra Reddy     ASSERT_EQ(__llvm_libc::pthread_mutex_unlock(&step_lock), 0);
120*0a537a12SSiva Chandra Reddy     if (current_step_value)
121*0a537a12SSiva Chandra Reddy       break;
122*0a537a12SSiva Chandra Reddy   }
123*0a537a12SSiva Chandra Reddy 
124*0a537a12SSiva Chandra Reddy   void *retval = reinterpret_cast<void *>(123);
125*0a537a12SSiva Chandra Reddy   __llvm_libc::pthread_join(thread, &retval);
126*0a537a12SSiva Chandra Reddy   ASSERT_EQ(uintptr_t(retval), uintptr_t(nullptr));
127*0a537a12SSiva Chandra Reddy 
128*0a537a12SSiva Chandra Reddy   __llvm_libc::pthread_mutex_destroy(&start_lock);
129*0a537a12SSiva Chandra Reddy   __llvm_libc::pthread_mutex_destroy(&step_lock);
130*0a537a12SSiva Chandra Reddy }
131*0a537a12SSiva Chandra Reddy 
132*0a537a12SSiva Chandra Reddy static constexpr int THREAD_COUNT = 10;
133*0a537a12SSiva Chandra Reddy static pthread_mutex_t multiple_waiter_lock;
134*0a537a12SSiva Chandra Reddy static pthread_mutex_t counter_lock;
135*0a537a12SSiva Chandra Reddy static int wait_count = 0;
136*0a537a12SSiva Chandra Reddy 
waiter_func(void *)137*0a537a12SSiva Chandra Reddy void *waiter_func(void *) {
138*0a537a12SSiva Chandra Reddy   __llvm_libc::pthread_mutex_lock(&counter_lock);
139*0a537a12SSiva Chandra Reddy   ++wait_count;
140*0a537a12SSiva Chandra Reddy   __llvm_libc::pthread_mutex_unlock(&counter_lock);
141*0a537a12SSiva Chandra Reddy 
142*0a537a12SSiva Chandra Reddy   // Block on the waiter lock until the main
143*0a537a12SSiva Chandra Reddy   // thread unblocks.
144*0a537a12SSiva Chandra Reddy   __llvm_libc::pthread_mutex_lock(&multiple_waiter_lock);
145*0a537a12SSiva Chandra Reddy   __llvm_libc::pthread_mutex_unlock(&multiple_waiter_lock);
146*0a537a12SSiva Chandra Reddy 
147*0a537a12SSiva Chandra Reddy   __llvm_libc::pthread_mutex_lock(&counter_lock);
148*0a537a12SSiva Chandra Reddy   --wait_count;
149*0a537a12SSiva Chandra Reddy   __llvm_libc::pthread_mutex_unlock(&counter_lock);
150*0a537a12SSiva Chandra Reddy 
151*0a537a12SSiva Chandra Reddy   return nullptr;
152*0a537a12SSiva Chandra Reddy }
153*0a537a12SSiva Chandra Reddy 
multiple_waiters()154*0a537a12SSiva Chandra Reddy void multiple_waiters() {
155*0a537a12SSiva Chandra Reddy   __llvm_libc::pthread_mutex_init(&multiple_waiter_lock, nullptr);
156*0a537a12SSiva Chandra Reddy   __llvm_libc::pthread_mutex_init(&counter_lock, nullptr);
157*0a537a12SSiva Chandra Reddy 
158*0a537a12SSiva Chandra Reddy   __llvm_libc::pthread_mutex_lock(&multiple_waiter_lock);
159*0a537a12SSiva Chandra Reddy   pthread_t waiters[THREAD_COUNT];
160*0a537a12SSiva Chandra Reddy   for (int i = 0; i < THREAD_COUNT; ++i) {
161*0a537a12SSiva Chandra Reddy     __llvm_libc::pthread_create(waiters + i, nullptr, waiter_func, nullptr);
162*0a537a12SSiva Chandra Reddy   }
163*0a537a12SSiva Chandra Reddy 
164*0a537a12SSiva Chandra Reddy   // Spin until the counter is incremented to the desired
165*0a537a12SSiva Chandra Reddy   // value.
166*0a537a12SSiva Chandra Reddy   while (true) {
167*0a537a12SSiva Chandra Reddy     __llvm_libc::pthread_mutex_lock(&counter_lock);
168*0a537a12SSiva Chandra Reddy     if (wait_count == THREAD_COUNT) {
169*0a537a12SSiva Chandra Reddy       __llvm_libc::pthread_mutex_unlock(&counter_lock);
170*0a537a12SSiva Chandra Reddy       break;
171*0a537a12SSiva Chandra Reddy     }
172*0a537a12SSiva Chandra Reddy     __llvm_libc::pthread_mutex_unlock(&counter_lock);
173*0a537a12SSiva Chandra Reddy   }
174*0a537a12SSiva Chandra Reddy 
175*0a537a12SSiva Chandra Reddy   __llvm_libc::pthread_mutex_unlock(&multiple_waiter_lock);
176*0a537a12SSiva Chandra Reddy 
177*0a537a12SSiva Chandra Reddy   void *retval;
178*0a537a12SSiva Chandra Reddy   for (int i = 0; i < THREAD_COUNT; ++i) {
179*0a537a12SSiva Chandra Reddy     __llvm_libc::pthread_join(waiters[i], &retval);
180*0a537a12SSiva Chandra Reddy   }
181*0a537a12SSiva Chandra Reddy 
182*0a537a12SSiva Chandra Reddy   ASSERT_EQ(wait_count, 0);
183*0a537a12SSiva Chandra Reddy 
184*0a537a12SSiva Chandra Reddy   __llvm_libc::pthread_mutex_destroy(&multiple_waiter_lock);
185*0a537a12SSiva Chandra Reddy   __llvm_libc::pthread_mutex_destroy(&counter_lock);
186*0a537a12SSiva Chandra Reddy }
187*0a537a12SSiva Chandra Reddy 
main()188*0a537a12SSiva Chandra Reddy int main() {
189*0a537a12SSiva Chandra Reddy   relay_counter();
190*0a537a12SSiva Chandra Reddy   wait_and_step();
191*0a537a12SSiva Chandra Reddy   multiple_waiters();
192*0a537a12SSiva Chandra Reddy   return 0;
193*0a537a12SSiva Chandra Reddy }
194