Suppose I have a C library with code like this:
typedef int (callback_t)(int);
void register_callback(callback_t cb);
I want to write go bindings for this function and pass arbitrary go callbacks.
I found an excellent answer here. However, it is a trick that makes use of the fact that the callback accepts a void *, through which Go passes the function pointer to C and receives it back. However, this can't be applied in my example since there isn't a user void *.
The best I could do is:
/*
extern int gobridge(int data);
static int cbridge(void)
{
register_callback(gobridge);
}
*/
import "C"
type Callback func (int) int
var g_cb Callback
//export gobridge
func gobridge(data C.int) C.int {
return C.int(g_cb(int(data)))
}
func RegisterCallback(cb Callback) {
g_cb = cb //save callback in a global
C.cbridge()
}
func Count(left, right int) {
C.count(C.int(left), C.int(right))
}
This only works for a single register_callback (because of the global variable), but the C library can register many callbacks and invoke them all.
I hoped to achieve something like this, but this doesn't compile (put aside the clojure, it can't convert the go function to c function even though the signature is the same):
import "C"
func RegisterCallback(cb Callback) {
f := func (d C.int) C.int {
return C.int(cb(int(d)))
}
C.register_callback(f)
}
func Count(left, right int) {
C.count(C.int(left), C.int(right))
}
Is there a way to properly bind the C library?
You could create an array of callbacks and have the bridge iterate the array of callbacks if the there is no return value (void function).
Related
I have C API that I use from Swift.
In Swift, I have:
enum GetSnapshotResult {
case success(snapshot: UIImage, String)
case failure()
}
func getSnapshot(completion: #escaping (GetSnapshotResult) -> Void) {
CAPIGetSnapshot(nil) { (_) in
completion(
.success(
snapshot: UIImage(),
"test"
)
)
}
}
And in C API:
void CAPIGetSnapshot(void * ptr, void(*callbackOnFinish)(void *)) {
//do something in background thread
//and on its finish, call callbackOnFinish from thread
callbackOnFinish(ptr);
}
However, with this I get:
A C function pointer cannot be formed from a closure that captures context
How do I solve this?
You need a wrapper class so that a void pointer to the instance can be tunneled through the C function to the callback. The combination of passRetained() and takeRetainedValue() ensures that the wrapper instance is released only after the completion function has been called.
func getSnapshot(completion: #escaping (GetSnapshotResult) -> Void) {
class Wrapper {
let completion: (GetSnapshotResult) -> Void
init(completion: #escaping (GetSnapshotResult) -> Void) {
self.completion = completion
}
}
let wrapper = Wrapper(completion: completion)
let observer = UnsafeMutableRawPointer(Unmanaged.passRetained(wrapper).toOpaque())
CAPIGetSnapshot(observer) { theObserver in
let theWrapper = Unmanaged<Wrapper>.fromOpaque(theObserver!).takeRetainedValue()
theWrapper.completion(
.success( snapshot: UIImage(), "test")
)
}
}
Some remarks:
I am assuming that the C function passes the ptr argument to the callback.
passRetained(wrapper) retains the object. That ensures that the wrapper instance is not released when the getSnapshot() function returns.
takeRetainedValue() in the closure consumes the retain. As a consequence, the wrapper instance is released when the closure returns.
completion is a closure and closures are reference types. wrapper.completion holds a reference to that closure as long as the wrapper instance exists.
Of course you can use the same variable names (“observer”, “wrapper”) inside the closure. I chose different names here (“theObserver”, “theWrapper”) only to emphasize that they are different variables, i.e. that the closure does not capture context anymore.
observer needs to be a mutable raw pointer only because the first argument of the C function is declared as void * ptr. If you can change the function declaration to
void CAPIGetSnapshot(const void * ptr, void(*callbackOnFinish)(const void *))
then let observer = UnsafeRawPointer(...) works as well.
For more information about conversion between object references to void pointers see for example How to cast self to UnsafeMutablePointer<Void> type in swift.
Instead of a custom wrapper class you can also take advantage of the fact that arbitrary Swift values are automatically boxed in a class type when cast to AnyObject (see for example AnyObject not working in Xcode8 beta6?).
func getSnapshot(completion: #escaping (GetSnapshotResult) -> Void) {
let wrapper = completion as AnyObject
let observer = UnsafeRawPointer(Unmanaged.passRetained(wrapper).toOpaque())
CAPIGetSnapshot(observer) { theObserver in
let theCompletion = Unmanaged<AnyObject>.fromOpaque(theObserver!).takeRetainedValue()
as! ((GetSnapshotResult) -> Void)
theCompletion(
.success( snapshot: UIImage(), "test")
)
}
}
The forced unwraps and forced casts are safe here because you know what it passed to the function. A failure to unwrap or cast would indicate a programming error. But I would prefer the first version instead of relying on this “magic”.
I'm trying to setup a simple GLFW application in Swift 3. Currently I'm stuck trying to set a callback function.
func setupGLFW() {
...
glfwSetErrorCallback(errorCallback)
...
}
func errorCallback(error: Int32, description: UnsafePointer<Int8>) {
...
}
This worked in Swift 2 but now I get this error:
cannot convert value of type '(Int32, UnsafePointer) -> ()' to expected argument type 'GLFWerrorfun!'
After consulting the section Interacting with C APIs in the documentation, I also tried this signature:
func errorCallback(error: CInt, description: UnsafePointer<CChar>) {
...
}
This leads to the same error.
The C signature for GLFWerrorfun is:
typedef void(* GLFWerrorfun) (int, const char *)
Try with:
func errorCallback(error: Int32, description: UnsafePointer<Int8>?) {
(Please do not miss the ? after UnsafePointer<Int8>.)
In Swift 3, nullable pointer are imported as Optional pointer, so you need ?.
You could have the callback inline where you call glfwSetErrorCallback:
glfwSetErrorCallback { (error, description) in
//
}
Or, use a closure stored in a variable:
let callback: GLFWerrorfun = { (error, description) in
//
}
glfwSetErrorCallback(callback)
You can see how this typedef is bridged to Swift by Option + Left Clicking on the symbol:
In this case I didn't have the actual GLFW headers, so I just dropped the declaration in a Bridging Header. Your generated interface may show more information.
Consider the following stack implementation in go:
package main
import "fmt"
var a [10]int
var top int = -1
func main() {
printStack()
push(1)
printStack()
push(23)
printStack()
pop()
push(2)
printStack()
println("Top element is", getTop)
}
func push(x int) {
top += 1
a[top] = x
}
func pop() {
top -= 1
}
func getTop() int {
return a[top]
}
func printStack() {
fmt.Println(top+1, "Stack: ", a, "Top", getTop)
}
Questions:
When I use println("Top element is", getTop), it prints out memory address 0x193928 but when I call println("Top element is", getTop()), it returns 2. Returning 2 makes sense but I don't understand why its returning memory address? shouldn't call getTop without brackets be invalid?
It seems that you can't have variable & functions with same name in golang. is that correct assumption to make?
Play: https://play.golang.org/p/vvOGG296gr
You can pass your function as a var, for example: https://play.golang.org/p/wzGVtsEFQk . So getTop is a "function pointer", which explains the address being printed
Explained by #1: if it is declared in the same scope, your var name and function name collide
Delegates in D seem to capture local values by reference, which has weird side effects when creating closures in loops: In the end, you have n closures with equal context pointers. Take this example:
import std.stdio;
alias Closure = void delegate();
Closure[] closures;
void main(){
foreach(a; ["Je", "Tu", "En", "Oui", "Na"])
closures ~= {write(a);};
foreach(c; closures)
c();
writeln(" batman");
}
This prints NaNaNaNaNa batman.
Is this expected behavior? If so, how would I work around it so it properly prints all array elements?
It gets even funnier when using a for-loop with counter variable, in the end i is equal to the array size, and when using closures[i] in the delegate it throws an out of bounds error.
Yes, that is expected behavior (EDIT: ...it is actually an oldstanding known bug! https://issues.dlang.org/show_bug.cgi?id=2043 so only expected in that it happens and you can easily get used to it, but it actually isn't supposed to happen) and is also seen in other languages, so this is a good principle to know.
To get a separate copy of the variables in the loop, call another function that returns the delegate you want to store, passing the loop variable to it.
import std.stdio;
alias Clojure = void delegate();
Clojure[] clojures;
void main(){
foreach(a; ["Je", "Tu", "En", "Oui", "Na"])
clojures ~= ((b) => { write(b);})(a);
foreach(c; clojures)
c();
writeln(" batman");
}
The clojures ~= ((b) => { write(b);})(a); line has changed: that defines a quick delegate that returns the delegate. The extra function-returning-function closes over a snapshot of the loop state, instead of just the function-level local variables.
I use this a lot in JavaScript too:
function makeHandler(item) {
return function() {
// use item here
};
}
var array = [1,2,3];
for(var I = 0; I < array.length; I++)
foo.addEventListener("click", makeHandler(array[I]));
This is the same thing done for the same reason as the D, just in different syntax, and broken up into bigger functions instead of trying to do it as a one-liner.
We define a function which returns a function that uses the captured loop variable. At the usage point, we call the one function which returns the delegate that is stored for later.
In the shorthand D syntax, ((b) => { write(b);})(a);, the (b) => ... is the makeHandler function seen in the javascript. The { write(b); } it returns is shorthand for return function() { ... } in JS (BTW that same JS syntax basically works ion D too, you can write a longhand thing with the delegate or function keywords. D's function doesn't capture variables though, delegate does that..)
Then, finally, the parenthesis around it and the (a) at the end is just to call the function. The stuff inside is the same as makeHandler, the (...)(a) calls it; it is makeHadndler(a).
I'm playing around with wrapping FUSE with Go. However I've come stuck with how to deal with struct fuse_operations. I can't seem to expose the operations struct by declaring type Operations C.struct_fuse_operations as the members are lower case, and my pure-Go sources would have to use C-hackery to set the members anyway. My first error in this case is "can't set getattr" in what looks to be the Go equivalent of a default copy constructor. My next attempt is to expose an interface that expects GetAttr, ReadLink etc, and then generate C.struct_fuse_operations and bind the function pointers to closures that call the given interface.
This is what I've got (explanation continues after code):
package fuse
// #include <fuse.h>
// #include <stdlib.h>
import "C"
import (
//"fmt"
"os"
"unsafe"
)
type Operations interface {
GetAttr(string, *os.FileInfo) int
}
func Main(args []string, ops Operations) int {
argv := make([]*C.char, len(args) + 1)
for i, s := range args {
p := C.CString(s)
defer C.free(unsafe.Pointer(p))
argv[i] = p
}
cop := new(C.struct_fuse_operations)
cop.getattr = func(*C.char, *C.struct_stat) int {}
argc := C.int(len(args))
return int(C.fuse_main_real(argc, &argv[0], cop, C.size_t(unsafe.Sizeof(cop)), nil))
}
package main
import (
"fmt"
"fuse"
"os"
)
type CpfsOps struct {
a int
}
func (me *CpfsOps) GetAttr(string, *os.FileInfo) int {
return -1;
}
func main() {
fmt.Println(os.Args)
ops := &CpfsOps{}
fmt.Println("fuse main returned", fuse.Main(os.Args, ops))
}
This gives the following error:
fuse.go:21[fuse.cgo1.go:23]: cannot use func literal (type func(*_Ctype_char, *_Ctype_struct_stat) int) as type *[0]uint8 in assignment
I'm not sure what to pass to these members of C.struct_fuse_operations, and I've seen mention in a few places it's not possible to call from C back into Go code.
If it is possible, what should I do? How can I provide the "default" values for interface functions that acts as though the corresponding C.struct_fuse_operations member is set to NULL?
http://cheesesun.blogspot.com/2010/04/callbacks-in-cgo.html describes a general - if somewhat convoluted - technique. http://groups.google.com/group/golang-nuts/browse_thread/thread/abd0e30dafdbf297?tvc=2&pli=1 describes the problem.
I suspect that if you want to handle the function pointers as anything other than uintptrs, you'll have to hack on cgo.