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