Batch 5: kill-tree race + partial-failure, SingleInstance ownership, exceptional shutdown - #110
Merged
Merged
Conversation
…exceptional shutdown (#79, #81, #82) Safety-critical batch — kill path and lifecycle. #81 kill_process_tree, mirrored across all four Unix backends (linux, freebsd, macos, solaris): - Re-validate the ROOT against the caller's start-time token AFTER enumeration. Previously the token was checked once up front, then the tree was rebuilt from fresh kernel/proc state; if the root exited and its PID was reused in that window, the recycled process became the accepted identity and its whole tree could be signaled. Now a post-enumeration identity mismatch aborts. - Surface partial failure: a signal that failed (e.g. EPERM) on some tree member now returns success=false with a clear message, instead of success=true with the shortfall buried in error_message that both UIs can dismiss. A "skipped" (PID-reused-since-scan) count is informational, not a failure. #79 SingleInstance: - Only unlink the socket file if THIS instance actually bound+listened (owns_socket_). A secondary launch computes the same path but never bound it; its destructor used to delete the running primary's socket, so a third launch couldn't find the primary and wrongly became a second primary. - Bound the listener's per-connection read (SO_RCVTIMEO 2s) so a client that connects but never writes can't wedge the listener thread and hang the destructor's join(). #82 GUI lifecycle: - ImGuiApp: worker shutdown + callback detachment moved into an idempotent shutdown_workers(), called from both run()'s tail and ~ImGuiApp(). If run() throws after the workers start, the destructor now stops them and detaches the data_store/name_resolver callbacks that capture `this`. - main(): the SingleInstance raise callback (captures &app) is detached via a scope guard declared after `app`, so it's cleared before `app` is destroyed on the exception path too, not only on normal return. Built GUI+TUI+tests on Linux; 62 checks pass. FreeBSD/Solaris/macOS killer edits validated by CI. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xodto1bRjCSGEzLuz3JFbV
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Batch 5 — the safety-critical cluster (process-kill path + lifecycle). Written deliberately; the kill-path changes are compile-validated here and confirmed across the CI matrix, but not runtime-tested.
Closes #79
Closes #81
Closes #82
#81 — kill_process_tree (mirrored across linux/freebsd/macos/solaris)
success=falsewith a clear message, instead ofsuccess=truewith the shortfall buried inerror_messagethat both UIs can dismiss. A "skipped" (PID-reused-since-scan) count stays informational.#79 — SingleInstance
unlink()the socket if this instance actually bound it (owns_socket_). A secondary launch computed the same path but never bound it — its destructor deleted the running primary's socket, so a third launch became a wrongful second primary.SO_RCVTIMEO2s) so a silent client can't wedge the listener thread and hang the destructor'sjoin().#82 — GUI lifecycle
ImGuiApp: worker shutdown + callback detachment moved into an idempotentshutdown_workers(), called from bothrun()'s tail and~ImGuiApp(). An exception escapingrun()after the workers start no longer leaves them calling back into a destroyed app.main(): the SingleInstance raise callback (captures&app) is now detached via a scope guard declared afterapp, so it's cleared beforeappdies on the exception path too.Testing
Built GUI+TUI+tests on Linux; unit tests pass (62 checks). All four killer backends + the lifecycle changes compiled by the CI matrix. Kill-path behavior warrants runtime validation before relying on it.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Xodto1bRjCSGEzLuz3JFbV