Skip to content

Commit

Permalink
weak: move internal/weak to weak, and update according to proposal
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Carlos Amedee <[email protected]>
Auto-Submit: Michael Knyszek <[email protected]>
  • Loading branch information
mknyszek authored and gopherbot committed Nov 18, 2024
1 parent 5e82cba commit a65f1a4
Show file tree
Hide file tree
Showing 15 changed files with 129 additions and 110 deletions.
3 changes: 3 additions & 0 deletions api/next/67552.txt
Original file line number Diff line number Diff line change
@@ -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 changes: 12 additions & 0 deletions doc/next/6-stdlib/1-weak.md
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions doc/next/6-stdlib/99-minor/weak/67552.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!-- This is a new package; covered in 6-stdlib/1-weak.md. -->
3 changes: 0 additions & 3 deletions src/cmd/link/internal/loader/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -2336,9 +2336,6 @@ var blockedLinknames = map[string][]string{
// coroutines
"runtime.coroswitch": {"iter"},
"runtime.newcoro": {"iter"},
// weak references
"internal/weak.runtime_registerWeakPointer": {"internal/weak"},
"internal/weak.runtime_makeStrongFromWeak": {"internal/weak"},
// fips info
"go:fipsinfo": {"crypto/internal/fips/check"},
}
Expand Down
2 changes: 1 addition & 1 deletion src/go/build/deps_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ var depsRules = `
< internal/runtime/maps
< runtime
< sync/atomic
< internal/weak
< internal/sync
< weak
< sync
< internal/bisect
< internal/godebug
Expand Down
1 change: 1 addition & 0 deletions src/go/doc/comment/std.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

83 changes: 0 additions & 83 deletions src/internal/weak/pointer.go

This file was deleted.

6 changes: 3 additions & 3 deletions src/runtime/gc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"fmt"
"internal/asan"
"internal/testenv"
"internal/weak"
"math/bits"
"math/rand"
"os"
Expand All @@ -22,6 +21,7 @@ import (
"testing"
"time"
"unsafe"
"weak"
)

func TestGcSys(t *testing.T) {
Expand Down Expand Up @@ -826,7 +826,7 @@ func TestWeakToStrongMarkTermination(t *testing.T) {

// 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
// 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.
done := make(chan struct{})
go func() {
Expand All @@ -847,7 +847,7 @@ func TestWeakToStrongMarkTermination(t *testing.T) {
wg.Add(1)
go func() {
defer wg.Done()
wp.Strong()
wp.Value()
}()
}

Expand Down
2 changes: 1 addition & 1 deletion src/runtime/mgcsweep.go
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,7 @@ func (sl *sweepLocked) sweep(preserve bool) bool {
}
if hasFinAndRevived {
// 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 siter.valid() && uintptr(siter.s.offset) < endOffset {
// Find the exact byte for which the special was setup
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/mheap.go
Original file line number Diff line number Diff line change
Expand Up @@ -2092,12 +2092,12 @@ type specialWeakHandle struct {
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 {
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 {
handle := (*atomic.Uintptr)(u)

Expand Down
6 changes: 3 additions & 3 deletions src/unique/handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ package unique
import (
"internal/abi"
isync "internal/sync"
"internal/weak"
"runtime"
"sync"
"unsafe"
"weak"
)

var zero uintptr
Expand Down Expand Up @@ -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
// try to get the pointer we need out of it.
ptr = wp.Strong()
ptr = wp.Value()
if ptr != nil {
break
}
Expand Down Expand Up @@ -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
// deleted entries.
m.All()(func(key T, wp weak.Pointer[T]) bool {
if wp.Strong() == nil {
if wp.Value() == nil {
m.CompareAndDelete(key, wp)
}
return true
Expand Down
2 changes: 1 addition & 1 deletion src/unique/handle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func checkMapsFor[T comparable](t *testing.T, value T) {
if !ok {
return
}
if wp.Strong() != nil {
if wp.Value() != nil {
t.Errorf("value %v still referenced a handle (or tiny block?) ", value)
return
}
Expand Down
26 changes: 26 additions & 0 deletions src/weak/doc.go
Original file line number Diff line number Diff line change
@@ -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 changes: 62 additions & 0 deletions src/weak/pointer.go
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit a65f1a4

Please sign in to comment.