github.com/psiphon-Labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/common/quic/gquic-go/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 }