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 5package cgo 6 7import ( 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// } 97type 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. 108func 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. 121func (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. 134func (h Handle) Delete() { 135 _, ok := handles.LoadAndDelete(uintptr(h)) 136 if !ok { 137 panic("runtime/cgo: misuse of an invalid Handle") 138 } 139} 140 141var ( 142 handles = sync.Map{} // map[Handle]interface{} 143 handleIdx atomic.Uintptr 144) 145