| // Copyright 2021 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package cgo | |
| import ( | |
| "sync" | |
| "sync/atomic" | |
| ) | |
| // 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. 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 | |
| // | |
| // /* | |
| // #include <stdint.h> // for uintptr_t | |
| // | |
| // 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().(string) | |
| // println(val) | |
| // h.Delete() | |
| // } | |
| // | |
| // 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 | |
| // | |
| // // 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 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. | |
| // | |
| // Note that, as described in the [cmd/cgo] documentation, | |
| // the C code must not keep a copy of the Go pointer that it receives, | |
| // unless the memory is explicitly pinned using [runtime.Pinner]. | |
| // This example is OK because the C function myprint does not keep | |
| // a copy of the pointer. | |
| // | |
| // package main | |
| // | |
| // /* | |
| // extern void MyGoPrint(void *context); | |
| // static inline void myprint(void *context) { | |
| // MyGoPrint(context); | |
| // } | |
| // */ | |
| // import "C" | |
| // import ( | |
| // "runtime/cgo" | |
| // "unsafe" | |
| // ) | |
| // | |
| // //export MyGoPrint | |
| // func MyGoPrint(context unsafe.Pointer) { | |
| // h := *(*cgo.Handle)(context) | |
| // val := h.Value().(string) | |
| // println(val) | |
| // h.Delete() | |
| // } | |
| // | |
| // func main() { | |
| // val := "hello Go" | |
| // h := cgo.NewHandle(val) | |
| // // In this example, unsafe.Pointer(&h) is valid because myprint | |
| // // does not keep a copy of the pointer. If the C code keeps the | |
| // // pointer after the call returns, use runtime.Pinner to pin it. | |
| // C.myprint(unsafe.Pointer(&h)) | |
| // // Output: hello Go | |
| // } | |
| type Handle uintptr | |
| // NewHandle returns a handle for a given value. | |
| // | |
| // The handle is valid until the program calls Delete on it. The handle | |
| // uses resources, and this package assumes that C code may hold on to | |
| // the handle, so a program must explicitly call Delete when the handle | |
| // is no longer needed. | |
| // | |
| // The intended use is to pass the returned handle to C code, which | |
| // passes it back to Go, which calls Value. | |
| func NewHandle(v any) Handle { | |
| h := handleIdx.Add(1) | |
| if h == 0 { | |
| panic("runtime/cgo: ran out of handle space") | |
| } | |
| handles.Store(h, v) | |
| return Handle(h) | |
| } | |
| // Value returns the associated Go value for a valid handle. | |
| // | |
| // The method panics if the handle is invalid. | |
| func (h Handle) Value() any { | |
| v, ok := handles.Load(uintptr(h)) | |
| if !ok { | |
| panic("runtime/cgo: misuse of an invalid Handle") | |
| } | |
| return v | |
| } | |
| // Delete invalidates a handle. This method should only be called once | |
| // the program no longer needs to pass the handle to C and the C code | |
| // no longer has a copy of the handle value. | |
| // | |
| // The method panics if the handle is invalid. | |
| func (h Handle) Delete() { | |
| _, ok := handles.LoadAndDelete(uintptr(h)) | |
| if !ok { | |
| panic("runtime/cgo: misuse of an invalid Handle") | |
| } | |
| } | |
| var ( | |
| handles = sync.Map{} // map[Handle]interface{} | |
| handleIdx atomic.Uintptr | |
| ) |