fix(N34): E14 丢中断复核——芯片不丢事件;listen 排事件挪至 LISTEN 前+全局读收口+全库归因更正

48 轮直读 SINT 矩阵(8 周期×6 变体)复核历史"丢中断"说法:芯片侧事件
丢失 = 0。归类:drain 读清消费 3/48(drain-int 探针现场抓获)、门控
竞态 2/48、主机同步 1/48、幽灵态 0/48 未复现。

根除性修复:net_listen_locked / net_listener_try 的排事件读清从
listen 后挪至 LISTEN 命令之前——新连接 CONNECT 落进该窗即被本方读清
吞掉,即"数据被吞"的生产侧自伤机制(台架 3/48 为同形态放大版)。

全局读收口:全局中断寄存器唯一读者 = net_poll(I7);生产/测试/台架
游离全局读全部删除,ch395f.h 声明处加护栏注释。

归因更正:17 文件约 40 处"丢中断"措辞改为"事件未收到/读清消费竞态"
(机制全部保留,仅归因更正);设计文档 §5.2 新增 E14 锚点;Trap
Records TRAP-NET-17/-20/B3 归因更正段;配图生成器与 SVG 重生成。

台架:事件未收到复核探针保留(drain-int / SINT 补读×3 / 超时归类),
下次跑矩阵自动归类;实验注册(main.c/uvprojx)已完全还原。

