// A timers is a per-P set of timers.
type timers struct {
- // lock protects timers; timers are per-P, but the scheduler can
+ // mu protects timers; timers are per-P, but the scheduler can
// access the timers of another P, so we have to lock.
- lock mutex
+ mu mutex
// heap is the set of timers, ordered by t.when.
// Must hold lock to access.
minNextWhen atomic.Int64
}
+func (ts *timers) lock() {
+ lock(&ts.mu)
+}
+
+func (ts *timers) unlock() {
+ unlock(&ts.mu)
+}
+
// Timer state field.
// Note that state 0 must be "unlocked, not in heap" and usable,
// at least for time.Timer.Stop. See go.dev/issue/21874.
// temporarily not maintaining its invariant, such as during timers.adjust).
func (t *timer) updateHeap(state uint32, ts *timers) (newState uint32, updated bool) {
if ts != nil {
- assertLockHeld(&ts.lock)
+ assertLockHeld(&ts.mu)
}
if state&timerZombie != 0 {
// Take timer out of heap, applying final t.when update first.
// Callers that are not sure can call t.maybeAdd instead,
// but note that maybeAdd has different locking requirements.
func (ts *timers) addHeap(t *timer) {
- assertLockHeld(&ts.lock)
+ assertLockHeld(&ts.mu)
// Timers rely on the network poller, so make sure the poller
// has started.
if netpollInited.Load() == 0 {
// deleteMin removes timer 0 from ts.
// ts must be locked.
func (ts *timers) deleteMin() {
- assertLockHeld(&ts.lock)
+ assertLockHeld(&ts.mu)
t := ts.heap[0]
if t.ts != ts {
throw("wrong timers")
// t is not in a heap on entry to t.maybeAdd.
func (t *timer) maybeAdd() {
ts := &getg().m.p.ptr().timers
- lock(&ts.lock)
+ ts.lock()
state, mp := t.lock()
when := int64(0)
if t.needsAdd(state) {
when = t.when
}
t.unlock(state, mp)
- unlock(&ts.lock)
+ ts.unlock()
if when > 0 {
wakeNetPoller(when)
}
// slows down heap operations.
// The caller must have locked ts.
func (ts *timers) cleanHead() {
- assertLockHeld(&ts.lock)
+ assertLockHeld(&ts.mu)
gp := getg()
for {
if len(ts.heap) == 0 {
// protect against sysmon calling timeSleepUntil.
// This is the only case where we hold more than one ts.lock,
// so there are no deadlock concerns.
- lock(&src.lock)
- lock(&ts.lock)
+ src.lock()
+ ts.lock()
ts.move(src.heap)
src.heap = nil
src.len.Store(0)
src.zombies.Store(0)
src.minWhen.Store(0)
- unlock(&ts.lock)
- unlock(&src.lock)
+ ts.unlock()
+ src.unlock()
}
}
// This is currently called when the world is stopped, but the caller
// is expected to have locked ts.
func (ts *timers) move(timers []*timer) {
- assertLockHeld(&ts.lock)
+ assertLockHeld(&ts.mu)
for _, t := range timers {
state, mp := t.lock()
t.ts = nil
// it also moves timers that have been modified to run later,
// and removes deleted timers. The caller must have locked ts.
func (ts *timers) adjust(now int64, force bool) {
- assertLockHeld(&ts.lock)
+ assertLockHeld(&ts.mu)
// If we haven't yet reached the time of the earliest modified
// timer, don't do anything. This speeds up programs that adjust
// a lot of timers back and forth if the timers rarely expire.
return now, next, false
}
- lock(&ts.lock)
+ ts.lock()
if len(ts.heap) > 0 {
ts.adjust(now, force)
for len(ts.heap) > 0 {
ran = true
}
}
-
- unlock(&ts.lock)
+ ts.unlock()
return now, pollUntil, ran
}
//
//go:systemstack
func (ts *timers) run(now int64) int64 {
- assertLockHeld(&ts.lock)
+ assertLockHeld(&ts.mu)
Redo:
if len(ts.heap) == 0 {
return -1
}
ts.unlockAndRun(t, now, state, mp)
- assertLockHeld(&ts.lock) // t is unlocked now, but not ts
+ assertLockHeld(&ts.mu) // t is unlocked now, but not ts
return 0
}
//
//go:systemstack
func (ts *timers) unlockAndRun(t *timer, now int64, state uint32, mp *m) {
- assertLockHeld(&ts.lock)
+ assertLockHeld(&ts.mu)
if raceenabled {
tsLocal := &getg().m.p.ptr().timers
if tsLocal.raceCtx == 0 {
gp.racectx = gp.m.p.ptr().timers.raceCtx
}
- unlock(&ts.lock)
+ ts.unlock()
f(arg, seq)
- lock(&ts.lock)
+ ts.lock()
if raceenabled {
gp := getg()
// Looks like there are no timers, however another P
// may be adding one at this very moment.
// Take the lock to synchronize.
- lock(&pp.timers.lock)
+ pp.timers.lock()
if len(pp.timers.heap) == 0 {
timerpMask.clear(pp.id)
}
- unlock(&pp.timers.lock)
+ pp.timers.unlock()
}
// verifyTimerHeap verifies that the timers is in a valid state.
// This is only for debugging, and is only called if verifyTimers is true.
// The caller must have locked ts.
func (ts *timers) verify() {
- assertLockHeld(&ts.lock)
+ assertLockHeld(&ts.mu)
for i, t := range ts.heap {
if i == 0 {
// First timer has no parent.
// updateMinWhen sets ts.minWhen to ts.heap[0].when.
// The caller must have locked ts.
func (ts *timers) updateMinWhen() {
- assertLockHeld(&ts.lock)
+ assertLockHeld(&ts.mu)
if len(ts.heap) == 0 {
ts.minWhen.Store(0)
} else {