| author | |
| committer | |
| log | e8f3c4c4b12f59ac6fb1c2045a0635ce8f3d0dac |
| tree | 3e310c3db8301e11340b07800f8a1e8a2654feb9 |
| parent | 24b065a6a87da68bdefe228bb7e1d148e69edbd8 |
| parent | fb9376bd0499e2124616da1aeed7fe4e8bdd4f52 |
| signature | Signed by PGP key 4AEE18F83AFDEB23 |
return error.AlreadyTerminated from std.ChildProcess.kill when necessary3 files changed, 20 insertions(+), 5 deletions(-)
lib/std/child_process.zig+16-2| ... | ... | @@ -221,7 +221,18 @@ pub const ChildProcess = struct { |
| 221 | 221 | return term; |
| 222 | 222 | } |
| 223 | 223 | |
| 224 | try windows.TerminateProcess(self.id, exit_code); | |
| 224 | windows.TerminateProcess(self.id, exit_code) catch |err| switch (err) { | |
| 225 | error.PermissionDenied => { | |
| 226 | // Usually when TerminateProcess triggers a ACCESS_DENIED error, it | |
| 227 | // indicates that the process has already exited, but there may be | |
| 228 | // some rare edge cases where our process handle no longer has the | |
| 229 | // PROCESS_TERMINATE access right, so let's do another check to make | |
| 230 | // sure the process is really no longer running: | |
| 231 | windows.WaitForSingleObjectEx(self.handle, 0, false) catch return err; | |
| 232 | return error.AlreadyTerminated; | |
| 233 | }, | |
| 234 | else => return err, | |
| 235 | }; | |
| 225 | 236 | try self.waitUnwrappedWindows(); |
| 226 | 237 | return self.term.?; |
| 227 | 238 | } |
| ... | ... | @@ -231,7 +242,10 @@ pub const ChildProcess = struct { |
| 231 | 242 | self.cleanupStreams(); |
| 232 | 243 | return term; |
| 233 | 244 | } |
| 234 | try os.kill(self.id, os.SIG.TERM); | |
| 245 | os.kill(self.id, os.SIG.TERM) catch |err| switch (err) { | |
| 246 | error.ProcessNotFound => return error.AlreadyTerminated, | |
| 247 | else => return err, | |
| 248 | }; | |
| 235 | 249 | try self.waitUnwrapped(); |
| 236 | 250 | return self.term.?; |
| 237 | 251 | } |
lib/std/os.zig+2-2| ... | ... | @@ -639,14 +639,14 @@ pub fn raise(sig: u8) RaiseError!void { |
| 639 | 639 | @compileError("std.os.raise unimplemented for this target"); |
| 640 | 640 | } |
| 641 | 641 | |
| 642 | pub const KillError = error{PermissionDenied} || UnexpectedError; | |
| 642 | pub const KillError = error{ ProcessNotFound, PermissionDenied } || UnexpectedError; | |
| 643 | 643 | |
| 644 | 644 | pub fn kill(pid: pid_t, sig: u8) KillError!void { |
| 645 | 645 | switch (errno(system.kill(pid, sig))) { |
| 646 | 646 | .SUCCESS => return, |
| 647 | 647 | .INVAL => unreachable, // invalid signal |
| 648 | 648 | .PERM => return error.PermissionDenied, |
| 649 | .SRCH => unreachable, // always a race condition | |
| 649 | .SRCH => return error.ProcessNotFound, | |
| 650 | 650 | else => |err| return unexpectedErrno(err), |
| 651 | 651 | } |
| 652 | 652 | } |
lib/std/os/windows.zig+2-1| ... | ... | @@ -1593,11 +1593,12 @@ pub fn GetModuleFileNameW(hModule: ?HMODULE, buf_ptr: [*]u16, buf_len: DWORD) Ge |
| 1593 | 1593 | return buf_ptr[0..rc :0]; |
| 1594 | 1594 | } |
| 1595 | 1595 | |
| 1596 | pub const TerminateProcessError = error{Unexpected}; | |
| 1596 | pub const TerminateProcessError = error{ PermissionDenied, Unexpected }; | |
| 1597 | 1597 | |
| 1598 | 1598 | pub fn TerminateProcess(hProcess: HANDLE, uExitCode: UINT) TerminateProcessError!void { |
| 1599 | 1599 | if (kernel32.TerminateProcess(hProcess, uExitCode) == 0) { |
| 1600 | 1600 | switch (kernel32.GetLastError()) { |
| 1601 | Win32Error.ACCESS_DENIED => return error.PermissionDenied, | |
| 1601 | 1602 | else => |err| return unexpectedError(err), |
| 1602 | 1603 | } |
| 1603 | 1604 | } |