diff --git a/App/log/sys_log_mcu.c b/App/log/sys_log_mcu.c index 419390d8..1c6b84cc 100644 --- a/App/log/sys_log_mcu.c +++ b/App/log/sys_log_mcu.c @@ -7,6 +7,8 @@ * 创建日期:2026-09-14 * 修改记录: * v1.0 2026-09-14 王建锋 创建初始版本(设计见 docs/运行与自检记录设计说明.md §4.4) + * v1.1 2026-09-21 王建锋 消息队列改为内核启动后由 syslog_drain 惰性创建 + * (修复 osKernelStart 前创建 FreeRTOS 内核对象导致的启动失败) */ /* 头文件包含区 */ @@ -36,7 +38,8 @@ typedef struct { static syslog_entry_t s_preboot[SYSLOG_QUEUE_MAX]; /* 启动前待发数组(RTOS 前单生产者/后单消费者,免锁) */ static volatile uint8_t s_preboot_cnt; /* 数组条目数 */ -static osMessageQueueId_t s_queue; /* 运行期消息队列(syslog_mcu_init 创建) */ +static osMessageQueueId_t s_queue; /* 运行期消息队列(syslog_drain 首次调用时惰性创建) */ +static const osMessageQueueAttr_t s_queue_attr = { .name = "syslog" }; static volatile uint8_t s_fs_ready; /* 卷挂载 + /log 目录就绪后置位 */ /* 函数定义区 */ @@ -128,19 +131,17 @@ static int s_read_raw(syslog_id_t id, uint32_t idx, uint8_t *p_rec) { } /* - * 函数功能:日志引擎初始化(创建 FreeRTOS 消息队列) + * 函数功能:日志引擎初始化(内核启动前安全空操作) * 入口参数:无 - * 返回值:0 - 成功;-1 - 队列创建失败 int - * 限定条件:app_main_init() 起始处调用,先于任何 syslog_post() + * 返回值:0 - 成功 int + * 限定条件:app_main_init() 起始处调用(osKernelStart 之前); + * 不得调用任何 FreeRTOS API(内核对象须在内核启动后才可创建) + * 函数说明:启动前投递走 s_preboot 静态数组(syslog_post 按内核状态自动分流); + * FreeRTOS 消息队列由 syslog_drain 在运行期(defaultTask 上下文)惰性创建。 + * 历史缺陷:此处曾 osMessageQueueNew 创建队列,早于 osKernelInitialize + * 提前拉起内核,其后任务创建在未完成初始化的内核状态上执行,导致启动失败 */ int syslog_mcu_init(void) { - static const osMessageQueueAttr_t s_queue_attr = { .name = "syslog" }; - - s_queue = osMessageQueueNew(SYSLOG_QUEUE_MAX, sizeof(syslog_entry_t), &s_queue_attr); - if (s_queue == NULL) { - DBG_ERROR("queue create fail"); - return -1; - } return 0; } @@ -175,7 +176,7 @@ void syslog_mcu_mounted(void) { } /* - * 函数功能:排空待发日志并落盘(启动前数组 + 运行期队列,FIFO) + * 函数功能:排空待发日志并落盘(启动前数组 + 运行期队列,FIFO);首次调用时惰性创建运行期队列 * 入口参数:无 * 返回值:无 * 限定条件:仅 defaultTask(唯一写者)调用;卷未就绪时直接返回(条目滞留待重试) @@ -183,6 +184,14 @@ void syslog_mcu_mounted(void) { void syslog_drain(void) { syslog_entry_t e; + /* 运行期惰性创建消息队列:本函数仅由 defaultTask(调度器运行中)调用, + 保证内核对象创建发生在 osKernelStart 之后 */ + if (s_queue == NULL) { + s_queue = osMessageQueueNew(SYSLOG_QUEUE_MAX, sizeof(syslog_entry_t), &s_queue_attr); + if (s_queue == NULL) { + DBG_ERROR("queue create fail"); + } + } if (!s_fs_ready || s_queue == NULL) { return; }