diff options
author | Ian Lance Taylor <iant@golang.org> | 2019-04-10 18:13:24 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2019-10-22 19:05:29 +0000 |
commit | 7416315e3358b0bc2774c92f39d8f7c4b33790ad (patch) | |
tree | ad095b2f209515d3fc3ff837212a19170e44bf04 /src/runtime/time.go | |
parent | 2e0aa581b4a2544249ad2f8e86e17204ca778ca7 (diff) | |
download | go-7416315e3358b0bc2774c92f39d8f7c4b33790ad.tar.gz go-7416315e3358b0bc2774c92f39d8f7c4b33790ad.zip |
runtime: add new deltimer function
Updates #27707
Change-Id: I720e8af9e183c75abcb63ccc30466734c8dba74f
Reviewed-on: https://go-review.googlesource.com/c/go/+/171831
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Diffstat (limited to 'src/runtime/time.go')
-rw-r--r-- | src/runtime/time.go | 57 |
1 files changed, 51 insertions, 6 deletions
diff --git a/src/runtime/time.go b/src/runtime/time.go index b4f1c0205e..f2dd40e6b4 100644 --- a/src/runtime/time.go +++ b/src/runtime/time.go @@ -8,6 +8,7 @@ package runtime import ( "internal/cpu" + "runtime/internal/atomic" "unsafe" ) @@ -120,6 +121,16 @@ type timersBucket struct { // addtimer: // timerNoStatus -> timerWaiting // anything else -> panic: invalid value +// deltimer: +// timerWaiting -> timerDeleted +// timerModifiedXX -> timerDeleted +// timerNoStatus -> do nothing +// timerDeleted -> do nothing +// timerRemoving -> do nothing +// timerRemoved -> do nothing +// timerRunning -> wait until status changes +// timerMoving -> wait until status changes +// timerModifying -> panic: concurrent deltimer/modtimer calls // Values for the timer status field. const ( @@ -216,8 +227,8 @@ func startTimer(t *timer) { addtimer(t) } -// stopTimer removes t from the timer heap if it is there. -// It returns true if t was removed, false if t wasn't even there. +// stopTimer stops a timer. +// It reports whether t was stopped before being run. //go:linkname stopTimer time.stopTimer func stopTimer(t *timer) bool { return deltimer(t) @@ -335,14 +346,48 @@ func (tb *timersBucket) addtimerLocked(t *timer) bool { return true } -// Delete timer t from the heap. -// Do not need to update the timerproc: if it wakes up early, no big deal. +// 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 deltimer(t *timer) bool { if oldTimers { return deltimerOld(t) } - throw("no deltimer not yet implemented") - return false + + for { + switch s := atomic.Load(&t.status); s { + case timerWaiting, timerModifiedLater: + if atomic.Cas(&t.status, s, timerDeleted) { + // Timer was not yet run. + return true + } + case timerModifiedEarlier: + if atomic.Cas(&t.status, s, timerModifying) { + if !atomic.Cas(&t.status, timerModifying, timerDeleted) { + badTimer() + } + // Timer was not yet run. + return true + } + case timerDeleted, timerRemoving, timerRemoved: + // Timer was already run. + return false + case 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 false + case timerModifying: + // Simultaneous calls to deltimer and modtimer. + badTimer() + default: + badTimer() + } + } } func deltimerOld(t *timer) bool { |