src/runtime/time.go | 5 +++++ src/time/sleep_test.go | 16 ++++++++++++++++ diff --git a/src/runtime/time.go b/src/runtime/time.go index ec3eae9ccad4010fcd79afc8e71b46825844ab3d..de7468d1297ca45db9a63eb938c13e8d977abc15 100644 --- a/src/runtime/time.go +++ b/src/runtime/time.go @@ -254,6 +254,9 @@ t.status = timerWaiting when := t.when + // Disable preemption while using pp to avoid changing another P's heap. + mp := acquirem() + pp := getg().m.p.ptr() lock(&pp.timersLock) cleantimers(pp) @@ -261,6 +264,8 @@ doaddtimer(pp, t) unlock(&pp.timersLock) wakeNetPoller(when) + + releasem(mp) } // doaddtimer adds t to the current P's heap. diff --git a/src/time/sleep_test.go b/src/time/sleep_test.go index f5678020b9a04fea94c921846568ea8cb26ccfd1..ea253f870998f9452e3301f89d6dfbb2317bf5fc 100644 --- a/src/time/sleep_test.go +++ b/src/time/sleep_test.go @@ -501,3 +501,19 @@ defer checkZeroPanicString(t) var tr Timer tr.Stop() } + +// Test that zero duration timers aren't missed by the scheduler. Regression test for issue 44868. +func TestZeroTimer(t *testing.T) { + if testing.Short() { + t.Skip("-short") + } + + for i := 0; i < 1000000; i++ { + s := Now() + ti := NewTimer(0) + <-ti.C + if diff := Since(s); diff > 2*Second { + t.Errorf("Expected time to get value from Timer channel in less than 2 sec, took %v", diff) + } + } +}