github.com/anacrolix/torrent@v1.61.0/internal/mytimer/my-timer.go (about)

     1  package mytimer
     2  
     3  import (
     4  	"math"
     5  	"time"
     6  
     7  	"github.com/anacrolix/missinggo/v2/panicif"
     8  	"github.com/anacrolix/sync"
     9  )
    10  
    11  // Very common pattern I have in my code, a timer that coordinates resets from the callback
    12  // function, externally, and tracks when it's due. Only one instance of the timer callback can be
    13  // running at a time, and that callback is responsible for also returning the next delay.
    14  type Timer struct {
    15  	mu     sync.RWMutex
    16  	when   time.Time
    17  	f      Func
    18  	t      *time.Timer
    19  	inited bool
    20  }
    21  
    22  func (me *Timer) Init(first TimeValue, f Func) {
    23  	panicif.True(me.inited)
    24  	me.inited = true
    25  	me.f = f
    26  	me.when = first
    27  	d := time.Until(first)
    28  	if first.IsZero() {
    29  		d = math.MaxInt64
    30  	}
    31  	// Should we Stop the timer if there's no initial delay set? We can't update the timer
    32  	// externally unless we know if the timer is scheduled.
    33  	me.t = time.AfterFunc(d, me.innerCallback)
    34  }
    35  
    36  func (me *Timer) update(when time.Time) {
    37  	me.mu.Lock()
    38  	defer me.mu.Unlock()
    39  	// Avoid hammering the scheduler with changes. I think this will work, and is probably cheaper
    40  	// than avoiding our object's lock.
    41  	if when.Equal(me.when) {
    42  		return
    43  	}
    44  	if !me.t.Stop() {
    45  		// Timer callback might be active.
    46  		if !me.when.IsZero() {
    47  			// Timer callback is running.
    48  			return
    49  		}
    50  	}
    51  	me.reset(when)
    52  }
    53  
    54  func (me *Timer) reset(when time.Time) {
    55  	me.when = when
    56  	if !me.when.IsZero() {
    57  		panicif.True(me.t.Reset(time.Until(me.when)))
    58  	}
    59  }
    60  func (me *Timer) When() time.Time {
    61  	return me.when
    62  }
    63  
    64  func (me *Timer) innerCallback() {
    65  	panicif.True(me.when.IsZero())
    66  	panicif.True(time.Now().Before(me.when))
    67  	// Nobody else can set it while we're running (when is non-zero and the timer has fired
    68  	// already).
    69  	when := me.f()
    70  	me.mu.Lock()
    71  	me.reset(when)
    72  	me.mu.Unlock()
    73  }
    74  
    75  // Resets if the timer func hasn't fired.
    76  func (me *Timer) Update(when time.Time) {
    77  	me.update(when)
    78  }