Source file src/runtime/cgo/handle.go

     1  // Copyright 2021 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package cgo
     6  
     7  import (
     8  	"sync"
     9  	"sync/atomic"
    10  )
    11  
    12  // Handle provides a way to pass values that contain Go pointers
    13  // (pointers to memory allocated by Go) between Go and C without
    14  // breaking the cgo pointer passing rules. A Handle is an integer
    15  // value that can represent any Go value. A Handle can be passed
    16  // through C and back to Go, and Go code can use the Handle to
    17  // retrieve the original Go value.
    18  //
    19  // The underlying type of Handle is guaranteed to fit in an integer type
    20  // that is large enough to hold the bit pattern of any pointer. The zero
    21  // value of a Handle is not valid, and thus is safe to use as a sentinel
    22  // in C APIs.
    23  //
    24  // For instance, on the Go side:
    25  //
    26  //	package main
    27  //
    28  //	/*
    29  //	#include <stdint.h> // for uintptr_t
    30  //
    31  //	extern void MyGoPrint(uintptr_t handle);
    32  //	void myprint(uintptr_t handle);
    33  //	*/
    34  //	import "C"
    35  //	import "runtime/cgo"
    36  //
    37  //	//export MyGoPrint
    38  //	func MyGoPrint(handle C.uintptr_t) {
    39  //		h := cgo.Handle(handle)
    40  //		val := h.Value().(string)
    41  //		println(val)
    42  //		h.Delete()
    43  //	}
    44  //
    45  //	func main() {
    46  //		val := "hello Go"
    47  //		C.myprint(C.uintptr_t(cgo.NewHandle(val)))
    48  //		// Output: hello Go
    49  //	}
    50  //
    51  // and on the C side:
    52  //
    53  //	#include <stdint.h> // for uintptr_t
    54  //
    55  //	// A Go function
    56  //	extern void MyGoPrint(uintptr_t handle);
    57  //
    58  //	// A C function
    59  //	void myprint(uintptr_t handle) {
    60  //	    MyGoPrint(handle);
    61  //	}
    62  //
    63  // Some C functions accept a void* argument that points to an arbitrary
    64  // data value supplied by the caller. It is not safe to coerce a Handle
    65  // (an integer) to a Go [unsafe.Pointer], but instead we can pass the address
    66  // of the cgo.Handle to the void* parameter, as in this variant of the
    67  // previous example.
    68  //
    69  // Note that, as described in the [cmd/cgo] documentation,
    70  // the C code must not keep a copy of the Go pointer that it receives,
    71  // unless the memory is explicitly pinned using [runtime.Pinner].
    72  // This example is OK because the C function myprint does not keep
    73  // a copy of the pointer.
    74  //
    75  //	package main
    76  //
    77  //	/*
    78  //	extern void MyGoPrint(void *context);
    79  //	static inline void myprint(void *context) {
    80  //	    MyGoPrint(context);
    81  //	}
    82  //	*/
    83  //	import "C"
    84  //	import (
    85  //		"runtime/cgo"
    86  //		"unsafe"
    87  //	)
    88  //
    89  //	//export MyGoPrint
    90  //	func MyGoPrint(context unsafe.Pointer) {
    91  //		h := *(*cgo.Handle)(context)
    92  //		val := h.Value().(string)
    93  //		println(val)
    94  //		h.Delete()
    95  //	}
    96  //
    97  //	func main() {
    98  //		val := "hello Go"
    99  //		h := cgo.NewHandle(val)
   100  //		// In this example, unsafe.Pointer(&h) is valid because myprint
   101  //		// does not keep a copy of the pointer. If the C code keeps the
   102  //		// pointer after the call returns, use runtime.Pinner to pin it.
   103  //		C.myprint(unsafe.Pointer(&h))
   104  //		// Output: hello Go
   105  //	}
   106  type Handle uintptr
   107  
   108  // NewHandle returns a handle for a given value.
   109  //
   110  // The handle is valid until the program calls Delete on it. The handle
   111  // uses resources, and this package assumes that C code may hold on to
   112  // the handle, so a program must explicitly call Delete when the handle
   113  // is no longer needed.
   114  //
   115  // The intended use is to pass the returned handle to C code, which
   116  // passes it back to Go, which calls Value.
   117  func NewHandle(v any) Handle {
   118  	h := handleIdx.Add(1)
   119  	if h == 0 {
   120  		panic("runtime/cgo: ran out of handle space")
   121  	}
   122  
   123  	handles.Store(h, v)
   124  	return Handle(h)
   125  }
   126  
   127  // Value returns the associated Go value for a valid handle.
   128  //
   129  // The method panics if the handle is invalid.
   130  func (h Handle) Value() any {
   131  	v, ok := handles.Load(uintptr(h))
   132  	if !ok {
   133  		panic("runtime/cgo: misuse of an invalid Handle")
   134  	}
   135  	return v
   136  }
   137  
   138  // Delete invalidates a handle. This method should only be called once
   139  // the program no longer needs to pass the handle to C and the C code
   140  // no longer has a copy of the handle value.
   141  //
   142  // The method panics if the handle is invalid.
   143  func (h Handle) Delete() {
   144  	_, ok := handles.LoadAndDelete(uintptr(h))
   145  	if !ok {
   146  		panic("runtime/cgo: misuse of an invalid Handle")
   147  	}
   148  }
   149  
   150  var (
   151  	handles   = sync.Map{} // map[Handle]interface{}
   152  	handleIdx atomic.Uintptr
   153  )
   154  

View as plain text