Merge pull request #13610 from bcrist/child_process_already_terminated

return error.AlreadyTerminated from std.ChildProcess.kill when necessary
This commit is contained in:
Andrew Kelley 2023-10-18 10:23:23 -04:00 committed by GitHub
commit e8f3c4c4b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 20 additions and 5 deletions

View File

@ -221,7 +221,18 @@ pub const ChildProcess = struct {
return term; return term;
} }
try windows.TerminateProcess(self.id, exit_code); windows.TerminateProcess(self.id, exit_code) catch |err| switch (err) {
error.PermissionDenied => {
// Usually when TerminateProcess triggers a ACCESS_DENIED error, it
// indicates that the process has already exited, but there may be
// some rare edge cases where our process handle no longer has the
// PROCESS_TERMINATE access right, so let's do another check to make
// sure the process is really no longer running:
windows.WaitForSingleObjectEx(self.handle, 0, false) catch return err;
return error.AlreadyTerminated;
},
else => return err,
};
try self.waitUnwrappedWindows(); try self.waitUnwrappedWindows();
return self.term.?; return self.term.?;
} }
@ -231,7 +242,10 @@ pub const ChildProcess = struct {
self.cleanupStreams(); self.cleanupStreams();
return term; return term;
} }
try os.kill(self.id, os.SIG.TERM); os.kill(self.id, os.SIG.TERM) catch |err| switch (err) {
error.ProcessNotFound => return error.AlreadyTerminated,
else => return err,
};
try self.waitUnwrapped(); try self.waitUnwrapped();
return self.term.?; return self.term.?;
} }

View File

@ -639,14 +639,14 @@ pub fn raise(sig: u8) RaiseError!void {
@compileError("std.os.raise unimplemented for this target"); @compileError("std.os.raise unimplemented for this target");
} }
pub const KillError = error{PermissionDenied} || UnexpectedError; pub const KillError = error{ ProcessNotFound, PermissionDenied } || UnexpectedError;
pub fn kill(pid: pid_t, sig: u8) KillError!void { pub fn kill(pid: pid_t, sig: u8) KillError!void {
switch (errno(system.kill(pid, sig))) { switch (errno(system.kill(pid, sig))) {
.SUCCESS => return, .SUCCESS => return,
.INVAL => unreachable, // invalid signal .INVAL => unreachable, // invalid signal
.PERM => return error.PermissionDenied, .PERM => return error.PermissionDenied,
.SRCH => unreachable, // always a race condition .SRCH => return error.ProcessNotFound,
else => |err| return unexpectedErrno(err), else => |err| return unexpectedErrno(err),
} }
} }

View File

@ -1593,11 +1593,12 @@ pub fn GetModuleFileNameW(hModule: ?HMODULE, buf_ptr: [*]u16, buf_len: DWORD) Ge
return buf_ptr[0..rc :0]; return buf_ptr[0..rc :0];
} }
pub const TerminateProcessError = error{Unexpected}; pub const TerminateProcessError = error{ PermissionDenied, Unexpected };
pub fn TerminateProcess(hProcess: HANDLE, uExitCode: UINT) TerminateProcessError!void { pub fn TerminateProcess(hProcess: HANDLE, uExitCode: UINT) TerminateProcessError!void {
if (kernel32.TerminateProcess(hProcess, uExitCode) == 0) { if (kernel32.TerminateProcess(hProcess, uExitCode) == 0) {
switch (kernel32.GetLastError()) { switch (kernel32.GetLastError()) {
Win32Error.ACCESS_DENIED => return error.PermissionDenied,
else => |err| return unexpectedError(err), else => |err| return unexpectedError(err),
} }
} }