Black Lives Matter. Support the Equal Justice Initiative.

Source file src/runtime/cgo/handle.go

Documentation: runtime/cgo

     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  type Handle uintptr
    63  
    64  // NewHandle returns a handle for a given value.
    65  //
    66  // The handle is valid until the program calls Delete on it. The handle
    67  // uses resources, and this package assumes that C code may hold on to
    68  // the handle, so a program must explicitly call Delete when the handle
    69  // is no longer needed.
    70  //
    71  // The intended use is to pass the returned handle to C code, which
    72  // passes it back to Go, which calls Value.
    73  func NewHandle(v interface{}) Handle {
    74  	h := atomic.AddUintptr(&handleIdx, 1)
    75  	if h == 0 {
    76  		panic("runtime/cgo: ran out of handle space")
    77  	}
    78  
    79  	handles.Store(h, v)
    80  	return Handle(h)
    81  }
    82  
    83  // Value returns the associated Go value for a valid handle.
    84  //
    85  // The method panics if the handle is invalid.
    86  func (h Handle) Value() interface{} {
    87  	v, ok := handles.Load(uintptr(h))
    88  	if !ok {
    89  		panic("runtime/cgo: misuse of an invalid Handle")
    90  	}
    91  	return v
    92  }
    93  
    94  // Delete invalidates a handle. This method should only be called once
    95  // the program no longer needs to pass the handle to C and the C code
    96  // no longer has a copy of the handle value.
    97  //
    98  // The method panics if the handle is invalid.
    99  func (h Handle) Delete() {
   100  	_, ok := handles.LoadAndDelete(uintptr(h))
   101  	if !ok {
   102  		panic("runtime/cgo: misuse of an invalid Handle")
   103  	}
   104  }
   105  
   106  var (
   107  	handles   = sync.Map{} // map[Handle]interface{}
   108  	handleIdx uintptr      // atomic
   109  )
   110  

View as plain text