github.com/GeniusesGroup/libgo@v0.0.0-20220929090155-5ff932cb408e/timer/timing-heap.go (about)

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