authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-18 10:23:23-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-10-18 10:23:23-04:00
loge8f3c4c4b12f59ac6fb1c2045a0635ce8f3d0dac
tree3e310c3db8301e11340b07800f8a1e8a2654feb9
parent24b065a6a87da68bdefe228bb7e1d148e69edbd8
parentfb9376bd0499e2124616da1aeed7fe4e8bdd4f52
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #13610 from bcrist/child_process_already_terminated

return error.AlreadyTerminated from std.ChildProcess.kill when necessary

3 files changed, 20 insertions(+), 5 deletions(-)

lib/std/child_process.zig+16-2
...@@ -221,7 +221,18 @@ pub const ChildProcess = struct {...@@ -221,7 +221,18 @@ pub const ChildProcess = struct {
221 return term;221 return term;
222 }222 }
223223
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 try self.waitUnwrappedWindows();236 try self.waitUnwrappedWindows();
226 return self.term.?;237 return self.term.?;
227 }238 }
...@@ -231,7 +242,10 @@ pub const ChildProcess = struct {...@@ -231,7 +242,10 @@ pub const ChildProcess = struct {
231 self.cleanupStreams();242 self.cleanupStreams();
232 return term;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 try self.waitUnwrapped();249 try self.waitUnwrapped();
236 return self.term.?;250 return self.term.?;
237 }251 }
lib/std/os.zig+2-2
...@@ -639,14 +639,14 @@ pub fn raise(sig: u8) RaiseError!void {...@@ -639,14 +639,14 @@ pub fn raise(sig: u8) RaiseError!void {
639 @compileError("std.os.raise unimplemented for this target");639 @compileError("std.os.raise unimplemented for this target");
640}640}
641641
642pub const KillError = error{PermissionDenied} || UnexpectedError;642pub const KillError = error{ ProcessNotFound, PermissionDenied } || UnexpectedError;
643643
644pub fn kill(pid: pid_t, sig: u8) KillError!void {644pub fn kill(pid: pid_t, sig: u8) KillError!void {
645 switch (errno(system.kill(pid, sig))) {645 switch (errno(system.kill(pid, sig))) {
646 .SUCCESS => return,646 .SUCCESS => return,
647 .INVAL => unreachable, // invalid signal647 .INVAL => unreachable, // invalid signal
648 .PERM => return error.PermissionDenied,648 .PERM => return error.PermissionDenied,
649 .SRCH => unreachable, // always a race condition649 .SRCH => return error.ProcessNotFound,
650 else => |err| return unexpectedErrno(err),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,11 +1593,12 @@ pub fn GetModuleFileNameW(hModule: ?HMODULE, buf_ptr: [*]u16, buf_len: DWORD) Ge
1593 return buf_ptr[0..rc :0];1593 return buf_ptr[0..rc :0];
1594}1594}
15951595
1596pub const TerminateProcessError = error{Unexpected};1596pub const TerminateProcessError = error{ PermissionDenied, Unexpected };
15971597
1598pub fn TerminateProcess(hProcess: HANDLE, uExitCode: UINT) TerminateProcessError!void {1598pub fn TerminateProcess(hProcess: HANDLE, uExitCode: UINT) TerminateProcessError!void {
1599 if (kernel32.TerminateProcess(hProcess, uExitCode) == 0) {1599 if (kernel32.TerminateProcess(hProcess, uExitCode) == 0) {
1600 switch (kernel32.GetLastError()) {1600 switch (kernel32.GetLastError()) {
1601 Win32Error.ACCESS_DENIED => return error.PermissionDenied,
1601 else => |err| return unexpectedError(err),1602 else => |err| return unexpectedError(err),
1602 }1603 }
1603 }1604 }