ptrguard

package module
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 30, 2021 License: MIT Imports: 5 Imported by: 0

README

PtrGuard

Build Status Go Reference

PtrGuard is a small Go package that allows to pin objects referenced by a Go pointer (that is pointing to memory allocated by the Go runtime) so that it will not be touched by the garbage collector. This is done by creating a Pinner object that has a Pin() method, which accepts a pointer of any type and pins the referenced object, until the Unpin() method of the same Pinner is called. A Pinner can be used to pin more than one object, in which case Unpin() releases all the pinned objects of a Pinner.

Go pointers to pinned objects can either be directly stored in C memory with the Store() method, or are allowed to be contained in Go memory that is passed to C functions, which both usually violates the pointer passing rules. In the second case you might need the NoCheck() helper function to call the C function in a context, where the cgocheck debug feature is disabled. This is necessary because PtrGuard doesn't have any possibility to tell cgocheck, that certain pointers are pinned.

Example

Let's say we want to use a C API that uses vectored I/O, like the readv() POSIX system call, in order to read data into an array of buffers. Because we want to avoid making a copy of the data, we want to read directly into Go buffers. The pointer passing rules wouldn't allow that, because

  • either we can allocate the buffer array in C memory, but then we can't store the pointers of the Go buffers in it. (Storing Go pointers in C memory is forbidden.)
  • or we would allocate the buffer array in Go memory and store the Go buffers in it. But then we can't pass the pointer to that buffer array to a C function. (Passing a Go pointer that points to memory containing other Go pointers to a C function is forbidden.)

With PtrGuard both is still possible. (See examples.)

Documentation

Overview

Package ptrguard allows to pin a Go object (in memory allocated by the Go runtime), so that it will not be touched by the garbage collector until it is unpinned again.

Example (CAllocatedIovec)

Example how to use PtrGuard with a C allocated iovec array.

package main

import (
	"fmt"
	"math"

	"github.com/ansiwen/ptrguard"
	C "github.com/ansiwen/ptrguard/internal/testhelper"
)

func main() {
	var buffers [][]byte
	for i := 2; i < 12; i += 3 {
		buffers = append(buffers, make([]byte, i))
	}
	numberOfBuffers := len(buffers)

	cPtr := C.Malloc(C.SizeOfIovec * uintptr(len(buffers)))
	defer C.Free(cPtr)
	// This is a trick to create a slice on top of the C allocated array, for
	// easier and safer access.
	iovec := (*[math.MaxInt32]C.Iovec)(cPtr)[:numberOfBuffers:numberOfBuffers]

	var pinner ptrguard.Pinner
	defer pinner.Unpin()
	for i := range iovec {
		bufferPtr := &buffers[i][0]
		pinner.Pin(bufferPtr).Store(&iovec[i].Base)
		iovec[i].Len = C.Int(len(buffers[i]))
	}

	C.FillBuffersWithX(&iovec[0], len(iovec))

	for i := range buffers {
		fmt.Println(string(buffers[i]))
	}
}
Output:

XX
XXXXX
XXXXXXXX
XXXXXXXXXXX
Example (GoAllocatedIovec)

Example how to use PtrGuard with a Go allocated iovec slice.

package main

import (
	"fmt"
	"unsafe"

	"github.com/ansiwen/ptrguard"
	C "github.com/ansiwen/ptrguard/internal/testhelper"
)

func main() {
	var buffers [][]byte
	for i := 2; i < 12; i += 3 {
		buffers = append(buffers, make([]byte, i))
	}

	iovec := make([]C.Iovec, len(buffers))

	var pinner ptrguard.Pinner
	defer pinner.Unpin()
	for i := range iovec {
		bufferPtr := &buffers[i][0]
		pinner.Pin(bufferPtr)
		iovec[i].Base = unsafe.Pointer(bufferPtr)
		iovec[i].Len = C.Int(len(buffers[i]))
	}

	ptrguard.NoCheck(func() {
		C.FillBuffersWithX(&iovec[0], len(iovec))
	})

	for i := range buffers {
		fmt.Println(string(buffers[i]))
	}
}
Output:

XX
XXXXX
XXXXXXXX
XXXXXXXXXXX

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func NoCheck

func NoCheck(f func())

NoCheck temporarily disables cgocheck, which allows passing Go memory containing pinned Go pointers to a C function. Since this is a global setting, and if you are making C calls in parallel, theoretically it could happen that cgocheck is also disabled for some other C calls. If this is an issue, it is also possible to shadow the cgocheck call instead with this code line

_cgoCheckPointer := func(interface{}, interface{}) {}

right before the C function call.

Types

type Pinned added in v0.4.0

type Pinned struct {
	// contains filtered or unexported fields
}

Pinned pointer that can be stored with the Store() method.

func (*Pinned) Store added in v0.4.0

func (p *Pinned) Store(target interface{})

Store a pinned pointer at target. Target must be a pointer to a pointer of any type or a pointer to unsafe.Pointer, otherwise Store() panics.

type Pinner

type Pinner struct {
	// contains filtered or unexported fields
}

Pinner can pin Go objects (in memory allocated by Go runtime) with the Pin() method. A pinned pointer to these objects can be stored in C memory (allocated by malloc) with the `Store()` method. All pinned objects of a Pinner can be unpinned with the `Unpin()` method.

func (*Pinner) Pin added in v0.4.0

func (p *Pinner) Pin(pointer interface{}) *Pinned

Pin the Go object referenced by pointer and return a Pinned value. The pointer must be a pointer of any type or unsafe.Pointer, otherwise Pin() will panic. The object will not be touched by the garbage collector until the `Unpin()` method is called. Therefore pinned pointers to this object can be directly stored in C memory with the `Store()` method or can be contained in Go memory passed to C functions, which usually violates the pointer passing rules[1].

[1] https://golang.org/cmd/cgo/#hdr-Passing_pointers

func (*Pinner) Unpin added in v0.4.0

func (p *Pinner) Unpin()

Unpin all pinned objects of the Pinner and zero all memory where the pointer has been stored. Whenever Pin() has been called at least once on a Pinner, Unpin() must be called afterwards on the same Pinner, or the garbage collector thread will panic.

Directories

Path Synopsis
internal
testhelper
package testhelper
package testhelper

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL