aboutsummaryrefslogtreecommitdiff
path: root/src/internal
diff options
context:
space:
mode:
authorDamien Neil <dneil@google.com>2024-12-10 09:49:45 -0800
committerGopher Robot <gobot@golang.org>2024-12-10 19:51:25 +0000
commit4ce116a884bd55d7046dbc999f329fa417414c00 (patch)
treecc1f863bdb4d8494dceb66549eba189f53b4ed63 /src/internal
parente6de1b2debe2bc7211f6f9cac4b64d7cd90f7c4e (diff)
downloadgo-4ce116a884bd55d7046dbc999f329fa417414c00.tar.xz
runtime: avoid panic in expired synctest timer chan read
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>
Diffstat (limited to 'src/internal')
-rw-r--r--src/internal/synctest/synctest_test.go41
1 files changed, 39 insertions, 2 deletions
diff --git a/src/internal/synctest/synctest_test.go b/src/internal/synctest/synctest_test.go
index 2c4ac0ff64..7d1e04e2ba 100644
--- a/src/internal/synctest/synctest_test.go
+++ b/src/internal/synctest/synctest_test.go
@@ -105,7 +105,7 @@ func TestMallocs(t *testing.T) {
}
}
-func TestTimer(t *testing.T) {
+func TestTimerReadBeforeDeadline(t *testing.T) {
synctest.Run(func() {
start := time.Now()
tm := time.NewTimer(5 * time.Second)
@@ -116,6 +116,41 @@ func TestTimer(t *testing.T) {
})
}
+func TestTimerReadAfterDeadline(t *testing.T) {
+ synctest.Run(func() {
+ delay := 1 * time.Second
+ want := time.Now().Add(delay)
+ tm := time.NewTimer(delay)
+ time.Sleep(2 * delay)
+ got := <-tm.C
+ if got != want {
+ t.Errorf("<-tm.C = %v, want %v", got, want)
+ }
+ })
+}
+
+func TestTimerReset(t *testing.T) {
+ synctest.Run(func() {
+ start := time.Now()
+ tm := time.NewTimer(1 * time.Second)
+ if got, want := <-tm.C, start.Add(1*time.Second); got != want {
+ t.Errorf("first sleep: <-tm.C = %v, want %v", got, want)
+ }
+
+ tm.Reset(2 * time.Second)
+ if got, want := <-tm.C, start.Add((1+2)*time.Second); got != want {
+ t.Errorf("second sleep: <-tm.C = %v, want %v", got, want)
+ }
+
+ tm.Reset(3 * time.Second)
+ time.Sleep(1 * time.Second)
+ tm.Reset(3 * time.Second)
+ if got, want := <-tm.C, start.Add((1+2+4)*time.Second); got != want {
+ t.Errorf("third sleep: <-tm.C = %v, want %v", got, want)
+ }
+ })
+}
+
func TestTimeAfter(t *testing.T) {
synctest.Run(func() {
i := 0
@@ -138,9 +173,11 @@ func TestTimeAfter(t *testing.T) {
func TestTimerFromOutsideBubble(t *testing.T) {
tm := time.NewTimer(10 * time.Millisecond)
synctest.Run(func() {
- defer wantPanic(t, "timer moved between synctest groups")
<-tm.C
})
+ if tm.Stop() {
+ t.Errorf("synctest.Run unexpectedly returned before timer fired")
+ }
}
func TestChannelFromOutsideBubble(t *testing.T) {