Source File
time.go
Belonging Package
runtime
// Copyright 2009 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.// Time-related runtime and pieces of package time.package runtimeimport ()// Package time knows the layout of this structure.// If this struct changes, adjust ../time/sleep.go:/runtimeTimer.type timer struct {// If this timer is on a heap, which P's heap it is on.// puintptr rather than *p to match uintptr in the versions// of this struct defined in other packages.pp puintptr// Timer wakes up at when, and then at when+period, ... (period > 0 only)// each time calling f(arg, now) in the timer goroutine, so f must be// a well-behaved function and not block.//// when must be positive on an active timer.when int64period int64f func(any, uintptr)arg anyseq uintptr// What to set the when field to in timerModifiedXX status.nextwhen int64// The status field holds one of the values below.status atomic.Uint32}// Code outside this file has to be careful in using a timer value.//// The pp, status, and nextwhen fields may only be used by code in this file.//// Code that creates a new timer value can set the when, period, f,// arg, and seq fields.// A new timer value may be passed to addtimer (called by time.startTimer).// After doing that no fields may be touched.//// An active timer (one that has been passed to addtimer) may be// passed to deltimer (time.stopTimer), after which it is no longer an// active timer. It is an inactive timer.// In an inactive timer the period, f, arg, and seq fields may be modified,// but not the when field.// It's OK to just drop an inactive timer and let the GC collect it.// It's not OK to pass an inactive timer to addtimer.// Only newly allocated timer values may be passed to addtimer.//// An active timer may be passed to modtimer. No fields may be touched.// It remains an active timer.//// An inactive timer may be passed to resettimer to turn into an// active timer with an updated when field.// It's OK to pass a newly allocated timer value to resettimer.//// Timer operations are addtimer, deltimer, modtimer, resettimer,// cleantimers, adjusttimers, and runtimer.//// We don't permit calling addtimer/deltimer/modtimer/resettimer simultaneously,// but adjusttimers and runtimer can be called at the same time as any of those.//// Active timers live in heaps attached to P, in the timers field.// Inactive timers live there too temporarily, until they are removed.//// addtimer:// timerNoStatus -> timerWaiting// anything else -> panic: invalid value// deltimer:// timerWaiting -> timerModifying -> timerDeleted// timerModifiedEarlier -> timerModifying -> timerDeleted// timerModifiedLater -> timerModifying -> timerDeleted// timerNoStatus -> do nothing// timerDeleted -> do nothing// timerRemoving -> do nothing// timerRemoved -> do nothing// timerRunning -> wait until status changes// timerMoving -> wait until status changes// timerModifying -> wait until status changes// modtimer:// timerWaiting -> timerModifying -> timerModifiedXX// timerModifiedXX -> timerModifying -> timerModifiedYY// timerNoStatus -> timerModifying -> timerWaiting// timerRemoved -> timerModifying -> timerWaiting// timerDeleted -> timerModifying -> timerModifiedXX// timerRunning -> wait until status changes// timerMoving -> wait until status changes// timerRemoving -> wait until status changes// timerModifying -> wait until status changes// cleantimers (looks in P's timer heap):// timerDeleted -> timerRemoving -> timerRemoved// timerModifiedXX -> timerMoving -> timerWaiting// adjusttimers (looks in P's timer heap):// timerDeleted -> timerRemoving -> timerRemoved// timerModifiedXX -> timerMoving -> timerWaiting// runtimer (looks in P's timer heap):// timerNoStatus -> panic: uninitialized timer// timerWaiting -> timerWaiting or// timerWaiting -> timerRunning -> timerNoStatus or// timerWaiting -> timerRunning -> timerWaiting// timerModifying -> wait until status changes// timerModifiedXX -> timerMoving -> timerWaiting// timerDeleted -> timerRemoving -> timerRemoved// timerRunning -> panic: concurrent runtimer calls// timerRemoved -> panic: inconsistent timer heap// timerRemoving -> panic: inconsistent timer heap// timerMoving -> panic: inconsistent timer heap// Values for the timer status field.const (// Timer has no status set yet.timerNoStatus = iota// Waiting for timer to fire.// The timer is in some P's heap.timerWaiting// Running the timer function.// A timer will only have this status briefly.timerRunning// The timer is deleted and should be removed.// It should not be run, but it is still in some P's heap.timerDeleted// The timer is being removed.// The timer will only have this status briefly.timerRemoving// The timer has been stopped.// It is not in any P's heap.timerRemoved// The timer is being modified.// The timer will only have this status briefly.timerModifying// The timer has been modified to an earlier time.// The new when value is in the nextwhen field.// The timer is in some P's heap, possibly in the wrong place.timerModifiedEarlier// The timer has been modified to the same or a later time.// The new when value is in the nextwhen field.// The timer is in some P's heap, possibly in the wrong place.timerModifiedLater// The timer has been modified and is being moved.// The timer will only have this status briefly.timerMoving)// maxWhen is the maximum value for timer's when field.const maxWhen = 1<<63 - 1// verifyTimers can be set to true to add debugging checks that the// timer heaps are valid.const verifyTimers = false// Package time APIs.// Godoc uses the comments in package time, not these.// time.now is implemented in assembly.// timeSleep puts the current goroutine to sleep for at least ns nanoseconds.////go:linkname timeSleep time.Sleepfunc ( int64) {if <= 0 {return}:= getg():= .timerif == nil {= new(timer).timer =}.f = goroutineReady.arg =.nextwhen = nanotime() +if .nextwhen < 0 { // check for overflow..nextwhen = maxWhen}gopark(resetForSleep, unsafe.Pointer(), waitReasonSleep, traceBlockSleep, 1)}// resetForSleep is called after the goroutine is parked for timeSleep.// We can't call resettimer in timeSleep itself because if this is a short// sleep and there are many goroutines then the P can wind up running the// timer function, goroutineReady, before the goroutine has been parked.func ( *g, unsafe.Pointer) bool {:= (*timer)()resettimer(, .nextwhen)return true}// startTimer adds t to the timer heap.////go:linkname startTimer time.startTimerfunc ( *timer) {if raceenabled {racerelease(unsafe.Pointer())}addtimer()}// stopTimer stops a timer.// It reports whether t was stopped before being run.////go:linkname stopTimer time.stopTimerfunc ( *timer) bool {return deltimer()}// resetTimer resets an inactive timer, adding it to the heap.//// Reports whether the timer was modified before it was run.////go:linkname resetTimer time.resetTimerfunc ( *timer, int64) bool {if raceenabled {racerelease(unsafe.Pointer())}return resettimer(, )}// modTimer modifies an existing timer.////go:linkname modTimer time.modTimerfunc ( *timer, , int64, func(any, uintptr), any, uintptr) {modtimer(, , , , , )}// Go runtime.// Ready the goroutine arg.func ( any, uintptr) {goready(.(*g), 0)}// Note: this changes some unsynchronized operations to synchronized operations// addtimer adds a timer to the current P.// This should only be called with a newly created timer.// That avoids the risk of changing the when field of a timer in some P's heap,// which could cause the heap to become unsorted.func ( *timer) {// when must be positive. A negative value will cause runtimer to// overflow during its delta calculation and never expire other runtime// timers. Zero will cause checkTimers to fail to notice the timer.if .when <= 0 {throw("timer when must be positive")}if .period < 0 {throw("timer period must be non-negative")}if .status.Load() != timerNoStatus {throw("addtimer called with initialized timer")}.status.Store(timerWaiting):= .when// Disable preemption while using pp to avoid changing another P's heap.:= acquirem():= getg().m.p.ptr()lock(&.timersLock)cleantimers()doaddtimer(, )unlock(&.timersLock)wakeNetPoller()releasem()}// doaddtimer adds t to the current P's heap.// The caller must have locked the timers for pp.func ( *p, *timer) {// Timers rely on the network poller, so make sure the poller// has started.if netpollInited.Load() == 0 {netpollGenericInit()}if .pp != 0 {throw("doaddtimer: P already set in timer")}.pp.set():= len(.timers).timers = append(.timers, )siftupTimer(.timers, )if == .timers[0] {.timer0When.Store(.when)}.numTimers.Add(1)}// deltimer deletes the timer t. It may be on some other P, so we can't// actually remove it from the timers heap. We can only mark it as deleted.// It will be removed in due course by the P whose heap it is on.// Reports whether the timer was removed before it was run.func ( *timer) bool {for {switch := .status.Load(); {case timerWaiting, timerModifiedLater:// Prevent preemption while the timer is in timerModifying.// This could lead to a self-deadlock. See #38070.:= acquirem()if .status.CompareAndSwap(, timerModifying) {// Must fetch t.pp before changing status,// as cleantimers in another goroutine// can clear t.pp of a timerDeleted timer.:= .pp.ptr()if !.status.CompareAndSwap(timerModifying, timerDeleted) {badTimer()}releasem().deletedTimers.Add(1)// Timer was not yet run.return true} else {releasem()}case timerModifiedEarlier:// Prevent preemption while the timer is in timerModifying.// This could lead to a self-deadlock. See #38070.:= acquirem()if .status.CompareAndSwap(, timerModifying) {// Must fetch t.pp before setting status// to timerDeleted.:= .pp.ptr()if !.status.CompareAndSwap(timerModifying, timerDeleted) {badTimer()}releasem().deletedTimers.Add(1)// Timer was not yet run.return true} else {releasem()}case timerDeleted, timerRemoving, timerRemoved:// Timer was already run.return falsecase timerRunning, timerMoving:// The timer is being run or moved, by a different P.// Wait for it to complete.osyield()case timerNoStatus:// Removing timer that was never added or// has already been run. Also see issue 21874.return falsecase timerModifying:// Simultaneous calls to deltimer and modtimer.// Wait for the other call to complete.osyield()default:badTimer()}}}// dodeltimer removes timer i from the current P's heap.// We are locked on the P when this is called.// It returns the smallest changed index in pp.timers.// The caller must have locked the timers for pp.func ( *p, int) int {if := .timers[]; .pp.ptr() != {throw("dodeltimer: wrong P")} else {.pp = 0}:= len(.timers) - 1if != {.timers[] = .timers[]}.timers[] = nil.timers = .timers[:]:=if != {// Moving to i may have moved the last timer to a new parent,// so sift up to preserve the heap guarantee.= siftupTimer(.timers, )siftdownTimer(.timers, )}if == 0 {updateTimer0When()}:= .numTimers.Add(-1)if == 0 {// If there are no timers, then clearly none are modified..timerModifiedEarliest.Store(0)}return}// dodeltimer0 removes timer 0 from the current P's heap.// We are locked on the P when this is called.// It reports whether it saw no problems due to races.// The caller must have locked the timers for pp.func ( *p) {if := .timers[0]; .pp.ptr() != {throw("dodeltimer0: wrong P")} else {.pp = 0}:= len(.timers) - 1if > 0 {.timers[0] = .timers[]}.timers[] = nil.timers = .timers[:]if > 0 {siftdownTimer(.timers, 0)}updateTimer0When():= .numTimers.Add(-1)if == 0 {// If there are no timers, then clearly none are modified..timerModifiedEarliest.Store(0)}}// modtimer modifies an existing timer.// This is called by the netpoll code or time.Ticker.Reset or time.Timer.Reset.// Reports whether the timer was modified before it was run.func ( *timer, , int64, func(any, uintptr), any, uintptr) bool {if <= 0 {throw("timer when must be positive")}if < 0 {throw("timer period must be non-negative")}:= uint32(timerNoStatus):= falsevar boolvar *m:for {switch = .status.Load(); {case timerWaiting, timerModifiedEarlier, timerModifiedLater:// Prevent preemption while the timer is in timerModifying.// This could lead to a self-deadlock. See #38070.= acquirem()if .status.CompareAndSwap(, timerModifying) {= true // timer not yet runbreak}releasem()case timerNoStatus, timerRemoved:// Prevent preemption while the timer is in timerModifying.// This could lead to a self-deadlock. See #38070.= acquirem()// Timer was already run and t is no longer in a heap.// Act like addtimer.if .status.CompareAndSwap(, timerModifying) {= true= false // timer already run or stoppedbreak}releasem()case timerDeleted:// Prevent preemption while the timer is in timerModifying.// This could lead to a self-deadlock. See #38070.= acquirem()if .status.CompareAndSwap(, timerModifying) {.pp.ptr().deletedTimers.Add(-1)= false // timer already stoppedbreak}releasem()case timerRunning, timerRemoving, timerMoving:// The timer is being run or moved, by a different P.// Wait for it to complete.osyield()case timerModifying:// Multiple simultaneous calls to modtimer.// Wait for the other call to complete.osyield()default:badTimer()}}.period =.f =.arg =.seq =if {.when =:= getg().m.p.ptr()lock(&.timersLock)doaddtimer(, )unlock(&.timersLock)if !.status.CompareAndSwap(timerModifying, timerWaiting) {badTimer()}releasem()wakeNetPoller()} else {// The timer is in some other P's heap, so we can't change// the when field. If we did, the other P's heap would// be out of order. So we put the new when value in the// nextwhen field, and let the other P set the when field// when it is prepared to resort the heap..nextwhen =:= uint32(timerModifiedLater)if < .when {= timerModifiedEarlier}:= .pp.ptr()if == timerModifiedEarlier {updateTimerModifiedEarliest(, )}// Set the new status of the timer.if !.status.CompareAndSwap(timerModifying, ) {badTimer()}releasem()// If the new status is earlier, wake up the poller.if == timerModifiedEarlier {wakeNetPoller()}}return}// resettimer resets the time when a timer should fire.// If used for an inactive timer, the timer will become active.// This should be called instead of addtimer if the timer value has been,// or may have been, used previously.// Reports whether the timer was modified before it was run.func ( *timer, int64) bool {return modtimer(, , .period, .f, .arg, .seq)}// cleantimers cleans up the head of the timer queue. This speeds up// programs that create and delete timers; leaving them in the heap// slows down addtimer. Reports whether no timer problems were found.// The caller must have locked the timers for pp.func ( *p) {:= getg()for {if len(.timers) == 0 {return}// This loop can theoretically run for a while, and because// it is holding timersLock it cannot be preempted.// If someone is trying to preempt us, just return.// We can clean the timers later.if .preemptStop {return}:= .timers[0]if .pp.ptr() != {throw("cleantimers: bad p")}switch := .status.Load(); {case timerDeleted:if !.status.CompareAndSwap(, timerRemoving) {continue}dodeltimer0()if !.status.CompareAndSwap(timerRemoving, timerRemoved) {badTimer()}.deletedTimers.Add(-1)case timerModifiedEarlier, timerModifiedLater:if !.status.CompareAndSwap(, timerMoving) {continue}// Now we can change the when field..when = .nextwhen// Move t to the right position.dodeltimer0()doaddtimer(, )if !.status.CompareAndSwap(timerMoving, timerWaiting) {badTimer()}default:// Head of timers does not need adjustment.return}}}// moveTimers moves a slice of timers to pp. The slice has been taken// from a different P.// This is currently called when the world is stopped, but the caller// is expected to have locked the timers for pp.func ( *p, []*timer) {for , := range {:for {switch := .status.Load(); {case timerWaiting:if !.status.CompareAndSwap(, timerMoving) {continue}.pp = 0doaddtimer(, )if !.status.CompareAndSwap(timerMoving, timerWaiting) {badTimer()}breakcase timerModifiedEarlier, timerModifiedLater:if !.status.CompareAndSwap(, timerMoving) {continue}.when = .nextwhen.pp = 0doaddtimer(, )if !.status.CompareAndSwap(timerMoving, timerWaiting) {badTimer()}breakcase timerDeleted:if !.status.CompareAndSwap(, timerRemoved) {continue}.pp = 0// We no longer need this timer in the heap.breakcase timerModifying:// Loop until the modification is complete.osyield()case timerNoStatus, timerRemoved:// We should not see these status values in a timers heap.badTimer()case timerRunning, timerRemoving, timerMoving:// Some other P thinks it owns this timer,// which should not happen.badTimer()default:badTimer()}}}}// adjusttimers looks through the timers in the current P's heap for// any timers that have been modified to run earlier, and puts them in// the correct place in the heap. While looking for those timers,// it also moves timers that have been modified to run later,// and removes deleted timers. The caller must have locked the timers for pp.func ( *p, int64) {// If we haven't yet reached the time of the first timerModifiedEarlier// timer, don't do anything. This speeds up programs that adjust// a lot of timers back and forth if the timers rarely expire.// We'll postpone looking through all the adjusted timers until// one would actually expire.:= .timerModifiedEarliest.Load()if == 0 || > {if verifyTimers {verifyTimerHeap()}return}// We are going to clear all timerModifiedEarlier timers..timerModifiedEarliest.Store(0)var []*timerfor := 0; < len(.timers); ++ {:= .timers[]if .pp.ptr() != {throw("adjusttimers: bad p")}switch := .status.Load(); {case timerDeleted:if .status.CompareAndSwap(, timerRemoving) {:= dodeltimer(, )if !.status.CompareAndSwap(timerRemoving, timerRemoved) {badTimer()}.deletedTimers.Add(-1)// Go back to the earliest changed heap entry.// "- 1" because the loop will add 1.= - 1}case timerModifiedEarlier, timerModifiedLater:if .status.CompareAndSwap(, timerMoving) {// Now we can change the when field..when = .nextwhen// Take t off the heap, and hold onto it.// We don't add it back yet because the// heap manipulation could cause our// loop to skip some other timer.:= dodeltimer(, )= append(, )// Go back to the earliest changed heap entry.// "- 1" because the loop will add 1.= - 1}case timerNoStatus, timerRunning, timerRemoving, timerRemoved, timerMoving:badTimer()case timerWaiting:// OK, nothing to do.case timerModifying:// Check again after modification is complete.osyield()--default:badTimer()}}if len() > 0 {addAdjustedTimers(, )}if verifyTimers {verifyTimerHeap()}}// addAdjustedTimers adds any timers we adjusted in adjusttimers// back to the timer heap.func ( *p, []*timer) {for , := range {doaddtimer(, )if !.status.CompareAndSwap(timerMoving, timerWaiting) {badTimer()}}}// nobarrierWakeTime looks at P's timers and returns the time when we// should wake up the netpoller. It returns 0 if there are no timers.// This function is invoked when dropping a P, and must run without// any write barriers.////go:nowritebarrierrecfunc ( *p) int64 {:= .timer0When.Load():= .timerModifiedEarliest.Load()if == 0 || ( != 0 && < ) {=}return}// runtimer examines the first timer in timers. If it is ready based on now,// it runs the timer and removes or updates it.// Returns 0 if it ran a timer, -1 if there are no more timers, or the time// when the first timer should run.// The caller must have locked the timers for pp.// If a timer is run, this will temporarily unlock the timers.////go:systemstackfunc ( *p, int64) int64 {for {:= .timers[0]if .pp.ptr() != {throw("runtimer: bad p")}switch := .status.Load(); {case timerWaiting:if .when > {// Not ready to run.return .when}if !.status.CompareAndSwap(, timerRunning) {continue}// Note that runOneTimer may temporarily unlock// pp.timersLock.runOneTimer(, , )return 0case timerDeleted:if !.status.CompareAndSwap(, timerRemoving) {continue}dodeltimer0()if !.status.CompareAndSwap(timerRemoving, timerRemoved) {badTimer()}.deletedTimers.Add(-1)if len(.timers) == 0 {return -1}case timerModifiedEarlier, timerModifiedLater:if !.status.CompareAndSwap(, timerMoving) {continue}.when = .nextwhendodeltimer0()doaddtimer(, )if !.status.CompareAndSwap(timerMoving, timerWaiting) {badTimer()}case timerModifying:// Wait for modification to complete.osyield()case timerNoStatus, timerRemoved:// Should not see a new or inactive timer on the heap.badTimer()case timerRunning, timerRemoving, timerMoving:// These should only be set when timers are locked,// and we didn't do it.badTimer()default:badTimer()}}}// runOneTimer runs a single timer.// The caller must have locked the timers for pp.// This will temporarily unlock the timers while running the timer function.////go:systemstackfunc ( *p, *timer, int64) {if raceenabled {:= getg().m.p.ptr()if .timerRaceCtx == 0 {.timerRaceCtx = racegostart(abi.FuncPCABIInternal(runtimer) + sys.PCQuantum)}raceacquirectx(.timerRaceCtx, unsafe.Pointer())}:= .f:= .arg:= .seqif .period > 0 {// Leave in heap but adjust next time to fire.:= .when -.when += .period * (1 + -/.period)if .when < 0 { // check for overflow..when = maxWhen}siftdownTimer(.timers, 0)if !.status.CompareAndSwap(timerRunning, timerWaiting) {badTimer()}updateTimer0When()} else {// Remove from heap.dodeltimer0()if !.status.CompareAndSwap(timerRunning, timerNoStatus) {badTimer()}}if raceenabled {// Temporarily use the current P's racectx for g0.:= getg()if .racectx != 0 {throw("runOneTimer: unexpected racectx")}.racectx = .m.p.ptr().timerRaceCtx}unlock(&.timersLock)(, )lock(&.timersLock)if raceenabled {:= getg().racectx = 0}}// clearDeletedTimers removes all deleted timers from the P's timer heap.// This is used to avoid clogging up the heap if the program// starts a lot of long-running timers and then stops them.// For example, this can happen via context.WithTimeout.//// This is the only function that walks through the entire timer heap,// other than moveTimers which only runs when the world is stopped.//// The caller must have locked the timers for pp.func ( *p) {// We are going to clear all timerModifiedEarlier timers.// Do this now in case new ones show up while we are looping..timerModifiedEarliest.Store(0):= int32(0):= 0:= false:= .timers:for , := range {for {switch := .status.Load(); {case timerWaiting:if {[] =siftupTimer(, )}++continuecase timerModifiedEarlier, timerModifiedLater:if .status.CompareAndSwap(, timerMoving) {.when = .nextwhen[] =siftupTimer(, )++= trueif !.status.CompareAndSwap(timerMoving, timerWaiting) {badTimer()}continue}case timerDeleted:if .status.CompareAndSwap(, timerRemoving) {.pp = 0++if !.status.CompareAndSwap(timerRemoving, timerRemoved) {badTimer()}= truecontinue}case timerModifying:// Loop until modification complete.osyield()case timerNoStatus, timerRemoved:// We should not see these status values in a timer heap.badTimer()case timerRunning, timerRemoving, timerMoving:// Some other P thinks it owns this timer,// which should not happen.badTimer()default:badTimer()}}}// Set remaining slots in timers slice to nil,// so that the timer values can be garbage collected.for := ; < len(); ++ {[] = nil}.deletedTimers.Add(-).numTimers.Add(-)= [:].timers =updateTimer0When()if verifyTimers {verifyTimerHeap()}}// verifyTimerHeap verifies that the timer heap is in a valid state.// This is only for debugging, and is only called if verifyTimers is true.// The caller must have locked the timers.func ( *p) {for , := range .timers {if == 0 {// First timer has no parent.continue}// The heap is 4-ary. See siftupTimer and siftdownTimer.:= ( - 1) / 4if .when < .timers[].when {print("bad timer heap at ", , ": ", , ": ", .timers[].when, ", ", , ": ", .when, "\n")throw("bad timer heap")}}if := int(.numTimers.Load()); len(.timers) != {println("timer heap len", len(.timers), "!= numTimers", )throw("bad timer heap len")}}// updateTimer0When sets the P's timer0When field.// The caller must have locked the timers for pp.func ( *p) {if len(.timers) == 0 {.timer0When.Store(0)} else {.timer0When.Store(.timers[0].when)}}// updateTimerModifiedEarliest updates the recorded nextwhen field of the// earlier timerModifiedEarier value.// The timers for pp will not be locked.func ( *p, int64) {for {:= .timerModifiedEarliest.Load()if != 0 && int64() < {return}if .timerModifiedEarliest.CompareAndSwap(, ) {return}}}// timeSleepUntil returns the time when the next timer should fire. Returns// maxWhen if there are no timers.// This is only called by sysmon and checkdead.func () int64 {:= int64(maxWhen)// Prevent allp slice changes. This is like retake.lock(&allpLock)for , := range allp {if == nil {// This can happen if procresize has grown// allp but not yet created new Ps.continue}:= .timer0When.Load()if != 0 && < {=}= .timerModifiedEarliest.Load()if != 0 && < {=}}unlock(&allpLock)return}// Heap maintenance algorithms.// These algorithms check for slice index errors manually.// Slice index error can happen if the program is using racy// access to timers. We don't want to panic here, because// it will cause the program to crash with a mysterious// "panic holding locks" message. Instead, we panic while not// holding a lock.// siftupTimer puts the timer at position i in the right place// in the heap by moving it up toward the top of the heap.// It returns the smallest changed index.func ( []*timer, int) int {if >= len() {badTimer()}:= [].whenif <= 0 {badTimer()}:= []for > 0 {:= ( - 1) / 4 // parentif >= [].when {break}[] = []=}if != [] {[] =}return}// siftdownTimer puts the timer at position i in the right place// in the heap by moving it down toward the bottom of the heap.func ( []*timer, int) {:= len()if >= {badTimer()}:= [].whenif <= 0 {badTimer()}:= []for {:= *4 + 1 // left child:= + 2 // mid childif >= {break}:= [].whenif +1 < && [+1].when < {= [+1].when++}if < {:= [].whenif +1 < && [+1].when < {= [+1].when++}if < {==}}if >= {break}[] = []=}if != [] {[] =}}// badTimer is called if the timer data structures have been corrupted,// presumably due to racy use by the program. We panic here rather than// panicking due to invalid slice access while holding locks.// See issue #25686.func () {throw("timer data corruption")}
![]() |
The pages are generated with Golds v0.6.7. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |