Go callbacks from C

984 views
Skip to first unread message

Bryan Matsuo

unread,
Mar 29, 2016, 9:53:37 PM3/29/16
to golang-nuts
I have been a little confused since the new cgo pointer argument restrictions for go1.6 were announced about what the final verdict was regarding passing functions pointers to C, so they may be used as a callback in an event-driven system. For example, I understand that GUI toolkits like GTK require many callbacks to be set for handling to user events.

Is it possible for these systems to be integrated in Go? When is it acceptable to pass a function pointer to C, and for C to store that pointer for future use?

Naively it seems intuitive to me that passing closures can trivialaly violate the pointer passing restrictions (by closing over variables pointing to Go memory). But if I have exported a static function from Go (exported to C using `//export myFunc`). Then can I pass that a pointer to the exported function to cgo? A slight variant of this question would be, can I pass a pointer to a C function which calls a static Go function that was exported by my application?

Of course C is not supposed to store Go pointers according to the new restrictions, so really it is just unclear to me when pointers to static functions are actually "Go pointers" (using the specific terminology of the cgo specification, pointers pointing to memory allocated/managed by the Go runtime?).

I would really appreciate it if anyone could help shed light on this for me. Thanks for the help.

Cheers

Ian Lance Taylor

unread,
Mar 29, 2016, 10:38:53 PM3/29/16
to Bryan Matsuo, golang-nuts
In general, you can not pass a func value to C.

That said, it is fine to pass an exported function (with a `//export
NAME` comment) to C. And it is of course fine to pass a C function
pointer to C (accessing the C function as `C.CNAME`) and that C
function pointer can do whatever it likes, including calling a Go
function.

It is also fine to store a func value in a map, and pass the map index
to C, have the C function call a known Go function, and have that Go
function look up the index in the map and call the function. You can
see a simple version of this in the Go source code in
misc/cgo/test/callback.go.

Ian

Bryan Matsuo

unread,
Mar 29, 2016, 10:54:08 PM3/29/16
to golang-nuts, bryan....@gmail.com
Thank you so much for the clarification, Ian. This has helped me greatly. Though you never explicitly said that C can indefinitely store a pointer an exported static Go func (even after the cgo function call which passed it has returned). But from what you did say, it seems that is OK. Right?

Indeed I have used a map for dynamic dispatch of callbacks from C before, though iirc my implementation converted uintptr map keys (which were not real pointers) into a void* (unsafe.Pointer) at the cgo call site.

However, in a different case the callback function is in a very hot code path and dynamic dispatch is a pretty big performance killer. After discussing it with the maintainers of the C library we concluded that the direction of using //export and or writing/passing C functions was indeed the only reasonable way to make use of the functionality from a Go application.

Thanks again for all the help.

Cheers

Ian Lance Taylor

unread,
Mar 29, 2016, 11:03:27 PM3/29/16
to Bryan Matsuo, golang-nuts
On Tue, Mar 29, 2016 at 7:54 PM, Bryan Matsuo <bryan....@gmail.com> wrote:
> Thank you so much for the clarification, Ian. This has helped me greatly.
> Though you never explicitly said that C can indefinitely store a pointer an
> exported static Go func (even after the cgo function call which passed it
> has returned). But from what you did say, it seems that is OK. Right?

Yes, I think we pretty much have to assume that an exported function
can not move.

It now occurs to me, though, that to be fully safe for a callback you
should refer to the exported name using `C.NAME`. That will pick up
the version of the function callable directly from C.

Ian

Bryan Matsuo

unread,
Mar 29, 2016, 11:07:07 PM3/29/16
to golang-nuts, bryan....@gmail.com
Ah! It hadn't occurred to me that C.NAME would be defined in the cgo source file. But yes, that makes sense :)

Thanks again, Ian!
Reply all
Reply to author
Forward
0 new messages