E-02修复:timeSync对时读取改net_recv_to分片有界读(5ms片/30s总预算),消除空闲对时会话头阻塞冻结全网

This commit is contained in:
2026-09-22 13:00:42 +08:00
parent 7fb5d66799
commit 2643e936f5
+48 -4
View File
@@ -24,6 +24,19 @@
/* 监听端口:PC 推送端(TCP 客户端)需连到本端口 */
#define TIME_SYNC_PORT 8888
/*
* E-02 头阻塞修复(timeSync 侧;lftpd 侧见 lftpd_inet.c):
* 旧实现用单次 30s 阻塞 net_recv(默认 NET_RECV_TIMEOUT_MS)等时间包——等待期间
* netTask(全部 socket 操作的唯一执行者)被独占,其余任务的网络操作(远端显示 /
* FTP)整体停摆(docs/问题记录/错误码传播审计.md E-02)。
* 修法:等待切成 ≤TIME_SYNC_NET_SLICE_MS 的片(与 lftpd 同片长 = 其他任务最坏
* 等待,见 docs/测试说明/链路延迟测试说明.md §8.3),调用方累计总预算
* TIME_SYNC_TOTAL_BUDGET_MS——总超时语义与旧 30s 一致,任何时刻 netTask 占用
* 有界;片间 vTaskDelay(1) 让出 CPU,防空闲忙循环饿死低优先级任务。
*/
#define TIME_SYNC_NET_SLICE_MS 5U
#define TIME_SYNC_TOTAL_BUDGET_MS 30000U
/*
* 函数功能:创建并监听 TCP 时间同步服务端口
* 入口参数:无
@@ -75,14 +88,45 @@ static int time_sync_open_listener(void) {
* 函数功能:处理一个已建立的时间同步连接
* 入口参数:conn_sock - 已建立的连接 Socket 描述符(单连接模式下即监听 Socket 自身)
* 返回值:无
* 函数说明:阻塞读取 PC 发来的时间包("TIME"+uint32 大端 本地时间),解析后写回 RTC,然后关闭连接
* 函数说明:分片有界读取 PC 发来的时间包("TIME"+uint32 大端 本地时间),解析后
* 写回 RTC,然后关闭连接。读取用 net_recv_to 5ms 分片(E-02):单片不
* 长期占用 netTask,总预算 30s 与旧实现语义一致;跨片累积,容忍时间包
* 被 TCP 分段送达
*/
static void time_sync_handle_conn(int conn_sock) {
uint8_t buf[16];
int len;
int got = 0;
TickType_t t0 = xTaskGetTickCount();
len = net_recv(conn_sock, buf, sizeof(buf), 0);
if (len >= 8) {
while (got < (int)sizeof(buf)) {
/* 分片有界读(E-02):单片 netTask 占用 ≤ TIME_SYNC_NET_SLICE_MS */
int n = net_recv_to(conn_sock, buf + got, (int)(sizeof(buf) - got),
TIME_SYNC_NET_SLICE_MS);
if (n > 0) {
got += n;
if (got >= 8) {
break; /* 时间包收齐,解析 */
}
continue; /* 包未收齐(分段送达),继续等余下字节 */
}
if (n == 0) {
break; /* 对端关闭(EOF) */
}
if (n != -2) {
break; /* 真错误 */
}
/* 本片超时无数据:总预算未耗尽则继续等。
* **必须显式让出 CPU**:若某片因 net_poll 自身耗时在首轮就返回 -2,
* 本任务(Normal)立即重排队会形成忙循环 → 饿死 BelowNormal 的 uiTask
* (lftpd 侧同因,见链路延迟测试说明.md §8.3 第 3 条) */
if ((xTaskGetTickCount() - t0) >= pdMS_TO_TICKS(TIME_SYNC_TOTAL_BUDGET_MS)) {
DBG_INFO("time_sync: no TIME packet in 30s, drop conn");
break; /* 总预算耗尽(语义同旧 30s 超时) */
}
vTaskDelay(pdMS_TO_TICKS(1));
}
if (got >= 8) {
if (buf[0] == 'T' && buf[1] == 'I' && buf[2] == 'M' && buf[3] == 'E') {
uint32_t epoch = ((uint32_t)buf[4] << 24) |
((uint32_t)buf[5] << 16) |