SimpleKernel 1.17.0
Loading...
Searching...
No Matches
mutex_test.cpp
Go to the documentation of this file.
1
5#include "mutex.hpp"
6
7#include <atomic>
8#include <cstddef>
9#include <cstdint>
10
11#include "kernel.h"
12#include "kstd_memory"
13#include "syscall.hpp"
14#include "system_test.h"
16#include "task_manager.hpp"
17
18namespace {
19
20std::atomic<int> g_tests_completed{0};
21std::atomic<int> g_tests_failed{0};
22
23// =========================================================================
24// test_mutex_basic_lock_unlock
25// =========================================================================
26
27void test_mutex_basic_lock_unlock(void* /*arg*/) {
28 klog::Info("=== Mutex Basic Lock/Unlock Test ===");
29
30 Mutex mtx("basic_test");
31 bool passed = true;
32
33 if (mtx.IsLockedByCurrentTask()) {
34 klog::Err("test_mutex_basic: FAIL — mutex locked before Lock()");
35 passed = false;
36 }
37
38 auto lock_result = mtx.Lock();
39 if (!lock_result.has_value()) {
40 klog::Err("test_mutex_basic: FAIL — Lock() returned error");
41 passed = false;
42 }
43
44 if (!mtx.IsLockedByCurrentTask()) {
46 "test_mutex_basic: FAIL — IsLockedByCurrentTask false after Lock");
47 passed = false;
48 }
49
50 auto unlock_result = mtx.UnLock();
51 if (!unlock_result.has_value()) {
52 klog::Err("test_mutex_basic: FAIL — UnLock() returned error");
53 passed = false;
54 }
55
56 if (mtx.IsLockedByCurrentTask()) {
58 "test_mutex_basic: FAIL — IsLockedByCurrentTask true after UnLock");
59 passed = false;
60 }
61
62 if (passed) {
63 klog::Info("Mutex Basic Lock/Unlock Test: PASSED");
64 } else {
65 klog::Err("Mutex Basic Lock/Unlock Test: FAILED");
66 g_tests_failed++;
67 }
68
69 g_tests_completed++;
70 sys_exit(0);
71}
72
73// =========================================================================
74// test_mutex_trylock
75// =========================================================================
76
77struct TryLockArgs {
78 Mutex* mtx;
79 std::atomic<int> holder_locked{0};
80 std::atomic<int> holder_done{0};
81};
82
83void trylock_holder(void* arg) {
84 auto* ctx = reinterpret_cast<TryLockArgs*>(arg);
85 (void)ctx->mtx->Lock();
86 ctx->holder_locked.store(1);
87 (void)sys_sleep(200);
88 (void)ctx->mtx->UnLock();
89 ctx->holder_done.store(1);
90 sys_exit(0);
91}
92
93void test_mutex_trylock(void* /*arg*/) {
94 klog::Info("=== Mutex TryLock Test ===");
95
96 Mutex mtx("trylock_test");
97 bool passed = true;
98
99 auto try_result = mtx.TryLock();
100 if (!try_result.has_value()) {
101 klog::Err("test_mutex_trylock: FAIL — TryLock on free mutex failed");
102 passed = false;
103 }
104 (void)mtx.UnLock();
105
106 TryLockArgs ctx;
107 ctx.mtx = &mtx;
108
109 auto holder = kstd::make_unique<TaskControlBlock>(
110 "TryLockHolder", 10, trylock_holder, reinterpret_cast<void*>(&ctx));
111 TaskManagerSingleton::instance().AddTask(std::move(holder));
112
113 int timeout = 40;
114 while (timeout > 0 && ctx.holder_locked.load() == 0) {
115 (void)sys_sleep(50);
116 timeout--;
117 }
118
119 if (ctx.holder_locked.load() != 1) {
120 klog::Err("test_mutex_trylock: FAIL — holder did not acquire lock");
121 passed = false;
122 } else {
123 auto try_result2 = mtx.TryLock();
124 if (try_result2.has_value()) {
125 klog::Err("test_mutex_trylock: FAIL — TryLock succeeded on held mutex");
126 (void)mtx.UnLock();
127 passed = false;
128 }
129 }
130
131 timeout = 40;
132 while (timeout > 0 && ctx.holder_done.load() == 0) {
133 (void)sys_sleep(50);
134 timeout--;
135 }
136
137 if (passed) {
138 klog::Info("Mutex TryLock Test: PASSED");
139 } else {
140 klog::Err("Mutex TryLock Test: FAILED");
141 g_tests_failed++;
142 }
143
144 g_tests_completed++;
145 sys_exit(0);
146}
147
148// =========================================================================
149// test_mutex_contention
150// =========================================================================
151
152struct ContentionArgs {
153 Mutex* mtx;
154 std::atomic<int>* counter;
155};
156
157void contention_worker(void* arg) {
158 auto* ctx = reinterpret_cast<ContentionArgs*>(arg);
159 for (int i = 0; i < 5; ++i) {
160 (void)ctx->mtx->Lock();
161 int val = ctx->counter->load();
162 (void)sys_sleep(10);
163 ctx->counter->store(val + 1);
164 (void)ctx->mtx->UnLock();
165 }
166 sys_exit(0);
167}
168
169void test_mutex_contention(void* /*arg*/) {
170 klog::Info("=== Mutex Contention Test ===");
171
172 Mutex mtx("contention_test");
173 std::atomic<int> counter{0};
174 bool passed = true;
175
176 ContentionArgs ctx_a;
177 ctx_a.mtx = &mtx;
178 ctx_a.counter = &counter;
179
180 ContentionArgs ctx_b;
181 ctx_b.mtx = &mtx;
182 ctx_b.counter = &counter;
183
184 auto task_a = kstd::make_unique<TaskControlBlock>(
185 "ContentionA", 10, contention_worker, reinterpret_cast<void*>(&ctx_a));
186 auto task_b = kstd::make_unique<TaskControlBlock>(
187 "ContentionB", 10, contention_worker, reinterpret_cast<void*>(&ctx_b));
188
189 TaskManagerSingleton::instance().AddTask(std::move(task_a));
190 TaskManagerSingleton::instance().AddTask(std::move(task_b));
191
192 int timeout = 100;
193 while (timeout > 0 && counter.load() < 10) {
194 (void)sys_sleep(50);
195 timeout--;
196 }
197
198 if (counter.load() != 10) {
199 klog::Err("test_mutex_contention: FAIL — counter={}, expected 10",
200 counter.load());
201 passed = false;
202 }
203
204 if (passed) {
205 klog::Info("Mutex Contention Test: PASSED");
206 } else {
207 klog::Err("Mutex Contention Test: FAILED");
208 g_tests_failed++;
209 }
210
211 g_tests_completed++;
212 sys_exit(0);
213}
214
215// =========================================================================
216// test_mutex_ordering
217// =========================================================================
218
219struct OrderingArgs {
220 Mutex* mtx;
221 std::atomic<int>* sequence;
222 int task_id;
223};
224
225void ordering_first(void* arg) {
226 auto* ctx = reinterpret_cast<OrderingArgs*>(arg);
227 (void)ctx->mtx->Lock();
228 (void)sys_sleep(100);
229 ctx->sequence->store(ctx->task_id);
230 (void)ctx->mtx->UnLock();
231 sys_exit(0);
232}
233
234void ordering_second(void* arg) {
235 auto* ctx = reinterpret_cast<OrderingArgs*>(arg);
236 (void)sys_sleep(30);
237 (void)ctx->mtx->Lock();
238 int prev = ctx->sequence->load();
239 ctx->sequence->store(ctx->task_id);
240 (void)ctx->mtx->UnLock();
241 if (prev != 1) {
242 klog::Err("ordering_second: first writer was {} not 1", prev);
243 }
244 sys_exit(0);
245}
246
247void test_mutex_ordering(void* /*arg*/) {
248 klog::Info("=== Mutex Ordering Test ===");
249
250 Mutex mtx("ordering_test");
251 std::atomic<int> sequence{0};
252 bool passed = true;
253
254 OrderingArgs ctx_first;
255 ctx_first.mtx = &mtx;
256 ctx_first.sequence = &sequence;
257 ctx_first.task_id = 1;
258
259 OrderingArgs ctx_second;
260 ctx_second.mtx = &mtx;
261 ctx_second.sequence = &sequence;
262 ctx_second.task_id = 2;
263
264 auto first_task = kstd::make_unique<TaskControlBlock>(
265 "OrderFirst", 10, ordering_first, reinterpret_cast<void*>(&ctx_first));
266 auto second_task = kstd::make_unique<TaskControlBlock>(
267 "OrderSecond", 10, ordering_second, reinterpret_cast<void*>(&ctx_second));
268
269 TaskManagerSingleton::instance().AddTask(std::move(first_task));
270 TaskManagerSingleton::instance().AddTask(std::move(second_task));
271
272 int timeout = 100;
273 while (timeout > 0 && sequence.load() != 2) {
274 (void)sys_sleep(50);
275 timeout--;
276 }
277
278 if (sequence.load() != 2) {
279 klog::Err("test_mutex_ordering: FAIL — final sequence={}, expected 2",
280 sequence.load());
281 passed = false;
282 }
283
284 if (passed) {
285 klog::Info("Mutex Ordering Test: PASSED");
286 } else {
287 klog::Err("Mutex Ordering Test: FAILED");
288 g_tests_failed++;
289 }
290
291 g_tests_completed++;
292 sys_exit(0);
293}
294
295} // namespace
296
297auto mutex_test() -> bool {
298 klog::Info("=== Mutex System Test Suite ===");
299
300 g_tests_completed = 0;
301 g_tests_failed = 0;
302
303 auto& task_mgr = TaskManagerSingleton::instance();
304
305 auto test1 = kstd::make_unique<TaskControlBlock>(
306 "TestMutexBasic", 10, test_mutex_basic_lock_unlock, nullptr);
307 task_mgr.AddTask(std::move(test1));
308
309 auto test2 = kstd::make_unique<TaskControlBlock>("TestMutexTryLock", 10,
310 test_mutex_trylock, nullptr);
311 task_mgr.AddTask(std::move(test2));
312
313 auto test3 = kstd::make_unique<TaskControlBlock>(
314 "TestMutexContention", 10, test_mutex_contention, nullptr);
315 task_mgr.AddTask(std::move(test3));
316
317 auto test4 = kstd::make_unique<TaskControlBlock>(
318 "TestMutexOrdering", 10, test_mutex_ordering, nullptr);
319 task_mgr.AddTask(std::move(test4));
320
321 constexpr int kExpectedTests = 4;
322 int timeout = 400;
323 while (timeout > 0) {
324 (void)sys_sleep(50);
325 if (g_tests_completed >= kExpectedTests) {
326 break;
327 }
328 timeout--;
329 }
330
331 EXPECT_EQ(g_tests_completed.load(), kExpectedTests,
332 "All mutex tests should complete");
333 EXPECT_EQ(g_tests_failed.load(), 0, "No mutex tests should fail");
334
335 klog::Info("Mutex System Test Suite: COMPLETED");
336 return true;
337}
互斥锁(Mutex)
Definition mutex.hpp:30
auto Lock() -> Expected< void >
获取锁(阻塞)
Definition mutex.cpp:11
auto mutex_test() -> bool
auto Err(etl::format_string< Args... > fmt, Args &&... args) -> void
以 ERROR 级别记录日志
auto Info(etl::format_string< Args... > fmt, Args &&... args) -> void
以 INFO 级别记录日志
auto sys_sleep(uint64_t ms) -> int
休眠指定毫秒数
Definition syscall.cpp:90
auto sys_exit(int code) -> int
退出当前进程或线程
Definition syscall.cpp:75
#define EXPECT_EQ(val1, val2, msg)