fix(NET): 监听重建单一所有者收口 + 沉降窗 800ms 上限只留痕
T0 降噪 + T1 单一所有者:四处重建触发(recon/accept/eof/drop)与 pending 第五处统一走 net_listener_request(),由 net_listener_tick 单点执行; 沉降重试日志改"只留首末"(E0 口径),每次恢复少打 3 行重复行。 force open 降级为只留痕(E19 反事实 A/B 实测):芯片未回 CLOSED 时强行 open 注定吃 USE 错(TRAP-NET-09),放行与不放行的端口恢复时刻同一分布 (放行 +512 / 不放行 +505·533 / 降级后 +509 ms)——恢复由芯片何时回 CLOSED 决定。真正兜住"监听器永久失效"的是 D10 预算到期 + 对账形态④ 重新登记,不是放行。新增 s_relisten_capped[] 使上限留痕只打一次, 隔离标志不清 → 下一轮继续排空残渣(构建 B 实测每 30ms 两行会刷屏)。 负向注入三轮打靶(E18,注入代码不入库):形态① 吞掉 DISCONNECT 后 4/4 救回、③ 空闲监听器静默失位两轮独立复现、⑤ 开盲区吞掉芯片自发中断 + 收回 LISTEN 后 -> resync 命中且挂起 recv 被取消 → 三条均不可降级为 只留痕。顺带稳定复现 [ERR] relisten retry budget exhausted = 对端不配合 拆链的签名,非回归。 台架:boot PASS;ftp_abort_probe RST 10/10 + FIN 5/5;relisten_stress :21 50/50(p50 507ms);n30_repro 30/30。构建 0 错 0 警 Code=212316; netTask 静态最坏链 1920→1912 B;RAM 台账受管区已 --write 同步(RW +8B)。 文档:E17/E18/E19 三行 + §4.1 常态 0 命中归因 + §4.3 兜底归属改正; 登记簿 N-31 销项(结论沉淀进 §4.3 与 E19)。
This commit is contained in:
@@ -780,11 +780,11 @@ static void net_reconcile_tick(void) {
|
||||
/* 挂起 send 同样取消(会话已被芯片收走,剩余字节不可能送达) */
|
||||
net_send_pending_cancel(i, NET_ERR_CONNRESET);
|
||||
} else if ((bad == 3) || (bad == 4)) {
|
||||
/* 类型③④:监听失位/孤儿监听 → 重建(本层唯一重建入口;
|
||||
* 非阻塞:失败由 D10 重试轮询接管) */
|
||||
/* 类型③④:监听失位/孤儿监听 → **登记**重建请求(判据在此,动作在
|
||||
* net_listener_tick 一处;非阻塞,30ms 节奏重试) */
|
||||
DBG_INFO("sock%d reconcile: chip not listening (0x%02X/0x%02X, was state=%d) -> relisten",
|
||||
i, c.open, c.tcp_state, (int)p_sock->state);
|
||||
(void)net_listener_try(i);
|
||||
net_listener_request(i, NET_LISTENER_REQ_RECON);
|
||||
} else {
|
||||
/* 类型②:补做 standalone accept */
|
||||
DBG_INFO("sock%d reconcile: connection completed w/o CONNECT irq -> accept", i);
|
||||
@@ -806,8 +806,8 @@ static void net_reconcile_tick(void) {
|
||||
* 限定条件:必须在 netTask 上下文中调用(独占 CH395F 与 s_net_socks 访问权);
|
||||
* 由 net_task.c 在 net_stack_bring_up 之后每次 1ms 循环调用。
|
||||
* 函数说明:1. 四个自愈 tick 均非阻塞(绝不 osDelay 忙等,netTask 永不冻结),先于消息分派执行
|
||||
* 2. net_listener_retry_tick(D10):断连后按 30ms 节拍重试 open+listen,
|
||||
* 2s 时限到期放弃留痕;本 fd 有在途挂起 recv / send 时跳过(挂起保险)
|
||||
* 2. net_listener_tick(监听重建**唯一执行者**):消费各路径登记的请求,
|
||||
* 30ms 节奏 / 2s 预算;门集与"芯片在听就不 open"(U12 防护)都在这一处
|
||||
* 3. net_pending_tick:按节拍结束挂起 recv(数据/到点[仅显式预算]/断连)
|
||||
* 4. net_send_pending_tick:按节拍推进挂起 send(断连/推进/写完/无进展超时)
|
||||
* 5. net_reconcile_tick(TRAP-NET-17 + pump 合并,自愈收敛阶段 3):100ms 对账
|
||||
@@ -825,8 +825,8 @@ void net_process_messages(void) {
|
||||
}
|
||||
|
||||
/* 四个非阻塞自愈 tick 置于消息处理之前:断连后即使无应用消息,监听器也能自主恢复 */
|
||||
/* D10 重监听重试(TRAP-NET-09):沉降后重开芯片监听器 */
|
||||
net_listener_retry_tick();
|
||||
/* 监听重建唯一执行者(TRAP-NET-09 D10 节奏;消费各路径登记的请求) */
|
||||
net_listener_tick();
|
||||
/* 挂起 recv 完成检查:数据到达 / 到点 / 断连时通知调用方 */
|
||||
net_pending_tick(s_net_socks);
|
||||
/* 挂起 send 推进与完成检查(SEND pending):断连 / 推进写块 / 写完 / 无进展超时 */
|
||||
@@ -1516,13 +1516,13 @@ static int net_accept_locked(int sockfd, struct net_sockaddr *addr, int *addrlen
|
||||
drain_pending = 1;
|
||||
DBG_INFO("sock%d closed-with-data accept (drain pending)", sockfd);
|
||||
} else {
|
||||
/* 连接已断开(CLOSED)且无残留数据:先把 Socket 重新置回 LISTEN,
|
||||
* 下一次 accept 即可等待新连接(BSD 风格监听常驻)。
|
||||
* N-32 P2 修正:**保留本处即时重建** —— 它由消费者调 accept 触发
|
||||
/* 连接已断开(CLOSED)且无残留数据:登记重建请求,下一次 accept
|
||||
* 即可等待新连接(BSD 风格监听常驻)。
|
||||
* N-32 P2 修正:**保留本处即时登记** —— 它由消费者调 accept 触发
|
||||
* (消费者正在等新连接),不是周期性抢先;删掉会把 CLOSED 窗口
|
||||
* 拉长、导致调用方高频空转 accept(实测 [WD] task stall)。
|
||||
* 非阻塞:失败由 D10 重试轮询接管 */
|
||||
(void)net_listener_try(sockfd);
|
||||
* 单一所有者收口后:动作发生在下一轮 net_listener_tick(≤1ms),非阻塞 */
|
||||
net_listener_request(sockfd, NET_LISTENER_REQ_ACCEPT);
|
||||
}
|
||||
}
|
||||
if (drain_pending == 0) {
|
||||
@@ -2155,20 +2155,20 @@ static int net_recv_locked(net_sock_t *p_sock, void *buf, int len, int flags,
|
||||
* 有数据时走上方快路径(recv_len>0 优先),本判据只在"无数据"时生效,
|
||||
* 故不会把新连接的起始数据误判为 EOF。 */
|
||||
if ((p_sock->state == NET_SOCK_STATE_CLOSED) || (p_sock->session_dead != 0U)) {
|
||||
/* 启用自动重监听:先把监听器重新置回 LISTEN。
|
||||
* ⚠ 内层 `state == CLOSED` 门是**必需的**,不是冗余:
|
||||
* `net_listener_try` 无状态门,对已 LISTENING 的 fd 再 open+listen
|
||||
* 会让 ch395f_open_socket 返 USE,其失败分支会 ch395f_close_socket
|
||||
* —— 把正听着新 SYN 的 Socket 当场关掉(U12 同源事故)。
|
||||
* session_dead + 已回 LISTENING = 重建已由别处完成,这里只报 EOF。
|
||||
* N-32 P2 修正(2026-10-12 台架实证):**保留本处即时重建**。
|
||||
/* 启用自动重监听:登记重建请求(动作在 net_listener_tick 一处)。
|
||||
* ⚠ 原此处内层 `state == CLOSED` 门已**上收到 tick**:它防的是"对已
|
||||
* LISTENING 的 fd 再 open+listen → ch395f_open_socket 返 USE → 失败分支
|
||||
* ch395f_close_socket → 把正听着新 SYN 的 Socket 当场关掉"(U12 同源
|
||||
* 事故)。这是**执行侧安全不变量**,不该由每个登记点各自复述——
|
||||
* 漏一处即事故;收口后 tick 另加"芯片已在听即了结",结构上不可能再犯。
|
||||
* N-32 P2 修正(2026-10-12 台架实证):**保留本处即时登记**——
|
||||
* 它是"消费者动作触发"(消费者正在等这条连接的结局),不是周期性
|
||||
* "抢先";删掉它会把 CLOSED 窗口从 ~0 拉长到 pump 周期+隔离期
|
||||
* "抢先";删掉它会把 CLOSED 窗口从 ~0 拉长到 reconciler 周期+隔离期
|
||||
* (~100ms),期间调用方高频发起 net_accept(RPC 无上界)→
|
||||
* `[WD] task stall`(实测 uis 往返 1063ms)。周期性抢先由 reconciler 收敛即可。 */
|
||||
if ((p_sock->state == NET_SOCK_STATE_CLOSED) && (p_sock->auto_relisten != 0U)) {
|
||||
/* 非阻塞:失败由 D10 重试轮询接管 */
|
||||
(void)net_listener_try(sockfd);
|
||||
* `[WD] task stall`(实测 uis 往返 1063ms)。周期性兜底由 reconciler 收敛。 */
|
||||
if (p_sock->auto_relisten != 0U) {
|
||||
/* 非阻塞:下一轮 net_listener_tick 执行,30ms 节奏重试 */
|
||||
net_listener_request(sockfd, NET_LISTENER_REQ_EOF);
|
||||
}
|
||||
/* EOF:返回 0(非错误) */
|
||||
return 0;
|
||||
@@ -2247,9 +2247,10 @@ static int net_close_locked(net_sock_t *p_sock) {
|
||||
* "拆连接不拆监听"的应用侧形态
|
||||
* 2. 拆除=sock_reset QUARANTINE(TRAP-NET-18 异常释放语义:FIN + 排渣 +
|
||||
* 排空事件(quiescent) + 等 byte0=00H,内置二段 CLOSE 补发)
|
||||
* 3. auto_relisten(监听型 fd):收口 CLOSED 后即时 net_listener_try
|
||||
* (芯片已 CLOSED 直接 open 必成,E4 定案;失败交 D10 重试 +
|
||||
* reconciler 形态④);非 auto_relisten(client fd):收口 CLOSED,
|
||||
* 3. auto_relisten(监听型 fd):收口 CLOSED 后登记重建请求(动作在
|
||||
* net_listener_tick,≤1ms 后执行;芯片已 CLOSED 直接 open 必成,
|
||||
* E4 定案;未成则 30ms 节奏重试 + reconciler 形态④兜底);
|
||||
* 非 auto_relisten(client fd):收口 CLOSED,
|
||||
* 是否重连由调用方决定
|
||||
* 4. 挂起 recv 先结束(settle_close:排空尝试或取消,必通知)
|
||||
*/
|
||||
@@ -2275,8 +2276,8 @@ static int net_drop_conn_locked(net_sock_t *p_sock) {
|
||||
p_sock->lost_conn_seen = 0U;
|
||||
|
||||
if (p_sock->auto_relisten) {
|
||||
/* 监听型 fd:即时重建(非阻塞;失败 D10 重试轮询接管) */
|
||||
(void)net_listener_try(sockfd);
|
||||
/* 监听型 fd:登记重建请求(非阻塞;下一轮 net_listener_tick 执行) */
|
||||
net_listener_request(sockfd, NET_LISTENER_REQ_DROP);
|
||||
}
|
||||
|
||||
/* 拆除完成 */
|
||||
|
||||
Reference in New Issue
Block a user