1 //===-- Tests for mtx_t operations ----------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "src/threads/mtx_destroy.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"
16 #include "test/IntegrationTest/test.h"
20 constexpr int START
= 0;
21 constexpr int MAX
= 10000;
24 static int shared_int
= START
;
26 int counter(void *arg
) {
27 int last_count
= START
;
29 LIBC_NAMESPACE::mtx_lock(&mutex
);
30 if (shared_int
== last_count
+ 1) {
32 last_count
= shared_int
;
34 LIBC_NAMESPACE::mtx_unlock(&mutex
);
35 if (last_count
>= MAX
)
41 void relay_counter() {
42 ASSERT_EQ(LIBC_NAMESPACE::mtx_init(&mutex
, mtx_plain
),
43 static_cast<int>(thrd_success
));
45 // The idea of this test is that two competing threads will update
46 // a counter only if the other thread has updated it.
48 LIBC_NAMESPACE::thrd_create(&thread
, counter
, nullptr);
50 int last_count
= START
;
52 ASSERT_EQ(LIBC_NAMESPACE::mtx_lock(&mutex
), static_cast<int>(thrd_success
));
53 if (shared_int
== START
) {
55 last_count
= shared_int
;
56 } else if (shared_int
!= last_count
) {
57 ASSERT_EQ(shared_int
, last_count
+ 1);
59 last_count
= shared_int
;
61 ASSERT_EQ(LIBC_NAMESPACE::mtx_unlock(&mutex
),
62 static_cast<int>(thrd_success
));
68 LIBC_NAMESPACE::thrd_join(thread
, &retval
);
71 LIBC_NAMESPACE::mtx_destroy(&mutex
);
74 mtx_t start_lock
, step_lock
;
77 int stepper(void *arg
) {
78 LIBC_NAMESPACE::mtx_lock(&start_lock
);
80 LIBC_NAMESPACE::mtx_unlock(&start_lock
);
82 LIBC_NAMESPACE::mtx_lock(&step_lock
);
84 LIBC_NAMESPACE::mtx_unlock(&step_lock
);
88 void wait_and_step() {
89 ASSERT_EQ(LIBC_NAMESPACE::mtx_init(&start_lock
, mtx_plain
),
90 static_cast<int>(thrd_success
));
91 ASSERT_EQ(LIBC_NAMESPACE::mtx_init(&step_lock
, mtx_plain
),
92 static_cast<int>(thrd_success
));
94 // In this test, we start a new thread but block it before it can make a
95 // step. Once we ensure that the thread is blocked, we unblock it.
96 // After unblocking, we then verify that the thread was indeed unblocked.
99 ASSERT_EQ(LIBC_NAMESPACE::mtx_lock(&step_lock
),
100 static_cast<int>(thrd_success
));
103 LIBC_NAMESPACE::thrd_create(&thread
, stepper
, nullptr);
106 // Make sure the thread actually started.
107 ASSERT_EQ(LIBC_NAMESPACE::mtx_lock(&start_lock
),
108 static_cast<int>(thrd_success
));
110 ASSERT_EQ(LIBC_NAMESPACE::mtx_unlock(&start_lock
),
111 static_cast<int>(thrd_success
));
116 // Since |step_lock| is still locked, |step| should be false.
119 // Unlock the step lock and wait until the step is made.
120 ASSERT_EQ(LIBC_NAMESPACE::mtx_unlock(&step_lock
),
121 static_cast<int>(thrd_success
));
124 ASSERT_EQ(LIBC_NAMESPACE::mtx_lock(&step_lock
),
125 static_cast<int>(thrd_success
));
126 bool current_step_value
= step
;
127 ASSERT_EQ(LIBC_NAMESPACE::mtx_unlock(&step_lock
),
128 static_cast<int>(thrd_success
));
129 if (current_step_value
)
134 LIBC_NAMESPACE::thrd_join(thread
, &retval
);
135 ASSERT_EQ(retval
, 0);
137 LIBC_NAMESPACE::mtx_destroy(&start_lock
);
138 LIBC_NAMESPACE::mtx_destroy(&step_lock
);
141 static constexpr int THREAD_COUNT
= 10;
142 static mtx_t multiple_waiter_lock
;
143 static mtx_t counter_lock
;
144 static int wait_count
= 0;
146 int waiter_func(void *) {
147 LIBC_NAMESPACE::mtx_lock(&counter_lock
);
149 LIBC_NAMESPACE::mtx_unlock(&counter_lock
);
151 // Block on the waiter lock until the main
153 LIBC_NAMESPACE::mtx_lock(&multiple_waiter_lock
);
154 LIBC_NAMESPACE::mtx_unlock(&multiple_waiter_lock
);
156 LIBC_NAMESPACE::mtx_lock(&counter_lock
);
158 LIBC_NAMESPACE::mtx_unlock(&counter_lock
);
163 void multiple_waiters() {
164 LIBC_NAMESPACE::mtx_init(&multiple_waiter_lock
, mtx_plain
);
165 LIBC_NAMESPACE::mtx_init(&counter_lock
, mtx_plain
);
167 LIBC_NAMESPACE::mtx_lock(&multiple_waiter_lock
);
168 thrd_t waiters
[THREAD_COUNT
];
169 for (int i
= 0; i
< THREAD_COUNT
; ++i
) {
170 LIBC_NAMESPACE::thrd_create(waiters
+ i
, waiter_func
, nullptr);
173 // Spin until the counter is incremented to the desired
176 LIBC_NAMESPACE::mtx_lock(&counter_lock
);
177 if (wait_count
== THREAD_COUNT
) {
178 LIBC_NAMESPACE::mtx_unlock(&counter_lock
);
181 LIBC_NAMESPACE::mtx_unlock(&counter_lock
);
184 LIBC_NAMESPACE::mtx_unlock(&multiple_waiter_lock
);
187 for (int i
= 0; i
< THREAD_COUNT
; ++i
) {
188 LIBC_NAMESPACE::thrd_join(waiters
[i
], &retval
);
191 ASSERT_EQ(wait_count
, 0);
193 LIBC_NAMESPACE::mtx_destroy(&multiple_waiter_lock
);
194 LIBC_NAMESPACE::mtx_destroy(&counter_lock
);