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