net_recv_to补全分步注释:片超时-2返回码不依赖errno依据、值拷贝队列陷阱、三分支返回语义(E-02配套留档,无逻辑变化)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user