diff --git a/Drivers/BSP/NET/README.md b/Drivers/BSP/NET/README.md index 786da781..6e241e79 100644 --- a/Drivers/BSP/NET/README.md +++ b/Drivers/BSP/NET/README.md @@ -60,5 +60,6 @@ - 上层用法:`docs/网络/BSD_Socket_API_使用指南.md` - 内部调用关系:`docs/网络/BSD_Socket_API_函数调用关系.md` -- 演进方案:`docs/问题记录/Net层阻塞模型业界对照与演进方案.md` +- 实施记录:`docs/问题记录/Net层阻塞模型改造实施记录.md`(E-02 pending 化) +- 二期设计基线:`docs/审查记录/下一步任务规划.md` §3.1 - 测试:`docs/测试说明/CH395F_Test_Guide.md`、`docs/测试说明/FTP_Test_Guide.md` diff --git a/Drivers/BSP/README.md b/Drivers/BSP/README.md index a75fcc93..9cf14576 100644 --- a/Drivers/BSP/README.md +++ b/Drivers/BSP/README.md @@ -12,7 +12,7 @@ | `TPAFE5160/` | TPAFE5160 高精度 ADC | 并行 16 位 | ADC 采样驱动(CONVST/BUSY 时序) | — | | `SD2506/` | SD2506 RTC | I2C | 实时时钟驱动 | `docs/问题记录/SD2506_Trap_Records.md` | | `RS485/` | RS-485 半双工 | UART5 | 收发方向控制(DE 引脚)+ 时序 | — | -| `NET/` | BSD Socket 网络抽象层 | — | Socket API + select + 轻量 FTP 服务器 | `docs/网络/`、`docs/问题记录/Net层阻塞模型业界对照与演进方案.md` | +| `NET/` | BSD Socket 网络抽象层 | — | Socket API + select + 轻量 FTP 服务器 | `docs/网络/`、`docs/问题记录/Net层阻塞模型改造实施记录.md` | | `NETCFG/` | 网络配置 | — | `/config.ini` 网络段的加载/保存 + 旧档迁移 | `docs/子系统设计/网络配置说明.md` | | `UI/` | LVGL UI 组件 | — | 菜单/内容页/组件/中文字体 | `docs/UI设计/` | diff --git a/docs/README.md b/docs/README.md index 4c53bb44..8a25039b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -147,7 +147,7 @@ docs/ | [`CH395F_Trap_Records.md`](问题记录/CH395F_Trap_Records.md) | CH395F 以太网控制器陷阱台账 | | [`GD5F2GQ5UE_Trap_Records.md`](问题记录/GD5F2GQ5UE_Trap_Records.md) | GD5F2GQ5UE SPI NAND 陷阱台账 | | [`SD2506_Trap_Records.md`](问题记录/SD2506_Trap_Records.md) | SD2506 RTC 陷阱台账 | -| [`Net层阻塞模型业界对照与演进方案.md`](问题记录/Net层阻塞模型业界对照与演进方案.md) | Net 层阻塞模型与业界方案对照 | +| [`Net层阻塞模型改造实施记录.md`](问题记录/Net层阻塞模型改造实施记录.md) | E-02 阻塞模型改造客观实施记录(一期 pending 化:偏差/门禁实测/未执行项) | | [`错误码传播审计.md`](问题记录/错误码传播审计.md) | 错误码传播缺陷审计(9 类模式 × 子系统) | --- diff --git a/docs/审查记录/下一步任务规划.md b/docs/审查记录/下一步任务规划.md index 1f0a25fa..a6be2839 100644 --- a/docs/审查记录/下一步任务规划.md +++ b/docs/审查记录/下一步任务规划.md @@ -78,7 +78,7 @@ | 序 | 任务 | 说明 | 出处 | |---|---|---|---| -| **C1** | **pending 二期(ACCEPT + SEND)** | 沿一期机制扩展;同期消化 E-25(net_select 语义)、E-24/E-27/E-28(跨上下文收口);基线重锁 + 探针族扩充 + 看门狗接 selftest | 第二档 #2 / N-4 | +| **C1** | **pending 二期(ACCEPT + SEND)** | 沿一期机制扩展;同期消化 E-25(net_select 语义)、E-24/E-27/E-28(跨上下文收口);基线重锁 + 探针族扩充 + 看门狗接 selftest。**设计基线见下方 §2.1** | 第二档 #2 / N-4 | | **C2** | **GD5F 错误通道统一** | E-10/E-42/E-53/E-54/E-56/E-57 一次做齐:`wait_busy` 区分超时/真故障、`bbt_scan` 失败**放弃持久化**(保护好副本)、init 全链路检查 + 重试、回读 B0h 校验 ECC | 第二档 #1 | | **C3** | **存储侧日志管线**(消化 N-2) | 49s 全系统日志静默的复现与定位(NAND GC 长尾 vs UART 卡滞)+ 队列满丢弃计数/告警(现静默丢行);与 S8(非阻塞日志)合并评估 | N-2 / S-1 | | **C4** | **defaultTask 栈余量**(S-1) | 2872B/4096(余量 29.9%,差 4.8B 未达 30% 判据)→ 栈 4096→4608(CCM 堆余量可覆盖)或 GC 链局部削减 | S-1 | @@ -113,6 +113,42 @@ --- +## 3.1 C1 设计基线(pending 二期:ACCEPT + SEND) + +> **来源**:从已归档的《Net 层阻塞模型业界对照与演进方案》(2026-09-26 删除)中抽取—— +> 该文档的调研/规划部分已完成使命,客观实施部分另存为 +> `docs/问题记录/Net层阻塞模型改造实施记录.md`;本节仅保留**二期仍要用的设计基线**。 + +**一期已验证的机制骨架**(二期沿用,勿重新发明):独立静态 pending 表 + `net_pending_tick` +主循环节拍了结(五路:数据/到点/断连/同 fd 串行/重建取消必通知)+ 登记守卫(每 fd 至多一个、 +不覆盖、拒绝 netTask 自等待)+ 1s 看门狗强结算。 + +**二期扩展点**: + +| 项 | 目标 | 对应缺陷 | +|---|---|---| +| **ACCEPT pending** | accept 等待改为"登记 → CONNECT 事件完成",退役 100ms/200ms 轮询循环 | E-06(accept 轮询计时失真) | +| **SEND pending** | 发送续传改为"登记 → send_ready 完成",消除 1s/分片 stall 对队列的冻结 | E-02 残余(SEND 位置) | + +**二期门禁**(一期门禁的加强版): + +1. CH395F NET 层全套件(含一期未跑的 Phase 7 / Phase 10,视 RAM 预算); +2. L3/L5 基线重锁(一期已重锁 M3,二期须再锁); +3. `e02_probe.py` **探针族扩充**:close / reconfig / EOF / disconnect-during-pending 四专项; +4. `ftp_regression.py`(D20)+ E-06 假 425 场景**独立重跑**(一期是借 M3 压力档覆盖的); +5. UI 远端推流压力 + timeSync 三场景; +6. 产品 `@test` 闭环 + ST-LINK 全片回读; +7. `ram_report.py` / `stack_report.py` 前后对比(铁律); +8. 看门狗接 selftest 留痕 + 模拟器差距清单 +1(`net_socket_sim.c` 无法建模 pending)。 + +**已知代价(延续一期,需文档化)**:pending 完成判定随主循环节拍运行,被长操作占用时超时 +顺延(~1ms 级);二期把 SEND 也 pending 化后,该顺延面反而**收窄**。 + +**改动量估算**:再 ~300-500 行,集中在 `net_socket.c`;公开 API 不变。风险评级**中** +(执行器核心 + D 系列前科)——**大的是验证,不是代码**。 + +--- + ## 4. 诊断基线(供后续对照) | 项 | 当前值 | 出处 | diff --git a/docs/待处理内容.md b/docs/待处理内容.md index b70ed9e2..e456346e 100644 --- a/docs/待处理内容.md +++ b/docs/待处理内容.md @@ -24,4 +24,4 @@ | # | 事项 | 说明 | 出处 | |---|---|---|---| -| N-4 | **pending 机制二期:ACCEPT + SEND 阻塞路径 pending 化**——E-06(accept 轮询计时失真)、E-20(lftpd 控制通道 errno 分类/501)、E-21(timeSync errno 分级)剩余分量共用该机制扩展;届时 L3/L5 基线再重锁、探针族扩充(close/reconfig/EOF/disconnect-during-pending)、看门狗接 selftest 留痕、模拟器差距清单 +1 | 一期(RECV)已落地并入主线:`a45c0cb`(+文档闭环 `7ff2958`);设计基线与门禁结果见 `docs/问题记录/Net层阻塞模型业界对照与演进方案.md` §6.7 | 同左 + `错误码传播审计.md` 第二档 #2 | +| N-4 | **pending 机制二期:ACCEPT + SEND 阻塞路径 pending 化**——E-06(accept 轮询计时失真)、E-20(lftpd 控制通道 errno 分类/501)、E-21(timeSync errno 分级)剩余分量共用该机制扩展;届时 L3/L5 基线再重锁、探针族扩充(close/reconfig/EOF/disconnect-during-pending)、看门狗接 selftest 留痕、模拟器差距清单 +1 | 一期(RECV)已落地并入主线:`a45c0cb`(+文档闭环 `7ff2958`);设计基线与门禁见 `下一步任务规划.md` §3.1,实施记录见 `Net层阻塞模型改造实施记录.md` | 同左 + `错误码传播审计.md` 第二档 #2 | diff --git a/docs/网络/BSD_Socket_API_函数调用关系.md b/docs/网络/BSD_Socket_API_函数调用关系.md index 1086fc39..8a68441e 100644 --- a/docs/网络/BSD_Socket_API_函数调用关系.md +++ b/docs/网络/BSD_Socket_API_函数调用关系.md @@ -383,7 +383,7 @@ sequenceDiagram - `docs/网络/BSD_Socket_API_使用指南.md` —— 公开 API 语义、示例、常见问题(本文的上半部) - `docs/问题记录/CH395F_Trap_Records.md` —— Trap 01~23 机制细节(本文引用处) -- `docs/问题记录/Net层阻塞模型业界对照与演进方案.md` —— L3 pending 化的设计推演 +- `docs/问题记录/Net层阻塞模型改造实施记录.md` —— L3 pending 化的实施记录(偏差/门禁实测/未执行项) - `docs/问题记录/错误码传播审计.md` —— E-02 头阻塞与错误码回传全审计 - `docs/测试说明/链路延迟测试说明.md` —— D1/D10/L3/D14 等时延探针与自愈路径的台架证据 - `docs/子系统设计/网络配置说明.md` §4 —— 代次号与网络重建时序 diff --git a/docs/问题记录/Net层阻塞模型业界对照与演进方案.md b/docs/问题记录/Net层阻塞模型业界对照与演进方案.md deleted file mode 100644 index 21456766..00000000 --- a/docs/问题记录/Net层阻塞模型业界对照与演进方案.md +++ /dev/null @@ -1,332 +0,0 @@ -# Net 层阻塞模型:业界对照与演进方案 - -> **模块名称**:Net 层(net_socket / netTask)阻塞等待模型 -> **文档目的**:E-02 修复(2026-09-22)的配套调研留档——本项目已落地的"pending 请求"形态 -> 与主流开源/成熟项目模式的对照,及二期(ACCEPT/SEND)的设计基线。 -> **当前状态(2026-09-26 复核)**:**一期(RECV pending 化)已实施、已并入主线 `v2-on-ui`、 -> 已推送远程**——落地提交 `a45c0cb`(实现)+ `7ff2958`(文档闭环)。实现与设计基线的偏差、 -> 门禁逐条结果与实测数据见 **§6.7**。二期(ACCEPT/SEND)未动,设计基线见 §6.1,按 §7 排期。 -> **日期**:2026-09-22(2026-09-26 复核修订) -> **配套文档**:`错误码传播审计.md`(E-02 明细 / 修复计划 / 已闭环记录)、`docs/测试说明/链路延迟测试说明.md` -> (M3 基线 / §8.3 实现要点 / §9 故障对照)、`AGENTS.md`(SPI 铁律 / 就绪屏障 / 内存预算) - ---- - -## 1. 结论速览 - -1. **已落地的修复(pending 请求模型)在本项目约束类里是标准做法,且有官方认可**——不是野路子, - 无需推翻;已经台架 A/B 实证(挂起对时客户端下 FTP banner 28554ms → 92.5ms)与 - M3 压力档复验(p99 尾部 133.5ms → 69.3ms,零尖峰)。 -2. **业界最正统形态("执行者永不被占")在本项目不可达**——其前提是"数据到达可被执行者免费 - 观察到"(LwIP:网卡 DMA/IRQ 递 pbuf → tcpip 线程 O(1) signal 消费者)。本项目的"数据到达" - 观察手段是一次 SPI 事务,而 SPI 总线由 netTask 独占(铁律)→ 等待只能在 netTask 内执行, - 自由度只剩"每次占多久"与"等待期间还做什么"。pending 方案 = 把第二个自由度用满 - (占用降到主循环节拍级)。 -3. **演进方向 = pending 请求**(控制块登记 + 主循环节拍完成 + 取消必通知):消灭头阻塞缺陷类 - (不再依赖调用方纪律)、调用方从分片协议解放、成为 E-06/E-20/E-21 的公共地基。库内已有 - 生产验证先例——D10 的 `net_relisten_retry_tick`(登记→到点完成→全程不阻塞,恢复 588ms→89ms) - 就是该模式的缩小版。 -4. **一期已闭环,二期(ACCEPT/SEND)待排期**:残余分量 = 发送 stall、accept 轮询计时失真、 - errno 分级。代码改动不大(再 ~300-500 行、公开 API 不变),**大的是验证**(台架天量级)。 - ---- - -## 2. 背景:E-02 缺陷与已落地修复 - -**缺陷**(P1,`错误码传播审计.md` E-02):netTask 是全部 socket 操作的唯一执行者,`net_process_messages` -每次取一条消息处理到完成才取下一条。任一消费者发起的 30s 阻塞 `net_recv`(`net_recv_locked` 自旋 -`net_poll`+`ch395f_get_recv_len`)期间,队列整体停摆最长 30s——FTP 客户端空闲 >30s、对时客户端 -连上不发数据,均为常见触发工况。09-21 事故(errno 覆盖误断连)的姊妹缺陷。 - -**已落地修复**(2026-09-22 一期;2026-09-26 复核更正提交号): - -| 提交 | 内容 | -|---|---| -| `954a145` | 本调研文档留档(五类业界模式对照 + pending 演进方案) | -| `a45c0cb` | **一期实现**:阻塞 `recv` 改"挂起请求 + 主循环节拍完成",netTask 零占用;lftpd/timeSync 分片协议退役 | -| `7ff2958` | 文档闭环:E-02 审计两阶段闭环 + 本文 §6.7 实施记录 + M3 基线重锁(pending 构建)+ `待处理内容.md` 建立 | -| `93bae35` | 台架旁路:TC-NET-604 根因闭环(Trap 21,判定非缺陷),MSS=512 方案证伪回退 | - -> **注**:早期版本本文档把一期提交记为 `f16dc9a` / 分支 `wip/v2-pending-recv`——该分支与哈希 -> **在当前仓库不存在**(应为当时临时工作区,后续以 `a45c0cb` 正式落入 `v2-on-ui`)。以本表为准。 - -**A/B 台架实证**(`test/host/e02_probe.py`,2026-09-22,设备 192.168.1.100):挂起对时客户端连 :8888 -不发数据,2s 后 PC 测 FTP(:21) banner 时延 = 队列响应性——旧固件 **28554ms**(设备日志实证芯片侧 -握手与 MCU 侧处理相隔 27s;旧代码 30s 后静默拆连零日志)vs 一期修复后 **92.5ms**。30s 截止按主循环 -节拍精确触发。监听恢复 6.6s(2 次 Trap 09 重试,既有行为同构)。 - -**当前架构**(netTask 主循环,`App/task/net_task.c`): - -``` -for (;;) { - [reconfig 检查 → net_stack_bring_up 重建] - net_poll(); // 读芯片中断状态、分发事件、维护 readable 标志 - net_process_messages(); // ① net_pending_tick(一期:按节拍了结挂起 recv) - // ② net_relisten_retry_tick(D10:到点重试) - // ③ while(队列非空) 取一条消息;无数据阻塞 recv 则登记 pending 即返回 - osDelay(1); // 主循环节拍 ≈1ms -} -``` - ---- - -## 3. 业界调研:"带超时的等数据"的五类成熟模式 - -| # | 模式 | 代表项目 | 处理方式 | 执行者是否被占用 | -|---|---|---|---|---| -| A | 宿主事件循环 | Node.js/libuv、glib、Qt、POSIX select/poll | 非阻塞 I/O + 就绪通知(epoll/kqueue/IOCP)+ 定时器;等待 = 登记请求,由 OS 观察就绪,"就绪或超时"唤醒后处理就绪集 | **永不允许**——Node 官方文档明文 "never block the Event Loop";长任务的两条官方解法 = **分片(partitioning,定期让出)** 或 offload 到 worker 池 | -| B | RTOS 网络栈 | LwIP(ESP32/STM32 生态事实标准,FreeRTOS 任务模型与本项目同款) | 消费者线程在**自己上下文**带超时睡眠(信号量/mailbox);tcpip 线程只在包事件时 signal;超时用 poll timer 回调 | **永不**——官方 raw API 文档:"Raw API applications may **never block** since all packet processing… is done in a single execution context";多线程章节:"Application threads… communicate with this main thread through **message passing**" | -| C | 嵌入式事件循环 | Zephyr `net_context`、ESP-IDF `esp_event` | 应用线程阻塞在自己的 k_sem/事件上;net 线程只做完成回调("callback is called by RX thread so **its** stack and execution context is used here") | 永不 | -| D | 后台 I/O 线程 + 有界 poll | librdkafka(Kafka 官方客户端,生产级) | 后台线程循环**短超时** `poll()` + 每轮间隙排空内部工作队列("calls rd_kafka_poll(timeout) in a loop") | **有界**(短 poll 量子,队列不饿死) | -| E | 独占硬件属主(offload 芯片 / 总线属主) | W5500/W6500 类芯片驱动(CH395F 同类)、共享 SPI 的"专用任务 + 作业队列"模式 | 非阻塞原语 + **调用方预算循环**;或专用任务 + 作业队列、每个作业每轮推进一步(状态机步进) | 有界(每步/每片) | -| F | 每连接一线程 | 传统 threaded server(Apache worker、Java thread-per-connection) | 每连接独占线程,阻塞 recv 只冻结自己 | N/A(隔离) | - -**本项目归属**:E 类。CH395F 与 W5500 同属"SPI 总线上的硬连线 TCP/IP 协议栈"芯片(W5500 产品 -定义:"Hardwired Internet controller with an integrated full TCP/IP stack… over SPI");"专用任务 -+ 消息队列"是该类的标准串行化形态之一(另一形态"每调用加锁"在社区中常见,但会把"等待"也锁进 -临界区——正是 E-02 的形态)。F 类不可行:SPI 铁律决定所有 socket 操作必须经 netTask 串行, -不存在"每连接一线程"的空间。 - -**各模式关键证据**(2026-09-22 访问): - -- A:[Node.js《Don't Block the Event Loop (or the Worker Pool)》](https://nodejs.org/learn/asynchronous-work/dont-block-the-event-loop) - (partitioning 与 offloading 并列两条官方解法;"If a thread is blocked working on behalf of a - specific client request, pending requests for other clients may not get a turn") -- B:[LwIP raw API 文档](https://www.nongnu.org/lwip/2_0_x/raw_api.html)("must reside in different - execution contexts"、tcpip_thread、message passing、never block、`tcp_poll` 定时器回调); - [EEVblog LwIP 讨论](https://www.eevblog.com/forum/microcontrollers/anyone-here-familiar-with-lwip/75/) - ("the LwIP code is designed to never block when the core lock is held"); - [LwIP+RTOS netconn 阻塞问题](https://stackoverflow.com/questions/10848851/lwip-rtos-how-to-avoid-netconn-block-the-thread-forever); - [mbed-os LwIPSocket 非阻塞实现](https://github.com/ARMmbed/mbed-os/issues/13197) -- C:[Zephyr net_context 文档](https://docs.zephyrproject.org/latest/doxygen/html/net__context_8h.html)、 - [ESP-IDF esp_event](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/esp_event.html) -- D:[librdkafka INTRODUCTION](https://github.com/confluentinc/librdkafka/blob/master/INTRODUCTION.md)、 - [WaterDrop 对 librdkafka 后台线程的剖析](https://mensfeld.pl/2026/02/waterdrop-fd-polling-50-percent-faster/) -- E:[W5500 产品页](https://wiznet.io/products/ethernet-chips/w5500)、 - [FreeRTOS 论坛 W5500 多任务共享](https://forums.freertos.org/t/handle-several-sockets-w5500-tcp-stack/14524) - ---- - -## 4. 约束分析:为什么最正统形态(B 类)在本项目不可达 - -B 类(LwIP netconn)的三个构件在本项目的对应物: - -| LwIP 构件 | LwIP 里的形态 | 本项目对应物 | 差距 | -|---|---|---|---| -| 数据到达观测 | 网卡 DMA/IRQ → pbuf 递到 tcpip 线程(免费,O(1)) | 数据到达在 CH395F **芯片内部**;唯一观测手段 = SPI 事务(GET_REMV_LEN / socket 中断状态),而 SPI 只许 netTask 发起 | **观测本身占用执行者** → 等待无法挪出 netTask | -| 消费者侧睡眠 | 应用线程睡在自己的 sem/mailbox 上(带超时) | 调用方睡在任务通知上(`net_wait_result` 两段式等待,带全掩码清除) | **已一致** ✓ | -| 完成通知 | tcpip 线程事件驱动 signal | 当前 = 等待自旋结束才通知;pending 方案 = 主循环检测到完成条件即通知 | 差"事件完成"一步 | - -补充两条不可行路径: - -1. **消费者自行轮询就绪**(如读 INT# GPIO 电平):INT# 只是"某 socket 有事件"的全局电平, - 非 per-connection;且 AGENTS.md 明令"所有 CH395F 中断在 `net_poll()` 内集中读取并清除, - **不得**在 ISR 或其他地方单独处理"——纪律上禁止。 -2. **ISR 里读 per-socket 状态**:需要 SPI 事务,CH395F 驱动非 ISR 安全(设计即"中断集中读取")。 - -**结论**:本项目的等待只能在 netTask 内执行,设计自由度 = ①每次占用时长 ②等待期间是否/如何 -做其他事。**pending 方案 = 把两个自由度同时用满**:占用降到"登记一次 + 每轮 tick 一次读标志" -(主循环节拍级),等待期间 netTask 正常排空整个队列。 - ---- - -## 5. 方案的正当性(两代形态) - -本项目的等待模型经历两代,二者都属 E 类"有界执行者等待"的合法变体: - -| 代次 | 形态 | 状态 | -|---|---|---| -| 一代(分片有界等待) | `net_recv_to` + 5ms 片 + 30s 总预算 + 片间 `vTaskDelay(1)` 让出;调用方持有预算循环 | **已退役**(一期被 pending 取代) | -| 二代(pending 请求,现行) | 无数据即登记 pending、netTask 零占用返回;`net_pending_tick` 按主循环节拍(~1ms)了结 | **一线现行**(`a45c0cb`) | - -**一代的正当性**(留档,说明当时的取舍不是野路子): - -1. **官方认可**:Node 文档把"分片 + 定期让出"(partitioning)列为不阻塞事件循环的**一等官方解法** - (与 offload 并列;offload 在本项目不可行——SPI 独占)。5ms 片 + `vTaskDelay(1)` 让出即逐字对应。 -2. **生产级先例**:librdkafka 后台 I/O 线程 = 短超时 poll + 间隙排空队列,"有界执行者等待" - 在生产级客户端里被接受。 -3. **变体选择有据**:审计方向 ① 原文为 "DONTWAIT 分片 + 调用方重投",实际落地选**有界阻塞片**。 - 理由:DONTWAIT 每片一次完整队列往返(入队+调度+取消息+通知,L5 实测 ~1.2ms),30s 等待 = - ~2.5 万次往返;有界片让 netTask 片内连续多次 `net_poll`,片内到达的数据当片即收。M3 实测 - 支持:100ms 片受压帧 ~750ms → 5ms 片 ~10ms。 - -**二代相对一代的消除项**(为什么一期要推进): - -- 队列最坏滞后从"一个片(5ms)+ 往返"压到 **~1ms**(主循环节拍); -- **不再依赖调用方纪律**:新消费者写裸 `net_recv(fd, buf, len, 0)`(默认 30s、无分片)也**不会** - 复发头阻塞——一代的核心残留缺陷,二代结构性免疫; -- 调用方分片循环 + `vTaskDelay(1)` 让出协议(lftpd/timeSync 各 ~30 行)删除。 - -**仍存的残余**(转二期): - -- **SEND 的 1s/分片 stall 仍冻结队列**(审计 E-02 位置明列)——二期 pending 覆盖; -- 超时精度退化到主循环节拍(被长操作占用时顺延)——现状反向打平,需文档化。 - ---- - -## 6. 演进方案:RECV 消息 → pending 请求 - -> **一期(RECV)已实施**(`a45c0cb`),实现实测与基线的偏差见 §6.7;下文 §6.1 保留为设计基线 -> 原文(含二期扩展),§6.2~§6.6 为当初的利弊/改动量/门禁评估,§6.7 为落地实录。 - -### 6.1 机制 - - -- `net_sock_t` 增加 pending 字段:`buf 指针 / len / flags / deadline(tick) / caller 句柄 / active` - (≈20B/fd × 8 fd ≈ 160B 静态增长); -- `net_process_messages` 的 RECV 分支:数据已在 → 立即读出(**现快速路径不变**);数据未至且 - `timeout_ms > 0` → **登记 pending、跳过本次通知、继续循环取下一条消息**; -- 新增 `net_pending_tick()`(与 `net_relisten_retry_tick` 同位——主循环每轮调用),对每个带 - pending 的 fd 走五路完成/取消: - - | # | 条件 | 动作 | - |---|---|---| - | 1 | 数据到达(`readable` 标志已由 net_poll 每轮更新,零额外 SPI) | SPI 读出 + 通知调用方(结果 = 字节数) | - | 2 | `HAL_GetTick() >= deadline` | 通知(`NET_ERR_TIMEDOUT` → 对外 -2 映射保持) | - | 3 | EOF/DISCONNECT 事件(`handle_disconnect_event` 路径发现 pending) | 按 0(EOF) 完成 + auto_relisten + 通知 | - | 4 | 同 fd 的 CLOSE 等后续操作 | per-fd 串行:先完成 pending 再执行(冻结面从"全网"缩到"本 fd") | - | 5 | 网络重建(`net_stack_bring_up`,芯片复位) | **取消 + 必须通知**(调用方阻塞等回执,取消不通知 = 永久挂死) | - -- **调用方与公开 API 不变**:仍 `net_wait_result` 阻塞等通知(30s 睡眠发生在调用方自己上下文 - ——与 LwIP 模型一致);`net_recv`/`net_recv_to` 返回契约不变,测试/模拟器/既有调用方零改动。 - -### 6.2 好处 - -1. **头阻塞缺陷类消灭**(而非封顶):等待期间 netTask 零额外占用,队列延迟 = 一个主循环周期 - (~1ms); -2. **不再依赖调用方纪律**:任意新消费者写裸 `net_recv(..., 0)` 也不会冻结队列; -3. **调用方简化**:lftpd/timeSync 的分片循环 + `vTaskDelay(1)` 让出协议(各 ~30 行)删除, - 还原为一次 `net_recv_to(fd, ..., 30000)`; -4. **E-06/E-20/E-21 共用机制**:accept 轮询循环(100ms/200ms)、SEND 1s/分片 stall 同型转化 - (ACCEPT pending = CONNECT 事件完成;SEND 续传 = send_ready 完成)——第二档 #1 四条目收敛 - 为一个机制; -5. **长等待 SPI/CPU 成本归零**:30s 等待从 ~6000 次专属轮询降为搭主循环既有 `net_poll` 的便车。 - -### 6.3 坏处 / 代价 - -1. **执行者获得跨时间状态 → 边界交互面变大**:§6.1 五路语义每条都是新的时序边界,须逐一定义 - 并测试——本库 D 系列(D10~D20)历史即此类边界的坟场; -2. **只改 RECV 则收益对折**:SEND 1s/分片 stall 仍在(需二期); -3. **超时精度退化到主循环节拍**:主循环若正被长操作(如 SEND stall)占用,RECV 超时最多顺延 - 相应时长(现状是反方向,打平,需文档化); -4. **验证成本 >> 代码量**:net 层是回归最敏感区(09-21 事故、D 系列),执行器核心改动 = 全 - 套回归 + 基线重锁,台架投入天量级; -5. **新故障类**:"pending 登记后永不完成"(完成条件 bug / fd 状态与芯片失步)→ 调用方无限期 - 睡眠——需配套看门狗/自检(pending 最大龄告警); -6. **模拟器差距 +1**:`net_socket_sim.c`(单线程直连 Winsock)无法建模 pending,附录 D 结构性 - 差距清单加一条; -7. **排障文档需更新**:"结果缺失"类问题新增成因(pending 滞留),`net_wait_result` 两段式 - 等待与 [LAT] 探针的假设需补充说明。 - -### 6.4 改动量 - -| 阶段 | 内容 | 规模 | -|---|---|---| -| 一期(RECV) | `net_sock_t` pending 字段;RECV 分支"有数据即读 / 无数据登记";`net_pending_tick()` 五路完成/取消;close/rebuild 取消钩子 | **~200-400 行,集中在 `net_socket.c`;公开 API 零改动** | -| 调用方简化(可随一期) | lftpd `read_line`/`read`、timeSync `handle_conn` 分片循环 → 单次调用 | 各删 ~30 行 | -| 二期(可选:ACCEPT + SEND) | ACCEPT pending(E-06 accept 计时 / E-20 / E-21 轮询循环退役);SEND 续传 pending(1s stall 非占用化) | 再 ~300-500 行;L3/L5 基线再变 | - -风险评级:**中**(执行器核心 + D 系列前科)。代码量不是主要成本,验证才是。 - -### 6.5 验证门禁(实施时逐项过) - -1. CH395F NET 层全套件(Phase 6-14); -2. M3 基线重锁:L5 队列往返(预期 ~1ms 量级)、L3/L7 生产路径 Δ; -3. `test/host/e02_probe.py` A/B 回归(队列响应性应优于 5ms 片方案); -4. `test/host/ftp_regression.py`(D20)+ E-06 假 425 场景; -5. UI 远端推流压力(ui_net_sink 100Hz); -6. timeSync 三场景(挂起 / 部分包 / 正常包); -7. 产品构建 `@test` 闭环 + ST-LINK 全片回读; -8. `scripts/ram_report.py` 前后对比(铁律);`scripts/stack_report.py` 栈水位。 - -### 6.6 风险缓解 - -- 一期只做 RECV;**保留分片路径作影子对照/回退开关**(双路径并行验证后再摘除); -- 复用 D10 `net_relisten_retry_tick` 的"登记→到点完成"骨架(已在生产验证); -- 探针族扩充:close-during-pending / reconfig-during-pending / EOF-during-pending / - disconnect-during-pending(扩展 `e02_probe.py`); -- pending 最大龄自检(selftest 留痕,防"永不完成"); -- 排障文档同步(`错误码传播审计.md` / `链路延迟测试说明.md` §9 故障对照表)。 - -### 6.7 实施记录(一期,2026-09-22,commit `a45c0cb`) - -**实现与 §6.1 基线的一致性/偏差**(diff 已逐行评审): - -| 基线条目 | 实施 | 说明 | -|---|---|---| -| pending 控制块 ≈20B/fd | `net_pending_t` = {active 1B, buf 4B, len 4B, deadline 4B, registered 4B, caller 4B} ≈24B/fd × 8 = **192B**(+4B `s_net_task_handle`) | 实测 SRAM +200B,与估算同量级 | -| 控制块位置:`net_sock_t` 内 | **偏差:独立静态数组** `s_net_pending[NET_MAX_SOCKETS]` | `net_close_locked` 对 `net_sock_t` 做整块 memset——置入表内则 close 静默抹掉 pending(调用方悬空);独立表 = §6.3#1 预警的"跨时间状态"与 socket 表解耦,仿 D10 relisten 表的生产验证模式 | -| 无数据 → 登记 pending、跳过本次通知 | 哨兵 `NET_PENDING_REGISTERED`(0x70000000)→ dispatch `do_notify=0` | 逐字一致 | -| 五路完成/取消 | tick 实际顺序:① 数据(`readable` 门控 SPI 读,ESTABLISHED/UDP_OPEN;spurious readable 清除)② deadline(状态无关、有符号回绕安全差值)→ TIMEDOUT ③ CLOSED:排空→数据否则 EOF(0)+auto-relisten ④ 他态等待(**不做**状态推断取消)⑤ 1s 看门狗强结算 + DBG_ERROR | 基线 #3 的"EOF 发现"实现为 CLOSED 态排空判定;基线 #4(CLOSE 先行完成 pending)= `net_close` 的 settle 钩子(排空→数据否则 CONNRESET);基线 #5(重建取消必通知)= `net_init` 顶部 `net_pending_cancel_all(CONNRESET)`(先于芯片复位);RESYNC_LISTEN 陈旧分支/`net_socket` 另加 cancel/clear 钩子 | -| 看门狗/自检(§6.6) | 1s 最大龄看门狗强结算 + DBG_ERROR | 简化版:强结算防"永不完成",未接 selftest 留痕(留二期) | -| 调用方简化:单次 `net_recv_to(…, 30000)` | **偏差:剩余预算循环**(`rem = 预算 − 已耗时` 作片长,`n==-2` 续轮,`rem==0` 退出) | 公开契约(30s 总超时语义、跨 TCP 分段累积)要求调用方保留循环骨架;删掉的是分片常数 + `vTaskDelay(1)` 让出协议(改为睡任务通知)——净效果与基线 #3 目标一致 | -| 登记守卫(基线未列,实施新增) | 每 fd 至多一个 pending(**不覆盖**);`caller==NULL` 或 `caller==netTask` 拒绝(BUSY) | 覆盖 = 丢首个调用方通知 = 永久挂起;netTask 上下文自通知 = 无完成者死锁——§6.3#1 边界风险的两条实证化防线 | - -**§6.5 验证门禁逐条结果**(2026-09-22 下午,设备 192.168.1.100,pending 构建): - -| # | 门禁 | 结果 | -|---|---|---| -| 1 | CH395F NET 层套件 | **PASS(分组合并执行)**:F1 组合 Phase 6/9/11——64B/1460B 回显 11/11、select 回显 11/11、断开重连、KeepAlive 断连 + auto-relisten 全 PASS;F2 组合 Phase 8-RECV——100KB 阻塞接收 50/50 块(2048B/块)逐块校验 + CRC32 整包一致(0x9A0E0C8C)+ 收齐 close + auto-relisten。Phase 7(TC703 环境互斥 + 全 DONTWAIT 不经过 pending)、Phase 10(双 32KB 缓冲与全产品镜像结构性超 RAM)本轮未跑——DONTWAIT 路径另由 M3 探针族(L5~L7 全 DONTWAIT)重锁覆盖。TC-NET-604 4096B 子项 FAIL = **既有芯片侧问题**(A/B:切片构建行为逐字节相同,L3 无责;后续经真实路径 227 轮复测判定为非缺陷,2026-09-23 结案,见 `CH395F_Trap_Records.md` Trap 21) | -| 2 | M3 基线重锁 | **PASS**:静默档 host 帧 med 58.9/p95 69.9/max 72.1ms 零尖峰;压力档(FTP 头阻塞工况实发)med 60.1/p95 66.4/max 69.3ms 零尖峰(分片基线 65.0/133.5 → p99 尾部压缩近半);MCU `prod_cycle_mcu` med 6706µs 压力下平坦(min 6698/max 6720);relisten 89ms×3;L5~L7 探针路径(DONTWAIT)不受 pending 影响 | -| 3 | e02_probe A/B 回归 | **PASS 且优于分片方案**:队列响应性 92.5ms(分片 109/75ms);30s 截止按节拍精确触发(30.1s);超时留痕在位;TIME 正常路径全通;监听恢复 6.6s(2 次 Trap 09 重试,既有行为同构) | -| 4 | ftp_regression / E-06 假 425 | **随 F1/F2 台架 + M3 压力档覆盖**(FTP 空闲登录头阻塞工况 + 数据通道收发);未单独重跑 D20 脚本(其场景 = M3 压力档的 FTP 半登录态,已实证) | -| 5 | UI 远端推流压力 | **PASS** = M3 静默/压力两档(ui_net_sink :7003 100Hz 全帧 CRC 50/50,零尖峰) | -| 6 | timeSync 三场景 | **PASS**:挂起客户端(e02_probe 主场景)/ 正常包(wall clock updated + RTC 回写);部分包场景由 Phase 8-RECV 100KB 跨段累积(同 `handle_conn` 跨片累积逻辑的 pending 化形态)等效覆盖 | -| 7 | 产品 `@test` + 全片回读 | **PASS**:Required 全中/Forbidden 零命中;烧录回读 `No difference found` | -| 8 | RAM/栈前后对比 | **PASS**:SRAM +200B(192B pending 表 + 4B 句柄 + 4B 他项)/Flash +608B;netTask 运行栈峰值 488B/4096(余量 88%)、静态最坏链 432B——零占用设计落点;六任务水位全 PASS(defaultTask 29% 边际 = 既有静态链,与 L3 无关) | - -**未执行/延后项(如实留档)**: -- §6.6"保留分片路径作影子对照/回退开关"→ **未保留**,分片协议直接退役;对照目的由"旧镜像 A/B"承担(A/B 轮即影子验证),回退路径 = git revert(单提交、API 不变); -- 探针族扩充(close/reconfig/EOF/disconnect-during-pending 专项)→ 二期随 SEND/ACCEPT 一并建; -- pending 看门狗接 selftest 留痕 → 二期; -- 模拟器差距 +1(`net_socket_sim.c` 单线程 Winsock 无法建模 pending)→ 附录清单更新随二期; -- **tick 放置后果(一期文档化、不修)**:pending 完成判定随主循环节拍运行——队列里排着长 SEND/CLOSE 消息处理时,同 tick 的 pending 完成顺延至下轮(~1ms 级,长 SEND stall 1s 期间最多顺延相应时长)= §6.3#3 的已知代价,按"文档化"处置; -- 台架期间另发现一次 49s 全系统日志静默(defaultTask/NAND syslog 排空停滞,net 栈照常工作)——既有存储侧现象,与 L3 无关,转 `docs/待处理内容.md` N-2。 - ---- - -## 7. 结论与实施建议 - -1. **一期(RECV pending 化)已实施、已全量台架复验、已并入主线并推送**(`a45c0cb` + `7ff2958`, - `v2-on-ui`;门禁逐条结果见 §6.7):头阻塞缺陷类结构性消灭、调用方分片协议退役、M3 压力档 - p99 尾部 133.5ms→69.3ms、队列响应性 92.5ms、RAM +200B。**本项(E-02)至此闭环,无遗留动作。** -2. **二期(ACCEPT/SEND)待排期**——E-06/E-20/E-21 剩余分量(SEND 1s/分片 stall、accept 轮询 - 计时失真、errno 分级)共用同一 pending 机制扩展;届时 L3/L5 基线再重锁。 - **实施时机 = `项目审计改进清单.md` 第二档 #2**(与 GD5F 错误通道统一并列,见第 2 项)。 -3. **路线**:~~一期 RECV(影子验证)~~ ✅ 已完成 → 二期 ACCEPT → SEND(最复杂:多分片/短发送/ - L3 探针钩子)。 -4. **二期启动动作**:以 §6.1 为设计基线评审(含 §6.7 一期实测对基线的修正) → 按 §6.5 门禁执行 - → 按 E-01/E-31/E-32/E-02 的留档惯例更新 `错误码传播审计.md`(明细"已修复"+ 页脚闭环注记 + - 提交记录)+ 销 `docs/待处理内容.md` N-4。 - -**一句话**:好处 = 缺陷类消灭 + 调用方解放 + E-06/20/21 共用机制;坏处 = 执行器状态机复杂化 -+ 天量级台架验证;改动本身不大(一期 ~200-400 行、API 不变),大的是验证。**一期已验证此判断 -成立**(RAM +200B / Flash +608B,验证成本远超代码量)。 - ---- - -## 9. 修订记录 - -| 日期 | 内容 | -|---|---| -| 2026-09-22 | 初版:五类业界模式对照 + pending 演进方案 + §6.7 一期实施记录 | -| 2026-09-26 | 复核修订:①"已落地修复"由一代分片改为二代 pending(§1/§2/§5),一代降级为留档;②更正一期提交号 `f16dc9a`/`wip/v2-pending-recv` → `a45c0cb`(实测该分支与哈希不存在,应为临时工作区);③§7 一期标闭环、二期实施时机锚定审计清单第二档 #2 | - ---- - -## 8. 参考链接(2026-09-22 访问) - -| 来源 | 用途 | -|---|---| -| [Node.js:Don't Block the Event Loop (or the Worker Pool)](https://nodejs.org/learn/asynchronous-work/dont-block-the-event-loop) | A 类:never block 规则 + partitioning 官方解法 | -| [LwIP raw API 文档(2.0.x)](https://www.nongnu.org/lwip/2_0_x/raw_api.html) | B 类:tcpip_thread / message passing / never block / tcp_poll | -| [EEVblog:Anyone here familiar with LWIP?](https://www.eevblog.com/forum/microcontrollers/anyone-here-familiar-with-lwip/75/) | B 类:tcpip 线程不阻塞的设计陈述与社区讨论 | -| [SO:LWIP + RTOS how to avoid netconn block the thread forever](https://stackoverflow.com/questions/10848851/lwip-rtos-how-to-avoid-netconn-block-the-thread-forever) | B 类:netconn 阻塞超时/非阻塞的常见问法 | -| [mbed-os issue #13197:Non-blocking recv with lwip](https://github.com/ARMmbed/mbed-os/issues/13197) | B 类:LwIPSocket 非阻塞实现的真实案例 | -| [Zephyr:net_context API](https://docs.zephyrproject.org/latest/doxygen/html/net__context_8h.html) | C 类:回调在 RX 线程上下文执行 | -| [ESP-IDF:Event Loop Library](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/esp_event.html) | C 类:事件循环 + 队列 | -| [librdkafka INTRODUCTION](https://github.com/confluentinc/librdkafka/blob/master/INTRODUCTION.md) | D 类:多线程库 + 有界 poll | -| [WaterDrop:One Thread to Poll Them All(librdkafka 后台线程剖析)](https://mensfeld.pl/2026/02/waterdrop-fd-polling-50-percent-faster/) | D 类:后台线程 `rd_kafka_poll(timeout)` 循环 | -| [WIZnet W5500 产品页](https://wiznet.io/products/ethernet-chips/w5500) | E 类:同类 offload 芯片定义 | -| [FreeRTOS 论坛:Handle several sockets (W5500)](https://forums.freertos.org/t/handle-several-sockets-w5500-tcp-stack/14524) | E 类:多任务共享 offload 芯片的加锁/串行化实践 | -| 库内:`错误码传播审计.md` E-02 明细 / `docs/测试说明/链路延迟测试说明.md` §8.3 / AGENTS.md SPI 铁律 | 本项目约束与已验证基线 | diff --git a/docs/问题记录/Net层阻塞模型改造实施记录.md b/docs/问题记录/Net层阻塞模型改造实施记录.md new file mode 100644 index 00000000..3043181f --- /dev/null +++ b/docs/问题记录/Net层阻塞模型改造实施记录.md @@ -0,0 +1,97 @@ +# Net 层阻塞模型改造实施记录(E-02) + +> **模块名称**:Net 层(net_socket / netTask)阻塞等待模型 +> **文档性质**:**客观实施记录**——只记录"做了什么、实测到什么、哪些没做"。 +> 设计原理与机制细节见 `docs/网络/BSD_Socket_API_使用指南.md`、`docs/网络/BSD_Socket_API_函数调用关系.md`; +> 基线数据见 `docs/测试说明/链路延迟测试说明.md`;缺陷明细见 `错误码传播审计.md` E-02。 +> **状态**:**一期(RECV pending 化)已实施、已全量台架复验、已并入主线 `v2-on-ui` 并推送** +> (`a45c0cb` 实现 + `7ff2958` 文档闭环)。二期(ACCEPT/SEND)待排期—— +> 设计基线与排期见 `docs/审查记录/下一步任务规划.md`。 +> **日期**:2026-09-22(2026-09-26 复核修订) + +--- + +## 1. 缺陷与修复动机 + +**E-02**(P1,明细见 `错误码传播审计.md`):netTask 是全部 socket 操作的唯一执行者, +`net_process_messages` 每次取一条消息处理到完成才取下一条。任一消费者发起的 30s 阻塞 +`net_recv`(`net_recv_locked` 自旋 `net_poll` + `ch395f_get_recv_len`)期间,队列整体 +停摆最长 30s——FTP 客户端空闲 >30s、对时客户端连上不发数据,均为常见触发工况。 + +**台架实证**(`test/host/e02_probe.py`,2026-09-22,设备 192.168.1.100):挂起对时客户端 +连 :8888 不发数据,2s 后 PC 测 FTP(:21) banner 时延 = 队列响应性——修复前 **28554ms** +(设备日志实证芯片侧握手与 MCU 侧处理相隔 27s;旧代码 30s 后静默拆连零日志)。 + +--- + +## 2. 实施方案(两代形态) + +| 代次 | 形态 | 状态 | 提交 | +|---|---|---|---| +| 一代 | **分片有界等待**:`net_recv_to` + 5ms 片 + 30s 总预算 + 片间 `vTaskDelay(1)` 让出;调用方持有预算循环 | 已退役(一期取代) | `f8d6e90`(lftpd)/ `4a1605b`(timeSync) | +| 二代 | **pending 请求**:无数据即登记挂起、netTask 零占用返回;`net_pending_tick` 按主循环节拍(~1ms)了结 | **一线现行** | `a45c0cb`(一期) | + +**二代机制要点**(细节见 `docs/网络/` 两份文档): + +- `net_sock_t` 之外的**独立静态表** `s_net_pending[NET_MAX_SOCKETS]` 保存挂起请求; +- `net_process_messages` 的 RECV 分支:数据已在 → 立即读出(快速路径不变);无数据且 + `timeout_ms > 0` → 登记待定、跳过本次通知、继续取下一条; +- `net_pending_tick()` 每轮主循环执行,五路完成/取消:① 数据到达 ② 到点超时 + ③ EOF/DISCONNECT ④ 同 fd 后续操作先行结算 ⑤ 网络重建取消必通知; +- 公开 API 与调用契约不变;调用方仍在**自己上下文**睡任务通知(与 LwIP 模型一致)。 + +--- + +## 3. 实施与设计基线的偏差(如实留档) + +| 基线条目 | 实施 | 说明 | +|---|---|---| +| pending 控制块 ≈20B/fd | `net_pending_t` ≈24B/fd × 8 = **192B**(+4B `s_net_task_handle`) | 实测 SRAM +200B,与估算同量级 | +| 控制块置于 `net_sock_t` 内 | **偏差:独立静态数组** `s_net_pending[]` | `net_close_locked` 对 `net_sock_t` 整块 memset——置于表内则 close 静默抹掉 pendn(调用方悬空);独立表把"跨时间状态"与 socket 表解耦,仿 D10 relisten 表的生产验证模式 | +| 无数据 → 登记 pending、跳过通知 | 哨兵 `NET_PENDING_REGISTERED`(0x70000000)→ dispatch `do_notify=0` | 逐字一致 | +| 五路完成/取消 | tick 实际顺序:① 数据(`readable` 门控 SPI 读,ESTABLISHED/UDP_OPEN;spurious readable 清除)② deadline(状态无关、有符号回绕安全差值)→ TIMEDOUT ③ CLOSED:排空→数据否则 EOF(0)+auto-relisten ④ 他态等待(**不做**状态推断取消)⑤ 1s 看门狗强结算 + DBG_ERROR | CLOSE 先行完成 pending = `net_close` settle 钩子;重建取消必通知 = `net_init` 顶部 `net_pending_cancel_all(CONNRESET)`(先于芯片复位);RESYNC_LISTEN 陈旧分支另加 cancel/clear 钩子 | +| 看门狗 | 1s 最大龄强结算 + DBG_ERROR | 简化版:防"永不完成",未接 selftest 留痕(留二期) | +| 调用方改单次 `net_recv_to(…, 30000)` | **偏差:保留剩余预算循环**(`rem = 预算 − 已耗时` 作片长,`n==-2` 续轮,`rem==0` 退出) | 公开契约(30s 总超时语义、跨 TCP 分段累积)要求保留循环骨架;删掉的是分片常数 + `vTaskDelay(1)` 让出(改为睡任务通知) | +| 登记守卫(基线未列) | 每 fd 至多一个 pending(**不覆盖**);`caller==NULL` 或 `caller==netTask` 拒绝(BUSY) | 覆盖 = 丢首个调用方通知 = 永久挂起;netTask 上下文自通知 = 无完成者死锁 | + +--- + +## 4. 验证门禁逐条实测结果 + +(2026-09-22 下午,设备 192.168.1.100,pending 构建) + +| # | 门禁 | 结果 | +|---|---|---| +| 1 | CH395F NET 层套件 | **PASS(分组合并执行)**:F1 组合 Phase 6/9/11——64B/1460B 回显 11/11、select 回显 11/11、断开重连、KeepAlive 断连 + auto-relisten 全 PASS;F2 组合 Phase 8-RECV——100KB 阻塞接收 50/50 块(2048B/块)逐块校验 + CRC32 整包一致(0x9A0E0C8C)+ 收齐 close + auto-relisten。Phase 7(TC703 环境互斥 + 全 DONTWAIT 不经过 pending)、Phase 10(双 32KB 缓冲与全产品镜像结构性超 RAM)本轮未跑——DONTWAIT 路径另由 M3 探针族(L5~L7)重锁覆盖。TC-NET-604 4096B 子项 FAIL = **既有芯片侧问题**(A/B 切片构建行为逐字节相同,L3 无责;经真实路径 227 轮复测判定非缺陷,2026-09-23 结案,见 Trap 21) | +| 2 | M3 基线重锁 | **PASS**:静默档 host 帧 med 58.9/p95 69.9/max 72.1ms 零尖峰;压力档(FTP 头阻塞工况实发)med 60.1/p95 66.4/max 69.3ms 零尖峰(分片基线 65.0/133.5 → p99 尾部压缩近半);MCU `prod_cycle_mcu` med 6706µs 压力下平坦(min 6698/max 6720);relisten 89ms×3;L5~L7 探针路径(DONTWAIT)不受 pending 影响 | +| 3 | e02_probe A/B 回归 | **PASS 且优于分片方案**:队列响应性 **92.5ms**(分片 109/75ms);30s 截止按节拍精确触发(30.1s);超时留痕在位;TIME 正常路径全通;监听恢复 6.6s(2 次 Trap 09 重试,既有行为同构) | +| 4 | ftp_regression / E-06 假 425 | **随 F1/F2 台架 + M3 压力档覆盖**(FTP 空闲登录头阻塞工况 + 数据通道收发);未单独重跑 D20 脚本(其场景 = M3 压力档的 FTP 半登录态,已实证) | +| 5 | UI 远端推流压力 | **PASS** = M3 静默/压力两档(ui_net_sink :7003 100Hz 全帧 CRC 50/50,零尖峰) | +| 6 | timeSync 三场景 | **PASS**:挂起客户端(e02_probe 主场景)/ 正常包(wall clock updated + RTC 回写);部分包场景由 Phase 8-RECV 100KB 跨段累积等效覆盖 | +| 7 | 产品 `@test` + 全片回读 | **PASS**:Required 全中 / Forbidden 零命中;烧录回读 `No difference found` | +| 8 | RAM/栈前后对比 | **PASS**:SRAM **+200B**(192B pending 表 + 4B 句柄 + 4B 他项)/ Flash **+608B**;netTask 运行栈峰值 488B/4096(余量 88%)、静态最坏链 432B——零占用设计落点;六任务水位全 PASS(defaultTask 29% 边际 = 既有静态链,与 L3 无关) | + +--- + +## 5. 未执行 / 延后项(如实留档) + +- **未保留分片路径作影子对照/回退开关** → 分片协议直接退役;对照目的由"旧镜像 A/B"承担 + (A/B 轮即影子验证),回退路径 = git revert(单提交、API 不变); +- 探针族扩充(close/reconfig/EOF/disconnect-during-pending 专项)→ 二期随 SEND/ACCEPT 一并建; +- pending 看门狗接 selftest 留痕 → 二期; +- 模拟器差距 +1(`net_socket_sim.c` 单线程 Winsock 无法建模 pending)→ 附录清单更新随二期; +- **tick 放置后果(一期文档化、不修)**:pending 完成判定随主循环节拍运行——队列里排着长 + SEND/CLOSE 消息处理时,同 tick 的 pending 完成顺延至下轮(~1ms 级,长 SEND stall 1s 期间 + 最多顺延相应时长); +- 台架期间另发现一次 49s 全系统日志静默(defaultTask/NAND syslog 排空停滞,net 栈照常工作) + ——既有存储侧现象,与本次改造无关,转 `docs/待处理内容.md` N-2。 + +--- + +## 6. 结论 + +E-02 **已闭环,无遗留动作**。头阻塞缺陷类结构性消灭、调用方分片协议退役、M3 压力档 p99 尾部 +133.5ms→69.3ms、队列响应性 28554ms→92.5ms、RAM +200B / Flash +608B。 + +二期(ACCEPT/SEND)覆盖剩余分量(SEND 1s/分片 stall、accept 轮询计时失真、errno 分级)—— +设计基线与排期见 `docs/审查记录/下一步任务规划.md`。 diff --git a/docs/问题记录/错误码传播审计.md b/docs/问题记录/错误码传播审计.md index 367395fc..99d6b064 100644 --- a/docs/问题记录/错误码传播审计.md +++ b/docs/问题记录/错误码传播审计.md @@ -10,7 +10,7 @@ > **本版**:2026-09-25 重写 —— ① 已闭环项从正文移除,只在 §2 留一行索引;② 全部未闭环项 > **逐项回到当前代码复核**;③ 新增本轮复核发现。 > **代码基线**:`v2-on-ui` @ `9a8255f`(2026-09-24),复核日期 2026-09-25 -> **配套文档**:`docs/待处理内容.md`(N-2/N-4 登记项)、`docs/问题记录/Net层阻塞模型业界对照与演进方案.md`(E-02 配套)、 +> **配套文档**:`docs/待处理内容.md`(N-2/N-4 登记项)、`docs/问题记录/Net层阻塞模型改造实施记录.md`(E-02 配套)、 > `docs/问题记录/*_Trap_Records.md`(模块陷阱史)、`AGENTS.md`(已固化铁律) ---