Skip to content

Commit

Permalink
add test
Browse files Browse the repository at this point in the history
  • Loading branch information
devnexen committed Nov 29, 2023
1 parent 9f178f1 commit 193749b
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 41 deletions.
84 changes: 43 additions & 41 deletions src/unistd.rs
Expand Up @@ -2911,52 +2911,54 @@ mod getres {
}
}

feature! {
#![feature = "process"]
#[cfg(feature = "process")]
#[cfg(target_os = "freebsd")]
libc_bitflags! {
/// Flags for [`rfork`]
libc_bitflags! {
/// Flags for [`rfork`]
///
/// subset of flags supported by FreeBSD 12.x and onwards
/// with a safe outcome, thus as `RFMEM` can possibly lead to undefined behavior,
/// it is not in the list. And `rfork_thread` is deprecated.
pub struct RforkFlags: libc::c_int {
/// creates a new process.
RFPROC;
/// the child process will detach from the parent.
/// however, no status will be emitted at child's exit.
RFNOWAIT;
/// the file descriptor's table will be copied
RFFDG;
/// a new file descriptor's table will be created
RFCFDG;
/// force sharing the sigacts structure between
/// the child and the parent.
///
/// subset of flags supported by FreeBSD 12.x and onwards
/// with a safe outcome, thus as `RFMEM` can possibly lead to undefined behavior,
/// it is not in the list. And `rfork_thread` is deprecated.
pub struct RforkFlags: libc::c_int {
/// creates a new process.
RFPROC;
/// the child process will detach from the parent.
/// however, no status will be emitted at child's exit.
RFNOWAIT;
/// the file descriptor's table will be copied
RFFDG;
/// a new file descriptor's table will be created
RFCFDG;
/// force sharing the sigacts structure between
/// the child and the parent.
///
/// FIXME: waiting to be in the libc's crate.
// RFSIGSHARE;
/// enables kernel thread support.
RFTHREAD;
/// sets a status to emit at child's exit.
RFTSIGZMB;
/// linux's behavior compatibility setting.
/// emits SIGUSR1 as opposed to SIGCHLD upon child's exit.
RFLINUXTHPN;
}
/// FIXME: waiting to be in the libc's crate.
// RFSIGSHARE;
/// enables kernel thread support.
RFTHREAD;
/// sets a status to emit at child's exit.
RFTSIGZMB;
/// linux's behavior compatibility setting.
/// emits SIGUSR1 as opposed to SIGCHLD upon child's exit.
RFLINUXTHPN;
}
}

/// rfork can be used to have a tigher control about which resources child
/// and parent process will be sharing, file descriptors, address spaces
/// and child exit's behavior.
pub unsafe fn rfork(flags: RforkFlags) -> Result<ForkResult> {
let res = unsafe { libc::rfork(flags.bits()) };
use ForkResult::*;
feature! {
#![feature = "process"]
#[cfg(target_os = "freebsd")]
/// rfork can be used to have a tigher control about which resources child
/// and parent process will be sharing, file descriptors, address spaces
/// and child exit's behavior.
pub unsafe fn rfork(flags: RforkFlags) -> Result<ForkResult> {
use ForkResult::*;
let res = unsafe { libc::rfork(flags.bits()) };

Errno::result(res).map(|res| match res {
0 => Child,
res => Parent { child: Pid(res) },
})
}
Errno::result(res).map(|res| match res {
0 => Child,
res => Parent { child: Pid(res) },
})
}
}

#[cfg(feature = "fs")]
Expand Down
29 changes: 29 additions & 0 deletions test/test_unistd.rs
Expand Up @@ -66,6 +66,35 @@ fn test_fork_and_waitpid() {
}
}

#[test]
#[cfg(target_os = "freebsd")]
fn test_rfork_and_waitpid() {
let _m = crate::FORK_MTX.lock();

// Safe: Child only calls `_exit`, which is signal-safe
match unsafe { rfork(RforkFlags::RFPROC | RforkFlags::RFTHREAD) }.expect("Error: Rfork Failed") {
Child => unsafe { _exit(0) },
Parent { child } => {
// assert that child was created and pid > 0
let child_raw: ::libc::pid_t = child.into();
assert!(child_raw > 0);
let wait_status = waitpid(child, None);
match wait_status {
// assert that waitpid returned correct status and the pid is the one of the child
Ok(WaitStatus::Exited(pid_t, _)) => assert_eq!(pid_t, child),

// panic, must never happen
s @ Ok(_) => {
panic!("Child exited {s:?}, should never happen")
}

// panic, waitpid should never fail
Err(s) => panic!("Error: waitpid returned Err({s:?}"),
}
}
}
}

#[test]
fn test_wait() {
// Grab FORK_MTX so wait doesn't reap a different test's child process
Expand Down

0 comments on commit 193749b

Please sign in to comment.