mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-17 23:57:49 +00:00
fix wait.PollUntilContextCancel immediately executes condition once
This commit is contained in:
parent
4734021993
commit
79f9bfdc8e
@ -40,6 +40,10 @@ func loopConditionUntilContext(ctx context.Context, t Timer, immediate, sliding
|
|||||||
var timeCh <-chan time.Time
|
var timeCh <-chan time.Time
|
||||||
doneCh := ctx.Done()
|
doneCh := ctx.Done()
|
||||||
|
|
||||||
|
if !sliding {
|
||||||
|
timeCh = t.C()
|
||||||
|
}
|
||||||
|
|
||||||
// if immediate is true the condition is
|
// if immediate is true the condition is
|
||||||
// guaranteed to be executed at least once,
|
// guaranteed to be executed at least once,
|
||||||
// if we haven't requested immediate execution, delay once
|
// if we haven't requested immediate execution, delay once
|
||||||
@ -50,17 +54,27 @@ func loopConditionUntilContext(ctx context.Context, t Timer, immediate, sliding
|
|||||||
}(); err != nil || ok {
|
}(); err != nil || ok {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
if sliding {
|
||||||
timeCh = t.C()
|
timeCh = t.C()
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
|
||||||
|
// Wait for either the context to be cancelled or the next invocation be called
|
||||||
select {
|
select {
|
||||||
case <-doneCh:
|
case <-doneCh:
|
||||||
return ctx.Err()
|
return ctx.Err()
|
||||||
case <-timeCh:
|
case <-timeCh:
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
// IMPORTANT: Because there is no channel priority selection in golang
|
||||||
// checking ctx.Err() is slightly faster than checking a select
|
// it is possible for very short timers to "win" the race in the previous select
|
||||||
|
// repeatedly even when the context has been canceled. We therefore must
|
||||||
|
// explicitly check for context cancellation on every loop and exit if true to
|
||||||
|
// guarantee that we don't invoke condition more than once after context has
|
||||||
|
// been cancelled.
|
||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -77,21 +91,5 @@ func loopConditionUntilContext(ctx context.Context, t Timer, immediate, sliding
|
|||||||
if sliding {
|
if sliding {
|
||||||
t.Next()
|
t.Next()
|
||||||
}
|
}
|
||||||
|
|
||||||
if timeCh == nil {
|
|
||||||
timeCh = t.C()
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: b/c there is no priority selection in golang
|
|
||||||
// it is possible for this to race, meaning we could
|
|
||||||
// trigger t.C and doneCh, and t.C select falls through.
|
|
||||||
// In order to mitigate we re-check doneCh at the beginning
|
|
||||||
// of every loop to guarantee at-most one extra execution
|
|
||||||
// of condition.
|
|
||||||
select {
|
|
||||||
case <-doneCh:
|
|
||||||
return ctx.Err()
|
|
||||||
case <-timeCh:
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user