5224f21622
三处都由本轮 P1 新增的主机单测照出,用户逐条裁定后实施。共同性质:都不是改动引入
的回归,而是**从没被执行到的分支**——生产路径上要么没有调用者、要么没走边界,所以
编译器(0 错 0 警)、cppcheck、真机日志对它都无话可说。
1) 缺陷一(选 a:改名,行为零变化)
lftpd_string_trim 的尾部循环起点落在 strlen(p) 那一格 NUL,isspace(0) 为假 →
循环体一次都不执行,"尾部空白从未被裁",而名字承诺两头都去。改名
lftpd_string_ltrim + 删掉那条死循环 + 在 .h/.c 写明"只去前导"。不去尾才是对的:
RFC 959 以命令终止符 CRLF 界定命令,参数(PASS 口令、含空格的文件名)的尾随
空格属于参数本体,去掉等于静默改数据;CRLF 已由 lftpd_inet_read_line 截断。
调用点 lftpd.c 同步改名。全库无遗留真引用(余 6 处旧名均为解释改名历史的散文)。
2) 缺陷二(按推荐修)
net_select 的 timeout = {0,0} 换算出 timeout_ms = 0,而退出条件写着
if ((timeout_ms > 0) && (已用时 >= timeout_ms)) → 超时永不生效,退化成死等;
POSIX 语义是"只查一轮立即返回"。去掉 timeout_ms > 0 这个错误前置即可。就绪
检查在本判断之前,故有就绪时仍立刻带计数返回;同文件 net_poll_events 的
timeout >= 0 本来就对,现在两条对齐。风险面:拿它当"非阻塞查一遍"会让 netTask
回不到主循环,而 netTask 在 IWDG required_mask 里(串行 socket 栈唯一执行者)。
3) 缺陷三(选 ①:按 POSIX 置位)
exceptfds 是恒为空的死参数:循环开头 p_sock == NULL → continue 先跳过,而
check_socket_error() 只有"表项为空 / fd 越界"才返回 1,越界的 i 又不在本循环
范围内 → 调用方按 POSIX 直觉用它收异常,永远什么都收不到,且返回码不报错。
把异常判定提到 continue 之前:表项不存在的 fd 计入 exceptfds 与返回计数,并更新
函数注释。选 ① 会改变返回计数语义,故补一条"未请求异常集时不计数"的用例,
确保只查可读的老调用方不被误伤(TC-NETSEL-012b)。
测试同步翻转:原 TC-NETSEL-008 / TC-NETSEL-012 是"现状桩、改了会响",现在改成正向
契约,并新增 TC-NETSEL-012c(异常位只落到被请求的那个集合);TC-LFTSTR-005 从
"尾部不裁"的现状登记改为正向契约(尾随空格必须保留)。net_select 22/22、
lftpd_io 33/33 全绿。
@build:0 错误 0 警告。实测体积 ER_IROM1 232,512 B(快照 232,536 → **−24 B**)、
Flash 233,704 B(−20 B)、RW_IRAM1 75,272 B(+8 B 是上一提交 net_cfg 那个字节,
本批零新增)、**RW_CCM 57,376 B 不变**;四档百分比 22.2/57.4/87.9/22.3 全不变。
Code 减少 36 B 即删掉的死循环。
覆盖率台账:门禁如实报了一次 lftpd_string.c 已覆盖行 8 → 7(**代码少了一行**,不是
覆盖退化),已 --update-baseline 重登;现 22/22 套件、line=3003/3446(87.1%)、
func=236/259(91.1%)、tested_files=26、untested_files=118。
文档:主机单测覆盖率口径 §9 新增"三处死路径的处置"小节(裁定、改法、影响、钉住
它的用例一一对应),并把两处"等裁定"的登记改为已处置。
自查:coding-standard / test-cppcheck / id-check --strict(无台账外新账)/ doc-links
(35 处 = 存量)全过;八个改动文件与 HEAD 逐项比对 BOM/CR/U+FFFD/行尾无变化
(这几个文件本就不带 BOM,未被动过)。pre-commit --all-files 仍只有三条失败且与
本分支无关:mem-numbers / mem-budget(.map 与 docs/内存管理 受管快照漂移,增量见
上,按并行分支约定不在分支里 --write,等 Lead 合并后统一回填)与 ui-golden
(simulator/tests/ref/*.bin 在 .gitignore 内,新建 worktree 天生没有黄金参考)。
387 lines
15 KiB
C
387 lines
15 KiB
C
/*
|
||
* 模块名称:NET 层 select/poll 事件观测主机侧单元测试
|
||
* 模块功能:在 PC 上离线验证 Drivers/BSP/NET/net_select.c 的**就绪判定与超时算术**:
|
||
* fd 集只保留就绪位、socket 状态对可读/可写的准入、非法 fd 的处理、
|
||
* tv_sec/tv_usec 的换算与截断、poll 的 revents 语义。
|
||
*
|
||
* 被测对象:真实源文件 ../../../Drivers/BSP/NET/net_select.c(#include 原样纳入)。
|
||
* net_select.h / net_types.h / net_config.h 全用**真实头**(net_sock_t 的
|
||
* 字段名与 NET_SOCK_STATE_* 枚举一改就编译期报错)。桩四个:main.h
|
||
* (HAL_GetTick)、cmsis_os.h(osDelay)、FreeRTOS.h/task.h(空壳),
|
||
* 外加 net_socket.h 桩(只声明 net_get_sock,类型仍取真实 net_types.h)
|
||
* 与 ch395f.h 空桩(本文件一个芯片函数都不调)。
|
||
*
|
||
* 为什么要主机侧单测(而不是只靠台架):
|
||
* netTask 是**串行 socket 栈**的唯一执行者,且在 IWDG required_mask 里:这里的
|
||
* 等待逻辑一旦算错,表现是"整个网络停摆 + 到点喂不上狗复位",而日志里什么都没有。
|
||
* 台架上无法构造"没人来连、超时该怎么算"这类边界(对端行为不可控),主机侧把
|
||
* tick 与 osDelay 做成可控量后可以精确复现"第几轮该退出去"。
|
||
*
|
||
* 覆盖点:
|
||
* TC-NETSEL-001 nfds = 0 → -1
|
||
* TC-NETSEL-002 nfds 为负 → -1
|
||
* TC-NETSEL-003 nfds 超过 NET_MAX_SOCKETS → -1(不许越界扫 socket 表)
|
||
* TC-NETSEL-004 就绪位回写:入参集合里的未就绪 fd 必须被清掉,只留就绪的
|
||
* TC-NETSEL-005 三个集合都可以传 NULL(不崩、不误伤)
|
||
* TC-NETSEL-006 timeout=NULL 时无限等,靠"对端事件到来"唤醒(假 osDelay 造事件)
|
||
* TC-NETSEL-007 tv_usec 换算是**整除截断**(1999us → 1ms,不是 2ms)
|
||
* TC-NETSEL-008 timeout = {0, 0} 只查一轮立即返回(**2026-10-23 修**:原先因
|
||
* `(timeout_ms > 0)` 前置判断而永不过期,等于把"非阻塞探测"变成死等)
|
||
* TC-NETSEL-009 LISTENING 的 socket 即使 readable=1 也不算可读
|
||
* TC-NETSEL-010 ESTABLISHED + send_ready → 可写位置位
|
||
* TC-NETSEL-011 非 ESTABLISHED(CONNECTING)即使 send_ready=1 也不可写
|
||
* TC-NETSEL-012 表项不存在的 fd 计入异常集合(**2026-10-23 修**:判定原本排在
|
||
* continue 之后,exceptfds 是恒为空的死参数)
|
||
* TC-NETSEL-012b 未请求异常集时,缺失的 fd 不计数(不影响只查可读的调用方)
|
||
* TC-NETSEL-012c 异常位只落到被请求的那个集合
|
||
* TC-NETSEL-013 poll 传 NULL 或 nfds<=0 → -1
|
||
* TC-NETSEL-014 poll 非法 fd(负数 / 越界)→ NET_POLLNVAL 且计入 ready
|
||
* TC-NETSEL-015 poll 对 CLOSED socket 置 NET_POLLHUP
|
||
* TC-NETSEL-016 poll 命中 POLLIN → revents 含 NET_POLLIN
|
||
* TC-NETSEL-017 现状桩:NET_POLLERR 在本实现里**永远置不上**(死分支,已登记)
|
||
* TC-NETSEL-018 poll 的 timeout = 0 立即返回(首轮就退,一次都不睡)
|
||
* TC-NETSEL-019 poll 每轮先把 revents 清零,上一轮的位不会带到这一轮
|
||
*
|
||
* 两处"现状桩"(008 / 017)钉的是**当前行为**,不是期望行为:修好它们这两条会红,
|
||
* 那是提醒而不是回归。理由写在下面的注释里。
|
||
*
|
||
* 通过:全部 TC PASS(main 返回 0)。
|
||
* 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。
|
||
*
|
||
* 创建日期:2026-10-23
|
||
*/
|
||
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
|
||
#include "net_select.h"
|
||
#include "net_socket.h"
|
||
|
||
#include "net_select.c"
|
||
|
||
/* ===================== 断言框架 ===================== */
|
||
|
||
static int s_total;
|
||
static int s_passed;
|
||
static int s_failed;
|
||
|
||
#define CHECK(cond, name) do { \
|
||
s_total++; \
|
||
if (cond) { s_passed++; printf(" PASS %s\n", name); } \
|
||
else { s_failed++; printf(" FAIL %s (line %d)\n", name, __LINE__); } \
|
||
} while (0)
|
||
|
||
/* ===================== 可控 socket 表 ===================== */
|
||
|
||
static net_sock_t g_sock[NET_MAX_SOCKETS];
|
||
static uint8_t g_sock_valid[NET_MAX_SOCKETS];
|
||
|
||
const net_sock_t *net_get_sock(int sockfd)
|
||
{
|
||
if ((sockfd < 0) || (sockfd >= NET_MAX_SOCKETS)) {
|
||
return NULL;
|
||
}
|
||
if (g_sock_valid[sockfd] == 0u) {
|
||
return NULL;
|
||
}
|
||
return &g_sock[sockfd];
|
||
}
|
||
|
||
/* ===================== 可控时基与睡眠 ===================== */
|
||
|
||
static uint32_t g_tick;
|
||
static int g_delay_calls;
|
||
static int g_release_after; /* >0:睡够这个轮数后让 fd0 变可读(模拟对端事件) */
|
||
|
||
uint32_t HAL_GetTick(void)
|
||
{
|
||
return g_tick++; /* 每问一次时间就前进 1ms:轮数 = 毫秒数,便于精确断言 */
|
||
}
|
||
|
||
void osDelay(uint32_t ticks)
|
||
{
|
||
(void)ticks;
|
||
g_delay_calls++;
|
||
if (g_delay_calls > 500) {
|
||
/* 保险:本模块每条用例都必须在有限轮内退出(要么就绪、要么超时、要么由
|
||
* g_release_after 造事件)。跑飞就说明用例或实现出了问题——直接退出,
|
||
* 绝不能把挂死留给 pre-commit / CI(上一次就是这么卡住 exe 文件名的)。 */
|
||
printf(" ABORT 轮询跑飞(>500 轮未退出)\n");
|
||
fflush(stdout);
|
||
exit(2);
|
||
}
|
||
g_tick++;
|
||
if ((g_release_after > 0) && (g_delay_calls >= g_release_after)) {
|
||
g_sock_valid[0] = 1u;
|
||
g_sock[0].state = NET_SOCK_STATE_ESTABLISHED;
|
||
g_sock[0].readable = 1u;
|
||
}
|
||
}
|
||
|
||
/* ===================== 复位 ===================== */
|
||
|
||
static void reset_all(void)
|
||
{
|
||
(void)memset(g_sock, 0, sizeof(g_sock));
|
||
(void)memset(g_sock_valid, 0, sizeof(g_sock_valid));
|
||
g_tick = 0u;
|
||
g_delay_calls = 0;
|
||
g_release_after = 0;
|
||
}
|
||
|
||
static void make_sock(int fd, net_sock_state_t st, uint8_t readable, uint8_t send_ready)
|
||
{
|
||
g_sock_valid[fd] = 1u;
|
||
g_sock[fd].state = st;
|
||
g_sock[fd].readable = readable;
|
||
g_sock[fd].send_ready = send_ready;
|
||
}
|
||
|
||
/* ===================== 参数边界 ===================== */
|
||
|
||
static void tc_bounds(void)
|
||
{
|
||
net_fd_set_t r;
|
||
|
||
printf("-- TC-NETSEL-001..003 nfds bounds --\n");
|
||
reset_all();
|
||
NET_FD_ZERO(&r);
|
||
CHECK(net_select(0, &r, NULL, NULL, NULL) == -1, "TC-NETSEL-001 nfds=0 -> -1");
|
||
CHECK(net_select(-1, &r, NULL, NULL, NULL) == -1, "TC-NETSEL-002 nfds 为负 -> -1");
|
||
CHECK(net_select(NET_MAX_SOCKETS + 1, &r, NULL, NULL, NULL) == -1,
|
||
"TC-NETSEL-003 nfds 越界 -> -1(不许扫出表外)");
|
||
}
|
||
|
||
/* ===================== 就绪位与集合回写 ===================== */
|
||
|
||
static void tc_ready_sets(void)
|
||
{
|
||
net_fd_set_t r;
|
||
net_fd_set_t w;
|
||
int rc;
|
||
|
||
printf("-- TC-NETSEL-004..005 ready sets --\n");
|
||
reset_all();
|
||
make_sock(0, NET_SOCK_STATE_ESTABLISHED, 0u, 0u); /* 请求了但没就绪 */
|
||
make_sock(1, NET_SOCK_STATE_ESTABLISHED, 1u, 0u); /* 就绪 */
|
||
NET_FD_ZERO(&r);
|
||
NET_FD_SET(0, &r);
|
||
NET_FD_SET(1, &r);
|
||
rc = net_select(4, &r, NULL, NULL, NULL);
|
||
CHECK((rc == 1) && NET_FD_ISSET(1, &r) && !NET_FD_ISSET(0, &r),
|
||
"TC-NETSEL-004 回写只保留就绪位,未就绪的 fd0 被清掉");
|
||
|
||
reset_all();
|
||
make_sock(2, NET_SOCK_STATE_ESTABLISHED, 1u, 0u);
|
||
NET_FD_ZERO(&r);
|
||
NET_FD_SET(2, &r);
|
||
rc = net_select(3, &r, NULL, NULL, NULL); /* write/except 传 NULL */
|
||
CHECK((rc == 1) && (NET_FD_ISSET(2, &r)), "TC-NETSEL-005 其余集合可为 NULL");
|
||
|
||
/* 注意:timeout 传 NULL 时本函数会一直等到有事件(见 008 的现状说明),
|
||
* 所以这类用例必须让被请求的 fd 真的就绪,否则就是用例自己写死的死循环。 */
|
||
reset_all();
|
||
NET_FD_ZERO(&w);
|
||
NET_FD_ZERO(&r);
|
||
make_sock(2, NET_SOCK_STATE_ESTABLISHED, 0u, 1u); /* send_ready:可写就绪 */
|
||
NET_FD_SET(2, &w);
|
||
rc = net_select(3, NULL, &w, NULL, NULL);
|
||
CHECK((rc == 1) && NET_FD_ISSET(2, &w) && (r.fd_bits == 0u),
|
||
"TC-NETSEL-005b 只回写调用方真正请求过的集合");
|
||
}
|
||
|
||
/* ===================== 超时算术 ===================== */
|
||
|
||
static void tc_timeout(void)
|
||
{
|
||
net_fd_set_t r;
|
||
net_timeval_t tv;
|
||
int rc;
|
||
|
||
printf("-- TC-NETSEL-006..008 timeout arithmetic --\n");
|
||
reset_all();
|
||
g_release_after = 3; /* 第 3 轮睡完,对端才有数据 */
|
||
NET_FD_ZERO(&r);
|
||
NET_FD_SET(0, &r);
|
||
rc = net_select(1, &r, NULL, NULL, NULL); /* timeout = NULL:无限等 */
|
||
CHECK((rc == 1) && (g_delay_calls == 3) && NET_FD_ISSET(0, &r),
|
||
"TC-NETSEL-006 无限等被对端事件唤醒(第 3 轮)");
|
||
|
||
reset_all();
|
||
make_sock(0, NET_SOCK_STATE_ESTABLISHED, 0u, 0u);
|
||
NET_FD_ZERO(&r);
|
||
NET_FD_SET(0, &r);
|
||
tv.tv_sec = 0;
|
||
tv.tv_usec = 1999; /* 应为 1ms,不是 2ms */
|
||
rc = net_select(1, &r, NULL, NULL, &tv);
|
||
CHECK((rc == 0) && (g_delay_calls == 0),
|
||
"TC-NETSEL-007 tv_usec 整除截断:1999us 当 1ms,首轮即退");
|
||
|
||
/* 已修(2026-10-23):原来这里写的是 (timeout_ms > 0) && (已用时 >= timeout_ms),
|
||
* timeout = {0,0} 换算出 0 后**永不超时**,只能干等事件——而 POSIX 语义是
|
||
* "只查一轮立即返回"。调用方(netTask 在 IWDG required_mask 里)拿它当
|
||
* 非阻塞探测用就会卡死主循环。现在这条是正向断言。 */
|
||
reset_all();
|
||
make_sock(0, NET_SOCK_STATE_ESTABLISHED, 0u, 0u);
|
||
NET_FD_ZERO(&r);
|
||
NET_FD_SET(0, &r);
|
||
tv.tv_sec = 0;
|
||
tv.tv_usec = 0;
|
||
rc = net_select(1, &r, NULL, NULL, &tv);
|
||
CHECK((rc == 0) && (g_delay_calls == 0) && !NET_FD_ISSET(0, &r),
|
||
"TC-NETSEL-008 timeout={0,0} 只查一轮立即返回(与 poll 的 0 对齐)");
|
||
}
|
||
|
||
/* ===================== 状态准入 ===================== */
|
||
|
||
static void tc_state_admission(void)
|
||
{
|
||
net_fd_set_t r;
|
||
net_fd_set_t w;
|
||
net_timeval_t tv;
|
||
int rc;
|
||
|
||
printf("-- TC-NETSEL-009..012 state admission --\n");
|
||
reset_all();
|
||
make_sock(0, NET_SOCK_STATE_LISTENING, 1u, 0u); /* 监听中但报"可读" */
|
||
NET_FD_ZERO(&r);
|
||
NET_FD_SET(0, &r);
|
||
tv.tv_sec = 0;
|
||
tv.tv_usec = 1000;
|
||
rc = net_select(1, &r, NULL, NULL, &tv);
|
||
CHECK((rc == 0) && !NET_FD_ISSET(0, &r),
|
||
"TC-NETSEL-009 监听态不可读(accept 语义不在 select 这层)");
|
||
|
||
reset_all();
|
||
make_sock(0, NET_SOCK_STATE_ESTABLISHED, 0u, 1u);
|
||
NET_FD_ZERO(&w);
|
||
NET_FD_SET(0, &w);
|
||
rc = net_select(1, NULL, &w, NULL, &tv);
|
||
CHECK((rc == 1) && NET_FD_ISSET(0, &w),
|
||
"TC-NETSEL-010 已建立 + send_ready 才可写");
|
||
|
||
reset_all();
|
||
make_sock(0, NET_SOCK_STATE_CONNECTING, 0u, 1u);
|
||
NET_FD_ZERO(&w);
|
||
NET_FD_SET(0, &w);
|
||
rc = net_select(1, NULL, &w, NULL, &tv);
|
||
CHECK((rc == 0) && !NET_FD_ISSET(0, &w),
|
||
"TC-NETSEL-011 连接中不可写(send_ready 不作数)");
|
||
|
||
/* 已修(2026-10-23):异常判定原先排在 p_sock == NULL → continue 之后,而
|
||
* check_socket_error() 只有"表项为空 / fd 越界"才返回 1、越界的 i 又不在本循环
|
||
* 范围内 → exceptfds 是恒为空的死参数。现在把判定提到 continue 之前。 */
|
||
tv.tv_sec = 0;
|
||
tv.tv_usec = 1000;
|
||
reset_all();
|
||
g_sock_valid[0] = 0u;
|
||
NET_FD_ZERO(&r);
|
||
NET_FD_SET(0, &r);
|
||
rc = net_select(1, NULL, NULL, &r, &tv);
|
||
CHECK((rc == 1) && NET_FD_ISSET(0, &r),
|
||
"TC-NETSEL-012 表项不存在的 fd 计入异常集合");
|
||
reset_all();
|
||
g_sock_valid[0] = 0u;
|
||
NET_FD_ZERO(&r);
|
||
NET_FD_SET(0, &r); /* 只请求可读 */
|
||
rc = net_select(1, &r, NULL, NULL, &tv);
|
||
CHECK((rc == 0) && !NET_FD_ISSET(0, &r) && (g_delay_calls == 0),
|
||
"TC-NETSEL-012b 未请求异常集时不因缺失 fd 计数(不误伤只查可读的调用方)");
|
||
reset_all();
|
||
g_sock_valid[0] = 0u;
|
||
NET_FD_ZERO(&r);
|
||
NET_FD_SET(0, &r); /* 请求可读:不该置位 */
|
||
NET_FD_ZERO(&w);
|
||
NET_FD_SET(0, &w); /* 请求异常:应该置位 */
|
||
rc = net_select(1, &r, NULL, &w, &tv);
|
||
CHECK((rc == 1) && NET_FD_ISSET(0, &w) && !NET_FD_ISSET(0, &r),
|
||
"TC-NETSEL-012c 异常位只落到被请求的那个集合,不污染可读集合");
|
||
}
|
||
|
||
/* ===================== poll 语义 ===================== */
|
||
|
||
static void tc_poll(void)
|
||
{
|
||
net_pollfd_t p[4];
|
||
int rc;
|
||
|
||
printf("-- TC-NETSEL-013..019 poll --\n");
|
||
reset_all();
|
||
CHECK((net_poll_events(NULL, 1, 0) == -1) && (net_poll_events(p, 0, 0) == -1),
|
||
"TC-NETSEL-013 poll 参数非法 -> -1");
|
||
|
||
reset_all();
|
||
(void)memset(p, 0, sizeof(p));
|
||
p[0].fd = -1;
|
||
p[0].events = NET_POLLIN;
|
||
p[1].fd = NET_MAX_SOCKETS; /* 越界 */
|
||
p[1].events = NET_POLLIN;
|
||
rc = net_poll_events(p, 2, 0);
|
||
CHECK((rc == 2) && ((p[0].revents & NET_POLLNVAL) != 0) &&
|
||
((p[1].revents & NET_POLLNVAL) != 0),
|
||
"TC-NETSEL-014 负 fd 与越界 fd 都置 POLLNVAL 并计入 ready");
|
||
|
||
reset_all();
|
||
make_sock(0, NET_SOCK_STATE_CLOSED, 0u, 0u);
|
||
(void)memset(p, 0, sizeof(p));
|
||
p[0].fd = 0;
|
||
p[0].events = NET_POLLIN;
|
||
rc = net_poll_events(p, 1, 0);
|
||
CHECK((rc == 1) && ((p[0].revents & NET_POLLHUP) != 0),
|
||
"TC-NETSEL-015 CLOSED 置 POLLHUP");
|
||
|
||
reset_all();
|
||
make_sock(0, NET_SOCK_STATE_ESTABLISHED, 1u, 0u);
|
||
(void)memset(p, 0, sizeof(p));
|
||
p[0].fd = 0;
|
||
p[0].events = NET_POLLIN;
|
||
rc = net_poll_events(p, 1, 0);
|
||
CHECK((rc == 1) && ((p[0].revents & NET_POLLIN) != 0) &&
|
||
((p[0].revents & NET_POLLHUP) == 0),
|
||
"TC-NETSEL-016 可读置 POLLIN 且不误置 HUP");
|
||
|
||
reset_all();
|
||
make_sock(0, NET_SOCK_STATE_ESTABLISHED, 1u, 1u);
|
||
(void)memset(p, 0, sizeof(p));
|
||
p[0].fd = 0;
|
||
p[0].events = 0; /* 什么都不请求 */
|
||
(void)net_poll_events(p, 1, 0);
|
||
CHECK((p[0].revents & NET_POLLERR) == 0,
|
||
"TC-NETSEL-017 现状:POLLERR 实际永不为真(表项为空已被 POLLNVAL 抢先)");
|
||
|
||
reset_all();
|
||
make_sock(0, NET_SOCK_STATE_ESTABLISHED, 0u, 0u);
|
||
(void)memset(p, 0, sizeof(p));
|
||
p[0].fd = 0;
|
||
p[0].events = NET_POLLIN;
|
||
rc = net_poll_events(p, 1, 0); /* timeout = 0 */
|
||
CHECK((rc == 0) && (g_delay_calls == 0),
|
||
"TC-NETSEL-018 poll 的 timeout=0 立即返回(与 select 那条形成对照)");
|
||
|
||
reset_all();
|
||
make_sock(0, NET_SOCK_STATE_ESTABLISHED, 1u, 0u);
|
||
(void)memset(p, 0, sizeof(p));
|
||
p[0].fd = 0;
|
||
p[0].events = NET_POLLIN;
|
||
p[0].revents = NET_POLLOUT; /* 脏的上一轮残留 */
|
||
(void)net_poll_events(p, 1, 0);
|
||
CHECK((p[0].revents & NET_POLLOUT) == 0, "TC-NETSEL-019 每轮先清 revents");
|
||
}
|
||
|
||
/* ===================== 入口 ===================== */
|
||
|
||
int main(void)
|
||
{
|
||
printf("=== NET Select Tests ===\n");
|
||
|
||
tc_bounds();
|
||
tc_ready_sets();
|
||
tc_timeout();
|
||
tc_state_admission();
|
||
tc_poll();
|
||
|
||
printf("\n=== NET Select Tests: %d/%d PASSED (failed=%d) ===\n",
|
||
s_passed, s_total, s_failed);
|
||
return (s_failed == 0) ? 0 : 1;
|
||
}
|