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