-
Notifications
You must be signed in to change notification settings - Fork 126
fix(starry): FIOCLEX ioctl + /proc status ctxt_switches + quiet non-tty ioctl probes (TUI) #1168
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 9 additions & 0 deletions
9
test-suit/starryos/qemu-smp1/system/syscall-test-ioctl-cloexec/CMakeLists.txt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| cmake_minimum_required(VERSION 3.20) | ||
| project(test-ioctl-cloexec C) | ||
| set(CMAKE_C_STANDARD 11) | ||
| set(CMAKE_C_STANDARD_REQUIRED ON) | ||
| set(CMAKE_C_EXTENSIONS OFF) | ||
| add_executable(test-ioctl-cloexec src/main.c) | ||
| target_include_directories(test-ioctl-cloexec PRIVATE src) | ||
| target_compile_options(test-ioctl-cloexec PRIVATE -Wall -Wextra -Werror) | ||
| install(TARGETS test-ioctl-cloexec RUNTIME DESTINATION usr/bin/starry-test-suit) |
76 changes: 76 additions & 0 deletions
76
test-suit/starryos/qemu-smp1/system/syscall-test-ioctl-cloexec/src/main.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| #define _GNU_SOURCE | ||
| #include "test_framework.h" | ||
| #include <fcntl.h> | ||
| #include <sys/ioctl.h> | ||
| #include <unistd.h> | ||
|
|
||
| /* | ||
| * ioctl(FIOCLEX) / ioctl(FIONCLEX) 回归测试 — 对应 PR #1168 (fix-tui-procfs-ioctl)。 | ||
| * | ||
| * 触发背景 (为什么写这个测例): | ||
| * ncurses / CPython (glances/htop) 在每个新开 fd 上用 ioctl(FIOCLEX) 设置 | ||
| * close-on-exec —— 这是 fcntl(fd, F_SETFD, FD_CLOEXEC) 的 ioctl 拼写。starry | ||
| * 此前只在 tty 设备路径里识别 ioctl, 普通(非 tty) fd 上 FIOCLEX 落到通用 | ||
| * 分支 -> "Unsupported ioctl command: 21585" 并被拒绝, FD_CLOEXEC 没被设置。 | ||
| * | ||
| * man 2 ioctl_tty / linux ioctl 通用语义: | ||
| * FIOCLEX (0x5451): set close-on-exec == fcntl(fd, F_SETFD, FD_CLOEXEC) | ||
| * FIONCLEX (0x5450): clear close-on-exec == fcntl(fd, F_SETFD, 0) | ||
| * Linux 对**任意** fd 都通用实现 (不限于 tty)。 | ||
| * | ||
| * starry 实现 (kernel/src/syscall/fs/ctl.rs sys_ioctl): | ||
| * FIOCLEX/FIONCLEX 在 ioctl 入口直接改 FD_TABLE 项的 cloexec 位 (镜像 fcntl | ||
| * F_SETFD), 任意 fd 接受; 无效 fd 由入口 get_file_like(fd) 先返回 EBADF。 | ||
| * | ||
| * 修复前: ioctl(FIOCLEX) 在普通 fd 上失败 / FD_CLOEXEC 不变 -> 本测例 FAIL。 | ||
| * 修复后: FD_CLOEXEC 经 fcntl(F_GETFD) 可见地被 set/clear -> PASS。 | ||
| * | ||
| * 用非 tty fd: pipe (与 test_ioctl_fionbio_int 同源), 不依赖 /dev/tty 是否存在。 | ||
| */ | ||
|
|
||
| #ifndef FIOCLEX | ||
| #define FIOCLEX 0x5451 | ||
| #endif | ||
| #ifndef FIONCLEX | ||
| #define FIONCLEX 0x5450 | ||
| #endif | ||
|
|
||
| int main(void) | ||
| { | ||
| TEST_START("ioctl FIOCLEX/FIONCLEX -> FD_CLOEXEC"); | ||
|
|
||
| int p[2]; | ||
| CHECK_RET(pipe(p), 0, "pipe() 创建非 tty fd 成功"); | ||
|
|
||
| /* 新建 fd 默认 close-on-exec 关闭 */ | ||
| int fd0 = fcntl(p[0], F_GETFD); | ||
| CHECK(fd0 >= 0, "F_GETFD 初始读取成功"); | ||
| CHECK((fd0 & FD_CLOEXEC) == 0, "新 pipe fd 初始 FD_CLOEXEC 未设置"); | ||
|
|
||
| /* ---- FIOCLEX 应 set FD_CLOEXEC (等价 fcntl F_SETFD FD_CLOEXEC) ---- */ | ||
| CHECK_RET(ioctl(p[0], FIOCLEX), 0, "ioctl(FIOCLEX) 在非 tty fd 上返回 0"); | ||
| int fd1 = fcntl(p[0], F_GETFD); | ||
| CHECK(fd1 >= 0, "F_GETFD (FIOCLEX 后) 成功"); | ||
| CHECK((fd1 & FD_CLOEXEC) != 0, "FIOCLEX 后 FD_CLOEXEC 被设置"); | ||
|
|
||
| /* ---- FIONCLEX 应 clear FD_CLOEXEC ---- */ | ||
| CHECK_RET(ioctl(p[0], FIONCLEX), 0, "ioctl(FIONCLEX) 返回 0"); | ||
| int fd2 = fcntl(p[0], F_GETFD); | ||
| CHECK(fd2 >= 0, "F_GETFD (FIONCLEX 后) 成功"); | ||
| CHECK((fd2 & FD_CLOEXEC) == 0, "FIONCLEX 后 FD_CLOEXEC 被清除"); | ||
|
|
||
| /* ---- 与 fcntl(F_SETFD) 互证: 两条路径应一致 ---- */ | ||
| CHECK_RET(fcntl(p[0], F_SETFD, FD_CLOEXEC), 0, "fcntl(F_SETFD, FD_CLOEXEC) 成功"); | ||
| CHECK((fcntl(p[0], F_GETFD) & FD_CLOEXEC) != 0, "fcntl 设置后 FD_CLOEXEC 可见"); | ||
| CHECK_RET(ioctl(p[0], FIONCLEX), 0, "ioctl(FIONCLEX) 再次清除 fcntl 设的位"); | ||
| CHECK((fcntl(p[0], F_GETFD) & FD_CLOEXEC) == 0, "FIONCLEX 清除 fcntl 设的位生效"); | ||
|
|
||
| close(p[0]); | ||
| close(p[1]); | ||
|
|
||
| /* ---- 无效 fd 应返回 EBADF (入口 get_file_like 先校验) ---- */ | ||
| CHECK_ERR(ioctl(-1, FIOCLEX), EBADF, "ioctl(FIOCLEX) 无效 fd=-1 返回 EBADF"); | ||
| CHECK_ERR(ioctl(p[0], FIOCLEX), EBADF, "ioctl(FIOCLEX) 已关闭 fd 返回 EBADF"); | ||
|
|
||
| TEST_DONE(); | ||
| } |
85 changes: 85 additions & 0 deletions
85
test-suit/starryos/qemu-smp1/system/syscall-test-ioctl-cloexec/src/test_framework.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| #pragma once | ||
|
|
||
| /* 必须在最前面定义,确保 pipe2/gettid 等可用 */ | ||
| #ifndef _GNU_SOURCE | ||
| #define _GNU_SOURCE | ||
| #endif | ||
|
|
||
| /* | ||
| * StarryOS Syscall Test Framework | ||
| * | ||
| * 极简独立测试框架:每个文件测一个 syscall,独立编译运行。 | ||
| * 目标:出错时精确定位到 源文件:行号 -> 哪个调用 -> 什么结果 | ||
| * | ||
| * 用法: | ||
| * TEST_START("测试名"); | ||
| * CHECK(call == expected, "描述"); | ||
| * CHECK_ERR(call, EBADF, "描述"); | ||
| * TEST_DONE(); | ||
| */ | ||
|
|
||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include <errno.h> | ||
|
|
||
| static int __pass = 0; | ||
| static int __fail = 0; | ||
|
|
||
| /* ---- 核心: 带文件名+行号的检查宏 ---- */ | ||
|
|
||
| /* 检查条件为真 */ | ||
| #define CHECK(cond, msg) do { \ | ||
| if (cond) { \ | ||
| printf(" PASS | %s:%d | %s\n", __FILE__, __LINE__, msg); \ | ||
| __pass++; \ | ||
| } else { \ | ||
| printf(" FAIL | %s:%d | %s | errno=%d (%s)\n", \ | ||
| __FILE__, __LINE__, msg, errno, strerror(errno)); \ | ||
| __fail++; \ | ||
| } \ | ||
| } while(0) | ||
|
|
||
| /* 检查 syscall 返回特定值 */ | ||
| #define CHECK_RET(call, expected, msg) do { \ | ||
| errno = 0; \ | ||
| long _r = (long)(call); \ | ||
| long _e = (long)(expected); \ | ||
| if (_r == _e) { \ | ||
| printf(" PASS | %s:%d | %s (ret=%ld)\n", \ | ||
| __FILE__, __LINE__, msg, _r); \ | ||
| __pass++; \ | ||
| } else { \ | ||
| printf(" FAIL | %s:%d | %s | expected=%ld got=%ld | errno=%d (%s)\n", \ | ||
| __FILE__, __LINE__, msg, _e, _r, errno, strerror(errno));\ | ||
| __fail++; \ | ||
| } \ | ||
| } while(0) | ||
|
|
||
| /* 检查 syscall 失败且 errno 符合预期 */ | ||
| #define CHECK_ERR(call, exp_errno, msg) do { \ | ||
| errno = 0; \ | ||
| long _r = (long)(call); \ | ||
| if (_r == -1 && errno == (exp_errno)) { \ | ||
| printf(" PASS | %s:%d | %s (errno=%d as expected)\n", \ | ||
| __FILE__, __LINE__, msg, errno); \ | ||
| __pass++; \ | ||
| } else { \ | ||
| printf(" FAIL | %s:%d | %s | expected errno=%d got ret=%ld errno=%d (%s)\n", \ | ||
| __FILE__, __LINE__, msg, (int)(exp_errno), _r, errno, strerror(errno));\ | ||
| __fail++; \ | ||
| } \ | ||
| } while(0) | ||
|
|
||
| /* ---- 测试边界 ---- */ | ||
| #define TEST_START(name) \ | ||
| printf("================================================\n"); \ | ||
| printf(" TEST: %s\n", name); \ | ||
| printf(" FILE: %s\n", __FILE__); \ | ||
| printf("================================================\n") | ||
|
|
||
| #define TEST_DONE() \ | ||
| printf("------------------------------------------------\n"); \ | ||
| printf(" DONE: %d pass, %d fail\n", __pass, __fail); \ | ||
| printf("================================================\n\n"); \ | ||
| return __fail > 0 ? 1 : 0 |
9 changes: 9 additions & 0 deletions
9
test-suit/starryos/qemu-smp1/system/syscall-test-procfs-ctxt-switches/CMakeLists.txt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| cmake_minimum_required(VERSION 3.20) | ||
| project(test-procfs-ctxt-switches C) | ||
| set(CMAKE_C_STANDARD 11) | ||
| set(CMAKE_C_STANDARD_REQUIRED ON) | ||
| set(CMAKE_C_EXTENSIONS OFF) | ||
| add_executable(test-procfs-ctxt-switches src/main.c) | ||
| target_include_directories(test-procfs-ctxt-switches PRIVATE src) | ||
| target_compile_options(test-procfs-ctxt-switches PRIVATE -Wall -Wextra -Werror) | ||
| install(TARGETS test-procfs-ctxt-switches RUNTIME DESTINATION usr/bin/starry-test-suit) |
76 changes: 76 additions & 0 deletions
76
test-suit/starryos/qemu-smp1/system/syscall-test-procfs-ctxt-switches/src/main.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| #define _GNU_SOURCE | ||
| #include "test_framework.h" | ||
| #include <stdint.h> | ||
| #include <unistd.h> | ||
|
|
||
| /* | ||
| * /proc/<pid>/status 上下文切换计数回归测试 — 对应 PR #1168 (fix-tui-procfs-ioctl)。 | ||
| * | ||
| * 触发背景 (为什么写这个测例): | ||
| * htop / glances 解析 /proc/<pid>/status 的 voluntary_ctxt_switches / | ||
| * nonvoluntary_ctxt_switches 来显示每进程上下文切换数。starry 此前 status | ||
| * 缺这两行 -> TUI 解析得不到字段。补 stub 行后可被解析。 | ||
| * | ||
| * man 5 proc §/proc/[pid]/status: | ||
| * "voluntary_ctxt_switches, nonvoluntary_ctxt_switches: Number of voluntary | ||
| * and involuntary context switches (since Linux 2.6.23)." | ||
| * 格式: "<name>:\t<number>"。 | ||
| * | ||
| * starry 实现 (kernel/src/pseudofs/proc.rs): status 末尾追加两行 | ||
| * voluntary_ctxt_switches:\t<n> / nonvoluntary_ctxt_switches:\t<n>。 | ||
| * | ||
| * 修复前: 字段不存在 -> 找不到 -> FAIL。 | ||
| * 修复后: 两字段都存在且能解析为非负整数 -> PASS。 | ||
| * | ||
| * 同时覆盖 /proc/self/status 与 /proc/<getpid()>/status 两种路径。 | ||
| */ | ||
|
|
||
| /* 在 status 文件里查找 "<name>:" 行并把其后的整数解析到 *out。找到且可解析返回 0。 */ | ||
| static int find_status_field(const char *path, const char *name, unsigned long *out) | ||
| { | ||
| FILE *f = fopen(path, "r"); | ||
| if (!f) | ||
| return -1; | ||
| char line[256]; | ||
| int rc = -1; | ||
| size_t nlen = strlen(name); | ||
| while (fgets(line, sizeof line, f)) { | ||
| if (strncmp(line, name, nlen) == 0 && line[nlen] == ':') { | ||
| if (sscanf(line + nlen + 1, "%lu", out) == 1) | ||
| rc = 0; | ||
| break; | ||
| } | ||
| } | ||
| fclose(f); | ||
| return rc; | ||
| } | ||
|
|
||
| static void check_path(const char *path) | ||
| { | ||
| unsigned long v = 0; | ||
| char msg[160]; | ||
|
|
||
| int rc = find_status_field(path, "voluntary_ctxt_switches", &v); | ||
| snprintf(msg, sizeof msg, "%s: voluntary_ctxt_switches 存在且可解析为整数 (=%lu)", | ||
| path, v); | ||
| CHECK(rc == 0, msg); | ||
|
|
||
| v = 0; | ||
| rc = find_status_field(path, "nonvoluntary_ctxt_switches", &v); | ||
| snprintf(msg, sizeof msg, "%s: nonvoluntary_ctxt_switches 存在且可解析为整数 (=%lu)", | ||
| path, v); | ||
| CHECK(rc == 0, msg); | ||
| } | ||
|
|
||
| int main(void) | ||
| { | ||
| TEST_START("/proc/<pid>/status ctxt_switches"); | ||
|
|
||
| check_path("/proc/self/status"); | ||
|
|
||
| char pidpath[64]; | ||
| snprintf(pidpath, sizeof pidpath, "/proc/%d/status", (int)getpid()); | ||
| check_path(pidpath); | ||
|
|
||
| TEST_DONE(); | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.