diff options
| author | Damien Neil <dneil@google.com> | 2024-12-10 09:49:45 -0800 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2024-12-10 19:51:25 +0000 |
| commit | 4ce116a884bd55d7046dbc999f329fa417414c00 (patch) | |
| tree | cc1f863bdb4d8494dceb66549eba189f53b4ed63 /src/internal | |
| parent | e6de1b2debe2bc7211f6f9cac4b64d7cd90f7c4e (diff) | |
| download | go-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.go | 41 |
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) { |
