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  //		C.myprint(unsafe.Pointer(&h))
   101  //		// Output: hello Go
   102  //	}
   103  type Handle uintptr
   104  
   105  // NewHandle returns a handle for a given value.
   106  //
   107  // The handle is valid until the program calls Delete on it. The handle
   108  // uses resources, and this package assumes that C code may hold on to
   109  // the handle, so a program must explicitly call Delete when the handle
   110  // is no longer needed.
   111  //
   112  // The intended use is to pass the returned handle to C code, which
   113  // passes it back to Go, which calls Value.
   114  func NewHandle(v any) Handle {
   115  	h := handleIdx.Add(1)
   116  	if h == 0 {
   117  		panic("runtime/cgo: ran out of handle space")
   118  	}
   119  
   120  	handles.Store(h, v)
   121  	return Handle(h)
   122  }
   123  
   124  // Value returns the associated Go value for a valid handle.
   125  //
   126  // The method panics if the handle is invalid.
   127  func (h Handle) Value() any {
   128  	v, ok := handles.Load(uintptr(h))
   129  	if !ok {
   130  		panic("runtime/cgo: misuse of an invalid Handle")
   131  	}
   132  	return v
   133  }
   134  
   135  // Delete invalidates a handle. This method should only be called once
   136  // the program no longer needs to pass the handle to C and the C code
   137  // no longer has a copy of the handle value.
   138  //
   139  // The method panics if the handle is invalid.
   140  func (h Handle) Delete() {
   141  	_, ok := handles.LoadAndDelete(uintptr(h))
   142  	if !ok {
   143  		panic("runtime/cgo: misuse of an invalid Handle")
   144  	}
   145  }
   146  
   147  var (
   148  	handles   = sync.Map{} // map[Handle]interface{}
   149  	handleIdx atomic.Uintptr
   150  )
   151  

View as plain text