diff options
| author | Michael Anthony Knyszek <mknyszek@google.com> | 2024-04-04 04:50:13 +0000 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2024-04-18 21:25:11 +0000 |
| commit | dfc86e922cd033155339c22aff64e109f6c8cc89 (patch) | |
| tree | de0ed468258f04af1eaa6b60c16a13dd4698347e /src/internal/weak/pointer_test.go | |
| parent | fa470f6245191b3c2f0b715194edf7cdf951af48 (diff) | |
| download | go-dfc86e922cd033155339c22aff64e109f6c8cc89.tar.xz | |
internal/weak: add package implementing weak pointers
This change adds the internal/weak package, which exposes GC-supported
weak pointers to the standard library. This is for the upcoming weak
package, but may be useful for other future constructs.
For #62483.
Change-Id: I4aa8fa9400110ad5ea022a43c094051699ccab9d
Reviewed-on: https://go-review.googlesource.com/c/go/+/576297
Auto-Submit: Michael Knyszek <mknyszek@google.com>
Reviewed-by: David Chase <drchase@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Diffstat (limited to 'src/internal/weak/pointer_test.go')
| -rw-r--r-- | src/internal/weak/pointer_test.go | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/src/internal/weak/pointer_test.go b/src/internal/weak/pointer_test.go new file mode 100644 index 0000000000..e143749230 --- /dev/null +++ b/src/internal/weak/pointer_test.go @@ -0,0 +1,130 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package weak_test + +import ( + "internal/weak" + "runtime" + "testing" +) + +type T struct { + // N.B. This must contain a pointer, otherwise the weak handle might get placed + // in a tiny block making the tests in this package flaky. + t *T + a int +} + +func TestPointer(t *testing.T) { + bt := new(T) + wt := weak.Make(bt) + if st := wt.Strong(); st != bt { + t.Fatalf("weak pointer is not the same as strong pointer: %p vs. %p", st, bt) + } + // bt is still referenced. + runtime.GC() + + if st := wt.Strong(); st != bt { + t.Fatalf("weak pointer is not the same as strong pointer after GC: %p vs. %p", st, bt) + } + // bt is no longer referenced. + runtime.GC() + + if st := wt.Strong(); st != nil { + t.Fatalf("expected weak pointer to be nil, got %p", st) + } +} + +func TestPointerEquality(t *testing.T) { + bt := make([]*T, 10) + wt := make([]weak.Pointer[T], 10) + for i := range bt { + bt[i] = new(T) + wt[i] = weak.Make(bt[i]) + } + for i := range bt { + st := wt[i].Strong() + if st != bt[i] { + t.Fatalf("weak pointer is not the same as strong pointer: %p vs. %p", st, bt[i]) + } + if wp := weak.Make(st); wp != wt[i] { + t.Fatalf("new weak pointer not equal to existing weak pointer: %v vs. %v", wp, wt[i]) + } + if i == 0 { + continue + } + if wt[i] == wt[i-1] { + t.Fatalf("expected weak pointers to not be equal to each other, but got %v", wt[i]) + } + } + // bt is still referenced. + runtime.GC() + for i := range bt { + st := wt[i].Strong() + if st != bt[i] { + t.Fatalf("weak pointer is not the same as strong pointer: %p vs. %p", st, bt[i]) + } + if wp := weak.Make(st); wp != wt[i] { + t.Fatalf("new weak pointer not equal to existing weak pointer: %v vs. %v", wp, wt[i]) + } + if i == 0 { + continue + } + if wt[i] == wt[i-1] { + t.Fatalf("expected weak pointers to not be equal to each other, but got %v", wt[i]) + } + } + bt = nil + // bt is no longer referenced. + runtime.GC() + for i := range bt { + st := wt[i].Strong() + if st != nil { + t.Fatalf("expected weak pointer to be nil, got %p", st) + } + if i == 0 { + continue + } + if wt[i] == wt[i-1] { + t.Fatalf("expected weak pointers to not be equal to each other, but got %v", wt[i]) + } + } +} + +func TestPointerFinalizer(t *testing.T) { + bt := new(T) + wt := weak.Make(bt) + done := make(chan struct{}, 1) + runtime.SetFinalizer(bt, func(bt *T) { + if wt.Strong() != nil { + t.Errorf("weak pointer did not go nil before finalizer ran") + } + done <- struct{}{} + }) + + // Make sure the weak pointer stays around while bt is live. + runtime.GC() + if wt.Strong() == nil { + t.Errorf("weak pointer went nil too soon") + } + runtime.KeepAlive(bt) + + // bt is no longer referenced. + // + // Run one cycle to queue the finalizer. + runtime.GC() + if wt.Strong() != nil { + t.Errorf("weak pointer did not go nil when finalizer was enqueued") + } + + // Wait for the finalizer to run. + <-done + + // The weak pointer should still be nil after the finalizer runs. + runtime.GC() + if wt.Strong() != nil { + t.Errorf("weak pointer is non-nil even after finalization: %v", wt) + } +} |
