You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
close() no longer retries on EINTR — Previously, the internal close_retry helper
looped on EINTR, which is unsafe on all modern Unixes:
Linux: close() always releases the fd before returning EINTR.
Retrying can close an unrelated fd opened by another thread between attempts.
FreeBSD / macOS / other BSDs: The fd state after close() + EINTR is
unspecified per POSIX 2008+ (Austin Group defect 529), so retrying is equally dangerous.
The function has been renamed from close_retry to close_once and now calls close()
exactly once, treating both EINTR and EBADF as success — the same approach used by
Rust's std::fs::File::drop(), Go's runtime, and glibc internals.
Note: open() and dup2() in redirect_stdio() still correctly retry on EINTR,
as those calls do not release resources on interruption.
Improved
daemon() return value documentation — Made it prominent that daemon() only ever
returns Ok(Fork::Child) or Err(...) to the caller; Ok(Fork::Parent(_)) is never
returned because both parent processes call _exit(0) internally. Added recommended
if let and match usage patterns to the doc comment. Updated #[must_use] message
to reflect this guarantee.
Code Quality
Added test_daemon_never_returns_parent integration test confirming Fork::Parent is unreachable
Renamed test_close_retry_ok_and_ebadf to test_close_once_ok_and_ebadf
Replaced fragile tty command string-matching in test_daemon_no_controlling_terminal with
portable open("/dev/tty") check (works reliably across Linux, macOS, and BSDs)
Replaced fixed 100ms sleep in test_getppid_after_parent_exits with a retry loop (up to 1s),
preventing flaky failures on slow CI systems
Updated tests README to reflect new and renamed tests
0.6.0
Breaking Changes
getpgrp() signature changed - Now returns libc::pid_t directly instead of io::Result<libc::pid_t>
getpgrp() always succeeds per POSIX specification and cannot fail
Migration guide:
Change getpgrp()? to getpgrp()
Change getpgrp().expect("...") to getpgrp()
Change match getpgrp() { Ok(pgid) => ... } to let pgid = getpgrp();
Rationale: Aligns with POSIX.1 specification and matches getpid()/getppid() patterns
Verified on Linux, macOS, FreeBSD, OpenBSD per POSIX.1 specification
Updated all tests and documentation to reflect this guarantee
Improved
Enhanced documentation - Comprehensive improvements to library documentation
Added "Common Patterns" section with practical examples:
Process supervisor using HashMap with Fork
Inter-process communication via pipes
Daemon with PID file creation
Added "Safety and Best Practices" guidelines
Added detailed "Common Pitfalls and Safety Considerations" to fork():
Mutexes and locks (deadlock risks)
File descriptors (shared state issues)
Signal handlers (inheritance behavior)
Async-signal-safety between fork and exec
Memory usage (copy-on-write behavior)
Enhanced Fork enum documentation with helper method examples
Added "Platform Compatibility" information
Test quality improvements
Replaced deprecated signal() with sigaction() in EINTR tests
More portable signal handling for cross-platform compatibility
Renamed test_getpgrp_returns_io_error_type to test_getpgrp_returns_pid_type
Updated test README to reflect current test descriptions
Fixed
Documentation warnings - Resolved doctest warnings about main function wrapping
EINTR resilience - close_fd and redirect_stdio now retry on EINTR for close/open/dup2, preventing spurious failures under signal-heavy conditions on Linux, macOS, and BSD
Daemon exit safety - Replaced std::process::exit in post-fork parents with libc::_exit to avoid running non-async-signal-safe destructors, preventing undefined behavior between fork() and exec()
Code Quality
Modernized C string handling - Replaced runtime CString::new() allocations with compile-time c"" string literals (Rust 2024 feature)
chdir() now uses c"/" instead of CString::new("/")
redirect_stdio() now uses c"/dev/null" instead of CString::new("/dev/null")
Benefits: Eliminated dead error handling code, zero runtime overhead, compile-time validation
No API changes, fully backward compatible
Enhanced code clarity - Added clarifying comments to redirect_stdio() error handling logic explaining conditional cleanup of file descriptors
Comprehensive test coverage - Added 12 dedicated tests for chdir() function (346 lines)
Tests idempotent behavior, process isolation, concurrent usage
Validates modern c"" string literal implementation
Tests integration with setsid() (daemon pattern)
Total test count increased from 107 to 119 tests
0.5.0
Breaking Changes
waitpid() return type changed - Now returns io::Result<libc::c_int> instead of io::Result<()>
Returns the raw status code for inspection with WIFEXITED, WEXITSTATUS, WIFSIGNALED, WTERMSIG, etc.
Migration: Change waitpid(pid)? to let status = waitpid(pid)?; assert!(WIFEXITED(status));
Enables proper exit code checking and signal detection
See updated examples in documentation
Added
Fork helper methods - Added convenience methods to Fork enum
is_parent() - Check if this is the parent process
is_child() - Check if this is the child process
child_pid() - Get child PID if parent, otherwise None
Hash trait - Fork now derives Hash, enabling use in HashMap and HashSet
Useful for process supervisors and tracking multiple children
Examples: supervisor.rs and supervisor_advanced.rs
must_use attributes - Added #[must_use] to critical functions to prevent accidental misuse
fork() - Must check if parent or child
daemon() - Must check daemon result
setsid() - Must use session ID
getpgrp() - Must use process group ID
waitpid_nohang() function - Non-blocking variant of waitpid()
Returns Ok(Some(status)) if child has exited
Returns Ok(None) if child is still running
Essential for process supervisors and event loops
Enables polling patterns without blocking
Includes 7 comprehensive tests
PID helper functions - Convenience wrappers for getting process IDs
getpid() - Get current process ID (always succeeds, hides unsafe)
getppid() - Get parent process ID (always succeeds, hides unsafe)
Status macro re-exports - Convenient access to status inspection macros
Re-export WIFEXITED, WEXITSTATUS, WIFSIGNALED, WTERMSIG from libc
Users can now use fork::{waitpid, WIFEXITED, WEXITSTATUS} instead of separate libc import
Comprehensive test suite - Added extensive tests covering critical edge cases
tests/waitpid_tests.rs - Exit codes, signals, error handling, and non-blocking waits
tests/error_handling_tests.rs - Error paths and type verification