65 lines
1.2 KiB
Go
65 lines
1.2 KiB
Go
package windows
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
const exitPollInterval = 250 * time.Millisecond
|
|
|
|
type exitWaitClock interface {
|
|
Now() time.Time
|
|
Wait(context.Context, time.Duration) error
|
|
}
|
|
|
|
type systemExitWaitClock struct{}
|
|
|
|
func (systemExitWaitClock) Now() time.Time {
|
|
return time.Now()
|
|
}
|
|
|
|
func (systemExitWaitClock) Wait(ctx context.Context, duration time.Duration) error {
|
|
timer := time.NewTimer(duration)
|
|
defer timer.Stop()
|
|
select {
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
case <-timer.C:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func waitForExit(ctx context.Context, timeout time.Duration, running func() (bool, error), clock exitWaitClock) error {
|
|
if ctx == nil {
|
|
return fmt.Errorf("wait context is required")
|
|
}
|
|
if timeout <= 0 {
|
|
return fmt.Errorf("exit timeout must be positive")
|
|
}
|
|
if err := ctx.Err(); err != nil {
|
|
return err
|
|
}
|
|
deadline := clock.Now().Add(timeout)
|
|
for {
|
|
isRunning, err := running()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !isRunning {
|
|
return nil
|
|
}
|
|
remaining := deadline.Sub(clock.Now())
|
|
if remaining <= 0 {
|
|
return context.DeadlineExceeded
|
|
}
|
|
interval := exitPollInterval
|
|
if remaining < interval {
|
|
interval = remaining
|
|
}
|
|
if err := clock.Wait(ctx, interval); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|