Trap 21 主因定案:排空后50-100ms内第二条RX命令(剂量台架证伪满态时长说);新增N-7排空后RX守卫方案、指南最小复现配方
This commit is contained in:
@@ -547,31 +547,30 @@ CH395F 片内 TCP 状态机的角(芯片固件,MCU 侧无法修补),与"
|
||||
|
||||
1. **结构性前提**:窗口=剩余空间(手册 L1281)→ 守规矩的对端永远把窗口灌满 → 每个稳态轮次缓冲**恰好填满**(2048/2048,窗口=0)是结构性必达状态,无法通过几何裕量规避。
|
||||
2. **冻结机制**:缓冲恰好填满的状态与"在途段接收 / 窗口重通告 / MCU 排空"时序交叠时,芯片接收路径状态机卡死——停止对后续段的确认与接收(数据滞留线上、对端重传),缓冲保持空、窗口不更新、连接保持。WCH 在 CH395 系列官方 FAQ 中留档了同类现象:"接收缓冲区需要大于 2 倍设置的 MSS 值,否则……若对端设备不会根据 tcp 窗口来分包发送数据时,有可能会造成 CH395 收不到数据且 TCP 窗口不更新现象"(www.cnblogs.com/sw111/p/18750601,2025-03)。WIZnet W5500(同类:每 Socket 小型缓冲 + 片内 TCP + 窗口=剩余空间)官方文档同为"缓冲满则挂起连接等待空闲空间"模型,zero-window 停摆是该类芯片的经典病理(docs.wiznet.io W5500 TCP Application 文档;Wireshark 论坛 49849 实例)。
|
||||
3. **触发模式(2026-09-22 二次台架 2×2 复核,均为确定性而非随机竞态)**:
|
||||
- **三因子模型(MSS=1024 基线)**:① MCU 侧负载(testTask/netTask 活动使缓冲排空滞后)+ ② 同连接前序突发(缓冲经前序填/排周期预置)+ ③ 后续突发超缓冲容量(4096B > 2KB,需 ≥2 个填周期)——**三者齐备才触发,缺一不触发**(socket 新旧/历史无关,开机后首条连接在重负载下同样触发):
|
||||
3. **触发模式(2026-09-22 二次台架:2×2 交叉 + 排空节拍剂量 + 最小扰动实验,均为确定性而非随机竞态)**:
|
||||
- **三因子模型(MSS=1024 基线;主因已定案)**:① 同连接前序突发(芯片 RX 状态预置;高段密度可等效替代,见 MSS=512 条)+ ② 后续突发超缓冲容量(4096B > 2KB,需 ≥2 个填周期)+ ③ **填周期内第二条 RX 命令**(排空之后同一 socket 的任何额外 SPI 命令——纯状态读 GET_RECV_LEN 即足够)——**三者齐备才触发,缺一不触发**:
|
||||
|
||||
| 构建(负载) | PC 序列 | 运行间隔 | 结果 |
|
||||
|---|---|---|---|
|
||||
| Phase 6/9/11(重) | 64B×10+1460B+4096B | ~12s | **10/10 停摆**(4096B 步:前 2048B 回显正常,余停) |
|
||||
| Phase 6 only(轻) | 同上 | ~15s | **10/10 全过**(1460B/4096B 完全匹配) |
|
||||
| Phase 6 only(轻) | 同上 | 600ms 连续 | run1 全过;run2 起转 **Trap 22 失同步模式**(非本条冻结) |
|
||||
| 重负载、无前序突发 | 新连接独立 4096B | — | 过(31ms;probe_mss 对照) |
|
||||
| 变体 | 与 Phase 6-only(单 RX 命令路径)的差异 | 结果 |
|
||||
|---|---|---|
|
||||
| Phase 6/9/11(每周期多路 RX 命令) | Phase 9/11 各加一路 RX 命令/周期 | **10/10 停摆**(4096B 步:前 2048B 回显正常,余停) |
|
||||
| Phase 6-only + 排空间隔 10/20/40/60ms(E 系列) | **只拉长排空间隔,不加第二条命令** | **40/40 全过**(每档 10/10,含满态持续 60ms+) |
|
||||
| Phase 6 + 11 + 60ms 间隔(V1,最小扰动) | 每周期加一条 GET_RECV_LEN 状态读(落点 ≈ 排空后 45ms) | **10/10 停摆**(4096B 步,落点与经典模式一致) |
|
||||
| 多路 RX 命令、无前序突发 | 新连接独立 4096B | 过(31ms;probe_mss 对照——前序突发因子缺失) |
|
||||
|
||||
"负载"= testTask 每 tick 的 net_* 调用密度(Phase 9/11 的 select/recv/串口日志使排空节拍变稀);旧"队列竞争"表述作废(net_select 不产生队列消息,只读 RAM 状态)。
|
||||
- MSS=512:新连接 4096B 突发(8×512 段,4 段装不进 2KB 缓冲)**确定性停摆**,恒剩 64B 未达(4032/4096,2/2 同值)——段密度维度:满周期内段数越多越易触发,且一旦触发必现(该实验在重负载构建上执行,与三因子模型自洽)。
|
||||
- 单轮无溢出突发(≤2KB,如 1460B)在任何几何/负载下均正常。
|
||||
- **主因(本轮定案)**:冻结与缓冲"满"的持续时长**无关**——排空间隔拉到 60ms、缓冲满态持续 60ms+,单命令路径仍 40/40 干净("满了滞后不舀"假设被证伪)。芯片 RX 状态机敏感的是**排空(窗口重通告/再武装)之后 ~50–100ms 内到达的第二条 socket 命令**:V1 第二条命令落点 ≈ 排空后 45ms → 10/10 卡死;E 系列下一条命令落点 ≈ 95ms → 10/10 干净。旧"负载"因子据此降级:重载构建触发是因为 Phase 9/11 **每周期多一条 RX 命令**,而非拖慢排空;"队列竞争"表述彻底作废(队列消息对芯片不可见,MCU 到达芯片状态机的唯一通道 = SPI 命令总线)。
|
||||
- MSS=512:新连接 4096B 突发(8×512 段,4 段装不进 2KB 缓冲)**确定性停摆**,恒剩 64B 未达(4032/4096,2/2 同值)——段密度维度:满周期内段数越多,突发内自我预置越快,越易触发(该实验在多 RX 命令构建上执行,与主因模型自洽)。
|
||||
- 单轮无溢出突发(≤2KB,如 1460B)在任何几何/命令结构下均正常。
|
||||
4. **排除项**:① 驱动层"超限读静默丢弃"排除——SPI DMA 缓冲 = 2×MSS+4 = 2052B(载荷 2048 = 整个接收缓冲),整缓冲读单事务完成,失败运行中丢弃事件 0 次(Trap 13 所记 1500B DMA 缓冲为 8-Socket 改造前旧值,改造后扩至 2052B);② L3 pending 化排除(切片构建 A/B 行为逐字节一致);③ "RX > 2×MSS"裕量假设排除——MSS 1024→512 实验(2KB=4×MSS、1KB 裕量)既未消除原复现序列的停摆(10/10),又新增新连接停摆 → 已回退 1024。
|
||||
|
||||
### 解决(2026-09-22)
|
||||
芯片侧固件缺陷,MCU 无法修补;策略 = 低风险几何 + 可观测 + 断开重试:
|
||||
|
||||
1. **MSS 维持 1024**(布局允许最大值;实测 1024 下新连接 4096B 正常、每满周期段数少 = 触发概率最低)。MSS=512 裕量方案被证伪并回退。
|
||||
### 解决(2026-09-22;同日主因定案更新:存在 MCU 侧缓解路径)
|
||||
1. **MSS 维持 1024**(布局允许最大值;实测 1024 下新连接 4096B 正常、每满周期段数少 = 预置积累最慢)。MSS=512 裕量方案被证伪并回退。
|
||||
2. **缓冲块布局与 MSS 解耦**(`ch395f.h`):`CH395F_RECV_BLOCKS=4` / `CH395F_SEND_BLOCKS=2` 固定(此前由 MSS 推导,改 MSS 会连带缩小布局);`CH395F_SPI_DMA_BUF_SIZE = 接收缓冲 + 4`(此前 2×MSS+4,改 MSS 会缩到装不下整缓冲)。
|
||||
3. **超限读金丝雀**(`ch395f_read_recv_buf`):正常路径不可能发起超过接收缓冲(2KB)的读;守卫命中即留痕 `read_recv_buf OVERSIZE`(原为静默 return,会把窗口锁死在 0 且无从诊断)。
|
||||
4. **生产缓解(决策项,未实施)**:冻结不自恢复(对端重传 10s 无效;芯片无限期保持连接)。唯一恢复 = 断开受影响连接(释放芯片 per-socket 状态)+ 对端重试(新连接成功率高;台架实测停摆后重连回显正常)。现 lftpd 数据路径预算 `LFTPD_TOTAL_BUDGET_MS=30000`(每次读 30s)即实际停摆超时——若将**数据通道**预算单独缩短(10–15s,与控制行预算分离),可把停摆暴露时间从 30s 压缩到客户端重试路径;代价 = 慢速但健康的传输也会被中断(机器客户端不受影响,人工客户端受影响)→ 已列 `docs/待处理内容.md` N-1 待决策。
|
||||
4. **MCU 侧主因缓解(2026-09-22 主因定案后新增,待批准 → N-7)**:主因 = 排空后 ~50–100ms 内的第二条 RX 命令(台架 V1 10/10 / E 系列 40/40 定案),可在 net 层**关死该窗口**:排空整缓冲后,该 socket 的后续 RX 命令暂缓,直至 (a) 下一个 RECV_OK(数据真到达 = 芯片再武装完成,事件驱动、零额外时延)或 (b) ~120ms 冷却到期;TX 路径不受限(台架证实排空后的 TX 安全)。生产数据通道为主要受益者:lftpd `receive_file` 块循环每 1KB 一条 `net_recv`(结构性每填周期第二条 RX,间隔 15–70ms 正落台架实证危险区)→ 守卫将其变为事件驱动排空,消除生产停摆主因。
|
||||
5. **兜底缓解(决策项,未实施)**:冻结不自恢复(对端重传 10s 无效;芯片无限期保持连接)。唯一恢复 = 断开受影响连接(释放芯片 per-socket 状态)+ 对端重试(新连接成功率高;台架实测停摆后重连回显正常)。现 lftpd 数据路径预算 `LFTPD_TOTAL_BUDGET_MS=30000`(每次读 30s)即实际停摆超时——若将**数据通道**预算单独缩短(10–15s,与控制行预算分离),可把停摆暴露时间从 30s 压缩到客户端重试路径;代价 = 慢速但健康的传输也会被中断(机器客户端不受影响,人工客户端受影响)→ 已列 `docs/待处理内容.md` N-1 待决策(N-7 落地后本项紧迫性下降,保留为兜底)。
|
||||
|
||||
### 注意事项
|
||||
- 复现模式 = 三因子齐备(负载 + 前序突发 + 超容突发,见触发模式表):**台架复现 TC-NET-604 必须用 Phase 6/9/11 构建**(轻载 Phase 6-only 构建不触发,10/10 全过);生产中同数据连接带前序部分传输的 FTP STOR/RETR(叠加并发任务负载时)是主要风险场景;纯新连接大突发(4×1024)在 MSS=1024 下不触发。
|
||||
- 复现模式 = 三因子齐备(前序突发 + 超容突发 + 填周期内第二条 RX 命令,见触发模式表):**台架复现 TC-NET-604 需要数据 socket 带第二 RX 命令路径的构建**(Phase 6/9/11 组合,或最小复现配方 **Phase 6+11 + 60ms 排空间隔**,V1 配方 10/10);Phase 6-only 构建(单命令路径)在 ≤60ms 排空间隔下均不触发(E 系列 40/40 过)。生产主要风险场景 = **lftpd 数据通道 STOR(上传)**:块循环每 1KB 一条 `net_recv`(结构性第二 RX)+ 快速流式客户端 + 文件 >2KB → 块循环间隔(15–70ms)落入实证危险区(~50–100ms);RETR(下载,设备为发送方)不经过芯片 RX 缓冲填满路径,不受本机制影响;纯新连接大突发(4×1024)在 MSS=1024 下不触发(缺前序预置)。
|
||||
- 与 Trap 22 的鉴别(两者都可在断连/重监听后出现):本条 = RX 路径冻结(有 standalone accept、前段回显正常、其后 RECV_OK 永不再来、无 send 失败);Trap 22 = 连接状态失同步(缺 standalone accept + `send -1` + `WARNING: listen` + 监听死亡)。
|
||||
- 冻结是静默的:无 RST、无芯片中断、MCU 侧只见"缓冲空 + 无 RECV_OK + 连接存活"(与正常空闲完全同貌)——MCU 无直接信号,只能靠应用层数据预算(lftpd 30s / 客户端自身超时)发现。
|
||||
- E-02 审计"STOR 方向缓冲满 + 重传耗尽 → 必断"的预警方向成立(STOR 方向 = 致命),机制修正为本条 RX 冻结(非 RST 拆连)。
|
||||
|
||||
Reference in New Issue
Block a user