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