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