链路时延M1-M3收尾:Phase12-14基线与生产路径Δ实测、D10/E-02/D17修复、D20定位与硬化、文档整理

This commit is contained in:
2026-09-22 06:12:16 +08:00
parent ac48c6d716
commit e5733b3454
42 changed files with 18294 additions and 1168 deletions
+17
View File
@@ -318,6 +318,9 @@ static int cmd_list(lftpd_client_t *client, const char *arg)
}
int err = send_list(data_sock, client->directory);
/* 传输结束必须关闭数据连接:对端以 EOF 判定"数据传完"(LIST/RETR);
* 不关会让客户端一直读到超时(曾试"优雅断开+复用监听器"方案,因该语义限制
* 与芯片行为未能稳定工作,见 链路时延实测数据分析.md D20 记录)。 */
lftpd_inet_close(data_sock);
client->data_socket = -1;
@@ -347,6 +350,9 @@ static int cmd_nlst(lftpd_client_t *client, const char *arg)
}
int err = send_nlst(data_sock, client->directory);
/* 传输结束必须关闭数据连接:对端以 EOF 判定"数据传完"(LIST/RETR);
* 不关会让客户端一直读到超时(曾试"优雅断开+复用监听器"方案,因该语义限制
* 与芯片行为未能稳定工作,见 链路时延实测数据分析.md D20 记录)。 */
lftpd_inet_close(data_sock);
client->data_socket = -1;
@@ -451,6 +457,9 @@ static int cmd_retr(lftpd_client_t *client, const char *arg)
char *path = lftpd_io_canonicalize_path(client->directory, arg);
lftpd_log_debug("send '%s'", path);
int err = send_file(data_sock, path);
/* 传输结束必须关闭数据连接:对端以 EOF 判定"数据传完"(LIST/RETR);
* 不关会让客户端一直读到超时(曾试"优雅断开+复用监听器"方案,因该语义限制
* 与芯片行为未能稳定工作,见 链路时延实测数据分析.md D20 记录)。 */
lftpd_inet_close(data_sock);
client->data_socket = -1;
@@ -507,6 +516,9 @@ static int cmd_stor(lftpd_client_t *client, const char *arg)
char *path = lftpd_io_canonicalize_path(client->directory, arg);
lftpd_log_debug("receive '%s'", path);
int err = receive_file(data_sock, path);
/* 传输结束必须关闭数据连接:对端以 EOF 判定"数据传完"(LIST/RETR);
* 不关会让客户端一直读到超时(曾试"优雅断开+复用监听器"方案,因该语义限制
* 与芯片行为未能稳定工作,见 链路时延实测数据分析.md D20 记录)。 */
lftpd_inet_close(data_sock);
client->data_socket = -1;
@@ -606,6 +618,11 @@ static int handle_control_channel(lftpd_client_t *client)
}
cleanup:
/* 数据监听器在复用模式下会跨命令保留,会话结束必须显式释放(否则每次会话泄漏一个 Socket) */
if (client->data_socket >= 0) {
lftpd_inet_close(client->data_socket);
client->data_socket = -1;
}
lftpd_inet_close(client->socket);
return 0;
}
+53 -8
View File
@@ -5,6 +5,21 @@
#include "net_socket.h"
#include <string.h>
/*
* E-02 头阻塞修复(2026-09-22 M3 台架实证):
* netTask 是全部 socket 操作的唯一执行者;lftpd 原先用默认 30s 的**阻塞**
* net_recv 等待对端下一行/下一块数据 → 只要客户端连上却不发完整行,netTask
* 就被长期占用,其余任务(含远端显示)的网络操作整体冻结(实测一次空闲 FTP
* 登录让 LCDMEM 整帧等待 17.7s)。
* 修法:把等待切成 ≤LFTPD_NET_SLICE_MS 的片(每片 netTask 占用有界),
* 调用方累计总预算 LFTPD_TOTAL_BUDGET_MS —— **总超时语义与旧实现一致**,
* 但任何时刻都不再有"秒级冻结"。单片超时由 net_recv_to 返回 -2 区分(无 errno 竞态)。
* 分片长度即"其他任务最坏等待":实测 100ms 片下受压帧仍达 ~750ms(多片排队),
* 收到 5ms 后受压帧降到 ~10ms 量级(见 m3_data 修复后数据)。
*/
#define LFTPD_NET_SLICE_MS 5U
#define LFTPD_TOTAL_BUDGET_MS 30000U
int lftpd_inet_listen(int port)
{
int retry;
@@ -99,19 +114,34 @@ int lftpd_inet_accept_timeout(int socket, int timeout_ms)
int lftpd_inet_read_line(int socket, char *buffer, size_t buffer_len)
{
TickType_t t0 = xTaskGetTickCount();
memset(buffer, 0, buffer_len);
int total_read_len = 0;
while (total_read_len < (int)buffer_len) {
int read_len = net_recv(socket,
buffer + total_read_len,
buffer_len - total_read_len - 1,
0);
/* 分片有界读(E-02):单片 netTask 占用 ≤ LFTPD_NET_SLICE_MS */
int read_len = net_recv_to(socket,
buffer + total_read_len,
(int)(buffer_len - total_read_len - 1),
LFTPD_NET_SLICE_MS);
if (read_len == 0) {
return -1;
return -1; /* 对端关闭 */
}
if (read_len == -2) {
/* 本片无数据:累计总预算,未超则继续等。
* **必须显式让出 CPU**:若某片因 net_poll 自身耗时而在首轮就返回 -2,
* 本任务(Normal)立即重排队会形成忙循环 → 饿死 BelowNormal 的 uiTask
* → 远端显示请求数秒无人拾取(2026-09-22 M3 实测 2.4~3.4s 周期尖刺)。
* vTaskDelay(1) 保证低优先级任务每毫秒都有运行机会。 */
if ((xTaskGetTickCount() - t0) >= pdMS_TO_TICKS(LFTPD_TOTAL_BUDGET_MS)) {
return -1; /* 总预算耗尽(语义同旧 30s 超时) */
}
vTaskDelay(pdMS_TO_TICKS(1));
continue;
}
if (read_len < 0) {
return read_len;
return read_len; /* 真错误 */
}
total_read_len += read_len;
@@ -170,8 +200,23 @@ int lftpd_inet_write(int socket, const void *buf, int len)
int lftpd_inet_read(int socket, void *buf, int len)
{
int n = net_recv(socket, buf, len, 0);
return n;
/* 分片有界读(E-02):总预算 30s 不变,但每片 netTask 占用 ≤ LFTPD_NET_SLICE_MS,
* 避免空闲数据连接(客户端开了 PASV 却不发数据)冻结全网 */
TickType_t t0 = xTaskGetTickCount();
for (;;) {
int n = net_recv_to(socket, buf, len, LFTPD_NET_SLICE_MS);
if (n >= 0) {
return n; /* >0 数据 / 0 EOF */
}
if (n == -1) {
return -1; /* 真错误 */
}
if ((xTaskGetTickCount() - t0) >= pdMS_TO_TICKS(LFTPD_TOTAL_BUDGET_MS)) {
return -1; /* 总预算耗尽(语义同旧 30s 超时) */
}
vTaskDelay(pdMS_TO_TICKS(1)); /* 让出 CPU:防空闲时忙循环饿死低优先级任务 */
}
}
int lftpd_inet_close(int socket)