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

     1  /* For license and copyright information please see LEGAL file in repository */
     2  
     3  package timer
     4  
     5  import (
     6  	"sync"
     7  	"sync/atomic"
     8  	"unsafe"
     9  
    10  	"../cpu"
    11  	"../race"
    12  	"../time/monotonic"
    13  )
    14  
    15  // TimingHeap ...
    16  // Active timers live in the timers field as heap structure.
    17  // Inactive timers live there too temporarily, until they are removed.
    18  // Due to atomic function need memory alignment, Don't change fields order.
    19  //
    20  // https://github.com/search?l=go&q=timer&type=Repositories
    21  // https://github.com/RussellLuo/timingwheel/blob/master/delayqueue/delayqueue.go
    22  type TimingHeap struct {
    23  	coreID uint64 // CPU core number this heap run on it
    24  
    25  	// The when field of the first entry on the timer heap.
    26  	// This is updated using atomic functions.
    27  	// This is 0 if the timer heap is empty.
    28  	timer0When int64
    29  
    30  	// The earliest known when field of a timer with
    31  	// timerModifiedEarlier status. Because the timer may have been
    32  	// modified again, there need not be any timer with this value.
    33  	// This is updated using atomic functions.
    34  	// This is 0 if there are no timerModifiedEarlier timers.
    35  	timerModifiedEarliest int64
    36  
    37  	// Number of timers in P's heap.
    38  	// Modified using atomic instructions.
    39  	numTimers int32
    40  
    41  	// Number of timerDeleted timers in P's heap.
    42  	// Modified using atomic instructions.
    43  	deletedTimers int32
    44  
    45  	// Race context used while executing timer functions.
    46  	timerRaceCtx uintptr
    47  
    48  	// Lock for timers. We normally access the timers while running
    49  	// on this P, but the scheduler can also do it from a different P.
    50  	timersLock sync.Mutex
    51  	// Must hold timersLock to access.
    52  	// https://en.wikipedia.org/wiki/Heap_(data_structure)#Comparison_of_theoretic_bounds_for_variants
    53  	// Balancing a heap is done by th.siftUp or th.siftDown methods
    54  	timers []timerBucket
    55  }
    56  
    57  type timerBucket struct {
    58  	timer *Timer
    59  	// Two reason to have timer when here:
    60  	// - hot cache to prevent dereference timer to get when field
    61  	// - It can be difference with timer when filed in timerModifiedXX status.
    62  	when int64
    63  }
    64  
    65  func (th *TimingHeap) Init() {
    66  	// TODO::: let application flow choose timers init cap or force it?
    67  	// th.timers = make([]timerBucket, 1024)
    68  	th.coreID = cpu.ActiveCoreID()
    69  }
    70  
    71  // addTimer adds t to the timers queue.
    72  // The caller must have locked the th.timersLock
    73  func (th *TimingHeap) addTimer(t *Timer) {
    74  	th.timersLock.Lock()
    75  
    76  	th.cleanTimers()
    77  
    78  	var timerWhen = t.when
    79  	t.timers = th
    80  	var i = len(th.timers)
    81  	th.timers = append(th.timers, timerBucket{t, timerWhen})
    82  
    83  	th.siftUpTimer(i)
    84  	if t == th.timers[0].timer {
    85  		atomic.StoreInt64(&th.timer0When, timerWhen)
    86  	}
    87  	atomic.AddInt32(&th.numTimers, 1)
    88  
    89  	th.timersLock.Unlock()
    90  }
    91  
    92  // deleteTimer removes timer i from the timers heap.
    93  // It returns the smallest changed index in th.timers
    94  // The caller must have locked the th.timersLock
    95  func (th *TimingHeap) deleteTimer(i int) int {
    96  	th.timers[i].timer.timers = nil
    97  
    98  	var last = len(th.timers) - 1
    99  	if i != last {
   100  		th.timers[i] = th.timers[last]
   101  	}
   102  	th.timers[last].timer = nil
   103  	th.timers = th.timers[:last]
   104  
   105  	var smallestChanged = i
   106  	if i != last {
   107  		// Moving to i may have moved the last timer to a new parent,
   108  		// so sift up to preserve the heap guarantee.
   109  		smallestChanged = th.siftUpTimer(i)
   110  		th.siftDownTimer(i)
   111  	}
   112  	if i == 0 {
   113  		th.updateTimer0When()
   114  	}
   115  	atomic.AddInt32(&th.numTimers, -1)
   116  	return smallestChanged
   117  }
   118  
   119  // deleteTimer0 removes timer 0 from the timers heap.
   120  // It reports whether it saw no problems due to races.
   121  // The caller must have locked the th.timersLock
   122  func (th *TimingHeap) deleteTimer0() {
   123  	th.timers[0].timer.timers = nil
   124  
   125  	var last = len(th.timers) - 1
   126  	if last > 0 {
   127  		th.timers[0] = th.timers[last]
   128  	}
   129  	th.timers[last].timer = nil
   130  	th.timers = th.timers[:last]
   131  	if last > 0 {
   132  		th.siftDownTimer(0)
   133  	}
   134  	th.updateTimer0When()
   135  	atomic.AddInt32(&th.numTimers, -1)
   136  }
   137  
   138  // cleanTimers cleans up the head of the timer queue. This speeds up
   139  // programs that create and delete timers; leaving them in the heap
   140  // slows down addTimer. Reports whether no timer problems were found.
   141  // The caller must have locked the th.timersLock
   142  func (th *TimingHeap) cleanTimers() {
   143  	if len(th.timers) == 0 {
   144  		return
   145  	}
   146  
   147  	for {
   148  		// This loop can theoretically run for a while, and because
   149  		// it is holding timersLock it cannot be preempted.
   150  		// If someone is trying to preempt us, just return.
   151  		// We can clean the timers later.
   152  		// if gp.preemptStop {
   153  		// 	return
   154  		// }
   155  
   156  		var timerBucket = th.timers[0]
   157  		var timer = timerBucket.timer
   158  		var status = timer.status.Load()
   159  		switch status {
   160  		case status_Deleted:
   161  			if !timer.status.CompareAndSwap(status, status_Removing) {
   162  				continue
   163  			}
   164  			th.deleteTimer0()
   165  			if !timer.status.CompareAndSwap(status_Removing, status_Removed) {
   166  				badTimer()
   167  			}
   168  			atomic.AddInt32(&th.deletedTimers, -1)
   169  		case status_ModifiedEarlier, status_ModifiedLater:
   170  			if !timer.status.CompareAndSwap(status, status_Moving) {
   171  				continue
   172  			}
   173  			// Now we can change the when field of timerBucket.
   174  			th.timers[0].when = timer.when
   175  			// Move timer to the right position.
   176  			th.deleteTimer0()
   177  			th.addTimer(timer)
   178  			if !timer.status.CompareAndSwap(status_Moving, status_Waiting) {
   179  				badTimer()
   180  			}
   181  		default:
   182  			// Head of timers does not need adjustment.
   183  			return
   184  		}
   185  	}
   186  }
   187  
   188  // moveTimers moves a slice of timers to the timers heap.
   189  // The slice has been taken from a different Timers.
   190  // This is currently called when the world is stopped, but the caller
   191  // is expected to have locked the th.timersLock
   192  func (th *TimingHeap) moveTimers(timers []timerBucket) {
   193  	for _, timerBucket := range timers {
   194  		var timer = timerBucket.timer
   195  	loop:
   196  		for {
   197  			var status = timer.status.Load()
   198  			switch status {
   199  			case status_Waiting, status_ModifiedEarlier, status_ModifiedLater:
   200  				if !timer.status.CompareAndSwap(status, status_Moving) {
   201  					continue
   202  				}
   203  				timer.timers = nil
   204  				th.addTimer(timer)
   205  				if !timer.status.CompareAndSwap(status_Moving, status_Waiting) {
   206  					badTimer()
   207  				}
   208  				break loop
   209  			case status_Deleted:
   210  				if !timer.status.CompareAndSwap(status, status_Removed) {
   211  					continue
   212  				}
   213  				timer.timers = nil
   214  				// We no longer need this timer in the heap.
   215  				break loop
   216  			case status_Modifying:
   217  				// Loop until the modification is complete.
   218  				osyield()
   219  			case status_Unset, status_Removed:
   220  				// We should not see these status values in a timers heap.
   221  				badTimer()
   222  			case status_Running, status_Removing, status_Moving:
   223  				// Some other P thinks it owns this timer,
   224  				// which should not happen.
   225  				badTimer()
   226  			default:
   227  				badTimer()
   228  			}
   229  		}
   230  	}
   231  }
   232  
   233  // adjustTimers looks through the timers for any timers that have been modified to run earlier,
   234  // and puts them in the correct place in the heap. While looking for those timers,
   235  // it also moves timers that have been modified to run later, and removes deleted timers.
   236  // The caller must have locked the th.timersLock
   237  func (th *TimingHeap) adjustTimers(now int64) {
   238  	// If we haven't yet reached the time of the first status_ModifiedEarlier
   239  	// timer, don't do anything. This speeds up programs that adjust
   240  	// a lot of timers back and forth if the timers rarely expire.
   241  	// We'll postpone looking through all the adjusted timers until
   242  	// one would actually expire.
   243  	var first = atomic.LoadInt64(&th.timerModifiedEarliest)
   244  	if first == 0 || int64(first) > now {
   245  		if verifyTimers {
   246  			th.verifyTimerHeap()
   247  		}
   248  		return
   249  	}
   250  
   251  	// We are going to clear all status_ModifiedEarlier timers.
   252  	atomic.StoreInt64(&th.timerModifiedEarliest, 0)
   253  
   254  	var moved []*Timer
   255  	var timers = th.timers
   256  	var timersLen = len(timers)
   257  	for i := 0; i < timersLen; i++ {
   258  		var timerBucket = timers[i]
   259  		var timer = timerBucket.timer
   260  		var status = timer.status.Load()
   261  		switch status {
   262  		case status_Deleted:
   263  			if timer.status.CompareAndSwap(status, status_Removing) {
   264  				var changed = th.deleteTimer(i)
   265  				if !timer.status.CompareAndSwap(status_Removing, status_Removed) {
   266  					badTimer()
   267  				}
   268  				atomic.AddInt32(&th.deletedTimers, -1)
   269  				// Go back to the earliest changed heap entry.
   270  				// "- 1" because the loop will add 1.
   271  				i = changed - 1
   272  			}
   273  		case status_ModifiedEarlier, status_ModifiedLater:
   274  			if timer.status.CompareAndSwap(status, status_Moving) {
   275  				// Take t off the heap, and hold onto it.
   276  				// We don't add it back yet because the
   277  				// heap manipulation could cause our
   278  				// loop to skip some other timer.
   279  				var changed = th.deleteTimer(i)
   280  				moved = append(moved, timer)
   281  				// Go back to the earliest changed heap entry.
   282  				// "- 1" because the loop will add 1.
   283  				i = changed - 1
   284  			}
   285  		case status_Unset, status_Running, status_Removing, status_Removed, status_Moving:
   286  			badTimer()
   287  		case status_Waiting:
   288  			// OK, nothing to do.
   289  		case status_Modifying:
   290  			// Check again after modification is complete.
   291  			osyield()
   292  			i--
   293  		default:
   294  			badTimer()
   295  		}
   296  	}
   297  
   298  	if len(moved) > 0 {
   299  		th.addAdjustedTimers(moved)
   300  	}
   301  
   302  	if verifyTimers {
   303  		th.verifyTimerHeap()
   304  	}
   305  }
   306  
   307  // addAdjustedTimers adds any timers we adjusted in th.adjustTimers
   308  // back to the timer heap.
   309  func (th *TimingHeap) addAdjustedTimers(moved []*Timer) {
   310  	for _, t := range moved {
   311  		th.addTimer(t)
   312  		if !t.status.CompareAndSwap(status_Moving, status_Waiting) {
   313  			badTimer()
   314  		}
   315  	}
   316  }
   317  
   318  // runTimer examines the first timer in timers. If it is ready based on now,
   319  // it runs the timer and removes or updates it.
   320  // Returns 0 if it ran a timer, -1 if there are no more timers, or the time
   321  // when the first timer should run.
   322  // The caller must have locked the th.timersLock
   323  // If a timer is run, this will temporarily unlock the timers.
   324  func (th *TimingHeap) runTimer(now int64) int64 {
   325  	for {
   326  		var timerBucket = th.timers[0]
   327  		var timer = timerBucket.timer
   328  		var status = timer.status.Load()
   329  		switch status {
   330  		case status_Waiting:
   331  			if timer.when > now {
   332  				// Not ready to run.
   333  				return timer.when
   334  			}
   335  
   336  			if !timer.status.CompareAndSwap(status, status_Running) {
   337  				continue
   338  			}
   339  			// Note that runOneTimer may temporarily unlock th.timersLock
   340  			th.runOneTimer(timer, now)
   341  			return 0
   342  
   343  		case status_Deleted:
   344  			if !timer.status.CompareAndSwap(status, status_Removing) {
   345  				continue
   346  			}
   347  			th.deleteTimer0()
   348  			if !timer.status.CompareAndSwap(status_Removing, status_Removed) {
   349  				badTimer()
   350  			}
   351  			atomic.AddInt32(&th.deletedTimers, -1)
   352  			if len(th.timers) == 0 {
   353  				return -1
   354  			}
   355  
   356  		case status_ModifiedEarlier, status_ModifiedLater:
   357  			if !timer.status.CompareAndSwap(status, status_Moving) {
   358  				continue
   359  			}
   360  			th.deleteTimer0()
   361  			th.addTimer(timer)
   362  			if !timer.status.CompareAndSwap(status_Moving, status_Waiting) {
   363  				badTimer()
   364  			}
   365  
   366  		case status_Modifying:
   367  			// Wait for modification to complete.
   368  			osyield()
   369  		case status_Unset, status_Removed:
   370  			// Should not see a new or inactive timer on the heap.
   371  			badTimer()
   372  		case status_Running, status_Removing, status_Moving:
   373  			// These should only be set when timers are locked,
   374  			// and we didn't do it.
   375  			badTimer()
   376  		default:
   377  			badTimer()
   378  		}
   379  	}
   380  }
   381  
   382  // runOneTimer runs a single timer.
   383  // The caller must have locked the th.timersLock
   384  // This will temporarily unlock the timers while running the timer function.
   385  func (th *TimingHeap) runOneTimer(t *Timer, now int64) {
   386  	if race.DetectorEnabled {
   387  		ppcur := getg().m.p.ptr()
   388  		if ppcur.timerRaceCtx == 0 {
   389  			ppcur.timerRaceCtx = racegostart(abi.FuncPCABIInternal(runtimer) + sys.PCQuantum)
   390  		}
   391  		race.Acquirectx(ppcur.timerRaceCtx, unsafe.Pointer(t))
   392  	}
   393  
   394  	if t.period > 0 && t.periodNumber != 0 {
   395  		// Leave in heap but adjust next time to fire.
   396  		var delta = t.when - now
   397  		t.when += t.period * (1 + -delta/t.period)
   398  		if t.when < 0 { // check for overflow.
   399  			t.when = maxWhen
   400  		}
   401  		th.siftDownTimer(0)
   402  		if !t.status.CompareAndSwap(status_Running, status_Waiting) {
   403  			badTimer()
   404  		}
   405  		th.updateTimer0When()
   406  		if t.periodNumber > 0 {
   407  			t.periodNumber--
   408  		}
   409  	} else {
   410  		// Remove from heap.
   411  		th.deleteTimer0()
   412  		if !t.status.CompareAndSwap(status_Running, status_Unset) {
   413  			badTimer()
   414  		}
   415  	}
   416  
   417  	if race.DetectorEnabled {
   418  		// Temporarily use the current P's racectx for g0.
   419  		var gp = getg()
   420  		if gp.racectx != 0 {
   421  			panic("timer - runOneTimer: unexpected racectx")
   422  		}
   423  		gp.racectx = gp.m.p.ptr().timerRaceCtx
   424  	}
   425  
   426  	var callback = t.callback
   427  	var arg = t.arg
   428  	th.timersLock.Unlock()
   429  	callback(arg)
   430  	th.timersLock.Lock()
   431  
   432  	if race.DetectorEnabled {
   433  		var gp = getg()
   434  		gp.racectx = 0
   435  	}
   436  }
   437  
   438  // clearDeletedTimers removes all deleted timers from the timers heap.
   439  // This is used to avoid clogging up the heap if the program
   440  // starts a lot of long-running timers and then stops them.
   441  // For example, this can happen via context.WithTimeout.
   442  //
   443  // This is the only function that walks through the entire timer heap,
   444  // other than moveTimers which only runs when the world is stopped.
   445  //
   446  // The caller must have locked the th.timersLock
   447  func (th *TimingHeap) clearDeletedTimers() {
   448  	// We are going to clear all status_ModifiedEarlier timers.
   449  	// Do this now in case new ones show up while we are looping.
   450  	atomic.StoreInt64(&th.timerModifiedEarliest, 0)
   451  
   452  	var cdel = int32(0)
   453  	var to = 0
   454  	var changedHeap = false
   455  	var timers = th.timers
   456  	var timersLen = len(timers)
   457  nextTimer:
   458  	for i := 0; i < timersLen; i++ {
   459  		var timerBucket = timers[i]
   460  		var timer = timerBucket.timer
   461  		for {
   462  			var status = timer.status.Load()
   463  			switch status {
   464  			case status_Waiting:
   465  				if changedHeap {
   466  					timers[to] = timerBucket
   467  					th.siftUpTimer(to)
   468  				}
   469  				to++
   470  				continue nextTimer
   471  			case status_ModifiedEarlier, status_ModifiedLater:
   472  				if timer.status.CompareAndSwap(status, status_Moving) {
   473  					timerBucket.when = timer.when
   474  					timers[to] = timerBucket
   475  					th.siftUpTimer(to)
   476  					to++
   477  					changedHeap = true
   478  					if !timer.status.CompareAndSwap(status_Moving, status_Waiting) {
   479  						badTimer()
   480  					}
   481  					continue nextTimer
   482  				}
   483  			case status_Deleted:
   484  				if timer.status.CompareAndSwap(status, status_Removing) {
   485  					timer.timers = nil
   486  					cdel++
   487  					if !timer.status.CompareAndSwap(status_Removing, status_Removed) {
   488  						badTimer()
   489  					}
   490  					changedHeap = true
   491  					continue nextTimer
   492  				}
   493  			case status_Modifying:
   494  				// Loop until modification complete.
   495  				osyield()
   496  			case status_Unset, status_Removed:
   497  				// We should not see these status values in a timer heap.
   498  				badTimer()
   499  			case status_Running, status_Removing, status_Moving:
   500  				// Some other P thinks it owns this timer,
   501  				// which should not happen.
   502  				badTimer()
   503  			default:
   504  				badTimer()
   505  			}
   506  		}
   507  	}
   508  
   509  	// Set remaining slots in timers slice to nil,
   510  	// so that the timer values can be garbage collected.
   511  	for i := to; i < len(timers); i++ {
   512  		timers[i].timer = nil
   513  	}
   514  
   515  	atomic.AddInt32(&th.deletedTimers, -cdel)
   516  	atomic.AddInt32(&th.numTimers, -cdel)
   517  
   518  	timers = timers[:to]
   519  	th.timers = timers
   520  	th.updateTimer0When()
   521  
   522  	if verifyTimers {
   523  		th.verifyTimerHeap()
   524  	}
   525  }
   526  
   527  // verifyTimerHeap verifies that the timer heap is in a valid state.
   528  // This is only for debugging, and is only called if verifyTimers is true.
   529  // The caller must have locked the th.timersLock
   530  func (th *TimingHeap) verifyTimerHeap() {
   531  	var timers = th.timers
   532  	var timersLen = len(timers)
   533  	// First timer has no parent, so i must be start from 1.
   534  	for i := 1; i < timersLen; i++ {
   535  		var timerBucket = th.timers[0]
   536  		var timer = timerBucket.timer
   537  
   538  		// The heap is 4-ary. See siftUpTimer and siftDownTimer.
   539  		var p = (i - 1) / 4
   540  		if timer.when < timers[p].when {
   541  			print("timer: bad timer heap at ", i, ": ", p, ": ", th.timers[p].when, ", ", i, ": ", timer.when, "\n")
   542  			panic("timer: bad timer heap")
   543  		}
   544  	}
   545  	var numTimers = int(atomic.LoadInt32(&th.numTimers))
   546  	if timersLen != numTimers {
   547  		println("timer: heap len", len(th.timers), "!= numTimers", numTimers)
   548  		panic("timer: bad timer heap len")
   549  	}
   550  }
   551  
   552  // updateTimer0When sets the timer0When field by check first timer in queue.
   553  // The caller must have locked the th.timersLock
   554  func (th *TimingHeap) updateTimer0When() {
   555  	if len(th.timers) == 0 {
   556  		atomic.StoreInt64(&th.timer0When, 0)
   557  	} else {
   558  		atomic.StoreInt64(&th.timer0When, th.timers[0].when)
   559  	}
   560  }
   561  
   562  // updateTimerModifiedEarliest updates the th.timerModifiedEarliest value.
   563  // The timers will not be locked.
   564  func (th *TimingHeap) updateTimerModifiedEarliest(nextWhen int64) {
   565  	for {
   566  		var old = atomic.LoadInt64(&th.timerModifiedEarliest)
   567  		if old != 0 && int64(old) < nextWhen {
   568  			return
   569  		}
   570  		if atomic.CompareAndSwapInt64(&th.timerModifiedEarliest, old, nextWhen) {
   571  			return
   572  		}
   573  	}
   574  }
   575  
   576  // sleepUntil returns the time when the next timer should fire.
   577  func (th *TimingHeap) sleepUntil() (until int64) {
   578  	until = int64(maxWhen)
   579  
   580  	var timer0When = atomic.LoadInt64(&th.timer0When)
   581  	if timer0When != 0 && timer0When < until {
   582  		until = timer0When
   583  	}
   584  
   585  	timer0When = atomic.LoadInt64(&th.timerModifiedEarliest)
   586  	if timer0When != 0 && timer0When < until {
   587  		until = timer0When
   588  	}
   589  	return
   590  }
   591  
   592  // noBarrierWakeTime looks at timers and returns the time when we should wake up.
   593  // This function is invoked when dropping a Timers, and must run without any write barriers.
   594  // Unlike th.sleepUntil(), It returns 0 if there are no timers.
   595  func (th *TimingHeap) noBarrierWakeTime() (until int64) {
   596  	until = atomic.LoadInt64(&th.timer0When)
   597  	var nextAdj = atomic.LoadInt64(&th.timerModifiedEarliest)
   598  	if until == 0 || (nextAdj != 0 && nextAdj < until) {
   599  		until = nextAdj
   600  	}
   601  	return
   602  }
   603  
   604  // checkTimers runs any timers for the P that are ready.
   605  // If now is not 0 it is the current time.
   606  // It returns the passed time or the current time if now was passed as 0.
   607  // and the time when the next timer should run or 0 if there is no next timer,
   608  // and reports whether it ran any timers.
   609  // If the time when the next timer should run is not 0,
   610  // it is always larger than the returned time.
   611  // We pass now in and out to avoid extra calls of monotonic.RuntimeNano().
   612  func (th *TimingHeap) checkTimers(now int64) (rnow, pollUntil int64, ran bool) {
   613  	// If it's not yet time for the first timer, or the first adjusted
   614  	// timer, then there is nothing to do.
   615  	var next = th.noBarrierWakeTime()
   616  	if next == 0 {
   617  		// No timers to run or adjust.
   618  		return now, 0, false
   619  	}
   620  
   621  	if now == 0 {
   622  		now = monotonic.RuntimeNano()
   623  	}
   624  	if now < next {
   625  		// Next timer is not ready to run, but keep going
   626  		// if we would clear deleted timers.
   627  		// This corresponds to the condition below where
   628  		// we decide whether to call clearDeletedTimers.
   629  		if atomic.LoadInt32(&th.deletedTimers) <= atomic.LoadInt32(&th.numTimers)/4 {
   630  			return now, next, false
   631  		}
   632  	}
   633  
   634  	th.timersLock.Lock()
   635  
   636  	if len(th.timers) > 0 {
   637  		th.adjustTimers(now)
   638  		for len(th.timers) > 0 {
   639  			// Note that th.runTimer may temporarily unlock th.timersLock.
   640  			var tw = th.runTimer(now)
   641  			if tw != 0 {
   642  				if tw > 0 {
   643  					pollUntil = tw
   644  				}
   645  				break
   646  			}
   647  			ran = true
   648  		}
   649  	}
   650  
   651  	// If this is the local P, and there are a lot of deleted timers,
   652  	// clear them out. We only do this for the local P to reduce
   653  	// lock contention on timersLock.
   654  	if int(atomic.LoadInt32(&th.deletedTimers)) > len(th.timers)/4 {
   655  		th.clearDeletedTimers()
   656  	}
   657  
   658  	th.timersLock.Unlock()
   659  
   660  	return now, pollUntil, ran
   661  }
   662  
   663  // Check for deadlock situation
   664  func (th *TimingHeap) checkDead() {
   665  	// Maybe jump time forward for playground.
   666  	if faketime != 0 {
   667  		var when = th.sleepUntil()
   668  
   669  		faketime = when
   670  
   671  		var mp = mget()
   672  		if mp == nil {
   673  			// There should always be a free M since
   674  			// nothing is running.
   675  			throw("timers - checkDead: no m for timer")
   676  		}
   677  		return
   678  	}
   679  
   680  	// There are no goroutines running, so we can look at the P's.
   681  	if len(th.timers) > 0 {
   682  		return
   683  	}
   684  }
   685  
   686  // badTimer is called if the timer data structures have been corrupted,
   687  // presumably due to racy use by the program. We panic here rather than
   688  // panicing due to invalid slice access while holding locks.
   689  // See issue #25686.
   690  func badTimer() {
   691  	panic("timers: data corruption")
   692  }
   693  
   694  // Heap maintenance algorithms.
   695  // These algorithms check for slice index errors manually.
   696  // Slice index error can happen if the program is using racy
   697  // access to timers. We don't want to panic here, because
   698  // it will cause the program to crash with a mysterious
   699  // "panic holding locks" message. Instead, we panic while not
   700  // holding a lock.
   701  
   702  // siftUpTimer puts the timer at position i in the right place
   703  // in the heap by moving it up toward the top of the heap.
   704  // It returns the smallest changed index.
   705  func (th *TimingHeap) siftUpTimer(i int) int {
   706  	var timers = th.timers
   707  	var timerWhen = timers[i].when
   708  
   709  	var tmp = timers[i]
   710  	for i > 0 {
   711  		var p = (i - 1) / 4 // parent
   712  		if timerWhen >= timers[p].when {
   713  			break
   714  		}
   715  		timers[i] = timers[p]
   716  		i = p
   717  	}
   718  	if tmp != timers[i] {
   719  		timers[i] = tmp
   720  	}
   721  	return i
   722  }
   723  
   724  // siftDownTimer puts the timer at position i in the right place
   725  // in the heap by moving it down toward the bottom of the heap.
   726  func (th *TimingHeap) siftDownTimer(i int) {
   727  	var timers = th.timers
   728  	var timersLen = len(timers)
   729  	var timerWhen = timers[i].when
   730  
   731  	var tmp = timers[i]
   732  	for {
   733  		var c = i*4 + 1 // left child
   734  		var c3 = c + 2  // mid child
   735  		if c >= timersLen {
   736  			break
   737  		}
   738  		var w = timers[c].when
   739  		if c+1 < timersLen && timers[c+1].when < w {
   740  			w = timers[c+1].when
   741  			c++
   742  		}
   743  		if c3 < timersLen {
   744  			var w3 = timers[c3].when
   745  			if c3+1 < timersLen && timers[c3+1].when < w3 {
   746  				w3 = timers[c3+1].when
   747  				c3++
   748  			}
   749  			if w3 < w {
   750  				w = w3
   751  				c = c3
   752  			}
   753  		}
   754  		if w >= timerWhen {
   755  			break
   756  		}
   757  		timers[i] = timers[c]
   758  		i = c
   759  	}
   760  	if tmp != timers[i] {
   761  		timers[i] = tmp
   762  	}
   763  }