diff options
| author | Michael Anthony Knyszek <mknyszek@google.com> | 2024-11-15 20:42:32 +0000 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2024-11-18 22:29:23 +0000 |
| commit | a65f1a467ff6a10dc6688f292dfa8a2e08cc1eb4 (patch) | |
| tree | 4ca29ec30c468aa3a7c2fe3ffd63a9e8d18f4389 /src/internal/weak/pointer_test.go | |
| parent | 5e82cba9bdf45d81da549477d172f6b5e23106d4 (diff) | |
| download | go-a65f1a467ff6a10dc6688f292dfa8a2e08cc1eb4.tar.xz | |
weak: move internal/weak to weak, and update according to proposal
The updates are:
- API documentation changes.
- Removal of the old package documentation discouraging linkname.
- Addition of new package documentation with some advice.
- Renaming of weak.Pointer.Strong -> weak.Pointer.Value.
Fixes #67552.
Change-Id: Ifad7e629b6d339dacaf2ca37b459d7f903e31bf8
Reviewed-on: https://go-review.googlesource.com/c/go/+/628455
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Auto-Submit: Michael Knyszek <mknyszek@google.com>
Diffstat (limited to 'src/internal/weak/pointer_test.go')
| -rw-r--r-- | src/internal/weak/pointer_test.go | 212 |
1 files changed, 0 insertions, 212 deletions
diff --git a/src/internal/weak/pointer_test.go b/src/internal/weak/pointer_test.go deleted file mode 100644 index 5a861bb9ca..0000000000 --- a/src/internal/weak/pointer_test.go +++ /dev/null @@ -1,212 +0,0 @@ -// 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 ( - "context" - "internal/weak" - "runtime" - "sync" - "testing" - "time" -) - -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) - } -} - -// Regression test for issue 69210. -// -// Weak-to-strong conversions must shade the new strong pointer, otherwise -// that might be creating the only strong pointer to a white object which -// is hidden in a blackened stack. -// -// Never fails if correct, fails with some high probability if incorrect. -func TestIssue69210(t *testing.T) { - if testing.Short() { - t.Skip("this is a stress test that takes seconds to run on its own") - } - ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) - defer cancel() - - // What we're trying to do is manufacture the conditions under which this - // bug happens. Specifically, we want: - // - // 1. To create a whole bunch of objects that are only weakly-pointed-to, - // 2. To call Strong while the GC is in the mark phase, - // 3. The new strong pointer to be missed by the GC, - // 4. The following GC cycle to mark a free object. - // - // Unfortunately, (2) and (3) are hard to control, but we can increase - // the likelihood by having several goroutines do (1) at once while - // another goroutine constantly keeps us in the GC with runtime.GC. - // Like throwing darts at a dart board until they land just right. - // We can increase the likelihood of (4) by adding some delay after - // creating the strong pointer, but only if it's non-nil. If it's nil, - // that means it was already collected in which case there's no chance - // of triggering the bug, so we want to retry as fast as possible. - // Our heap here is tiny, so the GCs will go by fast. - // - // As of 2024-09-03, removing the line that shades pointers during - // the weak-to-strong conversion causes this test to fail about 50% - // of the time. - - var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() - for { - runtime.GC() - - select { - case <-ctx.Done(): - return - default: - } - } - }() - for range max(runtime.GOMAXPROCS(-1)-1, 1) { - wg.Add(1) - go func() { - defer wg.Done() - for { - for range 5 { - bt := new(T) - wt := weak.Make(bt) - bt = nil - time.Sleep(1 * time.Millisecond) - bt = wt.Strong() - if bt != nil { - time.Sleep(4 * time.Millisecond) - bt.t = bt - bt.a = 12 - } - runtime.KeepAlive(bt) - } - select { - case <-ctx.Done(): - return - default: - } - } - }() - } - wg.Wait() -} |