验证:@build 0 错误 0 警告;ci_local L0 32/0 + gitlint + L0.5
953/953;doc-links --all --sections-strict 通过;@test PASS(无
[ERR],net init 619ms);回归 :7003 300ms×10 = 10/10、:21 n30×50 =
0/50 失败。
This commit is contained in:
2026-10-14 02:48:50 +08:00
parent 1a35b3684c
commit a12367981d
55 changed files with 852 additions and 2721 deletions
+17 -17
View File
@@ -37,8 +37,8 @@ typedef enum {
NET_MSG_CONNECT,
NET_MSG_LISTEN,
NET_MSG_ACCEPT,
NET_MSG_DROP_CONN, /* N34 阶段 3(E-02 收口):主动拆会话、保监听(见 net_drop_conn) */
/* N34 阶段1(F-NET-2/3):NET_MSG_RESYNC_LISTEN / NET_MSG_RELISTEN 已删——
NET_MSG_DROP_CONN, /* 自愈收敛阶段 3(E-02 收口):主动拆会话、保监听(见 net_drop_conn) */
/* 自愈收敛阶段1(F-NET-2/3):NET_MSG_RESYNC_LISTEN / NET_MSG_RELISTEN 已删——
* 静默回收由对账⑤自动认领(net_reconcile_tick),重建由 reconciler
* 形态③④/D10 单一
* 所有者负责;手动自愈 API 面退役(生产调用者本就为零) */
@@ -51,7 +51,7 @@ typedef struct {
int len; /* 数据长度/缓冲区大小 */
int flags; /* 接收标志 */
uint32_t timeout_ms; /* 接收超时(入队方向;0 = 无限等待,无默认预算——
* N34 阶段 1.5 删除 NET_RECV_TIMEOUT_MS 30s 默认) */
* 自愈收敛阶段 1.5 删除 NET_RECV_TIMEOUT_MS 30s 默认) */
TaskHandle_t caller; /* 调用方任务句柄 */
int result; /* 操作结果 */
/* 连接参数 */
@@ -154,8 +154,8 @@ int net_listen(int sockfd);
*/
int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen);
/* N34 阶段1(F-NET-4):net_can_accept 已退役——只认 ESTABLISHED 的旧门控会把
* "监听器在服役、本轮待 CONNECT"窗口全挡掉(丢 CONNECT 探针因此从不运行);
/* 自愈收敛阶段1(F-NET-4):net_can_accept 已退役——只认 ESTABLISHED 的旧门控会把
* "监听器在服役、本轮待 CONNECT"窗口全挡掉(CONNECT 事件补 accept 探针因此从不运行);
* 监听 accept 门控统一用 net_listener_armed(),recv 门控 net_can_read() 保留。 */
/*
@@ -165,14 +165,14 @@ int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen);
* 返回值:1 - 就绪(ESTABLISHED 待 accept / LISTENING / CLOSED+auto_relisten
* +残留数据);0 - 不就绪 int
* 限定条件:net_init() 已调用;任意任务上下文
* 函数说明:1. N-32(P1 不变量 II,N34 阶段1 补齐 ESTABLISHED 放行):取代已退役的
* 函数说明:1. N-32(P1 不变量 II,自愈收敛阶段1 补齐 ESTABLISHED 放行):取代已退役的
* `net_can_accept()`(只认 ESTABLISHED)作为监听 accept 门控——原门控使
* :7003 永不进 `net_accept()`,
* `net_lost_connect_probe`(丢 CONNECT 中断补 accept,N-30 实证的
* `net_lost_connect_probe`(CONNECT 事件未收到补 accept,N-30 实证的
* "数据被吞/425"主根因修复)对该端口等于从未运行
* 2. 放行 LISTENING:探针与 "closed-but-readable 接受" 都发生在
* `net_accept_locked` **内部**,门控挡在外面就永远到不了
* 2b. 放行 ESTABLISHED(N34 阶段1 台架修正):单连接模型下 CONNECT 处理
* 2b. 放行 ESTABLISHED(自愈收敛阶段1 台架修正):单连接模型下 CONNECT 处理
* (net_poll 分派 / 探针补 accept / 对账② standalone accept)把监听 fd
* 转 ESTABLISHED,这正是"待 accept"电平——漏放行则任务周期慢的消费者
* (i104 200ms 抢不过对账② ~400ms 去抖)永不 accept、会话整场饿死
@@ -203,7 +203,7 @@ int net_listener_armed(int sockfd);
* 走调用方既有的错误分支重建,而不是静默卡死
* 4. ⚠ **不可作为唯一判据**:readable 只由 RECV_OK 中断置位,而
* net_reconcile_tick 的三类对账**不含**"芯片 RX 非空但 readable=0"
* → 中断丢失时本函数会恒返 0。调用方须保留**低频兜底 recv**
* → 事件未收到时本函数会恒返 0。调用方须保留**低频兜底 recv**
* (ui_net_sink 每 32 轮无条件收一次,最坏延迟 ≈320 ms)
*/
int net_can_read(int sockfd);
@@ -233,7 +233,7 @@ int net_connect(int sockfd, const struct net_sockaddr *addr, int addrlen);
int net_send(int sockfd, const void *buf, int len, int flags);
/*
* 函数功能:接收数据(TCP,**默认无限阻塞**——N34 阶段 1.5 语义主流化)
* 函数功能:接收数据(TCP,**默认无限阻塞**——自愈收敛阶段 1.5 语义主流化)
* 入口参数:sockfd - socket 描述符
* buf - 接收缓冲区
* len - 缓冲区大小
@@ -254,7 +254,7 @@ int net_send(int sockfd, const void *buf, int len, int flags);
int net_recv(int sockfd, void *buf, int len, int flags);
/*
* 函数功能:接收数据(非阻塞具名入口,原 NET_MSG_DONTWAIT 路径转正——N34 阶段 1.5)
* 函数功能:接收数据(非阻塞具名入口,原 NET_MSG_DONTWAIT 路径转正——自愈收敛阶段 1.5)
* 入口参数:sockfd - socket 描述符
* buf - 接收缓冲区
* len - 缓冲区大小
@@ -268,7 +268,7 @@ int net_recv_nb(int sockfd, void *buf, int len);
/*
* 函数功能:设置 Socket 阻塞/非阻塞**模式属性**(对齐 BSD O_NONBLOCK / Python
* setblocking——N34 阶段 1.5,模式挂 socket 控制块属性)
* setblocking——自愈收敛阶段 1.5,模式挂 socket 控制块属性)
* 入口参数:sockfd - socket 描述符
* on - 1 = 阻塞(net_socket 默认);0 = 非阻塞
* 返回值:0 成功;-1 失败(描述符无效/未占用)
@@ -289,7 +289,7 @@ int net_setblocking(int sockfd, int on);
* timeout_ms - 单次调用在 netTask 内的最长等待(毫秒,>0)
* 返回值:>0 实际字节数;0 = 对端关闭(EOF);-1 = 真错误(errno 可查);**-2 = 超时无数据**
* 限定条件:非 netTask 上下文;Socket 已连接
* 函数说明:1. **显式预算**便捷入口(等价 Python settimeout,N34 阶段 1.5 起
* 函数说明:1. **显式预算**便捷入口(等价 Python settimeout,自愈收敛阶段 1.5 起
* 不再有隐藏默认值):net_recv 的无限阻塞 + 本接口的显式预算构成
* 超时语义的全部来源;超时首选仍是 net_select
* 2. E-02 修复配套:lftpd 等"等对端下一行/下一块数据"的调用方
@@ -326,7 +326,7 @@ int net_sendto(int sockfd, const void *buf, int len, int flags,
* 返回值:实际接收字节数,失败返回 -1
* 限定条件:socket 已创建,指针非空
* 函数说明:1. 读取 CH395F 接收缓冲区,获取对端地址
* 2. 阻塞语义与 net_recv 同(N34 阶段 1.5):blocking 属性下无数据
* 2. 阻塞语义与 net_recv 同(自愈收敛阶段 1.5):blocking 属性下无数据
* 无限等待,DONTWAIT / 非阻塞属性立即 NET_ERR_WOULDBLOCK;
* 本接口为轮询自旋实现(历史遗留,UDP 专用),受 IWDG 监控的
* 任务同样禁止对其无限等待
@@ -344,14 +344,14 @@ int net_recvfrom(int sockfd, void *buf, int len, int flags,
int net_close(int sockfd);
/*
* 函数功能:主动拆掉当前 TCP 会话,**保留监听**(N34 阶段 3,E-02 收口)
* 函数功能:主动拆掉当前 TCP 会话,**保留监听**(自愈收敛阶段 3,E-02 收口)
* 入口参数:sockfd - socket 描述符
* 返回值:0 成功(含幂等:无活动会话),-1 失败
* 限定条件:非 netTask 上下文(经消息队列委托,同其它 net_* API)
* 函数说明:1. 适用场景=应用层放弃会话(对时 30s 预算耗尽、协议超时等):
* 单连接模型禁止对监听 fd net_close(连监听一起毁,AGENTS 约定),
* 而挂起但 TCP 仍活的客户端会永久占住单连接监听(PC 内核自动
* ACK keepalive,芯片僵尸判不死——实验方案 E13 §5 定案缺口)
* ACK keepalive,芯片僵尸判不死——《网络自愈架构设计》§5.2 E13 定案缺口)
* 2. 实现=sock_reset QUARANTINE(FIN 关闭 + 排渣 + 排空事件 + 等
* byte0=00H,TRAP-NET-18 异常释放语义);auto_relisten fd 随即重监听
* (失败交 D10 重试),非 auto_relisten(client fd)收口 CLOSED
@@ -400,7 +400,7 @@ int net_get_errno(void);
*/
int net_sock_state(int sockfd);
/* N34 阶段1(F-NET-3):net_resync_listen / net_relisten 声明已删——
/* 自愈收敛阶段1(F-NET-3):net_resync_listen / net_relisten 声明已删——
* 静默回收形态由对账⑤自动认领(2 轮去抖 + 1s 冷却,纪律"不发芯片命令"
* 原样保留在认领动作内);监听重建由 reconciler 形态③④(100ms 周期)/
* D10(30ms 重试)单一所有者。勿再引入"应用层手动自愈"入口。 */