blob: 80bffe29080ea4d1ce9bb6ee7dd526c0129c6555 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Package cpointer provides a mechanism for passing Go pointers through
// C/C++ code. Go does not allow programs to pass Go pointers to C++ code
// directly (see https://golang.org/cmd/cgo/#hdr-Passing_pointers). Code
// that needs to pass Go pointers through C/C++ code back to Go code can use
// this package to associate a unique C pointer with the Go pointer and then
// pass the C pointer through the C/C++ code. It is safe to call the
// functions in this package concurrently via multiple goroutines.
package cpointer
import (
"errors"
"sync"
"github.com/golang/glog"
)
var tab = struct {
sync.Mutex
m map[uintptr]interface{} // All valid C pointers.
next uintptr // Next C pointer to use.
}{
m: make(map[uintptr]interface{}),
next: uintptr(1607),
}
// ErrInvalid is returned if a caller calls a function with an invalid C pointer.
var ErrInvalid = errors.New("invalid C pointer")
// New allocates a C pointer, associates it with a Go value, and returns the new "C pointer" which
// can be passed to C.
func New(v interface{}) uintptr {
tab.Lock()
p := tab.next
tab.m[p] = v
tab.next++
tab.Unlock()
return p
}
// Delete removes a C pointer. Returns ErrInvalid if p is not a valid C pointer.
func Delete(p uintptr) error {
var err error
tab.Lock()
if _, ok := tab.m[p]; !ok {
err = ErrInvalid
} else {
delete(tab.m, p)
}
tab.Unlock()
return err
}
// MustDelete removes a C pointer and logs a fatal error if it cannot do so.
func MustDelete(p uintptr) {
if err := Delete(p); err != nil {
glog.Fatalf("Error deleting c pointer %#x: %v\n", p, err)
}
}
// Value returns the value associated with p. If p is not a valid C pointer, Value
// returns nil and ErrInvalid.
func Value(p uintptr) (interface{}, error) {
var err error
tab.Lock()
v, ok := tab.m[p]
if !ok {
err = ErrInvalid
}
tab.Unlock()
return v, err
}
// MustValue returns the value associated with p. It logs a fatal error if p is
// not a valid C pointer.
func MustValue(p uintptr) interface{} {
v, err := Value(p)
if err != nil {
glog.Fatalf("Error fetching value for C pointer %#x: %v\n", p, err)
}
return v
}