DragonOS/user/apps/c_unitest/test_tkill.c

301 lines
8.9 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/syscall.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <sys/wait.h>
#include <time.h>
// 系统调用号定义
#define SYS_TKILL 200
#define SYS_TGKILL 234
#define SYS_GETTID 186
// 测试结果统计
static int tests_passed = 0;
static int tests_failed = 0;
// 测试辅助宏
#define TEST_ASSERT(condition, message) do { \
if (condition) { \
printf("✓ %s\n", message); \
tests_passed++; \
} else { \
printf("✗ %s\n", message); \
tests_failed++; \
} \
} while(0)
// 信号处理函数
static volatile int signal_received = 0;
static volatile int received_signal = 0;
// 线程参数:用于回传可能为独立进程实现的“线程”的 PID/TID
typedef struct {
int thread_id;
pid_t pid; // 子“线程”的进程ID若为独立进程
int tid; // 子“线程”的内核线程ID
} thread_arg_t;
void signal_handler(int sig) {
signal_received = 1;
received_signal = sig;
printf("收到信号: %d\n", sig);
}
// 测试线程函数
void* test_thread(void* arg) {
thread_arg_t* targ = (thread_arg_t*)arg;
// 子线程也安装必要的信号处理,确保有序退出
signal(SIGUSR1, signal_handler);
signal(SIGTERM, signal_handler);
targ->pid = getpid();
targ->tid = syscall(SYS_GETTID);
printf("测试线程 %d 启动PID: %d, TID: %d\n", targ->thread_id, targ->pid, targ->tid);
// 等待信号
while (!signal_received) {
usleep(10000); // 10ms
}
printf("测试线程 %d 收到信号 %d退出\n", targ->thread_id, received_signal);
return NULL;
}
// 测试1: 基本功能测试
void test_basic_functionality() {
printf("\n=== 测试1: 基本功能测试 ===\n");
// 安装信号处理器
signal(SIGUSR1, signal_handler);
signal_received = 0;
received_signal = 0;
int tid = syscall(SYS_GETTID);
printf("当前线程TID: %d\n", tid);
// 测试发送信号给自己
int result = syscall(SYS_TKILL, tid, SIGUSR1);
TEST_ASSERT(result == 0, "tkill发送信号给自己应该成功");
// 等待信号处理
usleep(100000); // 100ms
TEST_ASSERT(signal_received == 1, "应该收到信号");
TEST_ASSERT(received_signal == SIGUSR1, "收到的信号应该是SIGUSR1");
}
// 测试2: 参数验证测试
void test_parameter_validation() {
printf("\n=== 测试2: 参数验证测试 ===\n");
int tid = syscall(SYS_GETTID);
// 测试无效的TID
int result = syscall(SYS_TKILL, -1, SIGUSR1);
TEST_ASSERT(result == -1 && errno == EINVAL, "无效TID应该返回EINVAL");
result = syscall(SYS_TKILL, 0, SIGUSR1);
TEST_ASSERT(result == -1 && errno == EINVAL, "TID为0应该返回EINVAL");
// 测试无效的信号
result = syscall(SYS_TKILL, tid, -1);
TEST_ASSERT(result == -1 && errno == EINVAL, "无效信号应该返回EINVAL");
result = syscall(SYS_TKILL, tid, 0);
TEST_ASSERT(result == 0, "信号为0探测模式应该成功");
}
// 测试3: 不存在的线程测试
void test_nonexistent_thread() {
printf("\n=== 测试3: 不存在的线程测试 ===\n");
// 使用一个不存在的TID
int result = syscall(SYS_TKILL, 99999, SIGUSR1);
TEST_ASSERT(result == -1 && errno == ESRCH, "不存在的线程应该返回ESRCH");
}
// 测试4: 多线程测试
void test_multithreaded() {
printf("\n=== 测试4: 多线程测试 ===\n");
pthread_t thread1, thread2;
thread_arg_t thread1_arg = { .thread_id = 1, .pid = 0, .tid = 0 };
thread_arg_t thread2_arg = { .thread_id = 2, .pid = 0, .tid = 0 };
// 重置信号状态
signal_received = 0;
received_signal = 0;
// 创建测试线程
pthread_create(&thread1, NULL, test_thread, &thread1_arg);
pthread_create(&thread2, NULL, test_thread, &thread2_arg);
// 等待线程启动
usleep(100000); // 100ms
// 获取线程TID这里简化处理实际应该通过其他方式获取
int tid = syscall(SYS_GETTID);
// 发送信号给当前线程
int result = syscall(SYS_TKILL, tid, SIGUSR1);
TEST_ASSERT(result == 0, "多线程环境下tkill应该工作");
// 等待信号处理
usleep(100000); // 100ms
// 主动通知子线程/子进程退出,避免遗留被 init 收养
if (thread1_arg.tid > 0) {
syscall(SYS_TKILL, thread1_arg.tid, SIGTERM);
}
if (thread2_arg.tid > 0) {
syscall(SYS_TKILL, thread2_arg.tid, SIGTERM);
}
// 清理线程
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
// 由于当前DragonOS下pthread实现可能使用独立进程模拟线程
// 这里主动回收任何遗留的“子线程”(子进程)避免程序退出时被init接管adopt_childen
int status;
for (;;) {
pid_t reaped = waitpid(-1, &status, WNOHANG);
if (reaped <= 0) {
break;
}
}
}
// 测试5: 探测模式测试
void test_probe_mode() {
printf("\n=== 测试5: 探测模式测试 ===\n");
int tid = syscall(SYS_GETTID);
// 测试探测模式信号为0
int result = syscall(SYS_TKILL, tid, 0);
TEST_ASSERT(result == 0, "探测模式应该成功");
// 测试对不存在线程的探测
result = syscall(SYS_TKILL, 99999, 0);
TEST_ASSERT(result == -1 && errno == ESRCH, "对不存在线程的探测应该返回ESRCH");
}
// 测试6: 与tgkill的对比测试
void test_tkill_vs_tgkill() {
printf("\n=== 测试6: tkill vs tgkill 对比测试 ===\n");
int tid = syscall(SYS_GETTID);
int tgid = getpid();
// 重置信号状态
signal_received = 0;
received_signal = 0;
// 使用tkill发送信号
int tkill_result = syscall(SYS_TKILL, tid, SIGUSR1);
TEST_ASSERT(tkill_result == 0, "tkill应该成功");
// 等待信号处理
usleep(100000); // 100ms
TEST_ASSERT(signal_received == 1, "tkill发送的信号应该被收到");
// 重置信号状态
signal_received = 0;
received_signal = 0;
// 使用tgkill发送信号
// 为SIGUSR2注册handler避免默认行为打印"User defined signal 2"
signal(SIGUSR2, signal_handler);
int tgkill_result = syscall(SYS_TGKILL, tgid, tid, SIGUSR2);
TEST_ASSERT(tgkill_result == 0, "tgkill应该成功");
// 等待信号处理
usleep(100000); // 100ms
TEST_ASSERT(signal_received == 1, "tgkill发送的信号应该被收到");
TEST_ASSERT(received_signal == SIGUSR2, "收到的信号应该是SIGUSR2");
}
// 测试7: 错误处理测试
void test_error_handling() {
printf("\n=== 测试7: 错误处理测试 ===\n");
// 测试各种错误情况
int result;
// 无效TID
result = syscall(SYS_TKILL, -1, SIGUSR1);
TEST_ASSERT(result == -1 && errno == EINVAL, "TID为-1应该返回EINVAL");
result = syscall(SYS_TKILL, 0, SIGUSR1);
TEST_ASSERT(result == -1 && errno == EINVAL, "TID为0应该返回EINVAL");
// 无效信号
result = syscall(SYS_TKILL, 1, -1);
TEST_ASSERT(result == -1 && errno == EINVAL, "信号为-1应该返回EINVAL");
// 不存在的线程
result = syscall(SYS_TKILL, 99999, SIGUSR1);
TEST_ASSERT(result == -1 && errno == ESRCH, "不存在的线程应该返回ESRCH");
}
// 测试8: 性能测试
void test_performance() {
printf("\n=== 测试8: 性能测试 ===\n");
int tid = syscall(SYS_GETTID);
int iterations = 1000;
clock_t start = clock();
for (int i = 0; i < iterations; i++) {
int result = syscall(SYS_TKILL, tid, 0); // 探测模式,不实际发送信号
if (result != 0) {
printf("性能测试中tkill失败: %d\n", result);
break;
}
}
clock_t end = clock();
double cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
printf("执行 %d 次tkill调用耗时: %.6f 秒\n", iterations, cpu_time_used);
printf("平均每次调用耗时: %.6f 秒\n", cpu_time_used / iterations);
TEST_ASSERT(cpu_time_used < 1.0, "性能测试应该在1秒内完成");
}
// 主函数
int main() {
printf("DragonOS SYS_TKILL 系统调用测试\n");
printf("================================\n");
// 运行所有测试
test_basic_functionality();
test_parameter_validation();
test_nonexistent_thread();
test_multithreaded();
test_probe_mode();
test_tkill_vs_tgkill();
test_error_handling();
test_performance();
// 输出测试结果
printf("\n================================\n");
printf("测试结果统计:\n");
printf("通过: %d\n", tests_passed);
printf("失败: %d\n", tests_failed);
printf("总计: %d\n", tests_passed + tests_failed);
if (tests_failed == 0) {
printf("🎉 所有测试通过!\n");
return 0;
} else {
printf("❌ 有测试失败!\n");
return 1;
}
}