Net 阻塞模型文档改写为架构设计并迁入 docs/网络
This commit is contained in:
+1
-2
@@ -78,7 +78,7 @@ docs/
|
||||
| [`运行与自检记录设计说明.md`](子系统设计/运行与自检记录设计说明.md) | `/log/run.log`·`selftest.log` 定长记录与待机显示 |
|
||||
| [`网络/BSD_Socket_API_使用指南.md`](网络/BSD_Socket_API_使用指南.md) | **上层视图**:BSD Socket API 公开语义、示例、常见问题 |
|
||||
| [`网络/BSD_Socket_API_函数调用关系.md`](网络/BSD_Socket_API_函数调用关系.md) | **内部视图**:netTask / 消息队列 / L3 挂起 / 重试对账的调用关系与设计意图 |
|
||||
|
||||
| [`网络/Net层阻塞模型架构设计.md`](网络/Net层阻塞模型架构设计.md) | **等待模型**:pending 请求架构、五路完成语义、设计边界与性能特征 |
|
||||
---
|
||||
|
||||
## 5. 测试说明
|
||||
@@ -147,7 +147,6 @@ 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) | E-02 阻塞模型改造客观实施记录(一期 pending 化:偏差/门禁实测/未执行项) |
|
||||
| [`错误码传播审计.md`](问题记录/错误码传播审计.md) | 错误码传播缺陷审计(9 类模式 × 子系统) |
|
||||
|
||||
---
|
||||
|
||||
@@ -115,9 +115,8 @@
|
||||
|
||||
## 3.1 C1 设计基线(pending 二期:ACCEPT + SEND)
|
||||
|
||||
> **来源**:从已归档的《Net 层阻塞模型业界对照与演进方案》(2026-09-26 删除)中抽取——
|
||||
> 该文档的调研/规划部分已完成使命,客观实施部分另存为
|
||||
> `docs/问题记录/Net层阻塞模型改造实施记录.md`;本节仅保留**二期仍要用的设计基线**。
|
||||
> **来源**:一期(RECV)架构现状见 `docs/网络/Net层阻塞模型架构设计.md`(含演进溯源附录);
|
||||
> 本节仅保留**二期仍要用的设计基线**。
|
||||
|
||||
**一期已验证的机制骨架**(二期沿用,勿重新发明):独立静态 pending 表 + `net_pending_tick`
|
||||
主循环节拍了结(五路:数据/到点/断连/同 fd 串行/重建取消必通知)+ 登记守卫(每 fd 至多一个、
|
||||
|
||||
+1
-1
@@ -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`);设计基线与门禁见 `下一步任务规划.md` §3.1,实施记录见 `Net层阻塞模型改造实施记录.md` | 同左 + `错误码传播审计.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`);架构现状见 `Net层阻塞模型架构设计.md`,二期设计基线与门禁见 `下一步任务规划.md` §3.1 | 同左 + `错误码传播审计.md` 第二档 #2 |
|
||||
|
||||
@@ -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` —— 阻塞等待模型的现状架构设计(pending 请求模型 / 五路完成语义)
|
||||
- `docs/问题记录/错误码传播审计.md` —— E-02 头阻塞与错误码回传全审计
|
||||
- `docs/测试说明/链路延迟测试说明.md` —— D1/D10/L3/D14 等时延探针与自愈路径的台架证据
|
||||
- `docs/子系统设计/网络配置说明.md` §4 —— 代次号与网络重建时序
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
# Net 层阻塞模型架构设计
|
||||
|
||||
> **模块名称**:Net 层(`net_socket.c` / netTask)阻塞等待模型
|
||||
> **文档定位**:**现状架构设计说明**——描述本层**当前如何组织等待与完成**、为什么这样设计、
|
||||
> 边界条件与已验证的性能特征。**不是历史记录**;演进过程与门禁实测数据作为溯源附于文末。
|
||||
> **状态**:设计已落地并全量台架验证(`v2-on-ui`)。
|
||||
> **日期**:2026-09-29
|
||||
> **相关文档**:
|
||||
> `docs/网络/BSD_Socket_API_使用指南.md`(应用视角 API 语义)、
|
||||
> `docs/网络/BSD_Socket_API_函数调用关系.md`(调用链与执行域)、
|
||||
> `docs/测试说明/链路延迟测试说明.md`(延迟基线与故障对照)、
|
||||
> `docs/审查记录/下一步任务规划.md` §3.1(二期 ACCEPT/SEND 扩展设计)
|
||||
|
||||
---
|
||||
|
||||
## 1. 问题域
|
||||
|
||||
netTask 是**全部 socket 操作的唯一执行者**——CH395F 的 SPI 总线归它独占(SPI 铁律),
|
||||
因此所有 socket 操作必须经消息队列串行化到 netTask 上下文完成。
|
||||
|
||||
这带来一个结构性约束:**消费者发起的"等待数据"会占住执行者**。若 `net_recv` 采用
|
||||
"在 netTask 内自旋轮询直到数据到达"的朴素形态,一条空闲连接即可让整个网络层停摆——
|
||||
所有其他 socket 的操作都要排队等它。
|
||||
|
||||
> **约束的本质**:本项目的"数据到达"无法被免费观测。业界正统形态(LwIP 等)依赖网卡
|
||||
> DMA/IRQ 把数据递到协议线程,数据到达是 O(1) 事件;而本项目的数据到达发生在 CH395F
|
||||
> **芯片内部**,唯一观测手段是一次 SPI 事务,而 SPI 只许 netTask 发起。
|
||||
> → **观测本身占用执行者**,等待无法挪出 netTask。
|
||||
|
||||
设计自由度因此只剩两条:① 每次占用执行者多久 ② 等待期间执行者还能做什么。
|
||||
本架构的答案:**占用降到登记一次(微秒级),等待期间执行者照常服务整个队列**。
|
||||
|
||||
---
|
||||
|
||||
## 2. 架构总览:pending 请求模型
|
||||
|
||||
核心思想:把"等数据"从**执行者内的自旋**改为**执行者外的登记**。
|
||||
|
||||
```
|
||||
调用方任务 netTask(执行者) CH395F 芯片
|
||||
────────── ───────────────── ────────────
|
||||
net_recv(fd, buf, len, timeout)
|
||||
│
|
||||
├─ 数据已在?── 是 ──→ 立即 SPI 读出 ────────────────────→ GET_REMV_LEN/READ
|
||||
│ 通知调用方(结果 = 字节数)
|
||||
│
|
||||
└─ 否,且 timeout>0
|
||||
│
|
||||
├─ 登记 pending 到 s_net_pending[fd] ← 占用执行者到此结束(微秒级)
|
||||
└─ 在自己上下文睡任务通知 ⟵──────────────┐
|
||||
│
|
||||
┌────────────────┴─────────────────┐
|
||||
│ netTask 主循环(~1ms 节拍) │
|
||||
│ net_poll() ← 刷新 readable
|
||||
│ net_pending_tick() ← 了结挂起
|
||||
│ net_relisten_retry_tick() │
|
||||
│ 排空消息队列 │
|
||||
└──────────────────────────────────┘
|
||||
│
|
||||
┌──────────────────────────────────────────────────┘
|
||||
│ 五路完成/取消判定(每轮对每个挂起 fd)
|
||||
│ ① 数据到达 → SPI 读出,通知调用方(结果 = 字节数)
|
||||
│ ② 到点 deadline → 通知 NET_ERR_TIMEDOUT
|
||||
│ ③ EOF/DISCONNECT → 按 0(EOF) 完成 + auto-relisten + 通知
|
||||
│ ④ 同 fd 后续操作 → 先行结算该 fd 的挂起,再执行新操作
|
||||
│ ⑤ 网络重建 → 取消 + **必须通知**(否则调用方永久挂死)
|
||||
└─→ xTaskNotify → 唤醒调用方
|
||||
```
|
||||
|
||||
**关键性质**:
|
||||
|
||||
- 等待期间 netTask **零额外占用**——`net_pending_tick` 只读标志与到期时间,
|
||||
数据到达判据 `readable` 由主循环既有的 `net_poll()` 每轮刷新,**不引入额外 SPI 事务**;
|
||||
- 调用方**在自己的上下文睡眠**(任务通知),与 LwIP 的消费者线程模型同构;
|
||||
- 公开 API 与调用契约**不变**——`net_recv` / `net_recv_to` 的签名、返回值、
|
||||
超时语义均与改造前一致,既有调用方、测试与模拟器零改动。
|
||||
|
||||
---
|
||||
|
||||
## 3. 数据结构
|
||||
|
||||
### 3.1 挂起请求表
|
||||
|
||||
| 项 | 设计 |
|
||||
|---|---|
|
||||
| 存储 | **独立静态数组** `s_net_pending[NET_MAX_SOCKETS]`(不置于 `net_sock_t` 内) |
|
||||
| 字段 | `active` / `buf` / `len` / `deadline` / `registered` / `caller` |
|
||||
| 容量 | 每 fd **至多一个**挂起请求 |
|
||||
| 占用 | ≈24B/fd × 8 fd = **192B**(+4B 任务句柄),实测 SRAM +200B |
|
||||
|
||||
**为什么独立成表而不是塞进 `net_sock_t`**:
|
||||
|
||||
`net_close_locked` 对 `net_sock_t` 做**整块 memset**。若挂起状态置于其中,`close` 会
|
||||
静默抹掉 pending——调用方永远等不到通知,**永久挂死**。独立表把"跨时间状态"与
|
||||
socket 生命周期解耦,与 `net_relisten_retry_tick` 的重试表同构。
|
||||
|
||||
### 3.2 登记守卫(两条硬防线)
|
||||
|
||||
| 守卫 | 理由 |
|
||||
|---|---|
|
||||
| 每 fd 至多一个,**不覆盖** | 覆盖 = 丢掉首个调用方的通知 = 该调用方永久挂起 |
|
||||
| `caller == NULL` 或 `caller == netTask` 时**拒绝**(返回 BUSY) | netTask 上下文自等待 = 无人能完成它 = 死锁;netTask 内必须用 DONTWAIT |
|
||||
|
||||
---
|
||||
|
||||
## 4. 完成与取消语义(五路)
|
||||
|
||||
`net_pending_tick()` 在主循环每轮运行,对每个挂起 fd 按序判定:
|
||||
|
||||
| # | 条件 | 动作 | 设计要点 |
|
||||
|---|---|---|---|
|
||||
| 1 | **数据到达** | SPI 读出 + 通知(结果 = 字节数) | 由 `net_poll` 维护的 `readable` 门控,**零额外 SPI**;仅 ESTABLISHED / UDP_OPEN 态可读;spurious readable 需清除 |
|
||||
| 2 | **到点** `now >= deadline` | 通知 `NET_ERR_TIMEDOUT`(对外 -2 映射保持) | 状态无关;用有符号回绕安全差值,防 tick 回绕 |
|
||||
| 3 | **CLOSED**(EOF/DISCONNECT) | 排空:有数据则读出;否则按 0(EOF) 完成 + `auto_relisten` + 通知 | CLOSE 先行完成挂起 = `net_close` 的 settle 钩子(排空→数据否则 CONNRESET) |
|
||||
| 4 | **同 fd 后续操作** | 先结算挂起,再执行新操作 | per-fd 串行——冻结面从"全网"缩到"本 fd" |
|
||||
| 5 | **网络重建**(`net_stack_bring_up`,芯片复位) | **取消 + 必须通知** | `net_init` 顶部 `net_pending_cancel_all(CONNRESET)`,先于芯片复位;**取消不通知 = 调用方永久挂死** |
|
||||
|
||||
**状态推断的克制**:CONNECTING / LISTENING 等中间态**保持等待**,**不做**状态推断式取消——
|
||||
CONNECT → ESTABLISHED 是合法迁移,推断取消会误杀正在建链的等待。
|
||||
|
||||
### 4.1 看门狗
|
||||
|
||||
到点后 1s 仍未了结 = 完成逻辑缺位 → **强制了结 + `DBG_ERROR`**。
|
||||
定位:防"挂起登记后永不完成"导致调用方无限期睡眠。
|
||||
|
||||
---
|
||||
|
||||
## 5. 调用方契约
|
||||
|
||||
调用方**不改协议、不改 API**,但需知悉三条:
|
||||
|
||||
| 契约 | 说明 |
|
||||
|---|---|
|
||||
| `buf` 生命周期 | 挂起期间 `buf` 指针须**保持有效**至调用返回(挂起表按指针写入) |
|
||||
| 剩余预算循环 | 调用方保留"总预算 − 已耗时"循环骨架(`n == -2` 续轮,预算耗尽退出)——这是**公开契约要求**(30s 总超时语义 + 跨 TCP 分段累积),与本架构无关 |
|
||||
| 超时精度 | 完成判定随主循环节拍(~1ms);主循环被长操作占用时,超时**最多顺延**相应时长(已知代价,见 §7) |
|
||||
|
||||
> **已退役形态**:改造前调用方需自行实现"5ms 分片 + `vTaskDelay(1)` 让出"协议。
|
||||
> 该协议已随本架构落地而删除——分片是"执行者被占"前提下的妥协,pending 模型下不再需要。
|
||||
|
||||
---
|
||||
|
||||
## 6. 性能特征(已验证)
|
||||
|
||||
| 指标 | 值 | 条件 |
|
||||
|---|---|---|
|
||||
| 队列响应性(挂起连接下) | **92.5ms** | 挂起对时客户端 + FTP banner 探测 |
|
||||
| 改造前同场景 | 28554ms | — |
|
||||
| M3 静默档帧周期 | med 58.9 / p95 69.9 / max 72.1ms | 零尖峰 |
|
||||
| M3 压力档帧周期 | med 60.1 / p95 66.4 / max 69.3ms | 零尖峰,p99 尾部 133.5→69.3ms |
|
||||
| netTask 栈峰值 | 488B / 4096(余量 88%) | 零占用设计落点 |
|
||||
| RAM / Flash 增量 | +200B / +608B | 相对改造前 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 设计边界与已知代价
|
||||
|
||||
| 项 | 现状 | 说明 |
|
||||
|---|---|---|
|
||||
| **SEND 路径未覆盖** | 发送仍为分块阻塞(1s/chunk stall) | 该期间队列仍被冻结;二期 pending 化解决 |
|
||||
| **ACCEPT 路径未覆盖** | accept 仍用轮询计时 | 需 pending 化(二期) |
|
||||
| **超时精度** | 随主循环节拍(~1ms),被长操作占用时顺延 | 一期文档化、不修;二期 SEND 化后该顺延面**收窄** |
|
||||
| **看门狗未接自检** | 强结算 + `DBG_ERROR`,未写 selftest | 二期补齐 |
|
||||
| **模拟器不可建模** | `net_socket_sim.c` 单线程 Winsock 无法复现挂起模型 | 该路径在模拟器上零覆盖,只能硬件验证 |
|
||||
|
||||
**二期扩展设计**(ACCEPT / SEND 的挂起化、门禁清单、改动量)见
|
||||
`docs/审查记录/下一步任务规划.md` §3.1。
|
||||
|
||||
---
|
||||
|
||||
## 8. 设计铁律(为什么是这样)
|
||||
|
||||
1. **执行者永不在等待中自旋**——等待必须在调用方上下文完成,netTask 只负责"登记"与"了结"。
|
||||
2. **取消必通知**——任何取消路径(close / 重建 / 陈旧重同步)都必须唤醒调用方,
|
||||
否则是永久挂死而非错误返回。
|
||||
3. **挂起状态与 socket 表解耦**——`net_sock_t` 会被整块 memset,跨时间状态不能寄居其中。
|
||||
4. **不做状态推断式取消**——中间态(CONNECTING/LISTENING)合法迁移存在,
|
||||
推断取消会误杀正常建链等待。
|
||||
5. **数据到达不引入额外 SPI**——判据复用主循环既有 `net_poll` 维护的 `readable` 标志。
|
||||
|
||||
---
|
||||
|
||||
## 附录 A:演进溯源
|
||||
|
||||
> 本架构由 E-02 缺陷修复演进而来(明细见 `错误码传播审计.md` E-02)。**以下为历史信息,
|
||||
> 描述"如何演到这里",不作为当前设计依据。**
|
||||
|
||||
**E-02 缺陷**:netTask 每次取一条消息处理到完成才取下一条;任一消费者发起的 30s 阻塞
|
||||
`net_recv` 期间队列整体停摆最长 30s(FTP 客户端空闲 >30s、对时客户端连上不发数据均可触发)。
|
||||
|
||||
**两代形态**:
|
||||
|
||||
| 代次 | 形态 | 状态 | 提交 |
|
||||
|---|---|---|---|
|
||||
| 一代 | 分片有界等待:`net_recv_to` + 5ms 片 + 30s 预算 + 片间 `vTaskDelay(1)` 让出 | 已退役 | `f8d6e90` / `4a1605b` |
|
||||
| 二代 | **pending 请求(本文档所述,现行)** | **一线现行** | `a45c0cb` |
|
||||
|
||||
**实施与初始设计基线的偏差**(如实留档):
|
||||
|
||||
| 基线条目 | 实施 | 说明 |
|
||||
|---|---|---|
|
||||
| pending 控制块 ≈20B/fd | ≈24B/fd × 8 = 192B | 实测 SRAM +200B,同量级 |
|
||||
| 控制块置于 `net_sock_t` 内 | **独立静态数组** | 见 §3.1 理由 |
|
||||
| 无数据 → 登记、跳过通知 | 哨兵 `NET_PENDING_REGISTERED`(0x70000000)→ `do_notify=0` | 逐字一致 |
|
||||
| 调用方改单次 `net_recv_to(…, 30000)` | **保留剩余预算循环** | 公开契约要求(见 §5) |
|
||||
|
||||
**验证门禁逐条实测**(2026-09-22,设备 192.168.1.100):
|
||||
|
||||
| # | 门禁 | 结果 |
|
||||
|---|---|---|
|
||||
| 1 | CH395F NET 层套件 | **PASS**:F1 组合 Phase 6/9/11(64B/1460B 回显 11/11、select 回显 11/11、断开重连、KeepAlive + auto-relisten);F2 组合 Phase 8-RECV(100KB 阻塞接收 50/50 块 + CRC32 整包一致 0x9A0E0C8C)。Phase 7/10 未跑(DONTWAIT 路径另由 M3 探针族 L5~L7 覆盖)。TC-NET-604 FAIL = 既有芯片侧问题(Trap 21,2026-09-23 结案非缺陷) |
|
||||
| 2 | M3 基线重锁 | **PASS**:见 §6 |
|
||||
| 3 | e02_probe A/B | **PASS 且优于分片方案**:队列响应性 92.5ms;30s 截止按节拍精确触发(30.1s);监听恢复 6.6s |
|
||||
| 4 | ftp_regression / E-06 假 425 | 随 F1/F2 + M3 压力档覆盖(FTP 半登录态即其场景) |
|
||||
| 5 | UI 远端推流压力 | **PASS**:`:7003` 100Hz 全帧 CRC 50/50,零尖峰 |
|
||||
| 6 | timeSync 三场景 | **PASS**:挂起 / 正常包;部分包由 Phase 8-RECV 跨段累积等效覆盖 |
|
||||
| 7 | 产品 `@test` + 全片回读 | **PASS**:Required 全中 / Forbidden 零命中;回读 `No difference found` |
|
||||
| 8 | RAM/栈前后对比 | **PASS**:见 §6 |
|
||||
|
||||
**未执行 / 延后项**:
|
||||
|
||||
- 未保留分片路径作影子对照 → 分片协议直接退役;对照由"旧镜像 A/B"承担,回退 = git revert
|
||||
(单提交、API 不变);
|
||||
- 探针族扩充(close/reconfig/EOF/disconnect-during-pending 专项)→ 二期;
|
||||
- 看门狗接 selftest 留痕 → 二期;
|
||||
- 模拟器差距 +1(`net_socket_sim.c` 无法建模挂起)→ 二期更新清单;
|
||||
- 台架期间另发现一次 49s 全系统日志静默(defaultTask/NAND syslog 排空停滞,net 栈照常工作)
|
||||
——既有存储侧现象,与本层无关,见 `docs/待处理内容.md` N-2。
|
||||
|
||||
## 附录 B:修订记录
|
||||
|
||||
| 日期 | 内容 |
|
||||
|---|---|
|
||||
| 2026-09-22 | 一期落地并全量台架验证(原《Net 层阻塞模型业界对照与演进方案》实施记录) |
|
||||
| 2026-09-26 | 调研文档退役,客观实施记录独立成文 |
|
||||
| 2026-09-29 | **改写为架构设计文档**:以"当前如何设计/为何如此"为主线重组织;历史演进与门禁实测降级为附录 A;迁入 `docs/网络/` |
|
||||
@@ -1,97 +0,0 @@
|
||||
# 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`。
|
||||
@@ -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`(已固化铁律)
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user