Clarify Windows process setup failures
This commit is contained in:
@@ -43,25 +43,44 @@ func (tree *windowsProcessTree) Start(cmd *exec.Cmd) error {
|
|||||||
withHandleErr := cmd.Process.WithHandle(func(handle uintptr) {
|
withHandleErr := cmd.Process.WithHandle(func(handle uintptr) {
|
||||||
assignErr = windows.AssignProcessToJobObject(job, windows.Handle(handle))
|
assignErr = windows.AssignProcessToJobObject(job, windows.Handle(handle))
|
||||||
})
|
})
|
||||||
if withHandleErr == nil && assignErr == nil {
|
if withHandleErr != nil {
|
||||||
assignErr = resumeInitialThread(uint32(cmd.Process.Pid))
|
return failWindowsProcessStart(cmd, job, fmt.Errorf("acquire stable process handle for job assignment: %w", withHandleErr))
|
||||||
}
|
}
|
||||||
if withHandleErr != nil || assignErr != nil {
|
if assignErr != nil {
|
||||||
killErr := cmd.Process.Kill()
|
return failWindowsProcessStart(cmd, job, fmt.Errorf("assign process to job object: %w", assignErr))
|
||||||
waitErr := cmd.Wait()
|
}
|
||||||
_ = windows.CloseHandle(job)
|
if err := resumeInitialThread(uint32(cmd.Process.Pid)); err != nil {
|
||||||
return joinErrors(
|
return failWindowsProcessStart(cmd, job, fmt.Errorf("resume initial process thread: %w", err))
|
||||||
fmt.Errorf("acquire process handle for job assignment: %w", withHandleErr),
|
|
||||||
fmt.Errorf("assign process to job object or resume initial thread: %w", assignErr),
|
|
||||||
killErr,
|
|
||||||
waitErr,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tree.job = job
|
tree.job = job
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func failWindowsProcessStart(cmd *exec.Cmd, job windows.Handle, setupErr error) error {
|
||||||
|
killErr := cmd.Process.Kill()
|
||||||
|
waitErr := cmd.Wait()
|
||||||
|
var exitErr *exec.ExitError
|
||||||
|
if killErr == nil && errors.As(waitErr, &exitErr) {
|
||||||
|
// A killed suspended child normally reports a non-zero exit from Wait;
|
||||||
|
// successful reaping is not an additional setup failure.
|
||||||
|
waitErr = nil
|
||||||
|
}
|
||||||
|
return joinErrors(
|
||||||
|
setupErr,
|
||||||
|
wrapWindowsProcessCleanupError("kill suspended child", killErr),
|
||||||
|
wrapWindowsProcessCleanupError("reap suspended child", waitErr),
|
||||||
|
wrapWindowsProcessCleanupError("close unowned job object", windows.CloseHandle(job)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapWindowsProcessCleanupError(operation string, err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("%s: %w", operation, err)
|
||||||
|
}
|
||||||
|
|
||||||
func resumeInitialThread(processID uint32) error {
|
func resumeInitialThread(processID uint32) error {
|
||||||
snapshot, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPTHREAD, 0)
|
snapshot, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPTHREAD, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user