]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/runtime/pinner.go
runtime: add available godoc link
[gostls13.git] / src / runtime / pinner.go
index 8bb351eb8f2876406a307688b878229027ad8d0a..ea5b909aea1a174144a6c9143cc5cd0ed0f18d4c 100644 (file)
@@ -9,26 +9,23 @@ import (
        "unsafe"
 )
 
-// A Pinner is a set of pinned Go objects. An object can be pinned with
-// the Pin method and all pinned objects of a Pinner can be unpinned with the
-// Unpin method.
+// A Pinner is a set of Go objects each pinned to a fixed location in memory. The
+// [Pin] method pins one object, while [Unpin] unpins all pinned objects. See their
+// comments for more information.
 type Pinner struct {
        *pinner
 }
 
 // Pin pins a Go object, preventing it from being moved or freed by the garbage
-// collector until the Unpin method has been called.
+// collector until the [Pinner.Unpin] method has been called.
 //
-// A pointer to a pinned
-// object can be directly stored in C memory or can be contained in Go memory
-// passed to C functions. If the pinned object itself contains pointers to Go
-// objects, these objects must be pinned separately if they are going to be
-// accessed from C code.
+// A pointer to a pinned object can be directly stored in C memory or can be
+// contained in Go memory passed to C functions. If the pinned object itself
+// contains pointers to Go objects, these objects must be pinned separately if they
+// are going to be accessed from C code.
 //
-// The argument must be a pointer of any type or an
-// unsafe.Pointer. It must be the result of calling new,
-// taking the address of a composite literal, or taking the address of a
-// local variable. If one of these conditions is not met, Pin will panic.
+// The argument must be a pointer of any type or an [unsafe.Pointer].
+// It's safe to call Pin on non-Go pointers, in which case Pin will do nothing.
 func (p *Pinner) Pin(pointer any) {
        if p.pinner == nil {
                // Check the pinner cache first.
@@ -59,11 +56,12 @@ func (p *Pinner) Pin(pointer any) {
                }
        }
        ptr := pinnerGetPtr(&pointer)
-       setPinned(ptr, true)
-       p.refs = append(p.refs, ptr)
+       if setPinned(ptr, true) {
+               p.refs = append(p.refs, ptr)
+       }
 }
 
-// Unpin unpins all pinned objects of the Pinner.
+// Unpin unpins all pinned objects of the [Pinner].
 func (p *Pinner) Unpin() {
        p.pinner.unpin()
 
@@ -143,15 +141,19 @@ func isPinned(ptr unsafe.Pointer) bool {
        return pinState.isPinned()
 }
 
-// setPinned marks or unmarks a Go pointer as pinned.
-func setPinned(ptr unsafe.Pointer, pin bool) {
+// setPinned marks or unmarks a Go pointer as pinned, when the ptr is a Go pointer.
+// It will be ignored while try to pin a non-Go pointer,
+// and it will be panic while try to unpin a non-Go pointer,
+// which should not happen in normal usage.
+func setPinned(ptr unsafe.Pointer, pin bool) bool {
        span := spanOfHeap(uintptr(ptr))
        if span == nil {
-               if isGoPointerWithoutSpan(ptr) {
-                       // this is a linker-allocated or zero size object, nothing to do.
-                       return
+               if !pin {
+                       panic(errorString("tried to unpin non-Go pointer"))
                }
-               panic(errorString("runtime.Pinner.Pin: argument is not a Go pointer"))
+               // This is a linker-allocated, zero size object or other object,
+               // nothing to do, silently ignore it.
+               return false
        }
 
        // ensure that the span is swept, b/c sweeping accesses the specials list
@@ -209,7 +211,7 @@ func setPinned(ptr unsafe.Pointer, pin bool) {
        }
        unlock(&span.speciallock)
        releasem(mp)
-       return
+       return true
 }
 
 type pinState struct {
@@ -265,14 +267,14 @@ func (p *pinnerBits) ofObject(n uintptr) pinState {
 }
 
 func (s *mspan) pinnerBitSize() uintptr {
-       return divRoundUp(s.nelems*2, 8)
+       return divRoundUp(uintptr(s.nelems)*2, 8)
 }
 
 // newPinnerBits returns a pointer to 8 byte aligned bytes to be used for this
 // span's pinner bits. newPinneBits is used to mark objects that are pinned.
 // They are copied when the span is swept.
 func (s *mspan) newPinnerBits() *pinnerBits {
-       return (*pinnerBits)(newMarkBits(s.nelems * 2))
+       return (*pinnerBits)(newMarkBits(uintptr(s.nelems) * 2))
 }
 
 // nosplit, because it's called by isPinned, which is nosplit