]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/cgo/handle.go
061dfb0e2e2194d599ea4ee6b99e765c81423a54
[gostls13.git] / 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 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 //      }
97 type 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.
108 func 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.
121 func (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.
134 func (h Handle) Delete() {
135         _, ok := handles.LoadAndDelete(uintptr(h))
136         if !ok {
137                 panic("runtime/cgo: misuse of an invalid Handle")
138         }
139 }
140
141 var (
142         handles   = sync.Map{} // map[Handle]interface{}
143         handleIdx atomic.Uintptr
144 )