1 //! Unix-only extensions, for sending signals.
2 
3 use std::io;
4 
5 pub trait SharedChildExt {
6     /// Send a signal to the child process with `libc::kill`. If the process
7     /// has already been waited on, this returns `Ok(())` and does nothing.
send_signal(&self, signal: libc::c_int) -> io::Result<()>8     fn send_signal(&self, signal: libc::c_int) -> io::Result<()>;
9 }
10 
11 impl SharedChildExt for super::SharedChild {
send_signal(&self, signal: libc::c_int) -> io::Result<()>12     fn send_signal(&self, signal: libc::c_int) -> io::Result<()> {
13         let status = self.state_lock.lock().unwrap();
14         if let super::ChildState::Exited(_) = *status {
15             return Ok(());
16         }
17         // The child is still running. Signal it. Holding the state lock
18         // is important to prevent a PID race.
19         // This assumes that the wait methods will never hold the child
20         // lock during a blocking wait, since we need it to get the pid.
21         let pid = self.id() as libc::pid_t;
22         match unsafe { libc::kill(pid, signal) } {
23             -1 => Err(io::Error::last_os_error()),
24             _ => Ok(()),
25         }
26     }
27 }
28 
29 #[cfg(test)]
30 mod tests {
31     use super::SharedChildExt;
32     use crate::tests::*;
33     use crate::SharedChild;
34     use std::os::unix::process::ExitStatusExt;
35 
36     #[test]
test_send_signal()37     fn test_send_signal() {
38         let child = SharedChild::spawn(&mut sleep_forever_cmd()).unwrap();
39         child.send_signal(libc::SIGABRT).unwrap();
40         let status = child.wait().unwrap();
41         assert_eq!(Some(libc::SIGABRT), status.signal());
42     }
43 }
44