diff --git a/App/time_sync.c b/App/time_sync.c index 03614fda..9e566339 100644 --- a/App/time_sync.c +++ b/App/time_sync.c @@ -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) |