/* 两把互斥锁的假实现。宿主机测试是**单线程**的,所以这里模拟的不是并发本身, 而是「加锁纪律」—— 谁拿了、放没放、有没有嵌套、该拿的时候拿了没有。 ⚠️ 单线程 sim 里「等一把别人持有的锁」永远等不到,所以: · 有限超时 → 把虚拟时钟往前拨满 timeout_ms,计一次超时,返回 HAL_ERR_TIMEOUT (这正是真板上等不到锁时该发生的事,调用方的处理路径因此测得到); · HAL_LOCK_FOREVER 且被别人持有 → 直接 abort。那在真板上是死锁, 在这里悄悄返回一个错误码只会把它藏起来。 「谁」是一个假任务号(`sim_lock_set_task()`),默认 0。测试用它扮演第二个任务。 */ #include #include #include "hal_lock.h" #include "sim_hal.h" #define NO_OWNER (-1) static int s_owner[HAL_LOCK_COUNT]; static uint32_t s_takes[HAL_LOCK_COUNT]; static uint32_t s_timeouts[HAL_LOCK_COUNT]; static uint32_t s_violations[HAL_LOCK_COUNT]; static bool s_require[HAL_LOCK_COUNT]; static int s_task; static bool s_inited; static int s_crit_depth; static uint32_t s_crit_enters; static uint32_t s_crit_blocking; void sim_lock_reset_internal(void); /* 只给 sim_hal_reset() 用 */ void sim_lock_reset_internal(void) { for (int i = 0; i < HAL_LOCK_COUNT; i++) { s_owner[i] = NO_OWNER; } memset(s_takes, 0, sizeof(s_takes)); memset(s_timeouts, 0, sizeof(s_timeouts)); memset(s_violations, 0, sizeof(s_violations)); memset(s_require, 0, sizeof(s_require)); s_task = 0; s_inited = false; s_crit_depth = 0; s_crit_enters = 0; s_crit_blocking = 0; } static bool valid(hal_lock_id_t id) { return id >= 0 && id < HAL_LOCK_COUNT; } hal_err_t hal_lock_init(void) { s_inited = true; return HAL_OK; } bool hal_lock_held(hal_lock_id_t id) { return valid(id) && s_owner[id] == s_task; } hal_err_t hal_lock_take(hal_lock_id_t id, uint32_t timeout_ms) { sim_crit_blocking_note(); /* 关着中断去等一把锁:真板上这是把系统钉死 */ if (!valid(id) || !s_inited) { return HAL_ERR_STATE; } /* 已经持有 = 重复加锁(这两把都不是递归锁);持有另一把 = 嵌套,见 hal_lock.h。 */ for (int i = 0; i < HAL_LOCK_COUNT; i++) { if (s_owner[i] == s_task) { return HAL_ERR_STATE; } } if (s_owner[id] != NO_OWNER) { assert(timeout_ms != HAL_LOCK_FOREVER); /* 单线程里死等 = 死锁 */ s_timeouts[id]++; hal_time_delay_ms(timeout_ms); /* 真板上这段时间是等掉的,虚拟时钟也要花掉 */ return HAL_ERR_TIMEOUT; } s_owner[id] = s_task; s_takes[id]++; return HAL_OK; } void hal_lock_give(hal_lock_id_t id) { assert(valid(id)); assert(s_owner[id] == s_task); /* 不是自己拿的 / 根本没人拿 */ s_owner[id] = NO_OWNER; } uint32_t hal_lock_timeouts(hal_lock_id_t id) { return valid(id) ? s_timeouts[id] : 0; } /* ---- 假板子这一侧的控制面 ------------------------------------------------ */ void sim_lock_set_task(int task) { s_task = task; } int sim_lock_task(void) { return s_task; } int sim_lock_owner(hal_lock_id_t id) { return valid(id) ? s_owner[id] : NO_OWNER; } uint32_t sim_lock_takes(hal_lock_id_t id) { return valid(id) ? s_takes[id] : 0; } void sim_lock_require(hal_lock_id_t id, bool on) { if (valid(id)) { s_require[id] = on; } } uint32_t sim_lock_violations(hal_lock_id_t id) { return valid(id) ? s_violations[id] : 0; } void sim_lock_check(hal_lock_id_t id) { if (valid(id) && s_require[id] && !hal_lock_held(id)) { s_violations[id]++; } } /* ---- 临界区(不是第三把锁,见 hal_lock.h) ------------------------------- 单线程 sim 里它没有任何互斥作用 —— 这里模拟的同样是**纪律**: 进出配不配对、里面有没有干会阻塞的事。 */ void hal_crit_enter(void) { s_crit_depth++; s_crit_enters++; } void hal_crit_exit(void) { assert(s_crit_depth > 0); /* 多放一次 = 真板上中断被提前打开,谁也发现不了 */ s_crit_depth--; } void sim_crit_blocking_note(void) { if (s_crit_depth > 0) { s_crit_blocking++; } } int sim_crit_depth(void) { return s_crit_depth; } uint32_t sim_crit_enters(void) { return s_crit_enters; } uint32_t sim_crit_blocking(void) { return s_crit_blocking; }