8#include <gmock/gmock.h>
9#include <gtest/gtest.h>
21static std::atomic<int> shared_counter{0};
22static std::atomic<int> thread_counter{0};
25class SpinLockTestable :
public SpinLock {
28 explicit SpinLockTestable(
const char* name) :
SpinLock(name) {}
29 SpinLockTestable() =
default;
32class SpinLockTest :
public ::testing::Test {
34 void SetUp()
override {
39 env_state_.InitializeCores(8);
40 env_state_.SetCurrentThreadEnvironment();
41 env_state_.BindThreadToCore(std::this_thread::get_id(), 0);
44 void TearDown()
override {
46 env_state_.ClearCurrentThreadEnvironment();
53TEST_F(SpinLockTest, BasicLockUnlock) {
54 SpinLockTestable lock(
"basic_test");
64TEST_F(SpinLockTest, InterruptControl) {
65 SpinLockTestable lock(
"interrupt_test");
80TEST_F(SpinLockTest, InterruptRestore) {
81 SpinLockTestable lock(
"intr_restore_test");
99TEST_F(SpinLockTest, ConcurrentAccess) {
100 SpinLockTestable lock(
"concurrent_test");
101 const int num_threads = 4;
102 const int increments_per_thread = 1000;
104 std::vector<std::thread> threads;
106 for (
int i = 0; i < num_threads; ++i) {
107 threads.emplace_back([
this, &lock, increments_per_thread, i]() {
108 env_state_.SetCurrentThreadEnvironment();
109 env_state_.BindThreadToCore(std::this_thread::get_id(),
110 i % env_state_.GetCoreCount());
111 for (
int j = 0; j < increments_per_thread; ++j) {
113 int temp = shared_counter.load();
114 std::this_thread::sleep_for(std::chrono::microseconds(1));
115 shared_counter.store(temp + 1);
121 for (
auto& thread : threads) {
126 EXPECT_EQ(shared_counter.load(), num_threads * increments_per_thread);
130TEST_F(SpinLockTest, ConcurrentAccessWithoutLock) {
131 const int num_threads = 4;
132 const int increments_per_thread = 1000;
134 std::vector<std::thread> threads;
136 for (
int i = 0; i < num_threads; ++i) {
137 threads.emplace_back([
this, increments_per_thread, i]() {
138 env_state_.SetCurrentThreadEnvironment();
139 env_state_.BindThreadToCore(std::this_thread::get_id(),
140 i % env_state_.GetCoreCount());
141 for (
int j = 0; j < increments_per_thread; ++j) {
143 int temp = thread_counter.load();
144 std::this_thread::sleep_for(std::chrono::microseconds(1));
145 thread_counter.store(temp + 1);
150 for (
auto& thread : threads) {
156 EXPECT_LE(thread_counter.load(), num_threads * increments_per_thread);
160TEST_F(SpinLockTest, NestedInterruptControl) {
161 SpinLockTestable lock1(
"nested_test1");
162 SpinLockTestable lock2(
"nested_test2");
173 (void)lock2.UnLock();
176 (void)lock1.UnLock();
181TEST_F(SpinLockTest, RecursiveLockDetection) {
182 SpinLockTestable lock(
"recursive_test");
197TEST_F(SpinLockTest, MultipleLockIndependence) {
198 SpinLockTestable lock1(
"independent_test1");
199 SpinLockTestable lock2(
"independent_test2");
205 (void)lock1.UnLock();
210TEST_F(SpinLockTest, PerformanceTest) {
211 SpinLockTestable lock(
"performance_test");
212 const int iterations = 100000;
214 auto start = std::chrono::high_resolution_clock::now();
216 for (
int i = 0; i < iterations; ++i) {
221 auto end = std::chrono::high_resolution_clock::now();
223 std::chrono::duration_cast<std::chrono::microseconds>(
end - start);
226 std::cout << std::format(
227 "SpinLock performance: {} lock/UnLock pairs in {} microseconds\n",
228 iterations, duration.count());
235TEST_F(SpinLockTest, EdgeCases) {
236 SpinLockTestable lock(
"edge_case_test");
239 for (
int i = 0; i < 1000; ++i) {
248TEST_F(SpinLockTest, InterruptDisabledDuringLock) {
249 SpinLockTestable lock(
"interrupt_disabled_test");
266TEST_F(SpinLockTest, FairnessTest) {
267 SpinLockTestable lock(
"fairness_test");
268 std::vector<int> execution_order;
269 std::mutex order_mutex;
270 const int num_threads = 5;
272 std::vector<std::thread> threads;
274 for (
int i = 0; i < num_threads; ++i) {
275 threads.emplace_back([
this, &lock, &execution_order, &order_mutex, i]() {
276 env_state_.SetCurrentThreadEnvironment();
277 env_state_.BindThreadToCore(std::this_thread::get_id(),
278 i % env_state_.GetCoreCount());
279 std::this_thread::sleep_for(std::chrono::milliseconds(i * 10));
283 std::lock_guard<std::mutex> guard(order_mutex);
284 execution_order.push_back(i);
286 std::this_thread::sleep_for(std::chrono::milliseconds(10));
291 for (
auto& thread : threads) {
296 EXPECT_EQ(execution_order.size(), num_threads);
300TEST_F(SpinLockTest, HighLoadPerformance) {
301 SpinLockTestable lock(
"high_load_test");
302 const int num_threads = 8;
303 const int operations_per_thread = 1000;
304 std::atomic<int> total_operations{0};
306 std::vector<std::thread> threads;
308 for (
int i = 0; i < num_threads; ++i) {
309 threads.emplace_back(
310 [
this, &lock, operations_per_thread, &total_operations, i]() {
311 env_state_.SetCurrentThreadEnvironment();
312 env_state_.BindThreadToCore(std::this_thread::get_id(),
313 i % env_state_.GetCoreCount());
314 for (
int j = 0; j < operations_per_thread; ++j) {
316 total_operations.fetch_add(1);
322 for (
auto& thread : threads) {
326 EXPECT_EQ(total_operations.load(), num_threads * operations_per_thread);
330TEST_F(SpinLockTest, NestedInterruptSaveRestore) {
331 SpinLockTestable lock1(
"nested1");
332 SpinLockTestable lock2(
"nested2");
333 SpinLockTestable lock3(
"nested3");
348 (void)lock3.UnLock();
351 (void)lock2.UnLock();
354 (void)lock1.UnLock();
359TEST_F(SpinLockTest, NoContentionSingleThread) {
360 SpinLockTestable lock(
"no_contention");
361 const int iterations = 10000;
363 auto start = std::chrono::high_resolution_clock::now();
365 for (
int i = 0; i < iterations; ++i) {
371 auto end = std::chrono::high_resolution_clock::now();
373 std::chrono::duration_cast<std::chrono::microseconds>(
end - start);
375 EXPECT_EQ(shared_counter.load(), iterations);
377 std::cout << std::format(
378 "Single thread (no contention): {} operations in {} microseconds\n",
379 iterations, duration.count());
383TEST_F(SpinLockTest, LongHoldTime) {
384 SpinLockTestable lock(
"long_hold");
385 std::atomic<bool> lock_held{
false};
386 std::atomic<bool> waiter_started{
false};
387 std::atomic<int> spin_count{0};
389 std::thread holder([
this, &lock, &lock_held, &waiter_started]() {
390 env_state_.SetCurrentThreadEnvironment();
391 env_state_.BindThreadToCore(std::this_thread::get_id(),
392 1 % env_state_.GetCoreCount());
397 while (!waiter_started.load()) {
398 std::this_thread::yield();
402 std::this_thread::sleep_for(std::chrono::milliseconds(50));
406 std::thread waiter([
this, &lock, &lock_held, &spin_count, &waiter_started]() {
407 env_state_.SetCurrentThreadEnvironment();
408 env_state_.BindThreadToCore(std::this_thread::get_id(),
409 2 % env_state_.GetCoreCount());
411 while (!lock_held.load()) {
412 std::this_thread::yield();
415 waiter_started =
true;
418 auto start_time = std::chrono::steady_clock::now();
423 auto end_time = std::chrono::steady_clock::now();
424 auto wait_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
425 end_time - start_time);
428 if (wait_duration.count() > 10) {
429 spin_count.fetch_add(1);
443TEST_F(SpinLockTest, MultipleThreads) {
444 SpinLockTestable lock(
"multi_thread");
445 std::vector<int> thread_results(4, 0);
446 std::vector<std::thread> threads;
448 for (
int i = 0; i < 4; ++i) {
449 threads.emplace_back([
this, &lock, &thread_results, i]() {
450 env_state_.SetCurrentThreadEnvironment();
451 env_state_.BindThreadToCore(std::this_thread::get_id(),
452 i % env_state_.GetCoreCount());
453 for (
int j = 0; j < 100; ++j) {
456 std::this_thread::sleep_for(std::chrono::microseconds(10));
462 for (
auto& thread : threads) {
467 for (
int i = 0; i < 4; ++i) {
473TEST_F(SpinLockTest, StateConsistency) {
474 SpinLockTestable lock(
"consistency");
488 for (
int i = 0; i < 100; ++i) {
__always_inline auto IsLockedByCurrentCore() -> bool
检查当前 core 是否获得此锁
TEST_F(KernelFdtTest, ConstructorTest)
bool GetInterruptStatus()
#define EXPECT_TRUE(cond, msg)
#define EXPECT_LE(val1, val2, msg)
#define EXPECT_LT(val1, val2, msg)
#define EXPECT_FALSE(cond, msg)
#define EXPECT_GT(val1, val2, msg)
#define EXPECT_EQ(val1, val2, msg)