diff --git a/library/std/src/process.rs b/library/std/src/process.rs index d91d4fa64caa5..4c14158fc01cc 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1860,6 +1860,38 @@ impl Child { self.handle.kill() } + /// Signals the child process to exit. If the child has already exited, an [`InvalidInput`] + /// error is returned. + /// + /// Unlike [`kill`] this allows the process to catch the signal and gracefully exit. + /// + /// The mapping to [`ErrorKind`]s is not part of the compatibility contract of the function. + /// + /// This is equivalent to sending a SIGINT on Unix platforms. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ```no_run + /// use std::process::Command; + /// + /// let mut command = Command::new("yes"); + /// if let Ok(mut child) = command.spawn() { + /// child.interrupt().expect("command wasn't running"); + /// } else { + /// println!("yes command didn't start"); + /// } + /// ``` + /// + /// [`ErrorKind`]: io::ErrorKind + /// [`InvalidInput`]: io::ErrorKind::InvalidInput + #[stable(feature = "process", since = "1.0.0")] + pub fn interrupt(&mut self) -> io::Result<()> { + self.handle.interrupt() + } + + /// Returns the OS-assigned process identifier associated with this child. /// /// # Examples diff --git a/library/std/src/sys/unix/process/process_fuchsia.rs b/library/std/src/sys/unix/process/process_fuchsia.rs index 73f5d3a618bad..e599378769efb 100644 --- a/library/std/src/sys/unix/process/process_fuchsia.rs +++ b/library/std/src/sys/unix/process/process_fuchsia.rs @@ -160,6 +160,16 @@ impl Process { Ok(()) } + pub fn interrupt(&mut self) -> io::Result<()> { + use crate::sys::process::zircon::*; + + unsafe { + zx_cvt(zx_task_kill(self.handle.raw()))?; + } + + Ok(()) + } + pub fn wait(&mut self) -> io::Result { use crate::default::Default; use crate::sys::process::zircon::*; diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 26ae62817713e..f821633c37efa 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -604,6 +604,20 @@ impl Process { cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop) } } + + pub fn interrupt(&mut self) -> io::Result<()> { + // If we've already waited on this process then the pid can be recycled + // and used for another process, and we probably shouldn't be interrupting + // random processes, so just return an error. + if self.status.is_some() { + Err(io::const_io_error!( + ErrorKind::InvalidInput, + "invalid argument: can't interrupt an exited process", + )) + } else { + cvt(unsafe { libc::kill(self.pid, libc::SIGINT) }).map(drop) + } + } pub fn wait(&mut self) -> io::Result { use crate::sys::cvt_r; diff --git a/library/std/src/sys/unix/process/process_unsupported.rs b/library/std/src/sys/unix/process/process_unsupported.rs index 72f9f3f9ca74c..5bcf62b648e58 100644 --- a/library/std/src/sys/unix/process/process_unsupported.rs +++ b/library/std/src/sys/unix/process/process_unsupported.rs @@ -42,6 +42,10 @@ impl Process { unsupported() } + pub fn interrupt(&mut self) -> io::Result<()> { + unsupported() + } + pub fn wait(&mut self) -> io::Result { unsupported() } diff --git a/library/std/src/sys/unix/process/process_vxworks.rs b/library/std/src/sys/unix/process/process_vxworks.rs index 200ef67196798..ba9a8f2ceaf4f 100644 --- a/library/std/src/sys/unix/process/process_vxworks.rs +++ b/library/std/src/sys/unix/process/process_vxworks.rs @@ -150,6 +150,20 @@ impl Process { } } + pub fn interrupt(&mut self) -> io::Result<()> { + // If we've already waited on this process then the pid can be recycled + // and used for another process, and we probably shouldn't be interrupting + // random processes, so just return an error. + if self.status.is_some() { + Err(io::const_io_error!( + ErrorKind::InvalidInput, + "invalid argument: can't kill an exited process", + )) + } else { + cvt(unsafe { libc::kill(self.pid, libc::SIGINT) }).map(drop) + } + } + pub fn wait(&mut self) -> io::Result { use crate::sys::cvt_r; if let Some(status) = self.status { diff --git a/library/std/src/sys/unsupported/process.rs b/library/std/src/sys/unsupported/process.rs index 633f17c054bc6..058b428426c92 100644 --- a/library/std/src/sys/unsupported/process.rs +++ b/library/std/src/sys/unsupported/process.rs @@ -182,6 +182,10 @@ impl Process { self.0 } + pub fn interrupt(&mut self) -> io::Result<()> { + self.0 + } + pub fn wait(&mut self) -> io::Result { self.0 }