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 [cgo.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  //	package main
    70  //
    71  //	/*
    72  //	extern void MyGoPrint(void *context);
    73  //	static inline void myprint(void *context) {
    74  //	    MyGoPrint(context);
    75  //	}
    76  //	*/
    77  //	import "C"
    78  //	import (
    79  //		"runtime/cgo"
    80  //		"unsafe"
    81  //	)
    82  //
    83  //	//export MyGoPrint
    84  //	func MyGoPrint(context unsafe.Pointer) {
    85  //		h := *(*cgo.Handle)(context)
    86  //		val := h.Value().(string)
    87  //		println(val)
    88  //		h.Delete()
    89  //	}
    90  //
    91  //	func main() {
    92  //		val := "hello Go"
    93  //		h := cgo.NewHandle(val)
    94  //		C.myprint(unsafe.Pointer(&h))
    95  //		// Output: hello Go
    96  //	}
    97  type Handle uintptr
    98  
    99  // NewHandle returns a handle for a given value.
   100  //
   101  // The handle is valid until the program calls Delete on it. The handle
   102  // uses resources, and this package assumes that C code may hold on to
   103  // the handle, so a program must explicitly call Delete when the handle
   104  // is no longer needed.
   105  //
   106  // The intended use is to pass the returned handle to C code, which
   107  // passes it back to Go, which calls Value.
   108  func NewHandle(v any) Handle {
   109  	h := handleIdx.Add(1)
   110  	if h == 0 {
   111  		panic("runtime/cgo: ran out of handle space")
   112  	}
   113  
   114  	handles.Store(h, v)
   115  	return Handle(h)
   116  }
   117  
   118  // Value returns the associated Go value for a valid handle.
   119  //
   120  // The method panics if the handle is invalid.
   121  func (h Handle) Value() any {
   122  	v, ok := handles.Load(uintptr(h))
   123  	if !ok {
   124  		panic("runtime/cgo: misuse of an invalid Handle")
   125  	}
   126  	return v
   127  }
   128  
   129  // Delete invalidates a handle. This method should only be called once
   130  // the program no longer needs to pass the handle to C and the C code
   131  // no longer has a copy of the handle value.
   132  //
   133  // The method panics if the handle is invalid.
   134  func (h Handle) Delete() {
   135  	_, ok := handles.LoadAndDelete(uintptr(h))
   136  	if !ok {
   137  		panic("runtime/cgo: misuse of an invalid Handle")
   138  	}
   139  }
   140  
   141  var (
   142  	handles   = sync.Map{} // map[Handle]interface{}
   143  	handleIdx atomic.Uintptr
   144  )
   145  

View as plain text