fix(auth): close cancellation and workspace races
This commit is contained in:
@@ -1,26 +1,50 @@
|
||||
package compose
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// terminateWindowsProcess reports a reap failure only when the process has not exited within the
|
||||
// final bound. taskkill and Process.Kill can both race with a child that has already been reaped.
|
||||
func terminateWindowsProcess(
|
||||
// processLifetime owns a started Docker CLI process until it has been reaped and every process
|
||||
// it may have started has been released. Platform implementations must make close idempotent.
|
||||
type processLifetime interface {
|
||||
terminate(done <-chan error) error
|
||||
close() error
|
||||
}
|
||||
|
||||
var startProcessForRunner = startProcess
|
||||
|
||||
var terminateProcessForRunner = func(process processLifetime, done <-chan error) error {
|
||||
return process.terminate(done)
|
||||
}
|
||||
|
||||
// terminateProcessTree terminates the owned tree before consulting the direct child's reaping
|
||||
// result. A direct child can be reaped while descendants survive, so a ready done channel is never
|
||||
// evidence that tree termination can be skipped. The direct kill is only a fallback when tree
|
||||
// ownership could not terminate the tree; an already-reaped direct child is benign in that case.
|
||||
func terminateProcessTree(
|
||||
done <-chan error,
|
||||
terminateTree func() error,
|
||||
terminateDirect func() error,
|
||||
bound time.Duration,
|
||||
) error {
|
||||
if processReaped(done) {
|
||||
return nil
|
||||
treeErr := terminateTree()
|
||||
var directErr error
|
||||
if treeErr != nil {
|
||||
directErr = terminateDirect()
|
||||
if errors.Is(directErr, os.ErrProcessDone) {
|
||||
directErr = nil
|
||||
}
|
||||
}
|
||||
_ = terminateTree()
|
||||
if processReaped(done) {
|
||||
return nil
|
||||
}
|
||||
_ = terminateDirect()
|
||||
if processReaped(done) {
|
||||
reapErr := waitForProcessReap(done, bound)
|
||||
if treeErr == nil && directErr == nil && reapErr == nil {
|
||||
return nil
|
||||
}
|
||||
return errors.Join(ErrProcessReap, treeErr, directErr, reapErr)
|
||||
}
|
||||
|
||||
func waitForProcessReap(done <-chan error, bound time.Duration) error {
|
||||
timer := time.NewTimer(bound)
|
||||
defer timer.Stop()
|
||||
select {
|
||||
@@ -30,12 +54,3 @@ func terminateWindowsProcess(
|
||||
return ErrProcessReap
|
||||
}
|
||||
}
|
||||
|
||||
func processReaped(done <-chan error) bool {
|
||||
select {
|
||||
case <-done:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user