1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
extern crate libc;

#[cfg(target_os = "freebsd")]
use std::os::unix::io::RawFd;

#[derive(Debug)]
pub struct ChildHandle {
    pub child_pid: libc::pid_t,
    #[cfg(target_os = "freebsd")]
    pub child_pd: RawFd,
}

impl ChildHandle {
    #[cfg(target_os = "freebsd")]
    pub fn signal(&self, sig: libc::c_int) -> bool {
        unsafe { libc::pdkill(self.child_pd, sig) == 0 }
    }

    #[cfg(not(target_os = "freebsd"))]
    pub fn signal(&self, sig: libc::c_int) -> bool {
        unsafe { libc::kill(self.child_pid, sig) == 0 }
    }
}

#[cfg(target_os = "freebsd")]
impl Drop for ChildHandle {
    fn drop(&mut self) {
        unsafe { libc::close(self.child_pd) };
    }
}

pub enum ForkResult {
    Parent(ChildHandle),
    Child,
    Fail,
}

#[cfg(target_os = "freebsd")]
pub fn fork() -> ForkResult {
    let mut child_pd = -1;
    let child_pid = unsafe { libc::pdfork(&mut child_pd, 0) };
    if child_pid < 0 {
        ForkResult::Fail
    } else if child_pid > 0 {
        ForkResult::Parent(ChildHandle {
            child_pid,
            child_pd,
        })
    } else {
        ForkResult::Child
    }
}

#[cfg(not(target_os = "freebsd"))]
pub fn fork() -> ForkResult {
    let child_pid = unsafe { libc::fork() };
    if child_pid < 0 {
        ForkResult::Fail
    } else if child_pid > 0 {
        ForkResult::Parent(ChildHandle {
            child_pid,
        })
    } else {
        ForkResult::Child
    }
}