修复 P2 全部 10 项:错误传播/竞态/门控/文档失真
待办池 docs/待处理内容.md §3.2 的 10 个 P2 全部闭环;逐项落代码 + 注释说明。 P2-1 cfg_file: 受管键行超 CFG_LINE_TEST_MAX 拒绝保存(防重复键行) P2-2 ch395f: DMA 失败传播状态 + 锁存通道故障 + 读不拷不可信数据 P2-7 net_select: LISTENING 不再恒判可读(消除 select 忙轮询地雷) P2-8 time_sync: 核实 L3 pending 改写已闭环(net_recv_to 分片 + 总预算) P2-9 sys_log: 挂载改幂等 + 卷锁,defaultTask 2s 重试建 /log P2-10 sys_log: s_read_raw 纳入卷锁 try(读者/写者 unlink 互斥) P2-11 net_task: RECONFIG 改 osEventFlagsWait 原子取走 + 清除 P2-12 app_cfg: APP_*_ENABLE 如实标注为未接线占位,删“开关”说法 P2-13 freertos: 产品构建 vTaskDelete(testTask) 回收 8KB CCM 栈 P2-15 download.bat: 先删旧日志 + 增“未产出日志”判定 P2-13 用 USER CODE 区回收而非生成区 #if 门控:生成区改动会被 CubeMX 重生成覆盖,本方案重生成不丢。P2-12 因产品定义 B0 未定、APP_NET_ENABLE 无单一接线点,按修复建议备选(删“开关”说法)处理。 验证:@build 0 错 0 警;主机单测 watchdog 39/39 + sys_clock 100/100 + cfg_file 149/149(新增 TC-CFG-044);pre-commit --all-files 17/17。
This commit is contained in:
+45
-4
@@ -16,6 +16,12 @@
|
||||
* v1.3 2026-10-02 王建锋 新增 sys_log_evidence():把看门狗停喂现场
|
||||
* 证据落 /log/wdev.log(掉电不丢)+ flush 诱导
|
||||
* (round 7 纯取证,见 docs/子系统设计/看门狗设计说明.md 2026-10-02 变更记录)
|
||||
* v1.4 2026-10-04 王建锋 P2-9:syslog_mcu_mounted() 改为幂等 + 卷锁保护;
|
||||
* defaultTask 每 2s 复查,建 /log 曾失败时自动重试
|
||||
* (原"仅调用一次"→ 失败后 drain 永久 no-op)。
|
||||
* P2-10:s_read_raw() 纳入卷锁 try 语义,与写者
|
||||
* s_append 的"容量满 unlink 重建"互斥,消除
|
||||
* "UI 读记录(FA_READ) 时文件被 unlink"竞态窗口。
|
||||
*/
|
||||
|
||||
/* 头文件包含区 */
|
||||
@@ -49,6 +55,7 @@ static volatile uint8_t s_preboot_cnt; /* 数组条目数 */
|
||||
static osMessageQueueId_t s_queue; /* 运行期消息队列(syslog_drain 首次调用时惰性创建) */
|
||||
static const osMessageQueueAttr_t s_queue_attr = { .name = "syslog" };
|
||||
static volatile uint8_t s_fs_ready; /* 卷挂载 + /log 目录就绪后置位 */
|
||||
static volatile uint8_t s_mount_fail_reported; /* P2-9:建目录失败日志去重(成功复位) */
|
||||
|
||||
/* 函数定义区 */
|
||||
|
||||
@@ -153,18 +160,28 @@ static int s_append(syslog_id_t id, const char *desc) {
|
||||
* 入口参数:id - 日志 ID syslog_id_t
|
||||
* idx - 记录序号(0 起) uint32_t
|
||||
* p_rec- 输出缓冲(SYSLOG_REC_SIZE 字节,不可为 NULL) uint8_t *
|
||||
* 返回值:0 - 成功;-1 - 越界/读失败 int
|
||||
* 返回值:0 - 成功;-1 - 越界/读失败/卷忙 int
|
||||
* 函数说明:P2-10(2026-10-04):读者纳入卷锁(try),与写者 s_append 的
|
||||
* "容量满 unlink 重建"互斥——原实现读时无锁,写者 unlink 与读者
|
||||
* open/read 可交错,读到的可能是半删除态文件。try 语义(timeout=0):
|
||||
* 本路径可由 uiTask 调用,uiTask 在 required_mask 内、须每 100ms 喂
|
||||
* 心跳,绝不能阻塞等锁;busy = 本次读失败(UI 下轮刷新重读,非故障)。
|
||||
*/
|
||||
static int s_read_raw(syslog_id_t id, uint32_t idx, uint8_t *p_rec) {
|
||||
FIL f;
|
||||
FRESULT fr;
|
||||
UINT br = 0u;
|
||||
int rc;
|
||||
|
||||
if (p_rec == NULL || idx >= syslog_count(id)) {
|
||||
return -1;
|
||||
}
|
||||
if (vol_lock_wait(0u) == 0u) {
|
||||
return -1; /* 卷被占用:本次读失败(非故障,下轮重读) */
|
||||
}
|
||||
fr = f_open(&f, s_paths[id], FA_READ);
|
||||
if (fr != FR_OK) {
|
||||
vol_lock_release();
|
||||
return -1;
|
||||
}
|
||||
fr = f_lseek(&f, (FSIZE_t)idx * SYSLOG_REC_SIZE);
|
||||
@@ -172,7 +189,9 @@ static int s_read_raw(syslog_id_t id, uint32_t idx, uint8_t *p_rec) {
|
||||
fr = f_read(&f, p_rec, SYSLOG_REC_SIZE, &br);
|
||||
}
|
||||
(void)f_close(&f);
|
||||
return (fr == FR_OK && br == SYSLOG_REC_SIZE) ? 0 : -1;
|
||||
rc = (fr == FR_OK && br == SYSLOG_REC_SIZE) ? 0 : -1;
|
||||
vol_lock_release();
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -194,20 +213,42 @@ int syslog_mcu_init(void) {
|
||||
* 函数功能:卷挂载成功后的一次性处理(建 /log 目录 + 写"上电/重启"分类记录)
|
||||
* 入口参数:无
|
||||
* 返回值:无
|
||||
* 限定条件:defaultTask f_mount/f_mkfs 成功且置位 SYS_EVT_STORAGE_READY 前调用一次
|
||||
* 限定条件:defaultTask f_mount/f_mkfs 成功后调用;**可重复调用(幂等)**——
|
||||
* 产品运行期 defaultTask 每 2s 复查一次(见下 P2-9 说明)
|
||||
* 函数说明:P2-9(2026-10-04):原实现"仅调用一次",若此处建 /log 失败则
|
||||
* s_fs_ready 恒 0 → syslog_drain 永久 no-op(运行期日志与自检全部
|
||||
* 滞留/丢弃),且无任何重试。现改为幂等:s_fs_ready 已置位则立即
|
||||
* 返回;否则重试建目录。defaultTask 在 STORAGE_READY 置位后每 2s
|
||||
* 调用本函数——卷已就绪但日志后端未就绪时自动补建目录。
|
||||
* FS 操作纳入卷锁 try:运行期重试时 ftpTask 可能正操作卷,try 失败
|
||||
* = 本轮顺延(下轮再试),绝不阻塞(本任务 = 看门狗喂狗点)。
|
||||
*/
|
||||
void syslog_mcu_mounted(void) {
|
||||
FILINFO finfo;
|
||||
uint32_t last = 0u;
|
||||
const char *desc = "power on";
|
||||
|
||||
if (s_fs_ready != 0u) {
|
||||
return; /* 幂等:已就绪 */
|
||||
}
|
||||
/* 卷锁 try:运行期重试时与 ftpTask 卷访问串行;busy = 本轮顺延 */
|
||||
if (vol_lock_wait(0u) == 0u) {
|
||||
return;
|
||||
}
|
||||
if (f_stat("/log", &finfo) != FR_OK) {
|
||||
FRESULT fr = f_mkdir("/log");
|
||||
if (fr != FR_OK && fr != FR_EXIST) {
|
||||
DBG_ERROR("mkdir /log fail (%d)", (int)fr);
|
||||
/* 失败日志去重:持续失败只报第一次(防 2s 周期刷屏),成功后复位 */
|
||||
if (s_mount_fail_reported == 0u) {
|
||||
s_mount_fail_reported = 1u;
|
||||
DBG_ERROR("mkdir /log fail (%d), will retry", (int)fr);
|
||||
}
|
||||
vol_lock_release();
|
||||
return;
|
||||
}
|
||||
}
|
||||
vol_lock_release();
|
||||
s_mount_fail_reported = 0u;
|
||||
s_fs_ready = 1u;
|
||||
|
||||
/* 上电/重启分类:末条 epoch 距 now < SYSLOG_REBOOT_WINDOW_S → 重启,否则上电 */
|
||||
|
||||
Reference in New Issue
Block a user