-
Notifications
You must be signed in to change notification settings - Fork 126
fix(starry): preserve vfork parent blocking #693
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
Changes from all commits
3d7a748
e2dc89c
d8d574c
9dbd685
11ffb55
4bbbca4
844b825
5100ef5
1136567
5084a6a
4503b5f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,7 @@ | ||
| #define _GNU_SOURCE | ||
| #define _DEFAULT_SOURCE | ||
| #define _POSIX_C_SOURCE 199309L | ||
| #include <sched.h> | ||
| #include <stdio.h> | ||
| #include <unistd.h> | ||
| #include <stdlib.h> | ||
|
|
@@ -34,6 +36,12 @@ static inline pid_t raw_vfork(void) { | |
| #define do_vfork() vfork() | ||
| #endif | ||
|
|
||
| static int clone_child_sleep(void *arg) { | ||
| (void)arg; | ||
| sleep(2); | ||
| _exit(0); | ||
| } | ||
|
|
||
| /* Test 1: Memory Sniff - Check if vfork shares address space */ | ||
| int test_vfork_memory_sniff(void) { | ||
| volatile int stack_var = 0; | ||
|
|
@@ -92,15 +100,47 @@ int test_vfork_execution_order(void) { | |
| return 0; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 测试与 Linux 行为对比 在标准 Linux 上运行此测试会失败,因为 Linux 的 建议在测试注释中明确说明这是一个 StarryOS 特有行为测试,而非 Linux 兼容性测试: /* NOTE: This tests StarryOS-specific behavior. On Linux, CLONE_VFORK always
blocks the parent regardless of the stack parameter, so this test would
fail there. StarryOS only blocks when stack == 0 (bare vfork). */
int test_vfork_clone_child_stack_nonblocking(void) {此外,CI 的 "Test starry self-hosted board orangepi-5-plus / run_host" 检查失败了,建议确认该失败是否与本次修改相关。 |
||
| } | ||
|
|
||
| /* Test 3: Linux-compatible clone semantics. CLONE_VFORK blocks the parent | ||
| until the child exits or execs even when the caller passes a private child | ||
| stack. BusyBox shell/timeout code depends on this ordering. */ | ||
| int test_vfork_clone_child_stack_blocking(void) { | ||
| static char child_stack[16384]; | ||
| char *stack_top = child_stack + sizeof(child_stack); | ||
| struct timespec start, end; | ||
|
|
||
| clock_gettime(CLOCK_MONOTONIC, &start); | ||
| int pid = clone(clone_child_sleep, stack_top, CLONE_VM | CLONE_VFORK | SIGCHLD, NULL); | ||
| if (pid < 0) { | ||
| perror("clone(CLONE_VM|CLONE_VFORK) failed"); | ||
| return -1; | ||
| } | ||
|
|
||
| clock_gettime(CLOCK_MONOTONIC, &end); | ||
|
|
||
| int status = 0; | ||
| waitpid(pid, &status, 0); | ||
| if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { | ||
| return 0; | ||
| } | ||
|
|
||
| long elapsed_ms = (end.tv_sec - start.tv_sec) * 1000 + | ||
| (end.tv_nsec - start.tv_nsec) / 1000000; | ||
|
|
||
| return (elapsed_ms >= 1500) ? 1 : 0; | ||
| } | ||
|
|
||
| int main(void) { | ||
| int vfork_mem_pass = 0, vfork_exec_pass = 0; | ||
| int vfork_mem_pass = 0, vfork_exec_pass = 0, clone_stack_pass = 0; | ||
|
|
||
| /* Test 1: vfork memory sharing */ | ||
| vfork_mem_pass = test_vfork_memory_sniff(); | ||
|
|
||
| /* Test 2: vfork execution blocking */ | ||
| vfork_exec_pass = test_vfork_execution_order(); | ||
|
|
||
| /* Test 3: CLONE_VFORK with a private child stack still blocks parent */ | ||
| clone_stack_pass = test_vfork_clone_child_stack_blocking(); | ||
|
|
||
| /* Report results */ | ||
| if (vfork_mem_pass > 0) { | ||
| printf("VFORK: PASS (Memory shared)\n"); | ||
|
|
@@ -114,8 +154,14 @@ int main(void) { | |
| printf("VFORK: FAIL (Parent NOT blocked)\n"); | ||
| } | ||
|
|
||
| /* Return success only if both vfork tests pass */ | ||
| if (vfork_mem_pass > 0 && vfork_exec_pass > 0) { | ||
| if (clone_stack_pass > 0) { | ||
| printf("VFORK: PASS (Child stack clone blocked parent)\n"); | ||
| } else { | ||
| printf("VFORK: FAIL (Child stack clone did NOT block parent)\n"); | ||
| } | ||
|
|
||
| /* Return success only if all vfork-related tests pass */ | ||
| if (vfork_mem_pass > 0 && vfork_exec_pass > 0 && clone_stack_pass > 0) { | ||
| printf("VFORK TEST: ALL TESTS PASSED\n"); | ||
| return 0; | ||
| } else { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
在 Linux 内核中,
CLONE_VFORK无论stack是否为 0 都会阻塞父进程。Linux 的kernel_clone()在设置了CLONE_VFORK时总会创建completion并调用wait_for_vfork_done(),与stack参数无关。当前修改仅在
stack == 0时阻塞父进程,这意味着CLONE_VM|CLONE_VFORK|SIGCHLD+ 独立 child stack 的组合不再阻塞父进程。这是对 LinuxCLONE_VFORK语义的有意偏离,建议在代码注释中明确标注这一点,例如:这样可以帮助后续维护者理解这是一个有意的设计决策而非疏忽。