"sync/atomic"
)
-// Handle provides a safe representation of Go values to pass between
-// Go and C. The zero value of a handle is not a valid handle, and thus
-// is safe to use as a sentinel in C APIs.
+// Handle provides a way to pass values that contain Go pointers
+// (pointers to memory allocated by Go) between Go and C without
+// breaking the cgo pointer passing rules. A Handle is an integer
+// value that can represent any Go value. A Handle can be passed
+// through C and back to Go, and Go code can use the Handle to
+// retrieve the original Go value.
//
// The underlying type of Handle is guaranteed to fit in an integer type
-// that is large enough to hold the bit pattern of any pointer.
+// that is large enough to hold the bit pattern of any pointer. The zero
+// value of a Handle is not valid, and thus is safe to use as a sentinel
+// in C APIs.
+//
// For instance, on the Go side:
//
-// package main
+// package main
//
-// /*
-// #include <stdint.h> // for uintptr_t
+// /*
+// #include <stdint.h> // for uintptr_t
//
-// extern void MyGoPrint(uintptr_t handle);
-// void myprint(uintptr_t handle);
-// */
-// import "C"
-// import "runtime/cgo"
+// extern void MyGoPrint(uintptr_t handle);
+// void myprint(uintptr_t handle);
+// */
+// import "C"
+// import "runtime/cgo"
//
-// //export MyGoPrint
-// func MyGoPrint(handle C.uintptr_t) {
-// h := cgo.Handle(handle)
-// val := h.Value().(int)
-// println(val)
-// h.Delete()
-// }
+// //export MyGoPrint
+// func MyGoPrint(handle C.uintptr_t) {
+// h := cgo.Handle(handle)
+// val := h.Value().(string)
+// println(val)
+// h.Delete()
+// }
//
-// func main() {
-// val := 42
-// C.myprint(C.uintptr_t(cgo.NewHandle(val)))
-// // Output: 42
-// }
+// func main() {
+// val := "hello Go"
+// C.myprint(C.uintptr_t(cgo.NewHandle(val)))
+// // Output: hello Go
+// }
//
// and on the C side:
//
-// #include <stdint.h> // for uintptr_t
+// #include <stdint.h> // for uintptr_t
+//
+// // A Go function
+// extern void MyGoPrint(uintptr_t handle);
+//
+// // A C function
+// void myprint(uintptr_t handle) {
+// MyGoPrint(handle);
+// }
+//
+// Some C functions accept a void* argument that points to an arbitrary
+// data value supplied by the caller. It is not safe to coerce a [cgo.Handle]
+// (an integer) to a Go [unsafe.Pointer], but instead we can pass the address
+// of the cgo.Handle to the void* parameter, as in this variant of the
+// previous example:
+//
+// package main
+//
+// /*
+// extern void MyGoPrint(void *context);
+// static inline void myprint(void *context) {
+// MyGoPrint(context);
+// }
+// */
+// import "C"
+// import (
+// "runtime/cgo"
+// "unsafe"
+// )
//
-// // A Go function
-// extern void MyGoPrint(uintptr_t handle);
+// //export MyGoPrint
+// func MyGoPrint(context unsafe.Pointer) {
+// h := *(*cgo.Handle)(context)
+// val := h.Value().(string)
+// println(val)
+// h.Delete()
+// }
//
-// // A C function
-// void myprint(uintptr_t handle) {
-// MyGoPrint(handle);
-// }
+// func main() {
+// val := "hello Go"
+// h := cgo.NewHandle(val)
+// C.myprint(unsafe.Pointer(&h))
+// // Output: hello Go
+// }
type Handle uintptr
// NewHandle returns a handle for a given value.
//
// The intended use is to pass the returned handle to C code, which
// passes it back to Go, which calls Value.
-func NewHandle(v interface{}) Handle {
- h := atomic.AddUintptr(&handleIdx, 1)
+func NewHandle(v any) Handle {
+ h := handleIdx.Add(1)
if h == 0 {
panic("runtime/cgo: ran out of handle space")
}
// Value returns the associated Go value for a valid handle.
//
// The method panics if the handle is invalid.
-func (h Handle) Value() interface{} {
+func (h Handle) Value() any {
v, ok := handles.Load(uintptr(h))
if !ok {
panic("runtime/cgo: misuse of an invalid Handle")
var (
handles = sync.Map{} // map[Handle]interface{}
- handleIdx uintptr // atomic
+ handleIdx atomic.Uintptr
)