1 /* 2 Copyright 2023 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package wait 18 19 import ( 20 "time" 21 22 "k8s.io/utils/clock" 23 ) 24 25 // Timer abstracts how wait functions interact with time runtime efficiently. Test 26 // code may implement this interface directly but package consumers are encouraged 27 // to use the Backoff type as the primary mechanism for acquiring a Timer. The 28 // interface is a simplification of clock.Timer to prevent misuse. Timers are not 29 // expected to be safe for calls from multiple goroutines. 30 type Timer interface { 31 // C returns a channel that will receive a struct{} each time the timer fires. 32 // The channel should not be waited on after Stop() is invoked. It is allowed 33 // to cache the returned value of C() for the lifetime of the Timer. 34 C() <-chan time.Time 35 // Next is invoked by wait functions to signal timers that the next interval 36 // should begin. You may only use Next() if you have drained the channel C(). 37 // You should not call Next() after Stop() is invoked. 38 Next() 39 // Stop releases the timer. It is safe to invoke if no other methods have been 40 // called. 41 Stop() 42 } 43 44 type noopTimer struct { 45 closedCh <-chan time.Time 46 } 47 48 // newNoopTimer creates a timer with a unique channel to avoid contention 49 // for the channel's lock across multiple unrelated timers. 50 func newNoopTimer() noopTimer { 51 ch := make(chan time.Time) 52 close(ch) 53 return noopTimer{closedCh: ch} 54 } 55 56 func (t noopTimer) C() <-chan time.Time { 57 return t.closedCh 58 } 59 func (noopTimer) Next() {} 60 func (noopTimer) Stop() {} 61 62 type variableTimer struct { 63 fn DelayFunc 64 t clock.Timer 65 new func(time.Duration) clock.Timer 66 } 67 68 func (t *variableTimer) C() <-chan time.Time { 69 if t.t == nil { 70 d := t.fn() 71 t.t = t.new(d) 72 } 73 return t.t.C() 74 } 75 func (t *variableTimer) Next() { 76 if t.t == nil { 77 return 78 } 79 d := t.fn() 80 t.t.Reset(d) 81 } 82 func (t *variableTimer) Stop() { 83 if t.t == nil { 84 return 85 } 86 t.t.Stop() 87 t.t = nil 88 } 89 90 type fixedTimer struct { 91 interval time.Duration 92 t clock.Ticker 93 new func(time.Duration) clock.Ticker 94 } 95 96 func (t *fixedTimer) C() <-chan time.Time { 97 if t.t == nil { 98 t.t = t.new(t.interval) 99 } 100 return t.t.C() 101 } 102 func (t *fixedTimer) Next() { 103 // no-op for fixed timers 104 } 105 func (t *fixedTimer) Stop() { 106 if t.t == nil { 107 return 108 } 109 t.t.Stop() 110 t.t = nil 111 } 112 113 var ( 114 // RealTimer can be passed to methods that need a clock.Timer. 115 RealTimer = clock.RealClock{}.NewTimer 116 ) 117 118 var ( 119 // internalClock is used for test injection of clocks 120 internalClock = clock.RealClock{} 121 ) 122