Return Ok on kill if process has already exited

This commit is contained in:
Chris Denton 2023-06-13 20:32:31 +01:00
parent 2ca8d358e5
commit e7fda447e7
No known key found for this signature in database
GPG Key ID: 713472F2F45627DE
4 changed files with 17 additions and 14 deletions

View File

@ -1904,8 +1904,8 @@ impl FromInner<imp::ExitCode> for ExitCode {
} }
impl Child { impl Child {
/// Forces the child process to exit. If the child has already exited, an [`InvalidInput`] /// Forces the child process to exit. If the child has already exited, `Ok(())`
/// error is returned. /// is returned.
/// ///
/// The mapping to [`ErrorKind`]s is not part of the compatibility contract of the function. /// The mapping to [`ErrorKind`]s is not part of the compatibility contract of the function.
/// ///
@ -1920,7 +1920,7 @@ impl Child {
/// ///
/// let mut command = Command::new("yes"); /// let mut command = Command::new("yes");
/// if let Ok(mut child) = command.spawn() { /// if let Ok(mut child) = command.spawn() {
/// child.kill().expect("command wasn't running"); /// child.kill().expect("command couldn't be killed");
/// } else { /// } else {
/// println!("yes command didn't start"); /// println!("yes command didn't start");
/// } /// }

View File

@ -719,12 +719,9 @@ impl Process {
pub fn kill(&mut self) -> io::Result<()> { pub fn kill(&mut self) -> io::Result<()> {
// If we've already waited on this process then the pid can be recycled // 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 killing // and used for another process, and we probably shouldn't be killing
// random processes, so just return an error. // random processes, so return Ok because the process has exited already.
if self.status.is_some() { if self.status.is_some() {
Err(io::const_io_error!( Ok(())
ErrorKind::InvalidInput,
"invalid argument: can't kill an exited process",
))
} else { } else {
cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop) cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
} }

View File

@ -144,12 +144,9 @@ impl Process {
pub fn kill(&mut self) -> io::Result<()> { pub fn kill(&mut self) -> io::Result<()> {
// If we've already waited on this process then the pid can be recycled // 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 killing // and used for another process, and we probably shouldn't be killing
// random processes, so just return an error. // random processes, so return Ok because the process has exited already.
if self.status.is_some() { if self.status.is_some() {
Err(io::const_io_error!( Ok(())
ErrorKind::InvalidInput,
"invalid argument: can't kill an exited process",
))
} else { } else {
cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop) cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
} }

View File

@ -595,7 +595,16 @@ pub struct Process {
impl Process { impl Process {
pub fn kill(&mut self) -> io::Result<()> { pub fn kill(&mut self) -> io::Result<()> {
cvt(unsafe { c::TerminateProcess(self.handle.as_raw_handle(), 1) })?; let result = unsafe { c::TerminateProcess(self.handle.as_raw_handle(), 1) };
if result == c::FALSE {
let error = unsafe { c::GetLastError() };
// TerminateProcess returns ERROR_ACCESS_DENIED if the process has already been
// terminated (by us, or for any other reason). So check if the process was actually
// terminated, and if so, do not return an error.
if error != c::ERROR_ACCESS_DENIED || self.try_wait().is_err() {
return Err(crate::io::Error::from_raw_os_error(error as i32));
}
}
Ok(()) Ok(())
} }