aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/time.go
AgeCommit message (Collapse)Author
2025-06-04runtime: make bubbled timers more consistent with unbubbledDamien Neil
This CL makes two changes to reduce the predictability with which bubbled timers fire. When asynctimerchan=0 (the default), regular timers with an associated channel are only added to a timer heap when some channel operation is blocked on that channel. This allows us to garbage collect unreferenced, unstopped timers. Timers in a synctest bubble, in contrast, are always added to the bubble's timer heap. This CL changes bubbled timers with a channel to be handled the same as unbubbled ones, adding them to the bubble's timer heap only when some channel operation is blocked on the timer's channel. This permits unstopped bubbled timers to be garbage collected, but more importantly it makes all timers past their deadline behave identically, regardless of whether they are in a bubble. This CL also changes timer scheduling to execute bubbled timers immediately when possible rather than adding them to a heap. Timers in a bubble's heap are executed when the bubble is idle. Executing timers immediately avoids creating a predictable order of execution. For #73850 Fixes #73934 Change-Id: If82e441546408f780f6af6fb7f6e416d3160295d Reviewed-on: https://go-review.googlesource.com/c/go/+/678075 Auto-Submit: Damien Neil <dneil@google.com> Reviewed-by: Michael Pratt <mpratt@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-06-02runtime: randomize order of timers at the same instant in bubblesDamien Neil
In synctest bubbles, fire timers scheduled for the same instant in a randomized order. Pending timers are added to a heap ordered by the timer's wakeup time. Add a per-timer random value, set when the timer is added to a heap, to break ties between timers scheduled for the same instant. Only inject this randomness in synctest bubbles. We could do so for all timers at the cost of one cheaprand call per timer, but given that it's effectively impossible to create two timers scheduled for the same instant outside of a fake-time environment, don't bother. Fixes #73876 For #73850 Change-Id: Ie96c86a816f548d4c31e4e014bf9293639155bd4 Reviewed-on: https://go-review.googlesource.com/c/go/+/677276 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Damien Neil <dneil@google.com> Reviewed-by: Michael Pratt <mpratt@google.com>
2025-05-07runtime: use "bubble" terminology for synctestDamien Neil
We've settled on calling the group of goroutines started by synctest.Run a "bubble". At the time the runtime implementation was written, I was still calling this a "group". Update the code to match the current terminology. Change-Id: I31b757f31d804b5d5f9564c182627030a9532f4a Reviewed-on: https://go-review.googlesource.com/c/go/+/670135 Reviewed-by: Michael Pratt <mpratt@google.com> Auto-Submit: Damien Neil <dneil@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-03-21runtime: fix interactions between synctest, race detector, and timersDamien Neil
When an AfterFunc executes in a synctest bubble, there is a series of happens-before relationships: 1. The AfterFunc is created. 2. The AfterFunc goroutine executes. 3. The AfterFunc goroutine returns. 4. A subsequent synctest.Wait call returns. We were failing to correctly establish the happens-before relationship between the AfterFunc goroutine and the AfterFunc itself being created. When an AfterFunc executes, the G running the timer temporarily switches to the timer heap's racectx. It then calls time.goFunc, which starts a new goroutine to execute the timer. time.goFunc relies on the new goroutine inheriting the racectx of the G running the timer. Normal, non-synctest timers, execute with m.curg == nil, which causes new goroutines to inherit the g0 racectx. We were running synctest timers with m.curg set (to the G executing synctest.Run), so the new AfterFunc goroutine was created using m.curg's racectx. This resulted in us not properly establishing the happens-before relationship between AfterFunc being called and the AfterFunc goroutine starting. Fix this by setting m.curg to nil while executing timers. As one additional fix, when waking a blocked bubble, wake the root goroutine rather than a goroutine blocked in Wait if there is a timer that can fire. Fixes #72750 Change-Id: I2b2d6b0f17f64649409adc93c2603f720494af89 Reviewed-on: https://go-review.googlesource.com/c/go/+/658595 Auto-Submit: Damien Neil <dneil@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Pratt <mpratt@google.com>
2025-03-18runtime, time: don't use monotonic clock inside synctest bubblesDamien Neil
Don't include a monotonic time in time.Times created inside a bubble, to avoid the confusion of different Times using different monotonic clock epochs. For #67434 goos: darwin goarch: arm64 pkg: time cpu: Apple M1 Pro │ /tmp/bench.0 │ /tmp/bench.1 │ │ sec/op │ sec/op vs base │ Since-10 18.42n ± 2% 18.68n ± 1% ~ (p=0.101 n=10) Until-10 18.28n ± 2% 18.46n ± 2% +0.98% (p=0.009 n=10) geomean 18.35n 18.57n +1.20% Change-Id: Iaf1b80d0a4df52139c5b80d4bde4410ef8a49f2f Reviewed-on: https://go-review.googlesource.com/c/go/+/657415 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Damien Neil <dneil@google.com> Reviewed-by: Michael Pratt <mpratt@google.com>
2024-12-10runtime: avoid panic in expired synctest timer chan readDamien Neil
When reading from time.Timer.C for an expired timer using a fake clock (in a synctest bubble), the timer will not be in a heap. Avoid a spurious panic claiming the timer moved between synctest bubbles. Drop the panic when a bubbled goroutine reads from a non-bubbled timer channel: We allow bubbled goroutines to access non-bubbled channels in general. Fixes #70741 Change-Id: I27005e46f4d0067cc6846d234d22766d2e05d163 Reviewed-on: https://go-review.googlesource.com/c/go/+/634955 Auto-Submit: Damien Neil <dneil@google.com> Reviewed-by: Michael Pratt <mpratt@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-11-19internal/synctest: new package for testing concurrent codeDamien Neil
Add an internal (for now) implementation of testing/synctest. The synctest.Run function executes a tree of goroutines in an isolated environment using a fake clock. The synctest.Wait function allows a test to wait for all other goroutines within the test to reach a blocking point. For #67434 For #69687 Change-Id: Icb39e54c54cece96517e58ef9cfb18bf68506cfc Reviewed-on: https://go-review.googlesource.com/c/go/+/591997 Reviewed-by: Michael Pratt <mpratt@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-10-21runtime,time: use atomic.Int32 for isSendingMichael Anthony Knyszek
This change switches isSending to be an atomic.Int32 instead of an atomic.Uint8. The Int32 version is managed as a counter, which is something that we couldn't do with Uint8 without adding a new intrinsic which may not be available on all architectures. That is, instead of only being able to support 8 concurrent timer firings on the same timer because we only have 8 independent bits to set for each concurrent timer firing, we can now have 2^31-1 concurrent timer firings before running into any issues. Like the fact that each bit-set was matched with a clear, here we match increments with decrements to indicate that we're in the "sending on a channel" critical section in the timer code, so we can report the correct result back on Stop or Reset. We choose an Int32 instead of a Uint32 because it's easier to check for obviously bad values (negative values are always bad) and 2^31-1 concurrent timer firings should be enough for anyone. Previously, we avoided anything bigger than a Uint8 because we could pack it into some padding in the runtime.timer struct. But it turns out that the type that actually matters, runtime.timeTimer, is exactly 96 bytes in size. This means its in the next size class up in the 112 byte size class because of an allocation header. We thus have some free space to work with. This change increases the size of this struct from 96 bytes to 104 bytes. (I'm not sure if runtime.timer is often allocated directly, but if it is, we get lucky in the same way too. It's exactly 80 bytes in size, which means its in the 96-byte size class, leaving us with some space to work with.) Fixes #69969. Related to #69880 and #69312. Change-Id: I9fd59cb6a69365c62971d1f225490a65c58f3e77 Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest Reviewed-on: https://go-review.googlesource.com/c/go/+/621616 Reviewed-by: Ian Lance Taylor <iant@google.com> Auto-Submit: Michael Knyszek <mknyszek@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-10-14runtime: don't frob isSending for tickersIan Lance Taylor
The Ticker Stop and Reset methods don't report a value, so we don't need to track whether they are interrupting a send. This includes a test that used to fail about 2% of the time on my laptop when run under x/tools/cmd/stress. Change-Id: Ic6d14b344594149dd3c24b37bbe4e42e83f9a9ad Reviewed-on: https://go-review.googlesource.com/c/go/+/620136 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Ian Lance Taylor <iant@google.com> Auto-Submit: Michael Knyszek <mknyszek@google.com> Auto-Submit: Ian Lance Taylor <iant@google.com> Reviewed-by: Michael Knyszek <mknyszek@google.com>
2024-10-02runtime: clear isSending bit earlierIan Lance Taylor
I've done some more testing of the new isSending field. I'm not able to get more than 2 bits set. That said, with this change it's significantly less likely to have even 2 bits set. The idea here is to clear the bit before possibly locking the channel we are sending the value on, thus avoiding some delay and some serialization. For #69312 Change-Id: I8b5f167f162bbcbcbf7ea47305967f349b62b0f4 Reviewed-on: https://go-review.googlesource.com/c/go/+/617497 Reviewed-by: Ian Lance Taylor <iant@google.com> Reviewed-by: Michael Knyszek <mknyszek@google.com> Commit-Queue: Ian Lance Taylor <iant@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Ian Lance Taylor <iant@google.com>
2024-09-26runtime: if stop/reset races with running timer, return correct resultIan Lance Taylor
The timer code is careful to ensure that if stop/reset is called while a timer is being run, we cancel the run. However, the code failed to ensure that in that case stop/reset returned true, meaning that the timer had been stopped. In the racing case stop/reset could see that t.when had been set to zero, and return false, even though the timer had not and never would fire. Fix this by tracking whether a timer run is in progress, and using that to reliably detect that the run was cancelled, meaning that stop/reset should return true. Fixes #69312 Change-Id: I78e870063eb96650638f12c056e32c931417c84a Reviewed-on: https://go-review.googlesource.com/c/go/+/611496 Reviewed-by: David Chase <drchase@google.com> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> Reviewed-by: Michael Knyszek <mknyszek@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Ian Lance Taylor <iant@golang.org>
2024-08-02time: fix some typos in CL 512355Jes Cok
Change-Id: Id0fb180a2d7910cdff7f4ab7154d9ceeb2f1cb71 GitHub-Last-Rev: 03658dd9747684f69ea238a8d1d7f7d15446099e GitHub-Pull-Request: golang/go#68709 Reviewed-on: https://go-review.googlesource.com/c/go/+/602675 Reviewed-by: Ian Lance Taylor <iant@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Knyszek <mknyszek@google.com> Auto-Submit: Ian Lance Taylor <iant@google.com>
2024-07-23runtime,internal: move runtime/internal/sys to internal/runtime/sysDavid Chase
Cleanup and friction reduction For #65355. Change-Id: Ia14c9dc584a529a35b97801dd3e95b9acc99a511 Reviewed-on: https://go-review.googlesource.com/c/go/+/600436 Reviewed-by: Keith Randall <khr@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Keith Randall <khr@golang.org>
2024-03-29runtime: simplify timers.siftDownRuss Cox
No effect on benchmarks, but the code is clearer. goos: linux goarch: amd64 pkg: time cpu: AMD Ryzen 9 7950X 16-Core Processor │ s7base.txt │ s7.txt │ │ sec/op │ sec/op vs base │ AdjustTimers10000-32 195.9µ ± 13% 198.1µ ± 2% ~ (p=0.436 n=10) AdjustTimers10000SingleThread-32 1.573m ± 13% 1.566m ± 10% ~ (p=0.739 n=10) AdjustTimers10000NoReset-32 170.6µ ± 1% 170.4µ ± 1% ~ (p=0.912 n=10) AdjustTimers10000NoSleep-32 183.9µ ± 2% 181.4µ ± 2% -1.39% (p=0.045 n=10) AdjustTimers10000NoResetNoSleep-32 151.3µ ± 1% 150.0µ ± 1% -0.90% (p=0.007 n=10) goos: darwin goarch: arm64 pkg: time cpu: Apple M3 Pro │ m3base.txt │ m3.txt │ │ sec/op │ sec/op vs base │ AdjustTimers10000-12 234.2µ ± 1% 234.5µ ± 1% ~ (p=0.796 n=10) AdjustTimers10000SingleThread-12 1.191m ± 1% 1.272m ± 1% +6.81% (p=0.000 n=10) AdjustTimers10000NoReset-12 239.6µ ± 2% 236.3µ ± 9% ~ (p=0.971 n=10) AdjustTimers10000NoSleep-12 223.3µ ± 2% 221.4µ ± 3% ~ (p=0.579 n=10) AdjustTimers10000NoResetNoSleep-12 209.2µ ± 2% 209.0µ ± 4% ~ (p=0.796 n=10) Change-Id: Id48aa893235d652814b7fa4605037f09b0b4d73b Reviewed-on: https://go-review.googlesource.com/c/go/+/574897 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Ian Lance Taylor <iant@google.com>
2024-03-29runtime: move whenHeap into heap sliceRuss Cox
This CL changes the timer heap from a slice of timers to a slice of {timer, when} pairs, moving timer.whenHeap into the heap backing store itself. This makes the ownership clearer (t.whenHeap was always protected by the heap lock, not the timer's lock) and also avoids an indirection when doing heap operations, which look at the when field quite a lot. goos: linux goarch: amd64 pkg: time cpu: AMD Ryzen 9 7950X 16-Core Processor │ s7base.txt │ s7.txt │ │ sec/op │ sec/op vs base │ AdjustTimers10000-32 244.1µ ± 5% 195.9µ ± 13% -19.76% (p=0.001 n=10) AdjustTimers10000SingleThread-32 1.674m ± 6% 1.573m ± 13% -6.03% (p=0.001 n=10) AdjustTimers10000NoReset-32 194.0µ ± 2% 170.6µ ± 1% -12.06% (p=0.000 n=10) AdjustTimers10000NoSleep-32 223.0µ ± 7% 183.9µ ± 2% -17.54% (p=0.000 n=10) AdjustTimers10000NoResetNoSleep-32 181.1µ ± 1% 151.3µ ± 1% -16.45% (p=0.000 n=10) goos: darwin goarch: arm64 pkg: time cpu: Apple M3 Pro │ m3base.txt │ m3.txt │ │ sec/op │ sec/op vs base │ AdjustTimers10000-12 266.6µ ± 2% 234.2µ ± 1% -12.16% (p=0.000 n=10) AdjustTimers10000SingleThread-12 1.194m ± 0% 1.191m ± 1% -0.33% (p=0.029 n=10) AdjustTimers10000NoReset-12 260.9µ ± 2% 239.6µ ± 2% -8.15% (p=0.000 n=10) AdjustTimers10000NoSleep-12 247.8µ ± 2% 223.3µ ± 2% -9.90% (p=0.000 n=10) AdjustTimers10000NoResetNoSleep-12 231.7µ ± 2% 209.2µ ± 2% -9.68% (p=0.000 n=10) Change-Id: I546f077068476d7a7b855889419b292525fb2bc5 Reviewed-on: https://go-review.googlesource.com/c/go/+/574896 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Ian Lance Taylor <iant@google.com>
2024-03-28runtime: fix timer race introduced in CL 573455Russ Cox
There is a short window when timers.adjust could miss a timer update. Close that window. Does not change benchmark. goos: linux goarch: amd64 pkg: time cpu: AMD Ryzen 9 7950X 16-Core Processor │ s7base.txt │ s7.txt │ │ sec/op │ sec/op vs base │ AdjustTimers10000-32 239.9µ ± 5% 237.6µ ± 8% ~ (p=0.631 n=10) AdjustTimers10000SingleThread-32 1.686m ± 8% 1.710m ± 5% ~ (p=0.481 n=10) AdjustTimers10000NoReset-32 194.1µ ± 1% 190.8µ ± 2% -1.69% (p=0.023 n=10) AdjustTimers10000NoSleep-32 226.2µ ± 3% 222.9µ ± 3% ~ (p=0.143 n=10) AdjustTimers10000NoResetNoSleep-32 182.9µ ± 1% 180.9µ ± 2% ~ (p=0.165 n=10) goos: darwin goarch: arm64 pkg: time cpu: Apple M3 Pro │ m3base.txt │ m3.txt │ │ sec/op │ sec/op vs base │ AdjustTimers10000-12 269.3µ ± 2% 267.0µ ± 2% ~ (p=0.529 n=10) AdjustTimers10000SingleThread-12 1.176m ± 1% 1.213m ± 1% +3.15% (p=0.000 n=10) AdjustTimers10000NoReset-12 262.6µ ± 2% 261.4µ ± 3% ~ (p=0.123 n=10) AdjustTimers10000NoSleep-12 247.8µ ± 1% 246.5µ ± 1% ~ (p=0.393 n=10) AdjustTimers10000NoResetNoSleep-12 231.0µ ± 1% 232.3µ ± 1% ~ (p=0.684 n=10) Change-Id: Ifdfcdd5a25046027912a8b306644bde7ec2d3214 Reviewed-on: https://go-review.googlesource.com/c/go/+/574741 Auto-Submit: Russ Cox <rsc@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Ian Lance Taylor <iant@google.com>
2024-03-28runtime: adjust when timers.adjust is calledRuss Cox
This new logic more closely mimics what we did before my CL stack. I had reasoned that certainly ts.adjust(now, force=true) ts.run(now) would be faster than ts.adjust(now, force=false) ts.run(now) ts.adjust(now, force=true) But certainty is just an emotion, and that turns out not to be the case. I don't really understand why the second sequence is faster, but it definitely is, so put it back. goos: linux goarch: amd64 pkg: time cpu: AMD Ryzen 9 7950X 16-Core Processor │ s7base.txt │ s7.txt │ │ sec/op │ sec/op vs base │ AdjustTimers10000-32 263.3µ ± 4% 239.9µ ± 5% -8.87% (p=0.000 n=10) AdjustTimers10000SingleThread-32 1.742m ± 3% 1.686m ± 8% ~ (p=0.105 n=10) AdjustTimers10000NoReset-32 192.2µ ± 2% 194.1µ ± 1% +1.00% (p=0.009 n=10) AdjustTimers10000NoSleep-32 237.0µ ± 2% 226.2µ ± 3% -4.55% (p=0.001 n=10) AdjustTimers10000NoResetNoSleep-32 185.2µ ± 1% 182.9µ ± 1% -1.23% (p=0.003 n=10) goos: darwin goarch: arm64 pkg: time cpu: Apple M3 Pro │ m3base.txt │ m3.txt │ │ sec/op │ sec/op vs base │ AdjustTimers10000-12 272.6µ ± 3% 269.3µ ± 2% ~ (p=0.063 n=10) AdjustTimers10000SingleThread-12 1.126m ± 1% 1.176m ± 1% +4.42% (p=0.000 n=10) AdjustTimers10000NoReset-12 255.1µ ± 2% 262.6µ ± 2% +2.96% (p=0.000 n=10) AdjustTimers10000NoSleep-12 250.2µ ± 2% 247.8µ ± 1% ~ (p=0.063 n=10) AdjustTimers10000NoResetNoSleep-12 230.3µ ± 1% 231.0µ ± 1% ~ (p=0.280 n=10) Change-Id: I67b5765f97dfca0142ee38e15a9904b520f51e83 Reviewed-on: https://go-review.googlesource.com/c/go/+/574740 Auto-Submit: Russ Cox <rsc@golang.org> Reviewed-by: Ian Lance Taylor <iant@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-03-28runtime: optimize timers.cleanHeadRuss Cox
goos: linux goarch: amd64 pkg: time cpu: AMD Ryzen 9 7950X 16-Core Processor │ s7base.txt │ s7.txt │ │ sec/op │ sec/op vs base │ AdjustTimers10000-32 291.4µ ± 5% 263.3µ ± 4% -9.64% (p=0.000 n=10) AdjustTimers10000SingleThread-32 1.728m ± 5% 1.742m ± 3% ~ (p=0.796 n=10) AdjustTimers10000NoReset-32 253.1µ ± 6% 192.2µ ± 2% -24.07% (p=0.000 n=10) AdjustTimers10000NoSleep-32 277.3µ ± 3% 237.0µ ± 2% -14.54% (p=0.000 n=10) AdjustTimers10000NoResetNoSleep-32 241.4µ ± 2% 185.2µ ± 1% -23.30% (p=0.000 n=10) goos: darwin goarch: arm64 pkg: time cpu: Apple M3 Pro │ m3base.txt │ m3.txt │ │ sec/op │ sec/op vs base │ AdjustTimers10000-12 288.1µ ± 1% 272.6µ ± 3% -5.38% (p=0.000 n=10) AdjustTimers10000SingleThread-12 1.195m ± 1% 1.126m ± 1% -5.74% (p=0.000 n=10) AdjustTimers10000NoReset-12 280.8µ ± 1% 255.1µ ± 2% -9.14% (p=0.000 n=10) AdjustTimers10000NoSleep-12 292.5µ ± 1% 250.2µ ± 2% -14.47% (p=0.000 n=10) AdjustTimers10000NoResetNoSleep-12 279.8µ ± 2% 230.3µ ± 1% -17.69% (p=0.000 n=10) Change-Id: I36edb40ee2cd11ab44d20bff045fa77609dca648 Reviewed-on: https://go-review.googlesource.com/c/go/+/574739 Reviewed-by: Ian Lance Taylor <iant@google.com> Auto-Submit: Russ Cox <rsc@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-03-28runtime: avoid unnecessary netpoll wakeups during timer creationRuss Cox
goos: linux goarch: amd64 pkg: time cpu: AMD Ryzen 9 7950X 16-Core Processor │ s7base.txt │ s7.txt │ │ sec/op │ sec/op vs base │ AdjustTimers10000-32 315.1µ ± 4% 291.4µ ± 5% -7.52% (p=0.001 n=10) AdjustTimers10000SingleThread-32 1.728m ± 6% 1.728m ± 5% ~ (p=0.971 n=10) AdjustTimers10000NoReset-32 263.0µ ± 3% 253.1µ ± 6% -3.75% (p=0.023 n=10) AdjustTimers10000NoSleep-32 306.8µ ± 5% 277.3µ ± 3% -9.62% (p=0.000 n=10) AdjustTimers10000NoResetNoSleep-32 245.3µ ± 3% 241.4µ ± 2% ~ (p=0.529 n=10) goos: darwin goarch: arm64 pkg: time cpu: Apple M3 Pro │ m3base.txt │ m3.txt │ │ sec/op │ sec/op vs base │ AdjustTimers10000-12 385.5µ ± 3% 288.1µ ± 1% -25.26% (p=0.000 n=10) AdjustTimers10000SingleThread-12 1.213m ± 1% 1.195m ± 1% -1.45% (p=0.001 n=10) AdjustTimers10000NoReset-12 346.4µ ± 5% 280.8µ ± 1% -18.94% (p=0.000 n=10) AdjustTimers10000NoSleep-12 362.6µ ± 1% 292.5µ ± 1% -19.33% (p=0.000 n=10) AdjustTimers10000NoResetNoSleep-12 317.3µ ± 8% 279.8µ ± 2% -11.79% (p=0.000 n=10) Change-Id: Id3e10abfb1024f8e7883c8c366d941e4f1c2a894 Reviewed-on: https://go-review.googlesource.com/c/go/+/574738 Reviewed-by: Ian Lance Taylor <iant@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Russ Cox <rsc@golang.org>
2024-03-25runtime: migrate internal/atomic to internal/runtimeAndy Pan
For #65355 Change-Id: I65dd090fb99de9b231af2112c5ccb0eb635db2be Reviewed-on: https://go-review.googlesource.com/c/go/+/560155 Reviewed-by: David Chase <drchase@google.com> Reviewed-by: Michael Pratt <mpratt@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Ibrahim Bazoka <ibrahimbazoka729@gmail.com> Auto-Submit: Emmanuel Odeke <emmanuel@orijtech.com>
2024-03-22runtime: add fast path for (*timers).adjustIan Lance Taylor
Affected benchmark results, including new benchmark (some of these may just be noise, of course): AdjustTimers10000-12 797.7µ ± 2% 709.6µ ± 2% -11.04% (p=0.000 n=10) TickerResetNaive-12 62.69n ± 1% 63.56n ± 1% +1.40% (p=0.018 n=10) NowUnixMicro-12 29.95n ± 1% 30.25n ± 4% +1.00% (p=0.024 n=10) ParseDuration-12 81.88n ± 0% 81.45n ± 0% -0.51% (p=0.006 n=10) UnmarshalText-12 186.9n ± 1% 185.2n ± 1% -0.88% (p=0.006 n=10) geomean 151.8n 151.2n -0.40% Change-Id: I3ef8356249c5d703b314498e34ee8095093671c8 Reviewed-on: https://go-review.googlesource.com/c/go/+/573455 Reviewed-by: Austin Clements <austin@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Ian Lance Taylor <iant@google.com> Reviewed-by: Ian Lance Taylor <iant@google.com> Commit-Queue: Ian Lance Taylor <iant@google.com>
2024-03-14time: avoid stale receives after Timer/Ticker Stop/Reset returnRuss Cox
A proposal discussion in mid-2020 on #37196 decided to change time.Timer and time.Ticker so that their Stop and Reset methods guarantee that no old value (corresponding to the previous configuration of the Timer or Ticker) will be received after the method returns. The trivial way to do this is to make the Timer/Ticker channels unbuffered, create a goroutine per Timer/Ticker feeding the channel, and then coordinate with that goroutine during Stop/Reset. Since Stop/Reset coordinate with the goroutine and the channel is unbuffered, there is no possibility of a stale value being sent after Stop/Reset returns. Of course, we do not want an extra goroutine per Timer/Ticker, but that's still a good semantic model: behave like the channels are unbuffered and fed by a coordinating goroutine. The actual implementation is more effort but behaves like the model. Specifically, the timer channel has a 1-element buffer like it always has, but len(t.C) and cap(t.C) are special-cased to return 0 anyway, so user code cannot see what's in the buffer except with a receive. Stop/Reset lock out any stale sends and then clear any pending send from the buffer. Some programs will change behavior. For example: package main import "time" func main() { t := time.NewTimer(2 * time.Second) time.Sleep(3 * time.Second) if t.Reset(2*time.Second) != false { panic("expected timer to have fired") } <-t.C <-t.C } This program (from #11513) sleeps 3s after setting a 2s timer, resets the timer, and expects Reset to return false: the Reset is too late and the send has already occurred. It then expects to receive two values: the one from before the Reset, and the one from after the Reset. With an unbuffered timer channel, it should be clear that no value can be sent during the time.Sleep, so the time.Reset returns true, indicating that the Reset stopped the timer from going off. Then there is only one value to receive from t.C: the one from after the Reset. In 2015, I used the above example as an argument against this change. Note that a correct version of the program would be: func main() { t := time.NewTimer(2 * time.Second) time.Sleep(3 * time.Second) if !t.Reset(2*time.Second) { <-t.C } <-t.C } This works with either semantics, by heeding t.Reset's result. The change should not affect correct programs. However, one way that the change would be visible is when programs use len(t.C) (instead of a non-blocking receive) to poll whether the timer has triggered already. We might legitimately worry about breaking such programs. In 2020, discussing #37196, Bryan Mills and I surveyed programs using len on timer channels. These are exceedingly rare to start with; nearly all the uses are buggy; and all the buggy programs would be fixed by the new semantics. The details are at [1]. To further reduce the impact of this change, this CL adds a temporary GODEBUG setting, which we didn't know about yet in 2015 and 2020. Specifically, asynctimerchan=1 disables the change and is the default for main programs in modules that use a Go version before 1.23. We hope to be able to retire this setting after the minimum 2-year window. Setting asynctimerchan=1 also disables the garbage collection change from CL 568341, although users shouldn't need to know that since it is not a semantically visible change (unless we have bugs!). As an undocumented bonus that we do not officially support, asynctimerchan=2 disables the channel buffer change but keeps the garbage collection change. This may help while we are shaking out bugs in either of them. Fixes #37196. [1] https://github.com/golang/go/issues/37196#issuecomment-641698749 Change-Id: I8925d3fb2b86b2ae87fd2acd055011cbf7bd5916 Reviewed-on: https://go-review.googlesource.com/c/go/+/568341 Reviewed-by: Austin Clements <austin@google.com> Auto-Submit: Russ Cox <rsc@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-03-14runtime: fix lost sleep causing TestZeroTimer flakesRuss Cox
Classic operating system kernel mistake: if you start using per-CPU data without disabling interrupts on the CPU, and then an interrupt reschedules the process onto a different CPU, now you're using the wrong CPU's per-CPU data. The same thing happens in Go if you use per-M or per-P data structures while not holding a lock nor using acquirem. In the original timer.modify before CL 564977, I had been very careful about this during the "unlock t; lock ts" dance, only calling releasem after ts was locked. That made sure we used the right ts. The refactoring of that code into its own helper function in CL 564977 missed that nuance. The code ts := &getg().m.p.p.ptr().timers ts.lock() was now executing without holding any locks nor acquirem. If the goroutine changed its M or P between deciding which ts to use and actually locking that ts, the code would proceed to add the timer t to some other P's timers. If the P was idle by then, the scheduler could have already checked it for timers and not notice the newly added timer when deciding when the next timer should trigger. The solution is to do what the old code correctly did, namely acquirem before deciding which ts to use, rather than assume getg().m.p won't change before ts.lock can complete. This CL does that. Before CL 564977, stress ./time.test -test.run='ZeroTimer/impl=(func|cache)' -test.timeout=3m -test.count=20 ran without failure for over an hour on my laptop. Starting in CL 564977, it consistently failed within a few minutes. After this CL, it now runs without failure for over an hour again. Fixes #66006. Change-Id: Ib9e7ccaa0f22a326ce3fdef2b9a92f7f0bdafcbf Reviewed-on: https://go-review.googlesource.com/c/go/+/571196 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Russ Cox <rsc@golang.org> Reviewed-by: Ian Lance Taylor <iant@google.com>
2024-03-13time: garbage collect unstopped Tickers and TimersRuss Cox
From the beginning of Go, the time package has had a gotcha: if you use a select on <-time.After(1*time.Minute), even if the select finishes immediately because some other case is ready, the underlying timer from time.After keeps running until the minute is over. This pins the timer in the timer heap, which keeps it from being garbage collected and in extreme cases also slows down timer operations. The lack of garbage collection is the more important problem. The docs for After warn against this scenario and suggest using NewTimer with a call to Stop after the select instead, purely to work around this garbage collection problem. Oddly, the docs for NewTimer and NewTicker do not mention this problem, but they have the same issue: they cannot be collected until either they are Stopped or, in the case of Timer, the timer expires. (Tickers repeat, so they never expire.) People have built up a shared knowledge that timers and tickers need to defer t.Stop even though the docs do not mention this (it is somewhat implied by the After docs). This CL fixes the garbage collection problem, so that a timer that is unreferenced can be GC'ed immediately, even if it is still running. The approach is to only insert the timer into the heap when some channel operation is blocked on it; the last channel operation to stop using the timer takes it back out of the heap. When a timer's channel is no longer referenced, there are no channel operations blocked on it, so it's not in the heap, so it can be GC'ed immediately. This CL adds an undocumented GODEBUG asynctimerchan=1 that will disable the change. The documentation happens in the CL 568341. Fixes #8898. Fixes #61542. Change-Id: Ieb303b6de1fb3527d3256135151a9e983f3c27e6 Reviewed-on: https://go-review.googlesource.com/c/go/+/512355 Reviewed-by: Austin Clements <austin@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Russ Cox <rsc@golang.org>
2024-03-13runtime: add minimal debug tracing of runtime timersRuss Cox
Toggled by a compile-time const, so there should be no runtime footprint in ordinary builds. Change-Id: I7751847524f4fda3853388d3e5a18188bd737c27 Reviewed-on: https://go-review.googlesource.com/c/go/+/570336 Auto-Submit: Russ Cox <rsc@golang.org> Reviewed-by: Ian Lance Taylor <iant@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Austin Clements <austin@google.com>
2024-03-13runtime: clean up timer stateRuss Cox
The timers had evolved to the point where the state was stored as follows: if timer in heap: state has timerHeaped set if heap timer is stale: heap deadline in t.when real deadline in t.nextWhen state has timerNextWhen set else: real deadline in t.when t.nextWhen unset else: real deadline in t.when t.nextWhen unset That made it hard to find the real deadline and just hard to think about everything. The new state is: real deadline in t.when (always) if timer in heap: state has timerHeaped set heap deadline in t.whenHeap if heap timer is stale: state has timerModified set Separately, the 'state' word itself was being used as a lock and state bits because the code started with CAS loops, which we abstracted into the lock/unlock methods step by step. At this point, we can switch to a real lock, making sure to publish the one boolean needed by timers fast paths at each unlock. All this simplifies various logic considerably. Change-Id: I35766204f7a26d999206bd56cc0db60ad1b17cbe Reviewed-on: https://go-review.googlesource.com/c/go/+/570335 Auto-Submit: Russ Cox <rsc@golang.org> Reviewed-by: Austin Clements <austin@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Ian Lance Taylor <iant@google.com> Reviewed-by: Michael Pratt <mpratt@google.com>
2024-03-09time: move runtimeTimer out of Timer structRuss Cox
If user code has two timers t1 and t2 and does *t1 = *t2 (or *t1 = Timer{}), it creeps me out that we would be corrupting the runtime data structures inlined in the Timer struct. Replace that field with a pointer to the runtime data structure instead, so that the corruption cannot happen, even in a badly behaved program. In fact, remove the struct definition entirely and linkname a constructor instead. Now the runtime can evolve the struct however it likes without needing to keep package time in sync. Also move the workaround logic for #21874 out of runtime and into package time. Change-Id: Ia30f7802ee7b3a11f5d8a78dd30fd9c8633dc787 Reviewed-on: https://go-review.googlesource.com/c/go/+/568339 Reviewed-by: Ian Lance Taylor <iant@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-03-08runtime: fix spurious race using Ticker.ResetRuss Cox
Ticker.Reset was added in CL 217362 in 2020. It added the runtime helper modTimer, which is analogous to startTimer and resetTimer but for tickers. Unlike those, it does not contain a racerelease, which means that code synchronizing by starting a ticker will be diagnosed with a spurious race. Add racerelease to modTimer and add tests of all three racereleases (in startTimer, resetTimer, and modTimer). Also do not call time.resetTimer from elsewhere in runtime, since that function is only for package time. Use t.reset instead. For #33184. Change-Id: Ie40c1ad24911f21e81b1d3cc608cf086ff2bc83d Reviewed-on: https://go-review.googlesource.com/c/go/+/568340 Auto-Submit: Russ Cox <rsc@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Pratt <mpratt@google.com>
2024-03-08runtime: remove sched, allp < timers lockrank ruleRuss Cox
allp < timers has not been necessary since CL 258303. sched < timers was implied by allp < timers, and that was still necessary, but only when the world is stopped. Rewrite the code to avoid that lock since the world is stopped. Now timers and timer are independent of the scheduler, so they could call into the scheduler (for example to ready a goroutine) if we wanted them to. Change-Id: I12a93013c98e51c9e2f2148175b02afce8384a59 Reviewed-on: https://go-review.googlesource.com/c/go/+/568337 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Pratt <mpratt@google.com> Auto-Submit: Russ Cox <rsc@golang.org>
2024-03-08runtime: re-add call to ts.cleanHead (née cleantimers) during timer addRuss Cox
Before CL 564118, there were two ways to add a new timer: addtimer or modtimer. Much code was duplicated between them and it was always valid to call modtimer instead of addtimer (but not vice versa), so that CL changed all addtimer call sites to use modtimer and deleted addtimer. One thing that was unique to addtimer, however, was that it called cleantimers (now named ts.cleanHead) after locking the timers, while modtimer did not. This was the only difference in the duplicated code, and I missed it. Restore the call to ts.cleanHead when adding a new timer. Also fix double-unlock in cleanHead. Change-Id: I26cc50d650f31f977c0c31195cd013244883dba9 Reviewed-on: https://go-review.googlesource.com/c/go/+/568338 Reviewed-by: Ian Lance Taylor <iant@google.com> Auto-Submit: Russ Cox <rsc@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Pratt <mpratt@google.com>
2024-03-08runtime: avoid pp.timers.lock in updateTimerPMaskRuss Cox
The comment in updateTimerPMask is wrong. It says: // Looks like there are no timers, however another P // may be adding one at this very moment. // Take the lock to synchronize. This was my incorrect simplification of the original comment from CL 264477 when I was renaming all the things it mentioned: // Looks like there are no timers, however another P may transiently // decrement numTimers when handling a timerModified timer in // checkTimers. We must take timersLock to serialize with these changes. updateTimerPMask is being called by pidleput, so the P in question is not in use. And other P's cannot add to this P. As the original comment more precisely noted, the problem was that other P's might be calling timers.check, which updates ts.len occasionally while ts is locked, and one of those updates might "leak" an ephemeral len==0 even when the heap is not going to be empty when the P is finally unlocked. The lock/unlock in updateTimerPMask synchronizes to avoid that. But this defeats most of the purpose of using ts.len in the first place. Instead of requiring that synchronization, we can arrange that ts.len only ever shows a "publishable" length, meaning the len(ts.heap) we leave behind during ts.unlock. Having done that, updateTimerPMask can be inlined into pidleput. The big comment on updateTimerPMask explaining how timerpMask works is better placed as the doc comment for timerpMask itself, so move it there. Change-Id: I5442c9bb7f1473b5fd37c43165429d087012e73f Reviewed-on: https://go-review.googlesource.com/c/go/+/568336 Reviewed-by: Michael Pratt <mpratt@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Russ Cox <rsc@golang.org>
2024-03-08runtime: introduce timers.lock, timers.unlock methodsRuss Cox
No semantic changes here. Cleaning up for next change. Change-Id: I9706009739677ff9eb893bcc007d805f7877511e Reviewed-on: https://go-review.googlesource.com/c/go/+/568335 Reviewed-by: Austin Clements <austin@google.com> Auto-Submit: Russ Cox <rsc@golang.org> Reviewed-by: Michael Pratt <mpratt@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-03-08runtime: fix mishandling of timer zombie countRuss Cox
The timer zombie count was fundamentally racy and worked around in CL 569995. We worked around that by ignoring underflow. The fundamnental race was because t.ts was set before t was inserted into ts. CL 564997 corrected that fundamental problem, so now we can account for zombies completely accurately, never seeing values less than zero. Do that. Change-Id: Idfbccc6662af5935f29f2a06a35e8ea93929bed7 Reviewed-on: https://go-review.googlesource.com/c/go/+/569996 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Austin Clements <austin@google.com> Auto-Submit: Russ Cox <rsc@golang.org>
2024-03-08runtime: fix timers.wakeTime inaccuracy raceRuss Cox
timers.wakeTime, which is called concurrently by P's trying to decide how long they should sleep, can return inaccurate values while timers.adjust is running. (Before the refactoring, this was still true but the code did not have good names and was spread across more files, making the race harder to see.) The runtime thread sleeping code is complex enough that I am not confident that the inaccuracy can cause delayed timer wakeups, but I am also not confident that it can't, nor that it won't in the future. There are two parts to the fix: 1. A simple logic change in timers.adjust. 2. The introduction of t.maybeAdd to avoid having a t that is marked as belonging to a specific timers ts but not present in ts.heap. That was okay before when everything was racy but needs to be eliminated to make timers.adjust fully consistent. The cost of the change is an extra CAS-lock operation on a timer add (close to free since the CAS-lock was just unlocked) and a change in the static lock ranking to allow malloc while holding a timer lock. Change-Id: I1249e6e24ae9ef74a69837f453e15b513f0d75c0 Reviewed-on: https://go-review.googlesource.com/c/go/+/564977 Reviewed-by: Austin Clements <austin@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Russ Cox <rsc@golang.org>
2024-03-08runtime: update timers.len with Store instead of AddRuss Cox
Writes to timers.len are protected by the timers.lock. There is no need to use an Add instead of a Store, and the code is clearer (and perhaps slightly faster) using the Store. Change-Id: Icc6caef1b7405adec55c9b55b999b71de7d97484 Reviewed-on: https://go-review.googlesource.com/c/go/+/564976 Auto-Submit: Russ Cox <rsc@golang.org> Reviewed-by: Austin Clements <austin@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-03-08runtime: rename timers fields for clarityRuss Cox
These names were copied over from the p field names, but now that they are part of the timers type they can use shorter names that make the relationship clearer. timer0When -> minWhen timerModifiedEarliest -> minNextWhen This code change is only the renaming. Change-Id: I1c0adc0b3a1289d35639619d5c945585b2d81a9f Reviewed-on: https://go-review.googlesource.com/c/go/+/564975 Auto-Submit: Russ Cox <rsc@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Austin Clements <austin@google.com>
2024-03-08time: gracefully handle ts.zombies underflowRuss Cox
The current implementation sets t.ts before adding t to ts; that can cause inconsistencies with temporarily negative ts.zombies values. Handle them gracefully, since we only care about detecting very positive values. Pending CL 564977 removes the race that sets t.ts early, and then CL 569996 builds on top of that to make the count precise. This CL just gets examples like the new test working sooner. Change-Id: Ibe1aecc2554f83436f761f48e4050bd962982e4f Reviewed-on: https://go-review.googlesource.com/c/go/+/569995 Reviewed-by: Austin Clements <austin@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-02-29runtime: move per-P timers state into its own structRuss Cox
Continuing conversion from C to Go, introduce type timers encapsulating all timer heap state, with methods for operations. This should at least be easier to think about, instead of having these fields strewn through the P struct. It should also be easier to test. I am skeptical about the pair of atomic int64 deadlines: I think there are missed wakeups lurking. Having the code in an abstracted API should make it easier to reason through and fix if needed. [This is one CL in a refactoring stack making very small changes in each step, so that any subtle bugs that we miss can be more easily pinpointed to a small change.] Change-Id: If5ea3e0b946ca14076f44c85cbb4feb9eddb4f95 Reviewed-on: https://go-review.googlesource.com/c/go/+/564132 Reviewed-by: Austin Clements <austin@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Russ Cox <rsc@golang.org>
2024-02-28runtime: use methods for timerRuss Cox
Continuing conversion from C to Go, change timer API to use methods. [This is one CL in a refactoring stack making very small changes in each step, so that any subtle bugs that we miss can be more easily pinpointed to a small change.] Change-Id: I4cb88a366993a77aa4fad739793a7db7213cc38c Reviewed-on: https://go-review.googlesource.com/c/go/+/564131 Reviewed-by: Ian Lance Taylor <iant@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-02-28runtime: change timer.status to timer.stateRuss Cox
The status enumeration is simple enough now that we can view it as a bit set instead. Switch to a bit set, freeing up the remaining bits for use in followup work to allow garbage-collecting timers. [This is one CL in a refactoring stack making very small changes in each step, so that any subtle bugs that we miss can be more easily pinpointed to a small change.] Change-Id: I5f331fe3db1b5cb52f8571091f97f8ba029f3ac9 Reviewed-on: https://go-review.googlesource.com/c/go/+/564130 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Ian Lance Taylor <iant@google.com>
2024-02-28runtime: use timer.lock in moveTimersRuss Cox
Continue using timer.lock to simplify timer operations. [This is one CL in a refactoring stack making very small changes in each step, so that any subtle bugs that we miss can be more easily pinpointed to a small change.] Change-Id: Iaf371315308425d132217eacb20b1e120a6833c5 Reviewed-on: https://go-review.googlesource.com/c/go/+/564127 Reviewed-by: Ian Lance Taylor <iant@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-02-28runtime: use timer.lock in adjusttimersRuss Cox
Continue using timer.lock to simplify timer operations. [This is one CL in a refactoring stack making very small changes in each step, so that any subtle bugs that we miss can be more easily pinpointed to a small change.] Change-Id: I2298cede902cbf0aea268c54d741190007a733c8 Reviewed-on: https://go-review.googlesource.com/c/go/+/564128 Reviewed-by: Ian Lance Taylor <iant@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-02-28runtime: use timer.lock in runtimerRuss Cox
Continue using timer.lock to simplify timer operations. [This is one CL in a refactoring stack making very small changes in each step, so that any subtle bugs that we miss can be more easily pinpointed to a small change.] Change-Id: I504335a010d6eb4d7d627145b64a896582158406 Reviewed-on: https://go-review.googlesource.com/c/go/+/564129 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Ian Lance Taylor <iant@google.com>
2024-02-28runtime: use timer.lock in cleantimersRuss Cox
Continue using timer.lock to simplify timer operations. [This is one CL in a refactoring stack making very small changes in each step, so that any subtle bugs that we miss can be more easily pinpointed to a small change.] Change-Id: Ic12fd2630e8ac23cddd00fa7e3240a1ac19da596 Reviewed-on: https://go-review.googlesource.com/c/go/+/564126 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Ian Lance Taylor <iant@google.com>
2024-02-28runtime: use timer.lock in modtimerRuss Cox
Continue using timer.lock to simplify timer operations. Note the removal of a previous potential deadlock. (Explained at new line 325, there was a lock inversion between individual timer locks and the 'timers' lock.) [This is one CL in a refactoring stack making very small changes in each step, so that any subtle bugs that we miss can be more easily pinpointed to a small change.] Change-Id: I8c9be00d13c6acd171a8aa2882a4fc844498f754 Reviewed-on: https://go-review.googlesource.com/c/go/+/564125 Reviewed-by: Ian Lance Taylor <iant@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-02-28runtime: add timer lock to lock rankingRuss Cox
No deadlocks yet! Change-Id: I87fb3742a386d682fbcc8cb98e98771b54bc3fec Reviewed-on: https://go-review.googlesource.com/c/go/+/564133 Reviewed-by: Austin Clements <austin@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-02-28runtime: use timer.lock in deltimerRuss Cox
The state set is now simplified enough that all the CAS loops are starting to look the same: they are just spin locks. So introduce an actual timer.lock method and use it in deltimer. [This is one CL in a refactoring stack making very small changes in each step, so that any subtle bugs that we miss can be more easily pinpointed to a small change.] Change-Id: Ifd7f20eeede5c764ef10ecba64855c29a5ddbe39 Reviewed-on: https://go-review.googlesource.com/c/go/+/564124 Reviewed-by: Ian Lance Taylor <iant@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-02-28runtime: merge timerDeleted into timerModifiedRuss Cox
When we make a change to a timer, we have to note the desired change to t.when and then wait for the timer heap owner to apply the change. There are two possible changes: delete or set a new t.when. Most of the code for processing these changes is the same, so we can simplify the code by making both have the same state: timerDeleted is now timerModified with t.nextwhen == 0. This is part of a larger simplification of the state set. [This is one CL in a refactoring stack making very small changes in each step, so that any subtle bugs that we miss can be more easily pinpointed to a small change.] Change-Id: I1a2a12f8250bcd40f7b08b83f22c3a82b124eda6 Reviewed-on: https://go-review.googlesource.com/c/go/+/564123 Reviewed-by: Ian Lance Taylor <iant@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-02-28runtime: merge timerNoStatus into timerRemovedRuss Cox
For historical reasons, we have to treat a zero timer as the same as an initialized timer that was stopped (removed). The two states are already treated mostly identically. Merge them. This is part of a larger simplification of the state set. [This is one CL in a refactoring stack making very small changes in each step, so that any subtle bugs that we miss can be more easily pinpointed to a small change.] Change-Id: I9c3aeb8f92bafb18c47489c1ec20a7b87ac5cd9c Reviewed-on: https://go-review.googlesource.com/c/go/+/564122 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Ian Lance Taylor <iant@google.com>
2024-02-28runtime: merge timerMoving into timerModifyingRuss Cox
timerMoving is just a kind of "locked for modification", so merge it into timerModifying. This is part of a larger simplification of the state set. [This is one CL in a refactoring stack making very small changes in each step, so that any subtle bugs that we miss can be more easily pinpointed to a small change.] Change-Id: I5379122f96d9921ecda7a6a37cabd6c6b4d529a4 Reviewed-on: https://go-review.googlesource.com/c/go/+/564121 Reviewed-by: Ian Lance Taylor <iant@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>