use std::{mem, process}; use nix::{ errno, sched, unistd::{self, Pid}, }; #[repr(C)] #[derive(Debug, Default)] struct CloneArgs { flags: u64, pidfd: u64, child_tid: u64, parent_tid: u64, exit_signal: u64, stack: u64, stack_size: u64, tls: u64, } pub unsafe fn clone(flags: sched::CloneFlags) -> nix::Result { let mut args = CloneArgs { flags: flags.bits() as u64, exit_signal: libc::SIGCHLD as u64, ..CloneArgs::default() }; let size = mem::size_of_val(&args) as libc::size_t; let pid = libc::syscall(libc::SYS_clone3, &mut args, size); if pid < 0 { Err(errno::Errno::last()) } else if pid == 0 { Ok(unistd::ForkResult::Child) } else { Ok(unistd::ForkResult::Parent { child: Pid::from_raw(pid as libc::pid_t), }) } } pub unsafe fn spawn(flags: Option, f: F) -> nix::Result where F: FnOnce(), { let res = if let Some(flags) = flags { clone(flags) } else { unistd::fork() }; match res? { unistd::ForkResult::Parent { child } => Ok(child), unistd::ForkResult::Child => { f(); process::exit(0) } } }