L3 pending化文档闭环:E-02审计两阶段闭环+演进方案§6.7实施记录+M3基线重锁(pending构建)+待处理内容.md建立(台架A/B归因)

This commit is contained in:
2026-09-22 17:49:41 +08:00
parent a45c0cb883
commit 7ff2958b3b
6 changed files with 3715 additions and 40 deletions
+28
View File
@@ -0,0 +1,28 @@
# 待处理内容(登记簿)
> **用途**:跨文档的待办/观察项登记——台架与审计过程中发现、但**不属于当前修复范围**
> (或 A/B 归因为既有问题)的事项,在此留档防丢失。每项带发现日期、证据与出处;
> 消化(修复/关闭)时移入对应模块文档并在本表标"已消化(去向)"。
> **创建**:2026-09-22(L3 pending 台架收尾时建立,AGENTS.md 既有引用自此落文件)。
## 网络(CH395F / net 层)
| # | 事项 | 发现 | 证据与现状 | 出处 |
|---|---|---|---|---|
| N-1 | **TC-NET-604:4096B 经 2KB 芯片缓冲的回显残留停滞**——4096B 单段(2×2KB,芯片 socket RX 缓冲=2KB)回显:前半 2048B 正常回显,后半在 10s 内未被再读/回显,连接停摆至对端超时拆连。**前置 1460B 全 MSS 交换后触发(2/2 复现);独立 4096B(无前置交换)正常(117.8ms 全匹配)**→ 芯片 TCP 层"缓冲满时段的交付/重交付"路径问题,方向性触发条件 = 前序满 MSS 段 | 2026-09-22 17:00/17:03(L3 台架 F1 组合) | **A/B 归因:切片构建(2438de8,L3 前)同一序列逐字节同现**(11 回显 PASS、4096B 10s 超时、Phase 11 级联 FAIL,时序差 2ms)→ 既有芯片侧问题,**L3 pending 无责**(DONTWAIT 快速路径逐位未变)。复现探针(本地未跟踪工件,MDK-ARM/ 下):完整序列 = `test/ch395f_socket_test.py tcp_client --ip 192.168.1.100 --port 8080 --count 10`(F1 组合构建);独立 4096B = `MDK-ARM/probe_4096.py`。规避:Phase 6/8 同建时避免 4096B 子项紧随满 MSS 段;根治待芯片侧定位(`CMD_GET_SOCKET_STATUS_SN`/SINT 序列 + 缓冲水位观测) | `错误码传播审计.md` E-02 阶段二"台架新发现①";`链路延迟测试说明.md` §6.3 |
| N-2 | **49s 全系统日志静默(defaultTask/NAND syslog 排空停滞)**——串口日志 49s 无行(testTask 10s 周期行/netTask 事件行/[STACK] 行全缺),期间 net 栈照常处理外部连接(FTP banner 92ms)→ 日志管线(defaultTask 排空 → NAND+UART)停滞,队列满后各任务日志行被丢;系统功能不受损 | 2026-09-22 17:23:52~17:24:41(L3 台架 F2 运行中,gen 181) | **A/B 归因:L3 不触碰 defaultTask/syslog 路径 → 既有存储侧现象**。待办:① 复现条件定位(NAND 写/GC 长尾 vs UART TX 卡滞——对照 `CH395F` 无关的 SD2506 侧日志)② 日志队列满的丢弃计数/告警(现静默丢行,排障不可见)③ 与 S8(非阻塞日志)合并评估 | `错误码传播审计.md` E-02 阶段二"台架新发现②";`链路延迟测试说明.md` §6.7 注 |
| N-3 | **L5 队列往返基线(1223/988µs)的 L3 后重验**——L5 测 DONTWAIT 队列全程;L3 对该路径逐位不变、pending tick 无 pending 时为 µs 级指针读 → 机制上无影响,但基线数值属分片时代,严格重锁需跑一轮 Phase 13(需 PC peer,窗口与 N-1 定位可并案) | 2026-09-22(L3 收尾留档) | 低风险:10ms/100ms 阈值余量 >8×;下次 Phase 13 窗口顺带重锁即可 | `链路延迟测试说明.md` §6.4 L5 注¹ |
## 存储 / 日志管线
| # | 事项 | 发现 | 证据与现状 | 出处 |
|---|---|---|---|---|
| S-1 | defaultTask 静态最坏链余量贴线:2872B/4096(余量 1224B = 29.9% < 30% 判据,差 **4.8B**)——`storage_bring_up → … → dhara GC → SPI` 链,**L3 前即如此**(L3 不触 defaultTask 调用链) | 2026-09-22(L3 产品构建栈报告) | 处置方向二选一:栈 4096→4608(CCM 堆余量 4816B 可覆盖 +512B)或 GC 链缓冲局部削减;与 S8(非阻塞日志)并案评估 | `scripts/stack_report.py`(L3 产品构建档) |
| S-2 | N-1/N-2 消化后,台架 20MB 串口日志截头会丢早期 [STACK] 水位行——跨构建的"前后"栈水位对照建议固化 boot_log 快照(`%TEMP%\opencode\boot_log_*.txt`)进 `docs/测试说明/` 存档目录 | 2026-09-22(L3 收尾发现:切片时代水位行已被截头,A/B 只能定性) | 流程项,无代码改动 | 本文件 N-1/N-2 佐证 |
## 网络(二期排期,随第二档 #1)
| # | 事项 | 说明 | 出处 |
|---|---|---|---|
| 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)已落地:`f16dc9a`;设计基线与门禁结果见 `docs/问题记录/Net层阻塞模型业界对照与演进方案.md` §6.7 | 同左 + `错误码传播审计.md` 第二档 #1 |
| N-5 | E-03(`s_net_errno` 跨任务覆写竞态)——pending 化不改变 errno 通道现状;与 N-4 二期或独立小修(错误码经通知值直回,包装器去全局) | 既有 P1 | `错误码传播审计.md` E-03 |
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+57 -31
View File
@@ -61,7 +61,7 @@ sequenceDiagram
Note over F: D8 最多等 100ms 才轮到下一次 fetch_screen
F->>C: LCDMEM 请求 10B
C-->>N: RECV 中断 → net_poll
Note over N: D3 netMsgQueue 头阻塞窗口(已修复:5ms 分片+让出)
Note over N: D3 netMsgQueue 头阻塞窗口(已两阶段修复:分片 → L3 pending 零占用)
U->>N: net_recv(64B)(队列 + TaskNotify)
Note over U: D5 最多 10ms 相位 + LVGL 渲染占时(渲染实测 ~1ms)
N-->>U: 按键注入 UI
@@ -114,7 +114,7 @@ sequenceDiagram
| **L2** | SPI DMA | `ch395f_read_recv_buf(N)` 完整 DMA 事务(含 CS 切换),N ∈ {4, 64, 1024, 2048} | MCU,DWT µs,Phase 12,N=100/档 | 20 / 114 / **1611** / 3208µs(斜率 1.56µs/B + 固定 14µs) | SPI2/DMA/总线异常 |
| **L3** | 发送分块握手 | `write_send_buf(1KB)` → `SENBUF_FREE` 的等待时长(= `net_send_locked` 每 chunk 的真实等待) | MCU(netTask 上下文),Phase 13 | **219µs**/chunk | 芯片发送路径 / 重传(D1) / 链路(D7) |
| **L4** | 芯片→线上+PC | 数据交入芯片协议栈 → PC 首见字节 / 收齐全帧(peer 逐 `recv()` 批次打时间戳) | PC(peer),Phase 13/14 | 首批 8.6ms;**段间间隙 ≥200ms = 重传**(P0-a 后粒度;旧固件 500ms) | D1/D4/D7("网络延迟"直接证据) |
| **L5** | 队列往返 | 调用方视角 `net_recv(DONTWAIT)` / `net_send` 全程 = 入队 + netTask 调度 + 处理 + 通知 | MCU(调用方计时),Phase 13,**两档**:静默基线 + 压力档(并发 FTP 流量) | 静默:收 1223µs / 发 988µs(2026-09-22 重锁,P0-b 后) | D3(E-02 头阻塞,已修) / D5 调度 |
| **L5** | 队列往返 | 调用方视角 `net_recv(DONTWAIT)` / `net_send` 全程 = 入队 + netTask 调度 + 处理 + 通知 | MCU(调用方计时),Phase 13,**两档**:静默基线 + 压力档(并发 FTP 流量) | 静默:收 1223µs / 发 988µs(2026-09-22 重锁,P0-b 后;L3 对 DONTWAIT 路径逐位不变,重验留待 Phase 13 下次窗口) | D3(E-02 头阻塞,已两阶段修复) / D5 调度 |
| **L6** | 请求→首字节 | peer 发 10B 请求 → MCU 收齐并回显(服务端视角);与 PC 侧对照,差值 = 线路 + PC 栈 | MCU + PC 双侧,Phase 13 | MCU 986µs / PC 3.9ms | MCU 收路径/调度 |
| **L7** | 整帧 3209B 往返 | LCDMEM 全帧:PC 发 → 收齐(含 L3+L4) | PC 为主,Phase 13 | 61.0ms(M2);**spike(≥500ms)=0** | D1+D2+D4 综合 |
| **L8** | 生产路径帧周期 | **真实 uiTask + 真实 `ui_net_sink`**(:7003)完整帧周期:请求拾取(10ms 拍)+ 队列 + 发送 + L4 + peer 侧编码 | MCU 探针 + PC,Phase 14 | 真机 61.6ms / 模拟器 6.8ms(含 peer 100ms 节拍) | 全段(用户真实体感) |
@@ -395,24 +395,30 @@ D10 修复后实测 89ms(= 30ms 重试间隔 + 约 60ms 芯片沉降),故
| 指标 | 真机(50 帧静默档) | 模拟器(50 帧) | Δ(真机−模拟器) | 阈值 |
|---|---|---|---|---|
| 帧周期 total | **61.6ms**(50.4/69.8) | **6.8ms**(0.6/13.1) | **+54.8ms** | ≤80ms |
| 首字节 | 9.6ms(3.2/14.2) | 6.7ms(0.5/13.0) | +2.9ms | — |
| **尾批延迟 tail lag** | **52.6ms**(44.1/59.1) | **0.0ms**(0/0.1) | **+52.6ms** | — |
| 帧周期 total | **58.9ms**(47.7/72.1,p95 69.9) | **6.8ms**(0.6/13.1) | **+52.1ms** | ≤80ms |
| 首字节 | 9.2ms(3.7/16.7) | 6.7ms(0.5/13.0) | +2.5ms | — |
| **尾批延迟 tail lag** | **50.4ms**(43.4/58.6) | **0.0ms**(0/0.1) | **+50.4ms** | — |
| 帧 CRC / 位图非平凡 | 50/0、50/50 | 50/0、50/50 | — | 全通过 |
| 连接 / 断开重连(+INIT) | 17.1ms / 22.4ms | 10.5ms / 32.0ms | — | ≤150ms |
| 连接 / 断开重连(+INIT) | 20.9ms / 22.6ms(3/32.6) | 10.5ms / 32.0ms | — | ≤150ms |
(模拟器列为 2026-09-21 基线,模拟器工程本日未改动;真机列 = 2026-09-22 P0-a/P0-b 代码重测。
旧真机值:帧周期 66.0ms / 首字节 13.9ms / 重连 23.5~34.7ms。)
(模拟器列为 2026-09-21 基线,模拟器工程不受 L3 影响(公开 API 不变);真机列 =
**2026-09-22 16:42 L3 pending 构建重锁**(`m3_data/m3_pending_quiet.json`,50/50 帧全 OK、零尖峰)。
上一档真机值(P0-a/P0-b 分片代码,同日 11:35):帧周期 61.6ms / 首字节 9.6ms / 尾批 52.6ms /
重连 17.1/22.4ms → pending 构建:帧周期 med **58.9ms**(−2.7ms)、尾批 **50.4ms**(−2.2ms)——
执行器零占用使生产路径净缩短(更早的空闲窗口)。)
**压力档(`--ftp-stress`,E-02 复现;第 15 帧起 FTP 停留半登录态)**
**压力档(`--ftp-stress`,E-02 复现;第 25 帧起 FTP 空闲登录保持)**
| 分桶 | n | med | p95 | max | 尖峰(≥500ms) |
|---|---|---|---|---|---|
| quiet(0~14 帧) | 15 | 59.9ms | 65.3ms | 65.3ms | 0 |
| stress(15~44 帧,**E-02 修复后 + P0-a/P0-b**) | 30 | **65.0ms** | 73.9ms | **133.5ms** | **0** |
| quiet(0~24 帧) | 25 | 58.4ms | 69.0ms | 69.8ms | 0 |
| stress(25~49 帧,**L3 pending 构建**) | 25 | **60.1ms** | 66.4ms | **69.3ms** | **0** |
(E-02 修复前 stress 档 med 17718ms、尖峰 1 次 = 17.7s 全网冻结;修复后零尖峰,见 §8.1。
133.5ms 为压力启动瞬态单帧(FTP 连接建立与帧周期交叠),远低于 500ms 尖峰阈值。)
(E-02 修复前 stress 档 med 17718ms、尖峰 1 次 = 17.7s 全网冻结(旧固件);阶段一 5ms 分片修复后
med 65.0ms/max 133.5ms(133.5 = 压力启动瞬态单帧);**L3 pending 化后 med 60.1ms/max 69.3ms**
——p99 尾部较分片档压缩近半(133.5→69.3),MCU 侧 `prod_cycle_mcu` 6706µs 在压力下纹丝不动
(min 6698/max 6720):头阻塞工况不再向 UI 帧周期传导 = 结构性收益。本档重锁 =
`m3_data/m3_pending_stress.json`,2026-09-22 16:43。)
### 6.4 全段基线总表
@@ -421,20 +427,27 @@ D10 修复后实测 89ms(= 30ms 重试间隔 + 约 60ms 芯片沉降),故
| **L1** `spi_cmd_*` | SPI 字节命令(3 条) | 10 / 15 / 15µs | 10~16µs | 100 | 40/100µs | OK |
| **L2** `spi_dma_*` | SPI DMA 读(4/64/1024/2048B) | 20 / 114 / **1611** / 3208µs | ±2µs | 100 | 见 §6.1 | OK |
| **L3** `chunk_wait` | 写发送缓冲 → `SENBUF_FREE`(每 chunk) | **219µs** | 213/378µs | 64 | 10ms/500ms | OK |
| **L5** `queue_rt_recv` | 调用方 `net_recv(DONTWAIT)` 队列全程 | **1223µs** | 1194/1223µs | 20 | 10ms/100ms | OK |
| **L5** `queue_rt_send` | 调用方 `net_send` 队列全程 | **988µs** | 840/1216µs | 20 | 10ms/100ms | OK |
| **L5** `queue_rt_recv` | 调用方 `net_recv(DONTWAIT)` 队列全程 | **1223µs**¹ | 1194/1223µs | 20 | 10ms/100ms | OK |
| **L5** `queue_rt_send` | 调用方 `net_send` 队列全程 | **988µs**¹ | 840/1216µs | 20 | 10ms/100ms | OK |
| **L6** `req2first_mcu` | 10B 请求到齐 → 回显发出(MCU 侧) | **986µs** | 979/1015µs | 10 | 20ms/200ms | OK |
| **L7** `fullframe_mcu` | 9B 请求 → 3209B 全帧交给芯片 | **6614µs** | 6546/6649µs | 10 | 50ms/500ms | OK |
| **L8** `prod_cycle_mcu` | **生产路径**:LCDMEM 取帧+组帧+net_send(MCU 净成本) | **6707µs** | 6701/6757µs | 50 | 20ms/200ms | OK |
| **L8** `prod_cycle_mcu` | **生产路径**:LCDMEM 取帧+组帧+net_send(MCU 净成本) | **6706µs**(L3 重锁) | 6698/6720µs | 50 | 20ms/200ms | OK |
| **L10** `logtax_line` | 一行 60 字符 `printf` @115200 | **4402µs** | 4396/8779µs | 10 | 10ms/25ms | OK(D6 量化) |
| **L11** `ui_loop` | uiTask 生产循环实测周期 | **10986µs** | 10951/11022µs | 120 | 25ms/50ms | OK |
| **L9** `relisten` | 断线后自动重监听耗时(MCU 侧,修复后) | **89000µs** | 89000µs ×3 | 3 | 100ms/500ms | OK |
| **L4/L8** peer cycle | 生产客户端完整帧周期(发→收齐 3209B) | **61.6ms** | 50.4/69.8ms | 50 | — | 见 §7 |
| **Δ** | `peer cycle(设备) − peer cycle(模拟器)` | **54.8ms** | — | 50/50 | ≤80ms | 见 §7.1 |
| **L11** `ui_loop` | uiTask 生产循环实测周期 | **10986µs**(L3 重锁,值不变) | 10951/11022µs | 120 | 25ms/50ms | OK |
| **L9** `relisten` | 断线后自动重监听耗时(MCU 侧,修复后) | **90000µs**(L3 重锁) | 90000µs ×3 | 3 | 100ms/500ms | OK |
| **L4/L8** peer cycle | 生产客户端完整帧周期(发→收齐 3209B) | **58.9ms**(L3 重锁) | 47.7/72.1ms | 50 | — | 见 §7 |
| **Δ** | `peer cycle(设备) − peer cycle(模拟器)` | **52.1ms**(L3 重锁) | — | 50/50 | ≤80ms | 见 §7.1 |
数据来源:L1/L2 = §6.1;其余 MCU 侧 = M2 B2 档(200ms、per-recv 日志已删)/ M3 静默档的串口 `[LAT]` 行
(`m2_data/m2_quiet_r200.json`、`m3_data/m3_dev_quiet_r200.json`);A/B 对照档 = `m2_quiet_r500.json`(旧条件);
peer 侧 = `m3_data/m3_dev_*_r200.json`。旧 run15 摘录(`m2_serial_excerpt_run15.txt`)保留作 A/B 历史对照。
¹ L5 两行为 2026-09-22 上午分片时代(M2 B2 档)数值:L3 对 DONTWAIT 快速路径**逐位不变**(dispatch
→ `net_poll` → `get_recv_len` 读,无 readable 门控),pending tick 无 pending 时为纯指针读零 SPI
(µs 级)——机制上不影响 L5;M2 重验未在本轮执行(低风险,留待 Phase 13 下次窗口,见 `docs/待处理内容.md` N-3)。
数据来源:L1/L2 = §6.1;L3/L5/L6/L7 = M2 B2 档(200ms、per-recv 日志已删)串口 `[LAT]` 行
(`m2_data/m2_quiet_r200.json`);L8/L9/L11 = **L3 pending 构建 2026-09-22 16:42/16:43 重锁**
(`m3_data/m3_pending_quiet.json` / `m3_pending_stress.json` 之 MCU 侧 `[LAT]` 行);L10 = M3 静默档
(`m3_data/m3_dev_quiet_r200.json`,与 L3 无关的串口税段);A/B 对照档 = `m2_quiet_r500.json`(旧条件);
peer 侧 = `m3_data/m3_pending_*.json`(L3 重锁)与 `m3_data/m3_dev_*_r200.json`(上一档,历史对照)。
旧 run15 摘录(`m2_serial_excerpt_run15.txt`)保留作 A/B 历史对照。
### 6.5 重锁规则
@@ -592,10 +605,21 @@ sock4 auto-relisten ok / relisten retry ok ← 监听器随后自行恢复
1. **D10 重试必须防饥饿**:调用方(accept/recv 路径每 10ms 一次)只登记一次重试,实际重试由 netTask
轮询到点执行;若让调用方每次立即重试并重置时刻,会永不重试。重试间隔 100ms→30ms 后恢复时间
147ms→89ms(芯片沉降约 60ms);
2. **E-02 分片长度 = 其他任务的最坏等待**:100ms 片下受压帧仍 ~750ms(多片排队),收到 **5ms** 片后才降到
~75ms;
3. **分片循环必须显式让出 CPU**:某片可能因 `net_poll` 自身耗时首轮即返回超时 → 本任务(Normal)立即
重排队会形成忙循环并**饿死 BelowNormal 的 uiTask**(实测 2.4~3.4s 周期尖刺);`vTaskDelay(1)` 后尖刺归零。
2. **(历史,阶段一)E-02 分片长度 = 其他任务的最坏等待**:100ms 片下受压帧仍 ~750ms(多片排队),收到
**5ms** 片后才降到 ~75ms——该"分片即上限"模型已于 2026-09-22 由 **L3 pending 化**取代
(f16dc9a):执行器零占用后,其他任务的最坏等待 = 一个主循环节拍(~1ms),与任何片长无关
(M3 压力档实测:med 60.1ms/max 69.3ms,p99 尾部较分片档 133.5ms 压缩近半);
3. **(历史,阶段一)分片循环必须显式让出 CPU**:某片可能因 `net_poll` 自身耗时首轮即返回超时 → 本任务
(Normal)立即重排队会形成忙循环并**饿死 BelowNormal 的 uiTask**(实测 2.4~3.4s 周期尖刺);
`vTaskDelay(1)` 后尖刺归零——L3 pending 化后该让出协议随分片循环一并退役(调用方改睡任务通知,
天然让出;netTask 侧无循环可忙);
4. **(现行,L3 pending 化)阻塞等待不在执行器内发生**:`net_recv_locked` 阻塞分支在数据不可得时登记
pending(每 fd 至多一个、**不可覆盖**;`caller==NULL`/netTask 自身拒绝)即返回哨兵
`NET_PENDING_REGISTERED`;完成判定在 `net_pending_tick`(主循环节拍,与 `net_process_messages`
同位)按 数据→截止→CLOSED 排空/EOF+relisten→1s 看门狗 顺序执行,**cancel/settle 必通知**
(调用方永不悬空);pending 表独立于 `net_sock_t`(close 的 memset 不得抹掉跨时间状态)。
维护注意:队列中长 SEND/CLOSE 消息处理期间,pending 完成顺延至下轮 tick(~1ms 级;长 SEND
stall 期间最多顺延相应时长)——已知代价,勿"优化"回执行器内等待。
### 8.4 相关既有缺陷(会掩盖/放大延迟,见 `docs/问题记录/错误码传播审计.md`)
@@ -625,7 +649,7 @@ sock4 auto-relisten ok / relisten retry ok ← 监听器随后自行恢复
| L1/L2 超 crit | SPI 走线/PCB/SPI2 分频或 DMA 配置 | 对照 `docs/问题记录/CH395F_Trap_Records.md`;逻辑分析仪抓 SCK/CS |
| L3 spike ≥200ms(连续台阶;旧固件 500ms) | **D1 重传 / D7 链路** | Wireshark `tcp.analysis.retransmission`;查 PHY 协商/网线/Wi-Fi |
| L3 基线(非 spike)抬高 | 芯片发送路径 / 中断响应 | 对照 CH395F 手册 §5.17/5.18(注意:状态寄存器**不被 SET 类命令更新**,`GET_CMD_STATUS` 恒读到 RESET 的 0x10 陈旧残留,2026-09-22 台架实证——不可用作 SET 值验收) |
| L5 压力档爆表 | **E-02 头阻塞(已修)** → 回归 | 定位触发源(阻塞 recv 的 FTP/对时);核对 `net_recv_to` 分片在位 |
| L5 压力档爆表 | **E-02 头阻塞(已修)→ 回归** | 定位触发源(阻塞 recv 的 FTP/对时);核对 L3 pending 在位(`net_recv_locked` 阻塞分支 = 登记 pending 而非等待;`net_pending_tick` 在主循环) |
| L5/L6 静默档抬高 | D5 调度(任务抢占/节拍) | 查任务优先级与 osDelay;`stack_report.py` 核对栈水位 |
| L6/L7 整体抬高且 L1~L5 正常 | 线路+PC 段(L4) | Wireshark 段间间隙;`Δ` 对照定位 MCU 侧净贡献 |
| **L7/L8 尾批固定迟到 ~50ms** | 已定性(§7.3):次 MSS 尾段被 Nagle 扣住 + Windows 延迟 ACK | 客户端侧解法已实测(§7.4):`--ack-probe` / `--ack-fast` → tail 52→3.9ms;生产客户端已实装;**设备侧无解**,不必再投入 |
@@ -636,7 +660,7 @@ sock4 auto-relisten ok / relisten retry ok ← 监听器随后自行恢复
| **`[LAT]` 段行缺失/截断、wait-idle 判不出空闲** | **D12-b**:热路径日志洪水 | 删除 net 热路径逐调用日志(§8.1 D12-b) |
| **开机日志连续丢行**(含必检标记 `net init: OK` 等)但系统健康 | **日志并发竞态**:多任务并发 `printf` → 非重入 `fputc`/`HAL_UART_Transmit` 丢整行、UART 状态短暂卡住(2026-09-22 台架实证:boot 时 testTask 启动行与 netTask 日志并发 → 连续 4 行丢失、~2s 后自恢复) | 必现证据行采用"静默采集 + 延迟到安静窗口打印"模式(范例:P0-a 验收行曾按此模式实装,验收完成后探针已移除);根治 = S8 日志非阻塞/串行化(§10.2) |
| **`relisten` 段 FAIL、断线固定 ~588ms** | **D10** 回归(退回 `osDelay(500)`) | 核对 `net_relisten_try`/`net_relisten_retry_tick` 非阻塞重试在位(§8.1 D10) |
| **远端显示整帧卡住十几秒后自恢复** | **E-02** 回归 | 核对 `net_recv_to` 5ms 分片 + 让出在位(§8.1 E-02) |
| **远端显示整帧卡住十几秒后自恢复** | **E-02** 回归 | 核对 L3 pending 在位:`net_recv_locked` 阻塞分支登记 pending(哨兵 `NET_PENDING_REGISTERED`)+ `net_pending_tick` 在主循环 + 调用方剩余预算循环(lftpd/timeSync)(§8.3 要点 4) |
| **INIT 应答帧字节数字段恒为 0** | **D17** 回归 | 核对 `remo_send_init` 发满 8B(§8.1 D17) |
| **开机首个 FTP 会话第 2 个数据连接 425** | **D20**(已定位未修,§8.2) | 复现:`test/ftp_regression.py`(复位开边界);现场规避:客户端重试 425(瞬态 4xx);根治方向:数据 Socket 轮换 |
| **`[LAT]` 多段数值雷同 / 全 0 却 verdict=OK** | **D18/D19**(测试工装) | 核对 `lat_probe_add_seg` 段名过滤 + `lat_time_init` 调用 + `med==0` 判无效 |
@@ -655,7 +679,7 @@ sock4 auto-relisten ok / relisten retry ok ← 监听器随后自行恢复
|---|---|---|---|
| D1 | CH395F TCP 重传固定周期(非 RTT 自适应) | 台架链路(有线 100M 全双工)多轮零重传尖峰 → 台架无丢包;**弱网(Wi-Fi/双工不匹配)仍是秒级卡顿首要嫌疑**,200ms 粒度台阶 = 重传指纹(旧固件 500ms) | **已修(P0-a,2026-09-22)**:`NET_RETRANS_PERIOD_MS` 500→**200**(窗口 8×200=1.6s,原 4s)。台架验收说明:`GET_CMD_STATUS` 对 SET 类命令无判别力(500/2000ms 超限对照均读 0x10 陈旧残留,§9.2)→ 接受性以手册范围(≤1000ms)+ 全套件零回归(§6.2/§6.3)+ 与 500ms 行为同构为准。验收探针(3×20ms 状态轮询 + 证据行)验收完成后已从代码移除,结论保留于本文档 |
| D2 | 3209B × 1KB 发送 FIFO 停止等待(4 次串行分块握手,期间 netTask 全程占用) | `chunk_wait` 219µs/块 ≈ SPI 搬运成本的 1/7 → 握手本身**不是瓶颈**;每帧固定成本小(MCU 净 7.1ms) | 基线成本,可接受;根治 = 差量/RLE + 帧版本号(待办 S2) |
| D3 | netMsgQueue 头阻塞(= §8.1 E-02) | 已量化:一条空闲 FTP 控制连接冻结全网 17.7s | **已修复**(5ms 分片有界读 + 让出,§8.1) |
| D3 | netMsgQueue 头阻塞(= §8.1 E-02) | 已量化:一条空闲 FTP 控制连接冻结全网 17.7s | **两阶段闭环**:① 5ms 分片有界读 + 让出(f8d6e90/4a1605b,缓解)② **L3 pending 化**(f16dc9a,结构性——执行器零占用,缺陷类消灭,§8.3 要点 4) |
| D4 | PC 端延迟 ACK 与"每段等 ACK"停止等待交互 | `--ack-fast` 带内实验证实:关掉延迟 ACK 尾批自行消失(52→3.9ms) | **已客户端侧解决**(生产客户端关延迟 ACK/轻推兜底,§7.4) |
| D5 | uiTask 节拍:10ms 循环 + 每拍一次 64B recv + step 在 poll 前 | `ui_loop` 10986µs ≈ 设计值(渲染 ~1ms);拾取调度 ~2.3ms(P0-b 删 per-recv 日志后,原 ~6.8ms) | 基线行为;可选优化 S7(poll 前置 + while 排空),低优先 |
| D6 | 阻塞式日志在关键路径(fputc 逐字节 @115200) | `logtax_line` 4402µs/行;per-recv 日志已删(2026-09-22):`queue_rt_recv` 5997→1223µs、帧周期 66.0→61.6ms、首字节 13.9→9.6ms | **部分已修(P0-b,2026-09-22)**;S8 非阻塞日志仍待办(同时是开机日志并发丢行 §9.2 的根治项) |
@@ -722,7 +746,9 @@ sock4 auto-relisten ok / relisten retry ok ← 监听器随后自行恢复
| `m3_data/m3_dev_stress.json` | E-02 压力档(修复前:17.7s 尖峰) |
| `m3_data/m3_dev_stress_fixed.json` | E-02 压力档(修复后:med 74.7ms / max 106.8ms,零尖峰) |
| `m3_data/m3_dev_quiet_r200.json` | **2026-09-22 M3 静默档重锁基线**(50 帧,P0-a/P0-b 代码:帧周期 61.6ms) |
| `m3_data/m3_dev_stress_r200.json` | **2026-09-22 M3 压力档重锁基线**(45 帧,第 15 帧起 FTP stress:med 65.0ms / max 133.5ms,零尖峰) |
| `m3_data/m3_dev_stress_r200.json` | **2026-09-22 M3 压力档重锁基线**(45 帧,第 15 帧起 FTP stress:med 65.0ms / max 133.5ms,零尖峰)——分片时代数值,**已被 L3 档取代**(历史对照) |
| `m3_data/m3_pending_quiet.json` | **2026-09-22 M3 静默档 L3 重锁基线(当前)**(50 帧,pending 构建 16:42:帧周期 58.9ms / 首字节 9.2ms / 尾批 50.4ms,零尖峰,CRC 50/0) |
| `m3_data/m3_pending_stress.json` | **2026-09-22 M3 压力档 L3 重锁基线(当前)**(50 帧,第 25 帧起 FTP 空闲登录保持:stress 段 med 60.1ms / p95 66.4ms / max 69.3ms,零尖峰,CRC 50/0;MCU 侧 prod_cycle_mcu 6706µs 压力下平坦) |
| `m3_data/m3_sim_quiet.json` | 模拟器基线 50 帧(Δ 对照,tail=0) |
| `m3_data/m3_tail_ackprobe.json` | 尾批实验 ①:帧未收齐即回 1 字节(捎带 ACK)→ tail 3.9ms |
| `m3_data/m3_tail_ackfast.json` | 尾批实验 ②:Windows 立即 ACK(不发探测字节)→ tail 3.9ms |
@@ -5,6 +5,9 @@
> 成熟项目模式的对照;(2) 演进方向"RECV 消息 → pending 请求"(正统事件驱动形态)的利弊与改动量估算。
> **留作备用**:第二档 #1(E-02+E-06+E-20+E-21 阻塞模型改造)排期实施时,以 §6 为设计基线、
> §6.5 为验证门禁。
> **实施状态(2026-09-22 当日更新)**:**一期(RECV pending 化)已实施并全量台架复验**——
> commit `f16dc9a`(分支 `wip/v2-pending-recv`,基线 v2-on-ui `2438de8`);实现与 §6.1 基线的
> 偏差、§6.5 门禁逐条结果与实测数据见 **§6.7 实施记录**;二期(ACCEPT/SEND)未动,仍按 §7 排期。
> **日期**:2026-09-22
> **配套文档**:`错误码传播审计.md`(E-02 明细 / 修复计划 / 已闭环记录)、`docs/测试说明/链路延迟测试说明.md`
> (M3 基线 / §8.3 实现要点 / §9 故障对照)、`AGENTS.md`(SPI 铁律 / 就绪屏障 / 内存预算)
@@ -225,12 +228,50 @@ B 类(LwIP netconn)的三个构件在本项目的对应物:
- pending 最大龄自检(selftest 留痕,防"永不完成");
- 排障文档同步(`错误码传播审计.md` / `链路延迟测试说明.md` §9 故障对照表)。
### 6.7 实施记录(一期,2026-09-22,commit f16dc9a)
**实现与 §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 无责,转 `docs/待处理内容.md` N-1) |
| 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. **现状(分片)安全有效,不必急着演进**——残余风险可控且已基线锁定;pending 是结构演进,
不是缺陷修复,无时间压力。
1. **一期(RECV pending 化)已于 2026-09-22 实施并全量台架复验**(f16dc9a,`wip/v2-pending-recv`;
门禁逐条结果见 §6.7):头阻塞缺陷类结构性消灭、调用方分片协议退役、M3 压力档 p99 尾部
133.5ms→69.3ms、队列响应性 92.5ms、RAM +200B。**二期(ACCEPT/SEND)待排期**——
E-06/E-20/E-21 剩余分量(SEND 1s/分片 stall、accept 轮询计时失真、errno 分级)共用同一
pending 机制扩展;届时 L3/L5 基线再重锁。
2. **实施时机 = 第二档 #1 排期窗口**:E-06/E-20/E-21 迟早要做,pending 是四条的公共地基,
一次做齐比四个独立补丁便宜。
3. **路线**:一期 RECV(影子验证)→ 二期 ACCEPT → SEND(最复杂:多分片/短发送/L3 探针钩子)。
+16 -7
View File
@@ -40,7 +40,7 @@ E-60"write_enable WRTC2 与手册矛盾"经三方复核(手册表头 D7~D0 顺
| 编号 | 子系统 | 一句话 |
|---|---|---|
| E-02 | net 执行器 | **队列头阻塞**:任一消费者的阻塞 recv(30s)在 netTask 上下文空转 → 全体消费者的队列消息停摆最长 30s(事件仍处理);FTP 客户端空闲 >30s 即可触发。**已修复(2026-09-22)**:lftpd(f8d6e90)/timeSync(4a1605b)两个触发源均改 `net_recv_to` 5ms 分片有界读,台架 A/B 实证(明细见 §3.2) |
| E-02 | net 执行器 | **队列头阻塞**:任一消费者的阻塞 recv(30s)在 netTask 上下文空转 → 全体消费者的队列消息停摆最长 30s(事件仍处理);FTP 客户端空闲 >30s 即可触发。**两阶段闭环(2026-09-22)**:阶段一 `net_recv_to` 5ms 分片有界读缓解(lftpd f8d6e90 / timeSync 4a1605b);阶段二 **L3 pending 化**(f16dc9a)——阻塞 RECV 改挂起请求、执行器零占用零阻塞、调用方分片协议退役;台架全量实证(明细见 §3.2) |
| E-03 | net 层 | 全局 `s_net_errno` 跨任务覆写竞态(09-21 修复的**残留**):恢复与读取之间隔任务切换,健康连接可被误拆(ui_sink :460 每 10ms 读) |
| E-04 | UI 远端推流 | `remo_send` 丢弃 `net_send` 返回值 → 3205B 响应弱网短发送**静默截断**(09-21 事故机制的调用方一侧未闭环) |
| E-05 | net 层 | 3 任务直调 `net_socket/net_bind/net_getsockname` 跨任务写 netTask 属主的 socket 表 → alloc/close 交错可双分同一 fd(SPI 铁律未破,表属主破了) |
@@ -155,10 +155,19 @@ E-60"write_enable WRTC2 与手册矛盾"经三方复核(手册表头 D7~D0 顺
- **模式**:P4 变体(串行化头阻塞,非丢消息)
- **影响**:最长 30s 全网队列停摆——uiTask 100Hz 轮询、FTP 收发/accept、timeSync 全部排在队列里得不到处理;事件处理不受影响(等待循环内仍调 `net_poll`,`:1020`),受影响的**恰是队列**;与 E-06 叠加 → PASV 假 425;STOR 上传方向芯片 2KB 缓冲满 + 重传 8×500ms=4s 耗尽 → 必断
- **修复方向**:消费端阻塞 recv 改 `DONTWAIT` 分片 + 调用方重投 + 总超时(ui_sink 模式推广到 lftpd/timeSync);或 `net_process_messages` 在长阻塞间隙按 tick 继续排空队列;`NET_RECV_TIMEOUT_MS` 按服务可容忍量级分离(既有 P2-8 是本条的子集)
- **已修复(2026-09-22,两提交)**:落地方案为方向①的变体——"分片"用**有界阻塞片**而非 DONTWAIT 重投:新增 `net_recv_to` 接口(`msg.timeout_ms` 携带片长;片超时以独立返回码 -2 区分,无跨任务 errno 竞态);调用方累计总预算、片间 `vTaskDelay(1)` 让出 CPU(防 Normal 优先级忙循环饿死 BelowNormal 的 uiTask,M3 实证);5ms 片长 = 其他任务最坏等待(100ms 片下受压帧 ~750ms、5ms 片 ~10ms,`docs/测试说明/链路延迟测试说明.md` §8.3);30s 总预算保持旧超时语义
- **已修复(2026-09-22,两阶段)**:
**阶段一(缓解,两提交)**:落地方案为方向①的变体——"分片"用**有界阻塞片**而非 DONTWAIT 重投:新增 `net_recv_to` 接口(`msg.timeout_ms` 携带片长;片超时以独立返回码 -2 区分,无跨任务 errno 竞态);调用方累计总预算、片间 `vTaskDelay(1)` 让出 CPU(防 Normal 优先级忙循环饿死 BelowNormal 的 uiTask,M3 实证);5ms 片长 = 其他任务最坏等待(100ms 片下受压帧 ~750ms、5ms 片 ~10ms,`docs/测试说明/链路延迟测试说明.md` §8.3);30s 总预算保持旧超时语义
① **lftpd 侧(commit f8d6e90,M3 台架复验)**:`lftpd_inet_read_line`/`lftpd_inet_read` 的 30s 阻塞 recv 改 5ms 分片 + 30s 总预算;M3 压力档(空闲 FTP 半登录态)帧周期 med 17718ms/尖峰 17.7s → **med 65.0ms/max 133.5ms/零尖峰**
② **timeSync 侧(commit 4a1605b)**:`time_sync_handle_conn` 单次 30s 阻塞 `net_recv` 改同模式(5ms 片/30s 总预算/跨片累积容忍 TCP 分段/超时留痕 `time_sync: no TIME packet in 30s, drop conn`);产品构建 `@test` 闭环 PASS(Required 全中/Forbidden 零命中)
**A/B 台架对照(`test/e02_probe.py`,2026-09-22 13:07~13:16,设备 192.168.1.100)**:挂起客户端连 :8888 后不发数据,2s 后 PC 测 FTP(:21) banner 时延 = 队列响应性——旧固件 **28554ms**(队头冻结;设备日志实证芯片侧握手与 MCU 侧 "connection received" 相隔 27s;旧代码 30s 后静默拆连**零日志**)vs 修复后 **109ms(产品构建)/75ms(测试构建)**;30s 预算耗尽拆连后监听均经 2 次 Trap 09 重试 ~8s 恢复(两侧行为同构,非本修复引入);修复版超时留痕在位、正常路径(8B TIME 包)`wall clock updated` + RTC 回写 + 监听重建全通。(注:旧固件轮的芯片侧监听状态为上次烧录遗留——ST-LINK 仅复位 MCU、CH395F 状态延续,不影响队列冻结证据,冻结主体为旧固件 netTask 的阻塞 recv)
**阶段二(结构闭环,commit f16dc9a,分支 wip/v2-pending-recv,2026-09-22)**:**L3 pending 化**——阻塞 RECV 消息改为**挂起请求**,执行器(netTask)不再为任何调用方阻塞:`net_recv_locked` 阻塞分支在数据不可得时登记 `net_pending_t`(每 fd 至多一个,不覆盖;`caller==NULL`/`caller==netTask` 拒绝自通知死锁)即返回哨兵 `NET_PENDING_REGISTERED`(0x70000000,dispatch 跳过即时通知);完成判定收敛到主循环节拍 `net_pending_tick`(每次 `net_process_messages` 各跑一遍):① 数据(readable 门控 SPI 读,ESTABLISHED/UDP_OPEN)② 截止(`NET_RECV_TIMEOUT_MS` 30s,状态无关、有符号回绕安全差值)→ TIMEDOUT ③ CLOSED:排空→数据否则 EOF(0)+auto-relisten ④ 他态等待(不做状态推断取消)⑤ 1s 看门狗强结算 + DBG_ERROR;`net_init`/`net_close`/RESYNC_LISTEN 陈旧分支/`net_socket` 的 cancel/settle 钩子**一律通知**——调用方永不悬空。调用方(lftpd/timeSync)同步退役分片协议:改为"剩余总预算"循环(`rem = 预算 - 已耗时` 作每次片长,`net_recv_to` 无数据即睡在任务通知上,醒即续——片间 `vTaskDelay(1)` 不再需要)。公开 API/返回语义(>0/0/-1/-2)与"通知值唯一回传通道"不变;pending 表独立静态数组(close 时 memset 的 `net_sock_t` 之外),仿 D10 relisten 表模式。
**台架全量复验(2026-09-22 下午,pending 构建,分支 wip/v2-pending-recv)**:
- **e02_probe**:队列响应性 **92.5ms**(阶段一 109ms/75ms → 更快,执行器占用归零);30s 截止按节拍精确触发(30.1s,`no TIME packet in 30s, drop conn` 留痕在位);拆连后监听经 2 次 Trap 09 重试 6.6s 恢复(既有芯片行为,与阶段一同构);TIME 正常路径 `wall clock updated` PASS
- **M3 基线重锁(Phase 14,静默 + FTP 压力两档全 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)——**结构性收益:执行器零占用,头阻塞工况不再向 UI 帧周期传导**
- **功能套件(Phase 6/9/11 组合 + Phase 8-RECV 独占组合,分两次构建)**:64B/1460B 回显 11/11、select 回显 11/11、断开重连、KeepAlive 断连 + 自动重监听全 PASS;**Phase 8-RECV 100KB 阻塞接收(pending 主路径)50/50 块(2048B/块)逐块校验 + CRC32 整包一致**(0x9A0E0C8C),收齐后主动 close + auto-relisten 正常
- **产品构建 `@test`**:PASS(Required 全中/Forbidden 零命中);netTask 运行栈峰值 **488B/4096(余量 88%)**、静态最坏链 432B——零占用设计实测落点
- **RAM/Flash 代价(map A/B,同一测试配置)**:SRAM +200B(192B `s_net_pending[8]` + 4B `s_net_task_handle` + 4B 他项)、Flash +608B(code +528/RO +80)——远低于内存预算阈值
- **台架新发现(与 L3 无关,A/B 归因后转 `docs/待处理内容.md` N-1/N-2)**:① TC-NET-604 4096B 经 2KB 芯片缓冲的回显残留停滞(前置 1460B 全 MSS 交换后触发,独立 4096B 正常;**切片构建复现行为逐字节相同** → 既有芯片侧问题,L3 无责)② 台架运行中一次 49s 全系统日志静默(net 栈期间照常处理连接 = defaultTask/NAND syslog 排空停滞,既有存储侧现象,L3 无责)
#### E-03 全局 `s_net_errno` 跨任务覆写竞态(09-21 修复的残留)
- **位置**:写方 = `net_socket.c:39` 单全局;netTask 侧 `:362/365/375/385/410` + **notify 值构造 `:419-423`**(`s_notified` 分支读同一全局);6 个队列包装器在**调用方上下文** `:660/758/818/1233/1286/1333`(仅失败路径写);6 个直调 API 在**调用方上下文**失败时写(`net_socket :442/449`、`net_bind :482-538`、`net_sendto/net_recvfrom`、`net_getsockname :1953-1964`),**成功不写** → stale 滞留(`:1609` 文档化)。读端:`ui_net_sink.c:460`(uiTask 100Hz,BelowNormal 被抢占窗口最大)、`test/net_test_task.c:230/381`
@@ -312,8 +321,8 @@ E-60"write_enable WRTC2 与手册矛盾"经三方复核(手册表头 D7~D0 顺
| E-17 | `net_task.c:201-203` | RECONFIG `Get`+`Clear` 非原子 TOCTOU(=既有 P2-11)——**本次重评**:命令无载荷(执行读最新 RAM 副本、代次在执行时递增),丢失 = 本次重建跳过、下次保存/重启自愈,无数据丢失 → 维持清单、风险低于原评级 | `osEventFlagsWait` 原子消费 |
| E-18 | `freertos.c:422-424` | ftpTask `WaitAll(osWaitForever)` 无超时 → 生产端故障时 FTP 永久静默阻塞 | 超时 + 降级日志 |
| E-19 | `freertos.c:430`;`sys_events.h:28-29` | 死事件位:`FTP_READY` 置位在 `lftpd_start`(无限循环)返回后 = **不可达**;`TIMESYNC_READY` 从未置位 → 未来消费者 Will 永久阻塞 | 删除或改在首次监听成功后置位 |
| E-20 | `lftpd_inet.c:100-127`、`lftpd.c:555-561` | 控制通道 30s 阻塞 recv 兼存活判定 + 行>511B/EOF/真错误同返 -1 → 慢客户端被断、长命令杀会话、叠加 E-02 | DONTWAIT + 调用方状态机;超长回 501 保会话 |
| E-21 | `time_sync.c:128-144/:80-97` | accept 一切失败=无连接(200ms 静默重试、无 errno 分类/日志)+ 30s 阻塞 recv + close-then-rebuild 空窗 | errno 分级(BADF/INVAL→重建+日志);DONTWAIT + 会话超时(=既有 P2-8 扩展) |
| E-20 | `lftpd_inet.c:100-127`、`lftpd.c:555-561` | 控制通道 30s 阻塞 recv 兼存活判定 + 行>511B/EOF/真错误同返 -1 → 慢客户端被断、长命令杀会话、叠加 E-02 | DONTWAIT + 调用方状态机;超长回 501 保会话。(30s 阻塞 recv 分量已由 L3 pending 化解,f16dc9a:执行器不再阻塞;errno 分类/501 分量仍待办) |
| E-21 | `time_sync.c:128-144/:80-97` | accept 一切失败=无连接(200ms 静默重试、无 errno 分类/日志)+ 30s 阻塞 recv + close-then-rebuild 空窗 | errno 分级(BADF/INVAL→重建+日志);DONTWAIT + 会话超时(=既有 P2-8 扩展)。(30s 阻塞 recv 分量已由 L3 pending 化解,f16dc9a;errno 分级/空窗分量仍待办) |
| E-22 | `lftpd.c:608-626`、`time_sync.c:96/:146-149` | close-then-relisten 每会话端口空窗 ~0.2-1.7s(合规对照 = `ui_net_sink.c:446-457`:EOF 不 close、靠 auto_relisten 常驻) | 向 ui_sink 模式看齐 |
| E-23 | `test/net_test_task.c:869-917/:296-403` | 监听主循环与 phase7 无代次检查(网络重建后恒 BADF 空转)+ TC704 8 路 socket 与 3 个并发服务抢 8 槽 fd 池 → 假 FAIL | 代次检查 + 降并发/测试构建抑制服务任务 |
| E-24 | `net_socket.c:1971-1975 × :162`;`lftpd.c:398-413` | `s_local_ip` 逐字节拼读 × reconfig 重写不原子 → PASV 227 响应 IP 混拼(低频人工触发) | getsockname 入队列或临界区快照 |
@@ -399,7 +408,7 @@ E-60"write_enable WRTC2 与手册矛盾"经三方复核(手册表头 D7~D0 顺
| # | 项 | 内容 |
|---|---|---|
| 1 | **E-02+E-06+E-20+E-21** | 阻塞模型改造:lftpd 控制通道/timeSync 改 `DONTWAIT` + 调用方状态机(ui_sink 模式推广);`net_process_messages` 长阻塞间隙按 tick 继续排空队列;`accept_timeout` 墙钟计时 + 去跨任务 state 直读。**E-02 部分已闭环(2026-09-22,f8d6e90+4a1605b)**:两触发源改 `net_recv_to` 分片有界读(落地方案 = 有界阻塞片,非 DONTWAIT 重投),台架 A/B 实证;E-06/E-20/E-21 部分仍待办(候选公共地基 = pending 请求机制,利弊/改动量/验证门禁见 `docs/问题记录/Net层阻塞模型业界对照与演进方案.md` §6) |
| 1 | **E-02+E-06+E-20+E-21** | 阻塞模型改造:lftpd 控制通道/timeSync 改 `DONTWAIT` + 调用方状态机(ui_sink 模式推广);`net_process_messages` 长阻塞间隙按 tick 继续排空队列;`accept_timeout` 墙钟计时 + 去跨任务 state 直读。**E-02 已全量闭环(2026-09-22)**:阶段一 = `net_recv_to` 分片有界读(f8d6e90+4a1605b,缓解);阶段二 = **L3 pending 化**(f16dc9a,wip/v2-pending-recv)——阻塞 RECV 改挂起请求、执行器零占用零阻塞、调用方分片协议退役,台架全量复验(M3 重锁/功能套件/e02_probe/产品 @test 全 PASS,明细见 §3.2 E-02 段);E-06/E-20/E-21 剩余分量(SEND/ACCEPT 阻塞路径、errno 分级、501 保会话)待办——公共地基 pending 机制一期(RECV)已落地,二期(SEND/ACCEPT)沿用同一机制扩展(利弊/改动量/验证门禁见 `docs/问题记录/Net层阻塞模型业界对照与演进方案.md` §6) |
| 2 | **E-05** | `net_socket/net_bind/net_getsockname` 并入队列(新消息类型);过渡方案:alloc+init 临界区 + `s_dynamic_port` 收归 netTask |
| 3 | **E-10/E-42/E-53/E-54** | GD5F 驱动错误通道统一:init 重试 1~2 次;`wait_busy`/轮询路径 HAL 检查;ECC 使能回读校验;错误向上传递 |
| 4 | **E-22** | lftpd/timeSync 向 ui_sink close 规则看齐(EOF 不 close、auto_relisten 常驻、仅代次变化/判死时重建) |
@@ -503,7 +512,7 @@ E-60"write_enable WRTC2 与手册矛盾"经三方复核(手册表头 D7~D0 顺
| 队列 | 定义处 | 深度 | 条目形态 | 回传机制 | 免疫/风险 |
|---|---|---|---|---|---|
| `netMsgQueue` | `Src/freertos.c:166` | 8 | `net_msg_t` **按值**(fd/长度/输入指针) | 任务通知值(精确错误码/字节数);指针字段回写(net_accept 地址) | 09-21 后契约健全;残留 = 全局 errno 竞态(E-03)、头阻塞(E-02) |
| `netMsgQueue` | `Src/freertos.c:166` | 8 | `net_msg_t` **按值**(fd/长度/输入指针) | 任务通知值(精确错误码/字节数);指针字段回写(net_accept 地址) | 09-21 后契约健全;头阻塞(E-02)经 L3 pending 化解(f16dc9a:执行器零阻塞,阻塞 RECV 等待 = 挂起请求);残留 = 全局 errno 竞态(E-03) |
| syslog 队列 | `sys_log_mcu.c:218-223`(惰性) | 64 | 输入型(id + 静态串指针) | 无回传(fire-and-forget) | 结构免疫 P1;preboot 窗口(E-08) |
| `cfgSaveQueue` | `freertos.c`(defaultTask/uiTask 间) | 8 | 输入型(路径指针) | `s_save_pending` 锁存 + `s_save_result` 状态机 | 协议无损(§7-3) |
@@ -530,4 +539,4 @@ E-60"write_enable WRTC2 与手册矛盾"经三方复核(手册表头 D7~D0 顺
---
*报告完。59 项发现全部带 file:line 落点;P0/P1 核心机制经父审计组逐行复核(含 `docs/芯片手册/SD2506API-G.md` L392-398/L537/§4.8 原文核对与 `SD2506_Trap_Records.md` 硬件观测交叉验证)。2026-09-21 复核修订:E-32 由 P0 降 P2(充电器 P0 链被"出厂 82H"证伪)、E-39 机制改写(ARST 在 CTR3、驱动从未写过 CTR3)、E-60"write_enable WRTC2 与手册矛盾"经手册表头位序 + DFRobot GravityRtc 官方库/社区代码 + 实测三方复核证伪(0x84 本已含 D2=WRTC2,代码与手册 L392 一致)移除,见 §7-19;18H 寄存器事实经手册 §4.8 专用表复核(Bit7=EN_Charge、Bit1=Charge1、Bit0=Charge0,复位 0x03,出厂 0x82=EN+5k,总表 L119 该行转录有误以 §4.8 为准);§6 交叉引用补 P2-2/P2-6。审计期间未修改任何代码、未执行构建;2026-09-21 依第一档 #1 完成 E-32 修复(commit 41e111b:18H 回读校验 + 漂移时写允许窗口重置与回读验证、0FH 死写与误注移除、充电宏位订正;构建 0 错误 0 警告,台架 RTC 套件 Phase 1 6/6 + Phase 2 累计 17/17 PASS 含 set==readback,产品固件重烧后启动校验 PASS,ST-LINK 全片回读 No difference);同日依第一档 #2 完成 E-31 修复(commit da1a6e8:journal.c 三处错误源治理——扫描读失败不再覆盖为 TOO_BAD、读成功但 checkpoint 不符判 CORRUPT_MAP + nand_ftl.c 错误分类——仅真空白判 fresh、其余失败返回 STA_NOINIT 给 mount 层 + freertos.c 启动块重构为 storage_bring_up() 并加 3×2s 有界重试自愈策略;构建 0 错误 0 警告;产品固件台架回归 PASS:`@test` 闭环 Required(含 `Map resumed`/`FATFS mounted`)全中、Forbidden 零命中,既有卷 2441/96064 扇区 resume 成功、用户配置 523B 原样加载、FTP 屏障链通,ST-LINK 全片回读 No difference);2026-09-22 依第一档 #3 完成 E-01 修复(commit d030cb0:poll 超长判定基于 `cfg_store_stat` 真实 st.size 前置到 `s_load_file` 之前根治死码、超长走工厂默认+重建模板+自检留痕且不触发段回调保留在线修复通道、save 输出上限 CFG_OUT_MAX→CFG_FILE_MAX_LEN、`s_write_doc` 写盘唯一闸口硬拒超长、load/poll 超长处置补 SYSLOG_SELFTEST 留痕;构建 0 错误 0 警告;台架验证 PASS:FTP STOR 5047B → poll 守卫 4s 内触发并重建 523B 工厂模板(RETR 实测)、设备保持在线、重启 load 守卫同链自愈、再重启零 `[ERR]` 无销毁循环、selftest.log 双留痕、模拟器 cfgtest 两个新回归锁场景 PASS、@test 默认闭环 PASS、ST-LINK 全片回读 No difference;验证中暴露并修复关联缺陷 `cfg_store_write_atomic` f_rename 对已存在目标不覆盖致设备端一切覆盖写静默失败(commit 70f1cc8:rename 前先 unlink 目标),详见 E-01 明细"关联新发现");2026-09-22 依第二档 #1 完成 E-02 修复(commit f8d6e90:lftpd 侧 `net_recv_to` 5ms 分片有界读 + 30s 总预算,M3 压力档 17.7s 尖峰归零;commit 4a1605b:timeSync 侧同模式改造 + 超时留痕;产品构建 `@test` 闭环 PASS;台架 A/B(`test/e02_probe.py`):挂起对时客户端下 FTP banner 旧 28554ms → 新 109ms/75ms、30s 预算拆连留痕、监听恢复行为同构、正常对时路径全通;详见 E-02 明细"已修复")。*
*报告完。59 项发现全部带 file:line 落点;P0/P1 核心机制经父审计组逐行复核(含 `docs/芯片手册/SD2506API-G.md` L392-398/L537/§4.8 原文核对与 `SD2506_Trap_Records.md` 硬件观测交叉验证)。2026-09-21 复核修订:E-32 由 P0 降 P2(充电器 P0 链被"出厂 82H"证伪)、E-39 机制改写(ARST 在 CTR3、驱动从未写过 CTR3)、E-60"write_enable WRTC2 与手册矛盾"经手册表头位序 + DFRobot GravityRtc 官方库/社区代码 + 实测三方复核证伪(0x84 本已含 D2=WRTC2,代码与手册 L392 一致)移除,见 §7-19;18H 寄存器事实经手册 §4.8 专用表复核(Bit7=EN_Charge、Bit1=Charge1、Bit0=Charge0,复位 0x03,出厂 0x82=EN+5k,总表 L119 该行转录有误以 §4.8 为准);§6 交叉引用补 P2-2/P2-6。审计期间未修改任何代码、未执行构建;2026-09-21 依第一档 #1 完成 E-32 修复(commit 41e111b:18H 回读校验 + 漂移时写允许窗口重置与回读验证、0FH 死写与误注移除、充电宏位订正;构建 0 错误 0 警告,台架 RTC 套件 Phase 1 6/6 + Phase 2 累计 17/17 PASS 含 set==readback,产品固件重烧后启动校验 PASS,ST-LINK 全片回读 No difference);同日依第一档 #2 完成 E-31 修复(commit da1a6e8:journal.c 三处错误源治理——扫描读失败不再覆盖为 TOO_BAD、读成功但 checkpoint 不符判 CORRUPT_MAP + nand_ftl.c 错误分类——仅真空白判 fresh、其余失败返回 STA_NOINIT 给 mount 层 + freertos.c 启动块重构为 storage_bring_up() 并加 3×2s 有界重试自愈策略;构建 0 错误 0 警告;产品固件台架回归 PASS:`@test` 闭环 Required(含 `Map resumed`/`FATFS mounted`)全中、Forbidden 零命中,既有卷 2441/96064 扇区 resume 成功、用户配置 523B 原样加载、FTP 屏障链通,ST-LINK 全片回读 No difference);2026-09-22 依第一档 #3 完成 E-01 修复(commit d030cb0:poll 超长判定基于 `cfg_store_stat` 真实 st.size 前置到 `s_load_file` 之前根治死码、超长走工厂默认+重建模板+自检留痕且不触发段回调保留在线修复通道、save 输出上限 CFG_OUT_MAX→CFG_FILE_MAX_LEN、`s_write_doc` 写盘唯一闸口硬拒超长、load/poll 超长处置补 SYSLOG_SELFTEST 留痕;构建 0 错误 0 警告;台架验证 PASS:FTP STOR 5047B → poll 守卫 4s 内触发并重建 523B 工厂模板(RETR 实测)、设备保持在线、重启 load 守卫同链自愈、再重启零 `[ERR]` 无销毁循环、selftest.log 双留痕、模拟器 cfgtest 两个新回归锁场景 PASS、@test 默认闭环 PASS、ST-LINK 全片回读 No difference;验证中暴露并修复关联缺陷 `cfg_store_write_atomic` f_rename 对已存在目标不覆盖致设备端一切覆盖写静默失败(commit 70f1cc8:rename 前先 unlink 目标),详见 E-01 明细"关联新发现");2026-09-22 依第二档 #1 完成 E-02 修复(commit f8d6e90:lftpd 侧 `net_recv_to` 5ms 分片有界读 + 30s 总预算,M3 压力档 17.7s 尖峰归零;commit 4a1605b:timeSync 侧同模式改造 + 超时留痕;产品构建 `@test` 闭环 PASS;台架 A/B(`test/e02_probe.py`):挂起对时客户端下 FTP banner 旧 28554ms → 新 109ms/75ms、30s 预算拆连留痕、监听恢复行为同构、正常对时路径全通;详见 E-02 明细"已修复");2026-09-22 依第二档 #1 完成 E-02 阶段二(commit f16dc9a,分支 wip/v2-pending-recv):L3 pending 化——阻塞 RECV 改挂起请求(每 fd 一个、cancel/settle 必通知),完成判定收敛 netTask 主循环节拍 `net_pending_tick`(数据→截止→CLOSED 排空/EOF+relisten→1s 看门狗),执行器零占用零阻塞;lftpd/timeSync 分片协议退役为剩余预算循环;公开 API/返回语义不变。台架全量复验:M3 重锁静默 med 58.9/max 72.1ms、压力档 med 60.1/max 69.3/零尖峰(阶段一基线 65.0/133.5)、MCU 侧 prod_cycle_mcu 6706µs 压力下平坦;功能套件 6/9/11 全 PASS + Phase 8-RECV 100KB 阻塞接收 50/50 块 + CRC32 一致;e02_probe 队列响应性 92.5ms、30s 截止 30.1s 精确触发、TIME 路径全通;产品 `@test` PASS(netTask 栈峰值 488B/4096=88% 余量);RAM +200B/Flash +608B。台架新发现(A/B 归因与 L3 无关,转 `docs/待处理内容.md`):4096B 经 2KB 芯片缓冲的回显残留停滞(切片构建同现)+ 一次 49s defaultTask/NAND syslog 排空停滞。*