-
Notifications
You must be signed in to change notification settings - Fork 3
fix(app): terminate child process on parent crash via reaper #41
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
0299cab
870087a
66fe2b7
7fd6c9a
0882d0a
f83d552
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 |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| # Change: Fix child process cleanup on parent crash | ||
|
|
||
| ## Why | ||
|
|
||
| When Goggles crashes (e.g., due to Vulkan errors or device mismatch in multi-GPU systems), the spawned child process continues running headlessly. Users are unaware the child is still running, and subsequent launches may fail due to resource conflicts (e.g., capture socket already bound). | ||
|
|
||
| The previous approach using `PR_SET_PDEATHSIG` directly from a multi-threaded process is unreliable because the signal is tied to the **thread** that called `fork()`, not the entire process. | ||
|
|
||
| ## What Changes | ||
|
|
||
| Introduce a `goggles-reaper` watchdog process: | ||
|
|
||
| ``` | ||
| Goggles (main process, multi-threaded) | ||
| ↓ fork() + exec("goggles-reaper") [SAFE: immediate exec] | ||
| goggles-reaper (watchdog, single-threaded) | ||
| ↓ PR_SET_CHILD_SUBREAPER + PR_SET_PDEATHSIG | ||
| ↓ fork() + exec(target_app) [SAFE: no threads] | ||
| Target Application | ||
| ``` | ||
|
|
||
| Benefits: | ||
| - Single-threaded reaper ensures `PR_SET_PDEATHSIG` works reliably | ||
| - `PR_SET_CHILD_SUBREAPER` catches orphaned grandchildren | ||
| - Process group kill ensures all descendants are terminated | ||
|
|
||
| ## Impact | ||
|
|
||
| - Affected specs: `app-window` | ||
| - Affected code: | ||
| - `src/app/main.cpp` - spawn reaper instead of target app directly | ||
| - `src/app/reaper_main.cpp` - new watchdog process | ||
| - `src/app/CMakeLists.txt` - build reaper executable |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| ## ADDED Requirements | ||
|
|
||
| ### Requirement: Child Process Death Signal | ||
|
|
||
| The application SHALL configure spawned child processes to receive SIGTERM when the parent process terminates unexpectedly. | ||
|
|
||
| #### Scenario: Parent crash terminates child | ||
|
|
||
| - **GIVEN** a child process was spawned via `-- <app>` mode | ||
| - **WHEN** the parent goggles process is killed (SIGKILL, crash, or abnormal termination) | ||
| - **THEN** the child process SHALL receive SIGTERM automatically | ||
| - **AND** the child process SHALL terminate | ||
|
|
||
| #### Scenario: Parent PID 1 reparenting race | ||
|
|
||
| - **GIVEN** a child process is being spawned | ||
| - **WHEN** the parent dies between `fork()` and `prctl()` setup | ||
| - **THEN** the child SHALL detect reparenting to PID 1 | ||
| - **AND** SHALL exit immediately with failure code |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| ## 1. goggles-reaper Implementation | ||
|
|
||
| - [x] 1.1 Create `src/app/reaper_main.cpp` | ||
| - [x] 1.2 Set `PR_SET_CHILD_SUBREAPER` to adopt orphaned descendants | ||
| - [x] 1.3 Set `PR_SET_PDEATHSIG(SIGTERM)` to detect parent death | ||
| - [x] 1.4 Set up signal handlers for SIGTERM/SIGINT/SIGHUP to trigger child cleanup | ||
| - [x] 1.5 Spawn target app via `fork()` + `execvp()` | ||
| - [x] 1.6 Implement `kill_process_tree()` - recursively kill children via `/proc` scanning | ||
| - [x] 1.7 On signal: kill all children, wait for them, then exit | ||
| - [x] 1.8 Update `src/app/CMakeLists.txt` to build `goggles-reaper` | ||
|
|
||
| ## 2. main.cpp Changes | ||
|
|
||
| - [x] 2.1 Use `posix_spawn()` to exec `goggles-reaper` (safe: immediate exec) | ||
| - [x] 2.2 Pass env vars and target command as arguments to reaper | ||
| - [x] 2.3 Remove direct `PR_SET_PDEATHSIG` usage from main.cpp | ||
|
|
||
| ## 3. Testing | ||
|
|
||
| - [x] 3.1 Update `tests/app/test_child_death_signal.cpp` for reaper architecture | ||
| - [x] 3.2 Manual test: kill goggles, verify target app terminates | ||
| - [x] 3.3 Manual test: target app exits, verify goggles exits cleanly |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,155 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // goggles-reaper: single-threaded watchdog process | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Ensures target app and descendants are terminated when goggles dies | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <array> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <cerrno> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <csignal> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <cstdio> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <cstdlib> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <cstring> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <dirent.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <sys/prctl.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <sys/wait.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <unistd.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <vector> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| namespace { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| volatile sig_atomic_t g_should_run = 1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto get_child_pids(pid_t parent_pid) -> std::vector<pid_t> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| std::vector<pid_t> pids; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DIR* proc_dir = opendir("/proc"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (proc_dir == nullptr) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return pids; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| struct dirent* entry = nullptr; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| while ((entry = readdir(proc_dir)) != nullptr) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (entry->d_type != DT_DIR || entry->d_name[0] < '0' || entry->d_name[0] > '9') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| std::array<char, 64> path{}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| std::snprintf(path.data(), path.size(), "/proc/%s/stat", entry->d_name); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FILE* stat_file = std::fopen(path.data(), "r"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (stat_file == nullptr) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| std::array<char, 512> buf{}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (std::fgets(buf.data(), buf.size(), stat_file) == nullptr) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| std::fclose(stat_file); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| std::fclose(stat_file); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const char* comm_end = std::strrchr(buf.data(), ')'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (comm_end == nullptr || comm_end[1] == '\0') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| char state = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pid_t ppid = -1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (std::sscanf(comm_end + 1, " %c %d", &state, &ppid) != 2) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (ppid == parent_pid) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pids.push_back(static_cast<pid_t>(std::atoi(entry->d_name))); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| closedir(proc_dir); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return pids; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto kill_process_tree(pid_t pid, int sig) -> void { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const auto children = get_child_pids(pid); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| kill(pid, sig); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const pid_t child : children) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| kill_process_tree(child, sig); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto kill_all_children(int sig) -> void { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const auto children = get_child_pids(getpid()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const pid_t child : children) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| kill_process_tree(child, sig); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto wait_all_children() -> void { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| while (waitpid(-1, nullptr, 0) > 0 || errno == EINTR) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+67
to
+85
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. Termination/wait strategy can hang indefinitely; needs timeout + SIGKILL escalation. Even with perfect PID discovery, children can ignore SIGTERM. Sketch of bounded wait + escalation (minimal deps using usleep)-auto wait_all_children() -> void {
- while (waitpid(-1, nullptr, 0) > 0 || errno == EINTR) {
- }
-}
+auto reap_all_children_nonblocking() -> bool {
+ for (;;) {
+ const pid_t r = waitpid(-1, nullptr, WNOHANG);
+ if (r > 0) continue;
+ if (r == 0) return false; // still have children
+ return errno == ECHILD; // true => none left
+ }
+}
+
+auto wait_all_children_with_timeout_ms(int timeout_ms) -> bool {
+ const int step_us = 20 * 1000;
+ int waited_ms = 0;
+ while (waited_ms < timeout_ms) {
+ if (reap_all_children_nonblocking()) return true;
+ usleep(step_us);
+ waited_ms += 20;
+ }
+ return reap_all_children_nonblocking();
+}Then in cleanup: - kill_all_children(SIGTERM);
- wait_all_children();
+ kill_all_children(SIGTERM);
+ if (!wait_all_children_with_timeout_ms(2000)) {
+ kill_all_children(SIGKILL);
+ (void)wait_all_children_with_timeout_ms(2000);
+ }
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto signal_handler(int /*sig*/) -> void { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| g_should_run = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto setup_signal_handlers() -> void { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| struct sigaction sa{}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sa.sa_handler = signal_handler; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sigemptyset(&sa.sa_mask); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sigaction(SIGTERM, &sa, nullptr); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sigaction(SIGINT, &sa, nullptr); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sigaction(SIGHUP, &sa, nullptr); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+91
to
+98
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. Check sigaction return values. If 🛡️ Proposed fix auto setup_signal_handlers() -> void {
struct sigaction sa{};
sa.sa_handler = signal_handler;
sigemptyset(&sa.sa_mask);
- sigaction(SIGTERM, &sa, nullptr);
- sigaction(SIGINT, &sa, nullptr);
- sigaction(SIGHUP, &sa, nullptr);
+ if (sigaction(SIGTERM, &sa, nullptr) != 0) {
+ std::fprintf(stderr, "goggles-reaper: sigaction SIGTERM failed: %s\n", std::strerror(errno));
+ std::abort();
+ }
+ if (sigaction(SIGINT, &sa, nullptr) != 0) {
+ std::fprintf(stderr, "goggles-reaper: sigaction SIGINT failed: %s\n", std::strerror(errno));
+ std::abort();
+ }
+ if (sigaction(SIGHUP, &sa, nullptr) != 0) {
+ std::fprintf(stderr, "goggles-reaper: sigaction SIGHUP failed: %s\n", std::strerror(errno));
+ std::abort();
+ }
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } // namespace | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto main(int argc, char** argv) -> int { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (argc < 2) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| std::fprintf(stderr, "goggles-reaper: missing command\n"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return EXIT_FAILURE; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const pid_t parent_pid = getppid(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Become subreaper - orphaned descendants reparent to us | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Die when parent (goggles) dies | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (getppid() != parent_pid) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return EXIT_FAILURE; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+108
to
+118
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. Check prctl return values. Both
🐛 Proposed fix const pid_t parent_pid = getppid();
// Become subreaper - orphaned descendants reparent to us
- prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0);
+ if (prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0) != 0) {
+ std::fprintf(stderr, "goggles-reaper: PR_SET_CHILD_SUBREAPER failed: %s\n", std::strerror(errno));
+ return EXIT_FAILURE;
+ }
// Die when parent (goggles) dies
- prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0);
+ if (prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0) != 0) {
+ std::fprintf(stderr, "goggles-reaper: PR_SET_PDEATHSIG failed: %s\n", std::strerror(errno));
+ return EXIT_FAILURE;
+ }
if (getppid() != parent_pid) {
return EXIT_FAILURE;
}🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setup_signal_handlers(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+108
to
+119
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.
If Proposed error checks- prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0);
+ if (prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0) != 0) {
+ std::fprintf(stderr, "goggles-reaper: PR_SET_CHILD_SUBREAPER failed: %s\n", std::strerror(errno));
+ return EXIT_FAILURE;
+ }
@@
- prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0);
+ if (prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0) != 0) {
+ std::fprintf(stderr, "goggles-reaper: PR_SET_PDEATHSIG failed: %s\n", std::strerror(errno));
+ return EXIT_FAILURE;
+ }📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Fork and exec target app | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const pid_t child = fork(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (child < 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| std::fprintf(stderr, "goggles-reaper: fork failed: %s\n", std::strerror(errno)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return EXIT_FAILURE; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (child == 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| execvp(argv[1], &argv[1]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| std::fprintf(stderr, "goggles-reaper: exec failed: %s\n", std::strerror(errno)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _exit(EXIT_FAILURE); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Wait for primary child or signal | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int status = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| while (g_should_run != 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const pid_t pid = waitpid(child, &status, 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (pid == child) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (pid == -1 && errno != EINTR) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Cleanup all remaining children | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| g_should_run = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| kill_all_children(SIGKILL); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| wait_all_children(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (WIFEXITED(status)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return WEXITSTATUS(status); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return EXIT_FAILURE; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1
to
+155
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. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Search for reaper_main.cpp and Linux-specific symbols
rg -n "reaper_main\.cpp|goggles-reaper|PR_SET_CHILD_SUBREAPER|PR_SET_PDEATHSIG" -C 3Repository: K1ngst0m/Goggles Length of output: 10761 🏁 Script executed: #!/bin/bash
# Search for Linux platform guards in CMake and code
rg -n "if.*LINUX|__linux__|CMAKE_SYSTEM_NAME.*Linux|CMAKE_SYSTEM" -C 2Repository: K1ngst0m/Goggles Length of output: 402 🏁 Script executed: #!/bin/bash
# Look for CMakeLists.txt files to understand build structure
find . -name "CMakeLists.txt" -type f | head -20Repository: K1ngst0m/Goggles Length of output: 317 🏁 Script executed: #!/bin/bash
# Check the structure of src/app directory
ls -la src/app/ 2>/dev/null || find . -path "*/src/app*" -type f -name "*.cpp" -o -name "*.h" -o -name "CMakeLists.txt" | head -20Repository: K1ngst0m/Goggles Length of output: 823 🏁 Script executed: #!/bin/bash
# Read the src/app/CMakeLists.txt to see the full build configuration
cat -n src/app/CMakeLists.txtRepository: K1ngst0m/Goggles Length of output: 1107 🏁 Script executed: #!/bin/bash
# Search for any platform guards around the reaper_main.cpp or goggles-reaper build
rg -n -B10 -A5 "add_executable.*reaper|goggles-reaper" src/app/CMakeLists.txtRepository: K1ngst0m/Goggles Length of output: 525 🏁 Script executed: #!/bin/bash
# Check if there are any #ifdef or platform checks in reaper_main.cpp itself
head -30 src/app/reaper_main.cpp | cat -nRepository: K1ngst0m/Goggles Length of output: 1051 🏁 Script executed: #!/bin/bash
# Check the main CMakeLists.txt for any platform-specific logic
cat -n CMakeLists.txt | head -50Repository: K1ngst0m/Goggles Length of output: 1182 🏁 Script executed: #!/bin/bash
# Check the main CMakeLists.txt to see if there's any CMAKE_SYSTEM_NAME check
rg -n "CMAKE_SYSTEM_NAME|if.*WIN|if.*APPLE|if.*UNIX|if.*Linux" CMakeLists.txtRepository: K1ngst0m/Goggles Length of output: 42 🏁 Script executed: #!/bin/bash
# Verify the full reaper_main.cpp for any platform guards
wc -l src/app/reaper_main.cpp
cat -n src/app/reaper_main.cpp | grep -E "ifdef|if.*linux|if.*LINUX" || echo "No #ifdef guards found"Repository: K1ngst0m/Goggles Length of output: 110 🏁 Script executed: #!/bin/bash
# Check if there are any platform-specific configurations in Dependencies.cmake or CompilerConfig.cmake
rg -n "CMAKE_SYSTEM_NAME|WIN32|APPLE|LINUX" cmake/Repository: K1ngst0m/Goggles Length of output: 185 Add Linux platform guards to This file is inherently Linux-specific ( 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.