mirror of
https://github.com/golang/go
synced 2024-11-25 19:07:57 -07:00
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>
This commit is contained in:
parent
5e82cba9bd
commit
a65f1a467f
3
api/next/67552.txt
Normal file
3
api/next/67552.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pkg weak, func Make[$0 interface{}](*$0) Pointer[$0] #67552
|
||||||
|
pkg weak, method (Pointer[$0]) Value() *$0 #67552
|
||||||
|
pkg weak, type Pointer[$0 interface{}] struct #67552
|
12
doc/next/6-stdlib/1-weak.md
Normal file
12
doc/next/6-stdlib/1-weak.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
### New weak package
|
||||||
|
|
||||||
|
The new [weak](/pkg/weak) package provides weak pointers.
|
||||||
|
|
||||||
|
Weak pointers are a low-level primitive provided to enable the
|
||||||
|
creation of memory-efficient structures, such as weak maps for
|
||||||
|
associating values, canonicalization maps for anything not
|
||||||
|
covered by package [unique](/pkg/unique), and various kinds
|
||||||
|
of caches.
|
||||||
|
For supporting these use-cases, this release also provides
|
||||||
|
[runtime.AddCleanup](/pkg/runtime#AddCleanup) and
|
||||||
|
[maphash.Comparable](/pkg/maphash#Comparable).
|
1
doc/next/6-stdlib/99-minor/weak/67552.md
Normal file
1
doc/next/6-stdlib/99-minor/weak/67552.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
<!-- This is a new package; covered in 6-stdlib/1-weak.md. -->
|
@ -2336,9 +2336,6 @@ var blockedLinknames = map[string][]string{
|
|||||||
// coroutines
|
// coroutines
|
||||||
"runtime.coroswitch": {"iter"},
|
"runtime.coroswitch": {"iter"},
|
||||||
"runtime.newcoro": {"iter"},
|
"runtime.newcoro": {"iter"},
|
||||||
// weak references
|
|
||||||
"internal/weak.runtime_registerWeakPointer": {"internal/weak"},
|
|
||||||
"internal/weak.runtime_makeStrongFromWeak": {"internal/weak"},
|
|
||||||
// fips info
|
// fips info
|
||||||
"go:fipsinfo": {"crypto/internal/fips/check"},
|
"go:fipsinfo": {"crypto/internal/fips/check"},
|
||||||
}
|
}
|
||||||
|
@ -96,8 +96,8 @@ var depsRules = `
|
|||||||
< internal/runtime/maps
|
< internal/runtime/maps
|
||||||
< runtime
|
< runtime
|
||||||
< sync/atomic
|
< sync/atomic
|
||||||
< internal/weak
|
|
||||||
< internal/sync
|
< internal/sync
|
||||||
|
< weak
|
||||||
< sync
|
< sync
|
||||||
< internal/bisect
|
< internal/bisect
|
||||||
< internal/godebug
|
< internal/godebug
|
||||||
|
@ -47,4 +47,5 @@ var stdPkgs = []string{
|
|||||||
"unicode",
|
"unicode",
|
||||||
"unique",
|
"unique",
|
||||||
"unsafe",
|
"unsafe",
|
||||||
|
"weak",
|
||||||
}
|
}
|
||||||
|
@ -1,83 +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.
|
|
||||||
|
|
||||||
/*
|
|
||||||
The weak package is a package for managing weak pointers.
|
|
||||||
|
|
||||||
Weak pointers are pointers that explicitly do not keep a value live and
|
|
||||||
must be queried for a regular Go pointer.
|
|
||||||
The result of such a query may be observed as nil at any point after a
|
|
||||||
weakly-pointed-to object becomes eligible for reclamation by the garbage
|
|
||||||
collector.
|
|
||||||
More specifically, weak pointers become nil as soon as the garbage collector
|
|
||||||
identifies that the object is unreachable, before it is made reachable
|
|
||||||
again by a finalizer.
|
|
||||||
In terms of the C# language, these semantics are roughly equivalent to the
|
|
||||||
the semantics of "short" weak references.
|
|
||||||
In terms of the Java language, these semantics are roughly equivalent to the
|
|
||||||
semantics of the WeakReference type.
|
|
||||||
|
|
||||||
Using go:linkname to access this package and the functions it references
|
|
||||||
is explicitly forbidden by the toolchain because the semantics of this
|
|
||||||
package have not gone through the proposal process. By exposing this
|
|
||||||
functionality, we risk locking in the existing semantics due to Hyrum's Law.
|
|
||||||
|
|
||||||
If you believe you have a good use-case for weak references not already
|
|
||||||
covered by the standard library, file a proposal issue at
|
|
||||||
https://github.com/golang/go/issues instead of relying on this package.
|
|
||||||
*/
|
|
||||||
package weak
|
|
||||||
|
|
||||||
import (
|
|
||||||
"internal/abi"
|
|
||||||
"runtime"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Pointer is a weak pointer to a value of type T.
|
|
||||||
//
|
|
||||||
// This value is comparable is guaranteed to compare equal if the pointers
|
|
||||||
// that they were created from compare equal. This property is retained even
|
|
||||||
// after the object referenced by the pointer used to create a weak reference
|
|
||||||
// is reclaimed.
|
|
||||||
//
|
|
||||||
// If multiple weak pointers are made to different offsets within same object
|
|
||||||
// (for example, pointers to different fields of the same struct), those pointers
|
|
||||||
// will not compare equal.
|
|
||||||
// If a weak pointer is created from an object that becomes reachable again due
|
|
||||||
// to a finalizer, that weak pointer will not compare equal with weak pointers
|
|
||||||
// created before it became unreachable.
|
|
||||||
type Pointer[T any] struct {
|
|
||||||
u unsafe.Pointer
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make creates a weak pointer from a strong pointer to some value of type T.
|
|
||||||
func Make[T any](ptr *T) Pointer[T] {
|
|
||||||
// Explicitly force ptr to escape to the heap.
|
|
||||||
ptr = abi.Escape(ptr)
|
|
||||||
|
|
||||||
var u unsafe.Pointer
|
|
||||||
if ptr != nil {
|
|
||||||
u = runtime_registerWeakPointer(unsafe.Pointer(ptr))
|
|
||||||
}
|
|
||||||
runtime.KeepAlive(ptr)
|
|
||||||
return Pointer[T]{u}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strong creates a strong pointer from the weak pointer.
|
|
||||||
// Returns nil if the original value for the weak pointer was reclaimed by
|
|
||||||
// the garbage collector.
|
|
||||||
// If a weak pointer points to an object with a finalizer, then Strong will
|
|
||||||
// return nil as soon as the object's finalizer is queued for execution.
|
|
||||||
func (p Pointer[T]) Strong() *T {
|
|
||||||
return (*T)(runtime_makeStrongFromWeak(p.u))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implemented in runtime.
|
|
||||||
|
|
||||||
//go:linkname runtime_registerWeakPointer
|
|
||||||
func runtime_registerWeakPointer(unsafe.Pointer) unsafe.Pointer
|
|
||||||
|
|
||||||
//go:linkname runtime_makeStrongFromWeak
|
|
||||||
func runtime_makeStrongFromWeak(unsafe.Pointer) unsafe.Pointer
|
|
@ -8,7 +8,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"internal/asan"
|
"internal/asan"
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"internal/weak"
|
|
||||||
"math/bits"
|
"math/bits"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
@ -22,6 +21,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
"weak"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGcSys(t *testing.T) {
|
func TestGcSys(t *testing.T) {
|
||||||
@ -826,7 +826,7 @@ func TestWeakToStrongMarkTermination(t *testing.T) {
|
|||||||
|
|
||||||
// Start a GC, and wait a little bit to get something spinning in mark termination.
|
// Start a GC, and wait a little bit to get something spinning in mark termination.
|
||||||
// Simultaneously, fire off another goroutine to disable spinning. If everything's
|
// Simultaneously, fire off another goroutine to disable spinning. If everything's
|
||||||
// working correctly, then weak.Strong will block, so we need to make sure something
|
// working correctly, then weak.Value will block, so we need to make sure something
|
||||||
// prevents the GC from continuing to spin.
|
// prevents the GC from continuing to spin.
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
@ -847,7 +847,7 @@ func TestWeakToStrongMarkTermination(t *testing.T) {
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
wp.Strong()
|
wp.Value()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -564,7 +564,7 @@ func (sl *sweepLocked) sweep(preserve bool) bool {
|
|||||||
}
|
}
|
||||||
if hasFinAndRevived {
|
if hasFinAndRevived {
|
||||||
// Pass 2: queue all finalizers and clear any weak handles. Weak handles are cleared
|
// Pass 2: queue all finalizers and clear any weak handles. Weak handles are cleared
|
||||||
// before finalization as specified by the internal/weak package. See the documentation
|
// before finalization as specified by the weak package. See the documentation
|
||||||
// for that package for more details.
|
// for that package for more details.
|
||||||
for siter.valid() && uintptr(siter.s.offset) < endOffset {
|
for siter.valid() && uintptr(siter.s.offset) < endOffset {
|
||||||
// Find the exact byte for which the special was setup
|
// Find the exact byte for which the special was setup
|
||||||
|
@ -2092,12 +2092,12 @@ type specialWeakHandle struct {
|
|||||||
handle *atomic.Uintptr
|
handle *atomic.Uintptr
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:linkname internal_weak_runtime_registerWeakPointer internal/weak.runtime_registerWeakPointer
|
//go:linkname internal_weak_runtime_registerWeakPointer weak.runtime_registerWeakPointer
|
||||||
func internal_weak_runtime_registerWeakPointer(p unsafe.Pointer) unsafe.Pointer {
|
func internal_weak_runtime_registerWeakPointer(p unsafe.Pointer) unsafe.Pointer {
|
||||||
return unsafe.Pointer(getOrAddWeakHandle(unsafe.Pointer(p)))
|
return unsafe.Pointer(getOrAddWeakHandle(unsafe.Pointer(p)))
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:linkname internal_weak_runtime_makeStrongFromWeak internal/weak.runtime_makeStrongFromWeak
|
//go:linkname internal_weak_runtime_makeStrongFromWeak weak.runtime_makeStrongFromWeak
|
||||||
func internal_weak_runtime_makeStrongFromWeak(u unsafe.Pointer) unsafe.Pointer {
|
func internal_weak_runtime_makeStrongFromWeak(u unsafe.Pointer) unsafe.Pointer {
|
||||||
handle := (*atomic.Uintptr)(u)
|
handle := (*atomic.Uintptr)(u)
|
||||||
|
|
||||||
|
@ -7,10 +7,10 @@ package unique
|
|||||||
import (
|
import (
|
||||||
"internal/abi"
|
"internal/abi"
|
||||||
isync "internal/sync"
|
isync "internal/sync"
|
||||||
"internal/weak"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
"weak"
|
||||||
)
|
)
|
||||||
|
|
||||||
var zero uintptr
|
var zero uintptr
|
||||||
@ -76,7 +76,7 @@ func Make[T comparable](value T) Handle[T] {
|
|||||||
}
|
}
|
||||||
// Now that we're sure there's a value in the map, let's
|
// Now that we're sure there's a value in the map, let's
|
||||||
// try to get the pointer we need out of it.
|
// try to get the pointer we need out of it.
|
||||||
ptr = wp.Strong()
|
ptr = wp.Value()
|
||||||
if ptr != nil {
|
if ptr != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -132,7 +132,7 @@ func addUniqueMap[T comparable](typ *abi.Type) *uniqueMap[T] {
|
|||||||
// Delete all the entries whose weak references are nil and clean up
|
// Delete all the entries whose weak references are nil and clean up
|
||||||
// deleted entries.
|
// deleted entries.
|
||||||
m.All()(func(key T, wp weak.Pointer[T]) bool {
|
m.All()(func(key T, wp weak.Pointer[T]) bool {
|
||||||
if wp.Strong() == nil {
|
if wp.Value() == nil {
|
||||||
m.CompareAndDelete(key, wp)
|
m.CompareAndDelete(key, wp)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -114,7 +114,7 @@ func checkMapsFor[T comparable](t *testing.T, value T) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if wp.Strong() != nil {
|
if wp.Value() != nil {
|
||||||
t.Errorf("value %v still referenced a handle (or tiny block?) ", value)
|
t.Errorf("value %v still referenced a handle (or tiny block?) ", value)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
26
src/weak/doc.go
Normal file
26
src/weak/doc.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// 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 provides weak pointers with the goal of memory efficiency.
|
||||||
|
The primary use-cases for weak pointers are for implementing caches,
|
||||||
|
canonicalization maps (like the unique package), and for tying together
|
||||||
|
the lifetimes of separate values.
|
||||||
|
|
||||||
|
## Advice
|
||||||
|
|
||||||
|
This package is intended to target niche use-cases like the unique
|
||||||
|
package, not as a general replacement for regular Go pointers, maps,
|
||||||
|
etc.
|
||||||
|
Misuse of the structures in this package will generate unexpected and
|
||||||
|
hard-to-reproduce bugs.
|
||||||
|
Using the facilities in this package to try and resolve out-of-memory
|
||||||
|
issues and/or memory leaks is very likely the wrong answer.
|
||||||
|
|
||||||
|
The structures in this package are intended to be an implementation
|
||||||
|
detail of the package they are used by (again, see the unique package).
|
||||||
|
Avoid exposing weak structures across API boundaries, since that exposes
|
||||||
|
users of your package to the subtleties of this package.
|
||||||
|
*/
|
||||||
|
package weak
|
62
src/weak/pointer.go
Normal file
62
src/weak/pointer.go
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
import (
|
||||||
|
"internal/abi"
|
||||||
|
"runtime"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Pointer is a weak pointer to a value of type T.
|
||||||
|
//
|
||||||
|
// Two Pointer values compare equal if the pointers
|
||||||
|
// that they were created from compare equal. This property is retained even
|
||||||
|
// after the object referenced by the pointer used to create a weak reference
|
||||||
|
// is reclaimed.
|
||||||
|
//
|
||||||
|
// If multiple weak pointers are made to different offsets within same object
|
||||||
|
// (for example, pointers to different fields of the same struct), those pointers
|
||||||
|
// will not compare equal.
|
||||||
|
// If a weak pointer is created from an object that becomes unreachable, but is
|
||||||
|
// then resurrected due to a finalizer, that weak pointer will not compare equal
|
||||||
|
// with weak pointers created after resurrection.
|
||||||
|
//
|
||||||
|
// Calling Make with a nil pointer returns a weak pointer whose Value method
|
||||||
|
// always returns nil. The zero value of a Pointer behaves as if it was created
|
||||||
|
// by passing nil to Make and compares equal with such pointers.
|
||||||
|
type Pointer[T any] struct {
|
||||||
|
u unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make creates a weak pointer from a strong pointer to some value of type T.
|
||||||
|
func Make[T any](ptr *T) Pointer[T] {
|
||||||
|
// Explicitly force ptr to escape to the heap.
|
||||||
|
ptr = abi.Escape(ptr)
|
||||||
|
|
||||||
|
var u unsafe.Pointer
|
||||||
|
if ptr != nil {
|
||||||
|
u = runtime_registerWeakPointer(unsafe.Pointer(ptr))
|
||||||
|
}
|
||||||
|
runtime.KeepAlive(ptr)
|
||||||
|
return Pointer[T]{u}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value returns the original pointer used to create the weak pointer.
|
||||||
|
// It returns nil if the value pointed to by the original pointer was reclaimed by
|
||||||
|
// the garbage collector.
|
||||||
|
// If a weak pointer points to an object with a finalizer, then Value will
|
||||||
|
// return nil as soon as the object's finalizer is queued for execution.
|
||||||
|
func (p Pointer[T]) Value() *T {
|
||||||
|
return (*T)(runtime_makeStrongFromWeak(p.u))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implemented in runtime.
|
||||||
|
|
||||||
|
//go:linkname runtime_registerWeakPointer
|
||||||
|
func runtime_registerWeakPointer(unsafe.Pointer) unsafe.Pointer
|
||||||
|
|
||||||
|
//go:linkname runtime_makeStrongFromWeak
|
||||||
|
func runtime_makeStrongFromWeak(unsafe.Pointer) unsafe.Pointer
|
@ -6,11 +6,11 @@ package weak_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"internal/weak"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
"weak"
|
||||||
)
|
)
|
||||||
|
|
||||||
type T struct {
|
type T struct {
|
||||||
@ -23,19 +23,19 @@ type T struct {
|
|||||||
func TestPointer(t *testing.T) {
|
func TestPointer(t *testing.T) {
|
||||||
bt := new(T)
|
bt := new(T)
|
||||||
wt := weak.Make(bt)
|
wt := weak.Make(bt)
|
||||||
if st := wt.Strong(); st != bt {
|
if st := wt.Value(); st != bt {
|
||||||
t.Fatalf("weak pointer is not the same as strong pointer: %p vs. %p", st, bt)
|
t.Fatalf("weak pointer is not the same as strong pointer: %p vs. %p", st, bt)
|
||||||
}
|
}
|
||||||
// bt is still referenced.
|
// bt is still referenced.
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
|
|
||||||
if st := wt.Strong(); st != bt {
|
if st := wt.Value(); st != bt {
|
||||||
t.Fatalf("weak pointer is not the same as strong pointer after GC: %p vs. %p", 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.
|
// bt is no longer referenced.
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
|
|
||||||
if st := wt.Strong(); st != nil {
|
if st := wt.Value(); st != nil {
|
||||||
t.Fatalf("expected weak pointer to be nil, got %p", st)
|
t.Fatalf("expected weak pointer to be nil, got %p", st)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -48,7 +48,7 @@ func TestPointerEquality(t *testing.T) {
|
|||||||
wt[i] = weak.Make(bt[i])
|
wt[i] = weak.Make(bt[i])
|
||||||
}
|
}
|
||||||
for i := range bt {
|
for i := range bt {
|
||||||
st := wt[i].Strong()
|
st := wt[i].Value()
|
||||||
if st != bt[i] {
|
if st != bt[i] {
|
||||||
t.Fatalf("weak pointer is not the same as strong pointer: %p vs. %p", st, bt[i])
|
t.Fatalf("weak pointer is not the same as strong pointer: %p vs. %p", st, bt[i])
|
||||||
}
|
}
|
||||||
@ -65,7 +65,7 @@ func TestPointerEquality(t *testing.T) {
|
|||||||
// bt is still referenced.
|
// bt is still referenced.
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
for i := range bt {
|
for i := range bt {
|
||||||
st := wt[i].Strong()
|
st := wt[i].Value()
|
||||||
if st != bt[i] {
|
if st != bt[i] {
|
||||||
t.Fatalf("weak pointer is not the same as strong pointer: %p vs. %p", st, bt[i])
|
t.Fatalf("weak pointer is not the same as strong pointer: %p vs. %p", st, bt[i])
|
||||||
}
|
}
|
||||||
@ -83,7 +83,7 @@ func TestPointerEquality(t *testing.T) {
|
|||||||
// bt is no longer referenced.
|
// bt is no longer referenced.
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
for i := range bt {
|
for i := range bt {
|
||||||
st := wt[i].Strong()
|
st := wt[i].Value()
|
||||||
if st != nil {
|
if st != nil {
|
||||||
t.Fatalf("expected weak pointer to be nil, got %p", st)
|
t.Fatalf("expected weak pointer to be nil, got %p", st)
|
||||||
}
|
}
|
||||||
@ -101,7 +101,7 @@ func TestPointerFinalizer(t *testing.T) {
|
|||||||
wt := weak.Make(bt)
|
wt := weak.Make(bt)
|
||||||
done := make(chan struct{}, 1)
|
done := make(chan struct{}, 1)
|
||||||
runtime.SetFinalizer(bt, func(bt *T) {
|
runtime.SetFinalizer(bt, func(bt *T) {
|
||||||
if wt.Strong() != nil {
|
if wt.Value() != nil {
|
||||||
t.Errorf("weak pointer did not go nil before finalizer ran")
|
t.Errorf("weak pointer did not go nil before finalizer ran")
|
||||||
}
|
}
|
||||||
done <- struct{}{}
|
done <- struct{}{}
|
||||||
@ -109,7 +109,7 @@ func TestPointerFinalizer(t *testing.T) {
|
|||||||
|
|
||||||
// Make sure the weak pointer stays around while bt is live.
|
// Make sure the weak pointer stays around while bt is live.
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
if wt.Strong() == nil {
|
if wt.Value() == nil {
|
||||||
t.Errorf("weak pointer went nil too soon")
|
t.Errorf("weak pointer went nil too soon")
|
||||||
}
|
}
|
||||||
runtime.KeepAlive(bt)
|
runtime.KeepAlive(bt)
|
||||||
@ -118,7 +118,7 @@ func TestPointerFinalizer(t *testing.T) {
|
|||||||
//
|
//
|
||||||
// Run one cycle to queue the finalizer.
|
// Run one cycle to queue the finalizer.
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
if wt.Strong() != nil {
|
if wt.Value() != nil {
|
||||||
t.Errorf("weak pointer did not go nil when finalizer was enqueued")
|
t.Errorf("weak pointer did not go nil when finalizer was enqueued")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +127,7 @@ func TestPointerFinalizer(t *testing.T) {
|
|||||||
|
|
||||||
// The weak pointer should still be nil after the finalizer runs.
|
// The weak pointer should still be nil after the finalizer runs.
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
if wt.Strong() != nil {
|
if wt.Value() != nil {
|
||||||
t.Errorf("weak pointer is non-nil even after finalization: %v", wt)
|
t.Errorf("weak pointer is non-nil even after finalization: %v", wt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -150,7 +150,7 @@ func TestIssue69210(t *testing.T) {
|
|||||||
// bug happens. Specifically, we want:
|
// bug happens. Specifically, we want:
|
||||||
//
|
//
|
||||||
// 1. To create a whole bunch of objects that are only weakly-pointed-to,
|
// 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,
|
// 2. To call Value while the GC is in the mark phase,
|
||||||
// 3. The new strong pointer to be missed by the GC,
|
// 3. The new strong pointer to be missed by the GC,
|
||||||
// 4. The following GC cycle to mark a free object.
|
// 4. The following GC cycle to mark a free object.
|
||||||
//
|
//
|
||||||
@ -192,7 +192,7 @@ func TestIssue69210(t *testing.T) {
|
|||||||
wt := weak.Make(bt)
|
wt := weak.Make(bt)
|
||||||
bt = nil
|
bt = nil
|
||||||
time.Sleep(1 * time.Millisecond)
|
time.Sleep(1 * time.Millisecond)
|
||||||
bt = wt.Strong()
|
bt = wt.Value()
|
||||||
if bt != nil {
|
if bt != nil {
|
||||||
time.Sleep(4 * time.Millisecond)
|
time.Sleep(4 * time.Millisecond)
|
||||||
bt.t = bt
|
bt.t = bt
|
Loading…
Reference in New Issue
Block a user