github.com/apernet/quic-go@v0.43.1-0.20240515053213-5e9e635fd9f0/internal/utils/timer.go (about) 1 package utils 2 3 import ( 4 "math" 5 "time" 6 ) 7 8 // A Timer wrapper that behaves correctly when resetting 9 type Timer struct { 10 t *time.Timer 11 read bool 12 deadline time.Time 13 } 14 15 // NewTimer creates a new timer that is not set 16 func NewTimer() *Timer { 17 return &Timer{t: time.NewTimer(time.Duration(math.MaxInt64))} 18 } 19 20 // Chan returns the channel of the wrapped timer 21 func (t *Timer) Chan() <-chan time.Time { 22 return t.t.C 23 } 24 25 // Reset the timer, no matter whether the value was read or not 26 func (t *Timer) Reset(deadline time.Time) { 27 if deadline.Equal(t.deadline) && !t.read { 28 // No need to reset the timer 29 return 30 } 31 32 // We need to drain the timer if the value from its channel was not read yet. 33 // See https://groups.google.com/forum/#!topic/golang-dev/c9UUfASVPoU 34 if !t.t.Stop() && !t.read { 35 <-t.t.C 36 } 37 if !deadline.IsZero() { 38 t.t.Reset(time.Until(deadline)) 39 } 40 41 t.read = false 42 t.deadline = deadline 43 } 44 45 // SetRead should be called after the value from the chan was read 46 func (t *Timer) SetRead() { 47 t.read = true 48 } 49 50 func (t *Timer) Deadline() time.Time { 51 return t.deadline 52 } 53 54 // Stop stops the timer 55 func (t *Timer) Stop() { 56 t.t.Stop() 57 }