github.com/geniusesgroup/libgo@v0.0.0-20220713101832-828057a9d3d4/timer/timer-internal.go (about)

     1  /* For license and copyright information please see LEGAL file in repository */
     2  
     3  package timer
     4  
     5  import (
     6  	"sync/atomic"
     7  	"unsafe"
     8  
     9  	"../cpu"
    10  	"../protocol"
    11  	"../race"
    12  	"../time/monotonic"
    13  )
    14  
    15  // when is a helper function for setting the 'when' field of a Timer.
    16  // It returns what the time will be, in nanoseconds, Duration d in the future.
    17  // If d is negative, it is ignored. If the returned value would be less than
    18  // zero because of an overflow, MaxInt64 is returned.
    19  func when(d protocol.Duration) (t int64) {
    20  	t = monotonic.RuntimeNano()
    21  	if d <= 0 {
    22  		return
    23  	}
    24  	t += int64(d)
    25  	// check for overflow.
    26  	if t < 0 {
    27  		// N.B. monotonic.RuntimeNano() and d are always positive, so addition
    28  		// (including overflow) will never result in t == 0.
    29  		t = maxWhen
    30  	}
    31  	return
    32  }
    33  
    34  // use to prevent memory leak
    35  func (t *Timer) reset() {
    36  	t.callback = nil
    37  	t.arg = nil
    38  	t.timers = nil
    39  }
    40  
    41  // add adds a timer to the running cpu core timers.
    42  // This should only be called with a newly created timer.
    43  // That avoids the risk of changing the when field of a timer in some P's heap,
    44  // which could cause the heap to become unsorted.
    45  func (t *Timer) add(d protocol.Duration) {
    46  	if t.callback == nil {
    47  		panic("timer: Timer must initialized before start")
    48  	}
    49  	if t.status != status_Unset {
    50  		panic("timer: start called with initialized timer")
    51  	}
    52  	if t.timers != nil {
    53  		panic("timer: timers already set in timer")
    54  	}
    55  	// when must be positive. A negative value will cause ts.runTimer to
    56  	// overflow during its delta calculation and never expire other runtime timers.
    57  	// Zero will cause checkTimers to fail to notice the timer.
    58  	if d < 1 {
    59  		panic("timer: timer must have positive duration.")
    60  	}
    61  
    62  	if race.DetectorEnabled {
    63  		race.Release(unsafe.Pointer(t))
    64  	}
    65  	t.when = when(d)
    66  	t.status = status_Waiting
    67  	t.timers = &poolByCores[cpu.ActiveCoreID()]
    68  	t.timers.addTimer(t)
    69  }
    70  
    71  // delete deletes the timer t. It may be on some other P, so we can't
    72  // actually remove it from the timers heap. We can only mark it as deleted.
    73  // It will be removed in due course by the P whose heap it is on.
    74  // Reports whether the timer was removed before it was run.
    75  func (t *Timer) delete() bool {
    76  	if t.callback == nil {
    77  		panic("timer: Stop called on uninitialized Timer")
    78  	}
    79  
    80  	for {
    81  		var status = t.status.Load()
    82  		switch status {
    83  		case status_Waiting, status_ModifiedLater:
    84  			if t.status.CompareAndSwap(status, status_Modifying) {
    85  				// Must fetch t.timers before changing status,
    86  				// as ts.cleanTimers in another goroutine can clear t.timers of a status_Deleted timer.
    87  				var timers = t.timers
    88  				if !t.status.CompareAndSwap(status_Modifying, status_Deleted) {
    89  					badTimer()
    90  				}
    91  				atomic.AddInt32(&timers.deletedTimers, 1)
    92  				// Timer was not yet run.
    93  				return true
    94  			}
    95  		case status_ModifiedEarlier:
    96  			if t.status.CompareAndSwap(status, status_Modifying) {
    97  				var timers = t.timers
    98  				if !t.status.CompareAndSwap(status_Modifying, status_Deleted) {
    99  					badTimer()
   100  				}
   101  				atomic.AddInt32(&timers.deletedTimers, 1)
   102  				// Timer was not yet run.
   103  				return true
   104  			}
   105  		case status_Deleted, status_Removing, status_Removed:
   106  			// Timer was already run.
   107  			return false
   108  		case status_Running, status_Moving:
   109  			// The timer is being run or moved, by a different P.
   110  			// Wait for it to complete.
   111  			osyield()
   112  		case status_Unset:
   113  			// Removing timer that was never added or
   114  			// has already been run. Also see issue 21874.
   115  			return false
   116  		case status_Modifying:
   117  			// Simultaneous calls to delete and modify.
   118  			// Wait for the other call to complete.
   119  			osyield()
   120  		default:
   121  			badTimer()
   122  		}
   123  	}
   124  }
   125  
   126  // modify modifies an existing timer.
   127  // It's OK to call modify() on a newly allocated Timer.
   128  // Reports whether the timer was modified before it was run.
   129  func (t *Timer) modify(d protocol.Duration) (pending bool) {
   130  	// when must be positive. A negative value will cause ts.runTimer to
   131  	// overflow during its delta calculation and never expire other runtime timers.
   132  	// Zero will cause checkTimers to fail to notice the timer.
   133  	if d < 1 {
   134  		panic("timer: timer must have positive duration")
   135  	}
   136  	if t.callback == nil {
   137  		panic("timer: Timer must initialized before reset")
   138  	}
   139  
   140  	if race.DetectorEnabled {
   141  		race.Release(unsafe.Pointer(t))
   142  	}
   143  
   144  	var wasRemoved = false
   145  loop:
   146  	for {
   147  		var status = t.status.Load()
   148  		switch status {
   149  		case status_Waiting, status_ModifiedEarlier, status_ModifiedLater:
   150  			if t.status.CompareAndSwap(status, status_Modifying) {
   151  				pending = true // timer not yet run
   152  				break loop
   153  			}
   154  		case status_Unset, status_Removed:
   155  			// Timer was already run and t is no longer in a heap.
   156  			// Act like addTimer.
   157  			if t.status.CompareAndSwap(status, status_Modifying) {
   158  				wasRemoved = true
   159  				pending = false // timer already run or stopped
   160  				break loop
   161  			}
   162  		case status_Deleted:
   163  			if t.status.CompareAndSwap(status, status_Modifying) {
   164  				atomic.AddInt32(&t.timers.deletedTimers, -1)
   165  				pending = false // timer already stopped
   166  				break loop
   167  			}
   168  		case status_Running, status_Removing, status_Moving:
   169  			// The timer is being run or moved, by a different P.
   170  			// Wait for it to complete.
   171  			osyield()
   172  		case status_Modifying:
   173  			// Multiple simultaneous calls to modify.
   174  			// Wait for the other call to complete.
   175  			osyield()
   176  		default:
   177  			badTimer()
   178  		}
   179  	}
   180  
   181  	var timerOldWhen = t.when
   182  	var timerNewWhen = when(d)
   183  	t.when = timerNewWhen
   184  	if t.period != 0 {
   185  		t.period = int64(d)
   186  	}
   187  	if wasRemoved {
   188  		t.timers = poolByCores[cpu.ActiveCoreID()]
   189  		t.timers.addTimer(t)
   190  		if !t.status.CompareAndSwap(status_Modifying, status_Waiting) {
   191  			badTimer()
   192  		}
   193  	} else {
   194  		var newStatus = status_ModifiedLater
   195  		if timerNewWhen < timerOldWhen {
   196  			newStatus = status_ModifiedEarlier
   197  		}
   198  		if newStatus == status_ModifiedEarlier {
   199  			t.timers.updateTimerModifiedEarliest(timerNewWhen)
   200  		}
   201  
   202  		// Set the new status of the timer.
   203  		if !t.status.CompareAndSwap(status_Modifying, newStatus) {
   204  			badTimer()
   205  		}
   206  	}
   207  
   208  	return
   209  }