#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include // 兼容性处理:获取 SYS_rt_sigtimedwait 宏 #ifndef SYS_rt_sigtimedwait # ifdef __NR_rt_sigtimedwait # define SYS_rt_sigtimedwait __NR_rt_sigtimedwait # else # error "SYS_rt_sigtimedwait 未定义,无法直接进行系统调用测试" # endif #endif // libc 包装:优先使用 sigtimedwait,保证在不同libc/内核下参数兼容 static int rt_sigtimedwait_libc(const sigset_t *set, siginfo_t *info, const struct timespec *timeout) { return sigtimedwait(set, info, timeout); } // 原始syscall:用于特定场景(如测试非法sigsetsize) static int sys_rt_sigtimedwait_raw(const sigset_t *set, siginfo_t *info, const struct timespec *timeout, size_t sigsetsize) { return (int)syscall(SYS_rt_sigtimedwait, set, info, timeout, sigsetsize); } // 测试统计 static int total_tests = 0; static int passed_tests = 0; static int failed_tests = 0; static char failed_test_names[200][256]; static int failed_test_count = 0; #define TEST_ASSERT(condition, test_name) do { \ total_tests++; \ if (condition) { \ passed_tests++; \ printf("PASS - %s\n", test_name); \ } else { \ failed_tests++; \ if (failed_test_count < 200) { \ snprintf(failed_test_names[failed_test_count], sizeof(failed_test_names[failed_test_count]), "%s", test_name); \ failed_test_count++; \ } \ printf("FAIL - %s (errno=%d: %s)\n", test_name, errno, strerror(errno)); \ } \ } while(0) // 工具函数:阻塞/解除阻塞 指定信号 static int block_signal(int sig, sigset_t *oldset) { sigset_t set; sigemptyset(&set); sigaddset(&set, sig); return pthread_sigmask(SIG_BLOCK, &set, oldset); } static int unblock_signal(int sig, const sigset_t *oldset) { (void)sig; // 未使用,仅保持接口对称 return pthread_sigmask(SIG_SETMASK, oldset, NULL); } // 工具函数:使用rt_sigtimedwait带0超时轮询一次并(如存在)清理信号 static int poll_and_consume_signal_once(int sig) { sigset_t set; siginfo_t info; struct timespec ts = {0, 0}; sigemptyset(&set); sigaddset(&set, sig); int r = rt_sigtimedwait_libc(&set, &info, &ts); return r; // =sig 表示读到并消费;-1 且 errno=EAGAIN 表示无;其它为异常 } // 用于线程延迟发送信号 typedef struct { pid_t pid; int sig; int delay_ms; } sender_args_t; static void *delayed_kill_sender(void *arg) { sender_args_t *a = (sender_args_t *)arg; // 确保该线程不接收要发送的信号:阻塞之,让信号成为进程待处理,供主线程 sigtimedwait 消费 sigset_t set, oldset; sigemptyset(&set); sigaddset(&set, a->sig); pthread_sigmask(SIG_BLOCK, &set, &oldset); struct timespec ts; ts.tv_sec = a->delay_ms / 1000; ts.tv_nsec = (long)(a->delay_ms % 1000) * 1000000L; nanosleep(&ts, NULL); printf("[TEST_DEBUG]:delayed_kill_sender to kill %d sig %d\n", a->pid, a->sig); // 进程定向发送 kill(a->pid, a->sig); printf("[TEST_DEBUG]:delayed_kill_sender killed %d sig %d\n", a->pid, a->sig); // 还原该线程掩码 pthread_sigmask(SIG_SETMASK, &oldset, NULL); printf("[TEST_DEBUG]:delayed_kill_sender unblocked %d sig %d\n", a->pid, a->sig); return NULL; } // 基础功能:阻塞SIGUSR1 -> 自发 -> rt_sigtimedwait应立即返回该信号 static void test_rt_sigtimedwait_basic_self_kill_SIGUSR1() { printf("=== 测试: 基础 - 阻塞SIGUSR1后自发并等待 ===\n"); sigset_t oldset; int rc = block_signal(SIGUSR1, &oldset); TEST_ASSERT(rc == 0, "阻塞SIGUSR1"); // 确保没有遗留的待处理SIGUSR1 while (poll_and_consume_signal_once(SIGUSR1) == SIGUSR1) {} // 发送到自身 pid_t me = getpid(); rc = kill(me, SIGUSR1); TEST_ASSERT(rc == 0, "向自身发送SIGUSR1"); sigset_t waitset; sigemptyset(&waitset); sigaddset(&waitset, SIGUSR1); siginfo_t info; struct timespec timeout = {2, 0}; // 2秒超时,正常应很快返回 int ret = rt_sigtimedwait_libc(&waitset, &info, &timeout); TEST_ASSERT(ret == SIGUSR1, "rt_sigtimedwait 返回SIGUSR1"); if (ret == SIGUSR1) { TEST_ASSERT(info.si_signo == SIGUSR1, "info.si_signo == SIGUSR1"); // kill() 产生的应为 SI_USER TEST_ASSERT(info.si_code == SI_USER, "info.si_code == SI_USER"); TEST_ASSERT(info.si_pid == me, "info.si_pid 为当前进程"); TEST_ASSERT(info.si_uid == getuid(), "info.si_uid 为当前用户"); } rc = unblock_signal(SIGUSR1, &oldset); TEST_ASSERT(rc == 0, "恢复原有信号屏蔽集"); } // 超时:等待一个未发送的被阻塞信号,短超时应返回EAGAIN static void test_rt_sigtimedwait_timeout() { printf("\n=== 测试: 超时 - 无信号到达时返回EAGAIN ===\n"); const int sig = SIGUSR2; sigset_t oldset; int rc = block_signal(sig, &oldset); TEST_ASSERT(rc == 0, "阻塞SIGUSR2"); // 清理可能的遗留 while (poll_and_consume_signal_once(sig) == sig) {} sigset_t waitset; sigemptyset(&waitset); sigaddset(&waitset, sig); siginfo_t info; struct timespec timeout = {0, 100 * 1000 * 1000}; // 100ms int ret = rt_sigtimedwait_libc(&waitset, &info, &timeout); TEST_ASSERT(ret == -1 && errno == EAGAIN, "无信号到达时超时返回EAGAIN"); rc = unblock_signal(sig, &oldset); TEST_ASSERT(rc == 0, "恢复原有信号屏蔽集"); } // 非法timespec:tv_nsec越界应返回EINVAL static void test_rt_sigtimedwait_invalid_timespec() { printf("\n=== 测试: 参数校验 - 非法timespec返回EINVAL ===\n"); const int sig = SIGUSR1; sigset_t oldset; int rc = block_signal(sig, &oldset); TEST_ASSERT(rc == 0, "阻塞SIGUSR1"); sigset_t waitset; sigemptyset(&waitset); sigaddset(&waitset, sig); siginfo_t info; struct timespec bad = { .tv_sec = 0, .tv_nsec = 2000000000L }; // > 1e9-1 int ret = rt_sigtimedwait_libc(&waitset, &info, &bad); TEST_ASSERT(ret == -1 && errno == EINVAL, "tv_nsec越界 -> EINVAL"); rc = unblock_signal(sig, &oldset); TEST_ASSERT(rc == 0, "恢复原有信号屏蔽集"); } // 延迟发送:NULL超时指针(无限等待) + 后台线程延迟发送实时信号,调用应被唤醒并返回 static void test_rt_sigtimedwait_null_timeout_with_delayed_rt_signal() { printf("\n=== 测试: NULL超时 + 延迟发送SIGRTMIN+1 ===\n"); int rtsig = SIGRTMIN + 1; sigset_t oldset; int rc = block_signal(rtsig, &oldset); TEST_ASSERT(rc == 0, "阻塞SIGRTMIN+1"); // 线程延迟发送 pthread_t th; sender_args_t args = { .pid = getpid(), .sig = rtsig, .delay_ms = 100 }; rc = pthread_create(&th, NULL, delayed_kill_sender, &args); TEST_ASSERT(rc == 0, "创建延迟发送线程"); sigset_t waitset; sigemptyset(&waitset); sigaddset(&waitset, rtsig); siginfo_t info; printf("[TEST_DEBUG]: to call rt_sigtimedwait_libc\n"); // NULL超时:按规范为无限等待,但我们确保100ms内会到信号 int ret = rt_sigtimedwait_libc(&waitset, &info, NULL); printf("[TEST_DEBUG]: rt_sigtimedwait_libc returned %d\n", ret); TEST_ASSERT(ret == rtsig, "rt_sigtimedwait(NULL) 收到实时信号"); if (ret == rtsig) { TEST_ASSERT(info.si_signo == rtsig, "info.si_signo == 发送的实时信号"); TEST_ASSERT((info.si_code == SI_USER) || (info.si_code == SI_TKILL) || (info.si_code == SI_QUEUE), "info.si_code 合理"); TEST_ASSERT(info.si_pid == getpid(), "info.si_pid 为当前进程"); } printf("[TEST_DEBUG]: to join thread\n"); if (rc == 0) { pthread_join(th, NULL); } printf("[TEST_DEBUG]: to unblock signal\n"); rc = unblock_signal(rtsig, &oldset); TEST_ASSERT(rc == 0, "恢复原有信号屏蔽集"); } // 零超时轮询:ts={0,0} 未有信号立刻返回EAGAIN static void test_rt_sigtimedwait_zero_timeout_poll() { printf("\n=== 测试: 轮询模式 - 零超时无信号返回EAGAIN ===\n"); const int sig = SIGUSR1; sigset_t oldset; int rc = block_signal(sig, &oldset); TEST_ASSERT(rc == 0, "阻塞SIGUSR1"); // 清空待处理 while (poll_and_consume_signal_once(sig) == sig) {} sigset_t waitset; sigemptyset(&waitset); sigaddset(&waitset, sig); siginfo_t info; struct timespec ts = {0, 0}; int ret = rt_sigtimedwait_libc(&waitset, &info, &ts); TEST_ASSERT(ret == -1 && errno == EAGAIN, "零超时无信号 -> EAGAIN"); rc = unblock_signal(sig, &oldset); TEST_ASSERT(rc == 0, "恢复原有信号屏蔽集"); } // 非法sigsetsize:传0期望返回EINVAL(具体行为依赖内核,这里按Linux常见实现) static void test_rt_sigtimedwait_invalid_sigsetsize() { printf("\n=== 测试: 参数校验 - 非法sigsetsize返回EINVAL ===\n"); const int sig = SIGUSR1; sigset_t oldset; int rc = block_signal(sig, &oldset); TEST_ASSERT(rc == 0, "阻塞SIGUSR1"); sigset_t waitset; sigemptyset(&waitset); sigaddset(&waitset, sig); siginfo_t info; struct timespec ts = {0, 0}; int ret = sys_rt_sigtimedwait_raw(&waitset, &info, &ts, 0 /* 非法大小 */); TEST_ASSERT(ret == -1 && errno == EINVAL, "sigsetsize=0 -> EINVAL"); rc = unblock_signal(sig, &oldset); TEST_ASSERT(rc == 0, "恢复原有信号屏蔽集"); } int main() { printf("开始 rt_sigtimedwait 系统调用测试\n"); printf("当前进程 PID=%d\n", getpid()); test_rt_sigtimedwait_basic_self_kill_SIGUSR1(); test_rt_sigtimedwait_timeout(); test_rt_sigtimedwait_invalid_timespec(); test_rt_sigtimedwait_null_timeout_with_delayed_rt_signal(); test_rt_sigtimedwait_zero_timeout_poll(); test_rt_sigtimedwait_invalid_sigsetsize(); printf("\n=== rt_sigtimedwait 测试完成 ===\n"); printf("\n=== 测试结果总结 ===\n"); printf("总测试数: %d\n", total_tests); printf("通过: %d\n", passed_tests); printf("失败: %d\n", failed_tests); printf("成功率: %.1f%%\n", total_tests > 0 ? (float)passed_tests / total_tests * 100 : 0); if (failed_tests > 0) { printf("\n失败的测试用例:\n"); for (int i = 0; i < failed_test_count; i++) { printf(" - %s\n", failed_test_names[i]); } } else { printf("\n所有测试用例都通过了!\n"); } return failed_tests > 0 ? 1 : 0; }