]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/cgo/handle.go
runtime/cgo: add Handle for managing (c)go pointers
[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 safe representation of Go values to pass between
13 // Go and C. The zero value of a handle is not a valid handle, and thus
14 // is safe to use as a sentinel in C APIs.
15 //
16 // The underlying type of Handle is guaranteed to fit in an integer type
17 // that is large enough to hold the bit pattern of any pointer.
18 // For instance, on the Go side:
19 //
20 //      package main
21 //
22 //      /*
23 //      #include <stdint.h> // for uintptr_t
24 //
25 //      extern void MyGoPrint(uintptr_t handle);
26 //      void myprint(uintptr_t handle);
27 //      */
28 //      import "C"
29 //      import "runtime/cgo"
30 //
31 //      //export MyGoPrint
32 //      func MyGoPrint(handle C.uintptr_t) {
33 //              h := cgo.Handle(handle)
34 //              val := h.Value().(int)
35 //              println(val)
36 //              h.Delete()
37 //      }
38 //
39 //      func main() {
40 //              val := 42
41 //              C.myprint(C.uintptr_t(cgo.NewHandle(val)))
42 //              // Output: 42
43 //      }
44 //
45 // and on the C side:
46 //
47 //      #include <stdint.h> // for uintptr_t
48 //
49 //      // A Go function
50 //      extern void MyGoPrint(uintptr_t handle);
51 //
52 //      // A C function
53 //      void myprint(uintptr_t handle) {
54 //          MyGoPrint(handle);
55 //      }
56 type Handle uintptr
57
58 // NewHandle returns a handle for a given value.
59 //
60 // The handle is valid until the program calls Delete on it. The handle
61 // uses resources, and this package assumes that C code may hold on to
62 // the handle, so a program must explicitly call Delete when the handle
63 // is no longer needed.
64 //
65 // The intended use is to pass the returned handle to C code, which
66 // passes it back to Go, which calls Value.
67 func NewHandle(v interface{}) Handle {
68         h := atomic.AddUintptr(&handleIdx, 1)
69         if h == 0 {
70                 panic("runtime/cgo: ran out of handle space")
71         }
72
73         handles.Store(h, v)
74         return Handle(h)
75 }
76
77 // Value returns the associated Go value for a valid handle.
78 //
79 // The method panics if the handle is invalid.
80 func (h Handle) Value() interface{} {
81         v, ok := handles.Load(uintptr(h))
82         if !ok {
83                 panic("runtime/cgo: misuse of an invalid Handle")
84         }
85         return v
86 }
87
88 // Delete invalidates a handle. This method should only be called once
89 // the program no longer needs to pass the handle to C and the C code
90 // no longer has a copy of the handle value.
91 //
92 // The method panics if the handle is invalid.
93 func (h Handle) Delete() {
94         _, ok := handles.LoadAndDelete(uintptr(h))
95         if !ok {
96                 panic("runtime/cgo: misuse of an invalid Handle")
97         }
98 }
99
100 var (
101         handles   = sync.Map{} // map[Handle]interface{}
102         handleIdx uintptr      // atomic
103 )