[libc] Add simple implementations of mtx_lock and mtx_unlock.
[lldb.git] / libc / test / src / threads / mtx_test.cpp
1 //===---------------------- Unittests for mtx_t ---------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "include/threads.h"
10 #include "src/threads/mtx_init.h"
11 #include "src/threads/mtx_lock.h"
12 #include "src/threads/mtx_unlock.h"
13 #include "src/threads/thrd_create.h"
14 #include "src/threads/thrd_join.h"
15 #include "utils/UnitTest/Test.h"
16
17 constexpr int START = 0;
18 constexpr int MAX = 10000;
19
20 mtx_t mutex;
21 static int shared_int = START;
22
23 int counter(void *arg) {
24   int last_count = START;
25   while (true) {
26     __llvm_libc::mtx_lock(&mutex);
27     if (shared_int == last_count + 1) {
28       shared_int++;
29       last_count = shared_int;
30     }
31     __llvm_libc::mtx_unlock(&mutex);
32     if (last_count >= MAX)
33       break;
34   }
35   return 0;
36 }
37
38 TEST(MutexTest, RelayCounter) {
39   // The idea of this test is that two competing threads will update
40   // a counter only if the other thread has updated it.
41   thrd_t thread;
42   __llvm_libc::thrd_create(&thread, counter, nullptr);
43
44   int last_count = START;
45   while (true) {
46     ASSERT_EQ(__llvm_libc::mtx_lock(&mutex), (int)thrd_success);
47     if (shared_int == START) {
48       ++shared_int;
49       last_count = shared_int;
50     } else if (shared_int != last_count) {
51       ASSERT_EQ(shared_int, last_count + 1);
52       ++shared_int;
53       last_count = shared_int;
54     }
55     ASSERT_EQ(__llvm_libc::mtx_unlock(&mutex), (int)thrd_success);
56     if (last_count > MAX)
57       break;
58   }
59
60   int retval = 123;
61   __llvm_libc::thrd_join(&thread, &retval);
62   ASSERT_EQ(retval, 0);
63 }
64
65 mtx_t start_lock, step_lock;
66 bool start, step;
67
68 int stepper(void *arg) {
69   __llvm_libc::mtx_lock(&start_lock);
70   start = true;
71   __llvm_libc::mtx_unlock(&start_lock);
72
73   __llvm_libc::mtx_lock(&step_lock);
74   step = true;
75   __llvm_libc::mtx_unlock(&step_lock);
76   return 0;
77 }
78
79 TEST(MutexTest, WaitAndStep) {
80   // In this test, we start a new thread but block it before it can make a
81   // step. Once we ensure that the thread is blocked, we unblock it.
82   // After unblocking, we then verify that the thread was indeed unblocked.
83   step = false;
84   start = false;
85   ASSERT_EQ(__llvm_libc::mtx_lock(&step_lock), (int)thrd_success);
86
87   thrd_t thread;
88   __llvm_libc::thrd_create(&thread, stepper, nullptr);
89
90   while (true) {
91     // Make sure the thread actually started.
92     ASSERT_EQ(__llvm_libc::mtx_lock(&start_lock), (int)thrd_success);
93     bool s = start;
94     ASSERT_EQ(__llvm_libc::mtx_unlock(&start_lock), (int)thrd_success);
95     if (s)
96       break;
97   }
98
99   // Since |step_lock| is still locked, |step| should be false.
100   ASSERT_FALSE(step);
101
102   // Unlock the step lock and wait until the step is made.
103   ASSERT_EQ(__llvm_libc::mtx_unlock(&step_lock), (int)thrd_success);
104
105   while (true) {
106     ASSERT_EQ(__llvm_libc::mtx_lock(&step_lock), (int)thrd_success);
107     bool current_step_value = step;
108     ASSERT_EQ(__llvm_libc::mtx_unlock(&step_lock), (int)thrd_success);
109     if (current_step_value)
110       break;
111   }
112
113   int retval = 123;
114   __llvm_libc::thrd_join(&thread, &retval);
115   ASSERT_EQ(retval, 0);
116 }