refactor(NET): netMsgQueueHandle 收进 net_socket 私有,改为创建后绑定
结构债 S-2 的最后一步——**该族的 24 处手写跨模块裸 extern 就此全部清零**。 队列对象仍由 CubeMX 在 `MX_FREERTOS_Init()` 创建(**创建点不可外移**: `osKernelInitialize()` 之前的任何创建类 API 会杀死启动,见 `docs/架构设计/项目启动顺序管理.md`);改为创建后立刻在 `Src/freertos.c` 的 `USER CODE BEGIN RTOS_QUEUES` 区调用 `net_msg_queue_adopt(netMsgQueueHandle)`, 把句柄交给唯一使用者。`net_socket.c` 内改用 `static osMessageQueueId_t s_net_msg_queue`(21 处引用改名),BSP 对该全局变量的裸 `extern` 消失——现在 `netMsgQueueHandle` 只出现在生成文件自己的两处(定义 + 创建)。 两个刻意的设计决定: ① **不新建第二个队列**。自建队列 + 删 `.ioc` 里的 netMsgQueue 也能收口,但要 CubeMX 重生成(Ask-first),过渡期还会同时存在两个队列,白占 CCM 堆里 8 × `net_msg_t` 的空间——CCM 正是当下 87.9% 的红线。故选"创建后绑定"。 ② `adopt()` **拒绝重复绑定、保留首次句柄**。真出现两处绑定时,静默换句柄会让 已入队的请求留在旧队列里永不处理;拒掉第二个反而更容易暴露。绑定前的判空 是真实防线:丢了那一行,后果是"所有 net_* 请求被丢弃、网络全线静默不通", 不是崩溃。 **防回退**:`check_cubemx_survival.py` 新增存活项 `net-msgq-adopt`(region `RTOS_QUEUES`、`must_contain=["net_msg_queue_adopt"]`),易失清单 29 → 30 项全部 到位;基线已重建(有意的 USER CODE 区改动,按脚本文档流程 `--write`)。 **体量**:`Code` 213,204 → **213,236 B(+32)**、`ER_IROM1` **231,816 B(22.1%)**; `RW +4 / ZI −4` → `RW_IRAM1` 恒 **75,264 B(57.4%)**、`RW_CCM` 恒 **57,376 B (87.9%)**、`RW+ZI` 总量 132,688 B 不变(没有多占一个字节 RAM)。 **验证**:`@build` 0 错 0 警告;`@test` PASS——624 ms 到 `net init: OK`、`i104: listening on 2404`、无 `[ERR]`/Fault、`heap free=15800 min_ever=8464` 逐项不变。 另在真机跑了一次 FTP 控制通道往返:220 → `USER admin` 331 → `PASS admin` 230 → `PWD` 257 → `TYPE I` 200 → `QUIT` 221。每条命令都是一次过队列的 net_recv/net_send,证明绑定路径真在跑;`.map` 里 `freertos.o(MX_FREERTOS_Init) refers to net_socket.o(i.net_msg_queue_adopt)` 证明镜像含该行。 ⚠ **顺带揪出一条测试工具漂移(本次未修,等定夺)**: `test/host/ftp_up_dl_test.py:123/126` 仍写死 `USER anonymous` / `PASS test@test.com`,而设备自 N-19(2026-10-11)起按 `/config.ini [ftp]` 校验 admin/admin(SHA-256 `pwd_hash`)→ 该脚本必然登录失败。它是手工工具、不在任何 pre-commit 钩子里,所以 11 天没人发现,而 `docs/测试说明/FTP_Test_Guide.md` 把它 列为"推荐入口"。建议加 `--user/--password`(默认 admin/admin),并连 `ftp_speed_test.py` 一起核。 数字联动:两份 `data/` 快照重跑、`ram_baseline --update/--write`、 `check_mem_numbers --write`、FLASH 与任务栈两张配图常量重算并重新生成(逐文本按 字号与锚点复查越界 = 0)、报告 §1.3/§5.1/§5.4 与部署文档 §3.3 同步。报告 §0.4 的 S-2 行按「完成即销项」改写为已闭环,§9 拆出独立 S-2 行标 ✅。 门禁:`@build` 0/0、`@test` PASS、`layer-deps` / `cubemx-survival` / `mem-numbers` (本次改到台账受管区,scan 已过)/ `mem-budget`(57.4% / 87.9%)/ `task-table` / `doc-links --all`(146 文档 0 问题)/ `id-check --strict`(增量拦截通过、可判定 82.84%、存量债 640)全绿;14 个文件字节卫生 BOM 无 / CR 0 / U+FFFD 0 / 无尾空格。 未推送。
This commit is contained in:
@@ -69,12 +69,34 @@ static uint16_t s_dynamic_port = 49152; /* 动态端口分配起始
|
||||
static volatile uint32_t s_net_generation = 0; /* 网络代次号:网络重建完成时递增(服务据此重建监听) */
|
||||
|
||||
/*
|
||||
* 消息队列(线程安全核心)
|
||||
* 消息队列(线程安全核心,句柄由本模块私有持有)
|
||||
* 外部任务经 net_send/net_recv/net_close 等公开 API 投递请求
|
||||
* netTask 调 net_process_messages() 串行处理所有 CH395F 操作
|
||||
* 由 CubeMX 在 MX_FREERTOS_Init()(osKernelInitialize 之后)中创建
|
||||
* 队列对象由 CubeMX 在 MX_FREERTOS_Init()(osKernelInitialize 之后)创建,创建后
|
||||
* 立刻经 net_msg_queue_adopt() 绑定到这里;绑定之前恒为 NULL,各处投递前的判空
|
||||
* 因此是真实防线而不是形式(绑定失败的后果是"请求被丢弃",不是崩溃)。
|
||||
*/
|
||||
extern osMessageQueueId_t netMsgQueueHandle; /* CubeMX 生成的消息队列句柄 */
|
||||
static osMessageQueueId_t s_net_msg_queue;
|
||||
|
||||
/*
|
||||
* 函数功能:绑定消息队列句柄(本模块是该句柄的唯一使用者)
|
||||
* 入口参数:queue_id - 已创建的消息队列句柄
|
||||
* 返回值:0 = 绑定成功;-1 = 句柄为空或重复绑定(保留首次绑定,不覆盖)
|
||||
* 限定条件:osKernelInitialize() 之后、netTask 启动之前,由 MX_FREERTOS_Init() 调用一次
|
||||
* 函数说明:见 net_socket.h 同名声明处的完整说明。重复绑定**不覆盖**是刻意的——
|
||||
* 真出现两处绑定时,说明有人新加了调用点,此时保留先绑的那个并把后来者
|
||||
* 拒掉,比静默换句柄(已入队的请求会留在旧队列里永不处理)更容易暴露。
|
||||
*/
|
||||
int net_msg_queue_adopt(osMessageQueueId_t queue_id) {
|
||||
if (queue_id == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (s_net_msg_queue != NULL) {
|
||||
return -1;
|
||||
}
|
||||
s_net_msg_queue = queue_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================= 错误码存储(E-03 修复:按任务隔离,消除跨任务覆写竞态) =================
|
||||
*
|
||||
@@ -582,7 +604,7 @@ void net_process_messages(void) {
|
||||
net_msg_t msg;
|
||||
|
||||
/* 队列句柄未就绪(net_init 未完成):直接返回 */
|
||||
if (netMsgQueueHandle == NULL) {
|
||||
if (s_net_msg_queue == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -599,7 +621,7 @@ void net_process_messages(void) {
|
||||
net_reconcile_tick();
|
||||
|
||||
/* 队列排空:超时 0 非阻塞取,每条处理一轮,直到本轮队列为空 */
|
||||
while (osMessageQueueGet(netMsgQueueHandle, &msg, NULL, 0) == osOK) {
|
||||
while (osMessageQueueGet(s_net_msg_queue, &msg, NULL, 0) == osOK) {
|
||||
/* 默认处理完即发即时回执;RECV 挂起登记时置 0(回执推迟到
|
||||
* net_pending_tick 完成检查,避免"登记成功"被误报为处理结果) */
|
||||
int do_notify = 1;
|
||||
@@ -1120,7 +1142,7 @@ int net_listen(int sockfd) {
|
||||
}
|
||||
|
||||
/* 消息队列未创建(网络层未初始化)→ 通用错误 */
|
||||
if (netMsgQueueHandle == NULL) {
|
||||
if (s_net_msg_queue == NULL) {
|
||||
return NET_ERR_RETURN_1(NET_ERR);
|
||||
}
|
||||
|
||||
@@ -1136,7 +1158,7 @@ int net_listen(int sockfd) {
|
||||
msg.result = -1;
|
||||
|
||||
/* 入队:队列满时阻塞调用方直至有空位 */
|
||||
if (osMessageQueuePut(netMsgQueueHandle, &msg, 0, osWaitForever) != osOK) {
|
||||
if (osMessageQueuePut(s_net_msg_queue, &msg, 0, osWaitForever) != osOK) {
|
||||
/* 入队失败 → BUSY */
|
||||
return NET_ERR_RETURN_1(NET_ERR_BUSY);
|
||||
}
|
||||
@@ -1284,7 +1306,7 @@ int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen) {
|
||||
}
|
||||
|
||||
/* 消息队列未创建(网络层未初始化)→ 通用错误 */
|
||||
if (netMsgQueueHandle == NULL) {
|
||||
if (s_net_msg_queue == NULL) {
|
||||
return NET_ERR_RETURN_1(NET_ERR);
|
||||
}
|
||||
|
||||
@@ -1304,7 +1326,7 @@ int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen) {
|
||||
msg.result = -1;
|
||||
|
||||
/* 入队:队列满时阻塞调用方直至有空位 */
|
||||
if (osMessageQueuePut(netMsgQueueHandle, &msg, 0, osWaitForever) != osOK) {
|
||||
if (osMessageQueuePut(s_net_msg_queue, &msg, 0, osWaitForever) != osOK) {
|
||||
/* 入队失败 → BUSY */
|
||||
return NET_ERR_RETURN_1(NET_ERR_BUSY);
|
||||
}
|
||||
@@ -1445,7 +1467,7 @@ int net_connect(int sockfd, const struct net_sockaddr *addr, int addrlen) {
|
||||
}
|
||||
|
||||
/* 消息队列未创建(网络层未初始化)→ 通用错误 */
|
||||
if (netMsgQueueHandle == NULL) {
|
||||
if (s_net_msg_queue == NULL) {
|
||||
return NET_ERR_RETURN_1(NET_ERR);
|
||||
}
|
||||
|
||||
@@ -1474,7 +1496,7 @@ int net_connect(int sockfd, const struct net_sockaddr *addr, int addrlen) {
|
||||
msg.result = -1;
|
||||
|
||||
/* 入队:队列满时阻塞调用方直至有空位 */
|
||||
if (osMessageQueuePut(netMsgQueueHandle, &msg, 0, osWaitForever) != osOK) {
|
||||
if (osMessageQueuePut(s_net_msg_queue, &msg, 0, osWaitForever) != osOK) {
|
||||
/* 入队失败 → BUSY */
|
||||
return NET_ERR_RETURN_1(NET_ERR_BUSY);
|
||||
}
|
||||
@@ -2011,9 +2033,9 @@ static int net_drop_conn_locked(net_sock_t *p_sock) {
|
||||
* 限定条件:1. 必须在【非 netTask】上下文中调用(应用/测试任务);若在 netTask 内调用会自己等自己 → 死锁
|
||||
* (netTask 阻塞在 xTaskNotifyWait 而无人处理消息);netTask 内请直接用 net_send_locked()
|
||||
* 2. Socket 须处于 ESTABLISHED 状态
|
||||
* 3. net_init() + MX_FREERTOS_Init() 已执行,netMsgQueueHandle 已由 net_init 创建
|
||||
* 3. net_init() + MX_FREERTOS_Init() 已执行,消息队列已创建并绑定到本模块
|
||||
* 函数说明:1. 所有 CH395F SPI 访问只允许在 netTask 内串行执行(见 TRAP-NET-14)
|
||||
* 2. 本函数不直接触碰 SPI,而是把发送请求打包成 net_msg_t 投递到 netMsgQueueHandle
|
||||
* 2. 本函数不直接触碰 SPI,而是把发送请求打包成 net_msg_t 投递到本模块的消息队列
|
||||
* 3. netTask 的 net_process_messages() 取出并在 netTask 上下文调用 net_send_locked() 真正写 CH395F
|
||||
* 4. 调用方经 FreeRTOS TaskNotify 阻塞等待处理结果,对外呈现"同步发送"语义
|
||||
* 5. 函数返回 = 本次发送已被 netTask 处理完毕(成功或失败)
|
||||
@@ -2031,7 +2053,7 @@ int net_send(int sockfd, const void *buf, int len, int flags) {
|
||||
}
|
||||
|
||||
/* ---- 2. 运行环境检查:消息队列须已创建(网络层已初始化) ---- */
|
||||
if (netMsgQueueHandle == NULL) {
|
||||
if (s_net_msg_queue == NULL) {
|
||||
/* 网络层未初始化 */
|
||||
return NET_ERR_RETURN_1(NET_ERR);
|
||||
}
|
||||
@@ -2055,7 +2077,7 @@ int net_send(int sockfd, const void *buf, int len, int flags) {
|
||||
msg.result = -1;
|
||||
|
||||
/* ---- 4. 入队:将消息投递给 netTask,osWaitForever 表示队列满时阻塞调用方 ---- */
|
||||
if (osMessageQueuePut(netMsgQueueHandle, &msg, 0, osWaitForever) != osOK) {
|
||||
if (osMessageQueuePut(s_net_msg_queue, &msg, 0, osWaitForever) != osOK) {
|
||||
/* 入队失败(队列异常等极端情况) */
|
||||
return NET_ERR_RETURN_1(NET_ERR_BUSY);
|
||||
}
|
||||
@@ -2107,7 +2129,7 @@ int net_recv(int sockfd, void *buf, int len, int flags) {
|
||||
}
|
||||
|
||||
/* 消息队列未创建(网络层未初始化)→ 通用错误 */
|
||||
if (netMsgQueueHandle == NULL) {
|
||||
if (s_net_msg_queue == NULL) {
|
||||
return NET_ERR_RETURN_1(NET_ERR);
|
||||
}
|
||||
|
||||
@@ -2129,7 +2151,7 @@ int net_recv(int sockfd, void *buf, int len, int flags) {
|
||||
msg.result = -1;
|
||||
|
||||
/* 入队:队列满时阻塞调用方直至有空位 */
|
||||
if (osMessageQueuePut(netMsgQueueHandle, &msg, 0, osWaitForever) != osOK) {
|
||||
if (osMessageQueuePut(s_net_msg_queue, &msg, 0, osWaitForever) != osOK) {
|
||||
/* 入队失败 → BUSY */
|
||||
return NET_ERR_RETURN_1(NET_ERR_BUSY);
|
||||
}
|
||||
@@ -2193,7 +2215,7 @@ int net_recv_to(int sockfd, void *buf, int len, uint32_t timeout_ms) {
|
||||
}
|
||||
|
||||
/* ---- 2. 运行环境检查:消息队列须已创建(网络层已初始化) ---- */
|
||||
if (netMsgQueueHandle == NULL) {
|
||||
if (s_net_msg_queue == NULL) {
|
||||
/* 网络层未初始化 */
|
||||
return NET_ERR_RETURN_1(NET_ERR);
|
||||
}
|
||||
@@ -2225,7 +2247,7 @@ int net_recv_to(int sockfd, void *buf, int len, uint32_t timeout_ms) {
|
||||
msg.result = -1;
|
||||
|
||||
/* ---- 5. 入队:将消息投递给 netTask,osWaitForever 表示队列满时阻塞调用方 ---- */
|
||||
if (osMessageQueuePut(netMsgQueueHandle, &msg, 0, osWaitForever) != osOK) {
|
||||
if (osMessageQueuePut(s_net_msg_queue, &msg, 0, osWaitForever) != osOK) {
|
||||
/* 入队失败(队列异常等极端情况) */
|
||||
return NET_ERR_RETURN_1(NET_ERR_BUSY);
|
||||
}
|
||||
@@ -2278,7 +2300,7 @@ int net_close(int sockfd) {
|
||||
}
|
||||
|
||||
/* 消息队列未创建(网络层未初始化)→ 通用错误 */
|
||||
if (netMsgQueueHandle == NULL) {
|
||||
if (s_net_msg_queue == NULL) {
|
||||
return NET_ERR_RETURN_1(NET_ERR);
|
||||
}
|
||||
|
||||
@@ -2294,7 +2316,7 @@ int net_close(int sockfd) {
|
||||
msg.result = -1;
|
||||
|
||||
/* 入队:队列满时阻塞调用方直至有空位 */
|
||||
if (osMessageQueuePut(netMsgQueueHandle, &msg, 0, osWaitForever) != osOK) {
|
||||
if (osMessageQueuePut(s_net_msg_queue, &msg, 0, osWaitForever) != osOK) {
|
||||
/* 入队失败 → BUSY */
|
||||
return NET_ERR_RETURN_1(NET_ERR_BUSY);
|
||||
}
|
||||
@@ -2336,7 +2358,7 @@ int net_drop_conn(int sockfd) {
|
||||
}
|
||||
|
||||
/* 消息队列未创建(网络层未初始化)→ 通用错误 */
|
||||
if (netMsgQueueHandle == NULL) {
|
||||
if (s_net_msg_queue == NULL) {
|
||||
return NET_ERR_RETURN_1(NET_ERR);
|
||||
}
|
||||
|
||||
@@ -2352,7 +2374,7 @@ int net_drop_conn(int sockfd) {
|
||||
msg.result = -1;
|
||||
|
||||
/* 入队:队列满时阻塞调用方直至有空位 */
|
||||
if (osMessageQueuePut(netMsgQueueHandle, &msg, 0, osWaitForever) != osOK) {
|
||||
if (osMessageQueuePut(s_net_msg_queue, &msg, 0, osWaitForever) != osOK) {
|
||||
/* 入队失败 → BUSY */
|
||||
return NET_ERR_RETURN_1(NET_ERR_BUSY);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user