net_recv_to补全分步注释:片超时-2返回码不依赖errno依据、值拷贝队列陷阱、三分支返回语义(E-02配套留档,无逻辑变化)

This commit is contained in:
2026-09-22 15:37:19 +08:00
parent 954a145c4a
commit 4ce966dfb8
+39 -15
View File
@@ -1490,46 +1490,70 @@ int net_recv(int sockfd, void *buf, int len, int flags) {
* 超时用独立返回码 -2(而非靠 errno 区分)→ 无跨任务 errno 竞态。
*/
int net_recv_to(int sockfd, void *buf, int len, uint32_t timeout_ms) {
net_msg_t msg;
net_msg_t msg; /* 一次性消息结构体:队列按值存结构副本(仅指针、不拷数据),入队后由 netTask 取出处理 */
/* ---- 1. 参数合法性检查 ---- */
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) {
s_net_errno = NET_ERR_BADF;
s_net_errno = NET_ERR_BADF; /* 描述符越界 */
return -1;
}
/* ---- 2. 运行环境检查:消息队列须已创建(网络层已初始化) ---- */
if (netMsgQueueHandle == NULL) {
s_net_errno = NET_ERR;
s_net_errno = NET_ERR; /* 网络层未初始化 */
return -1;
}
/* ---- 3. 分片长度检查:timeout_ms = 0 在 netTask 侧意味着"改用默认
* NET_RECV_TIMEOUT_MS(30 秒)",恰是本接口要规避的长阻塞,直接拒绝 ---- */
if (timeout_ms == 0U) {
s_net_errno = NET_ERR_INVAL;
s_net_errno = NET_ERR_INVAL; /* 分片长度必须 > 0 */
return -1;
}
msg.type = NET_MSG_RECV;
msg.sockfd = sockfd;
msg.buf = buf;
msg.len = len;
msg.flags = 0; /* 阻塞式(分片有界) */
msg.timeout_ms = timeout_ms; /* 调用方指定(分片长度) */
msg.caller = xTaskGetCurrentTaskHandle();
msg.result = -1;
/* ---- 4. 组装消息:把本次分片读的全部上下文填入 msg ---- */
msg.type = NET_MSG_RECV; /* 消息类型,netTask 据此分派到 net_recv_locked */
msg.sockfd = sockfd; /* 目标 Socket */
msg.buf = buf; /* 接收缓冲(队列仅拷贝指针,buf 须有效至本函数返回) */
msg.len = len; /* 缓冲容量:单次读取字节数上限(允许部分读) */
msg.flags = 0; /* 阻塞式:netTask 侧轮询至"有数据"或"本片超时"(勿置 NET_MSG_DONTWAIT) */
msg.timeout_ms = timeout_ms; /* 本片预算:netTask 最多等待 timeout_ms,保证对 netTask 的占用有界(E-02) */
msg.caller = xTaskGetCurrentTaskHandle(); /* 记录调用任务句柄,netTask 处理后经 xTaskNotify() 精准回执 */
msg.result = -1; /* 预置失败(仅防御值;真实结果经任务通知值回传,见步骤 6) */
/* ---- 5. 入队:将消息投递给 netTask,osWaitForever 表示队列满时阻塞调用方 ---- */
if (osMessageQueuePut(netMsgQueueHandle, &msg, 0, osWaitForever) != osOK) {
s_net_errno = NET_ERR_BUSY;
s_net_errno = NET_ERR_BUSY; /* 入队失败(队列异常等极端情况) */
return -1;
}
msg.result = net_wait_result("rcv", sockfd);
/* ---- 6. 阻塞等待 netTask 处理完毕:netTask 执行 net_recv_locked 后经
* xTaskNotify() 把结果(字节数 / 0 / 负错误码)以 32 位通知值回传本任务;
* 注意 net_msg_t 按值拷入队列,队列里的 result 字段不会回来——
* 通知值是唯一的真实回传通道(勿给 net_msg_t 加"回传用"字段) ---- */
msg.result = net_wait_result("rcv", sockfd); /* 两段式等待:零等待拾取 + 阻塞,防丢失通知(见 net_wait_result) */
/* ---- 7. 回传结果(三分支:分片超时 / 真错误 / 数据或 EOF) ---- */
if (msg.result == NET_ERR_TIMEDOUT) {
return -2; /* 本片超时:非致命 */
/* 本片超时:timeout_ms 内未等到数据,非致命。
* 超时只凭返回码 -2 判定、不得依赖 errno:s_net_errno 是跨任务共享的
* 全局量,netTask 处理本片时写入的 NET_ERR_TIMEDOUT 随时可能被其他任务
* 的 net 调用覆盖;而返回码是 netTask 经任务通知值专为本任务回传的,
* 天然无竞态(本分支也不再改写 s_net_errno)。
* 调用方见到 -2 后累计自身总超时预算,决定是否发起下一片。
* (本判断必须先于下方通用 <0 分支:NET_ERR_TIMEDOUT = -9 同样满足 <0) */
return -2;
}
if (msg.result < 0) {
/* 真错误:netTask 把具体错误码(如 NET_ERR_WOULDBLOCK)以负值回传,
* 此处恢复为线程级错误码(可经 net_get_errno() 读取);
* 对外保持 BSD 语义——失败一律返回 -1 */
s_net_errno = msg.result;
return -1;
}
/* >= 0:0 = 对端关闭(EOF,net 层尽力自动重监听,失败由重试轮询接管);
* > 0 = 实际接收字节数(可能小于 len,属正常部分读) */
return msg.result;
}