export struct method to C-code as callback (cgo-related)

802 views
Skip to first unread message

and...@breakoutcommerce.com

unread,
Jun 17, 2016, 10:32:53 AM6/17/16
to golang-nuts
Hello,

Could you guys please help me. 

I can't find how to export method function which belongs to some go-struct to C-code (cgo part) as callback. I know how to export simple function which not belongs to any type and use it as callback for C-function, but is it possibly to export method of concrete struct instance? since I need additional info when callback will be called from C-code. As example what I'm trying to explain:

// extern int goCallbackHandler(int, int);
//
// static int doAdd(int a, int b) {
//     return goCallbackHandler(a, b);
// }
import "C"

type A struct {
... some data which used to process callback from C-side
}

// export cgo_callback
func (a *A) cgo_callback(...){ <-----main problem here
}

main {
   C.doAdd(...)
}

I can't modify c-side - I have only compiled library, so I don't know how to identify which instance of struct should be used to properly process C-call of go-side callback.

Thanks,
Andrey

andrey mirtchovski

unread,
Jun 17, 2016, 11:45:02 AM6/17/16
to and...@breakoutcommerce.com, golang-nuts
I doubt that the cgo_callback method has the type the C library
desires. from https://golang.org/ref/spec#Method_declarations:

The type of a method is the type of a function with the
receiver as first argument.

I.e., the type of cgo_callback is func(a *A, ...).

The solution is to have a proper C function callback with the correct
type signature expected by the C side and resolve the correct (a *A)
to call inside the callback. Something like:

//export _callbackfunc
func _callbackfunc(fd C.int, context unsafe.Pointer) C._error_t {
a := findA(context) // resolves the correct *A based on the context
return C._error_t(a.Callback(int(fd)))
> --
> You received this message because you are subscribed to the Google Groups
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to golang-nuts...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Andrey Salnikov

unread,
Jun 17, 2016, 3:18:56 PM6/17/16
to golang-nuts, and...@breakoutcommerce.com
Hi Andrey! thanks for answer!

But actually I don't understand how to receive context inside callback from C-code. May be I'm wrong here but as I understand you mean that I have to identify instance of *A using callback parameters received from C-side. But what about if I'll receive only sum of two arguments a+b, I don't know the result until I'll receive it from C-side and I don't know which instance should be called if callback receive ex: 10 - should it be an instance which handle 5+5 or another one used for 2+8.

Thanks again! Sorry if I don't understand you correctly.

Ian Lance Taylor

unread,
Jun 17, 2016, 4:02:40 PM6/17/16
to Andrey Salnikov, golang-nuts
On Fri, Jun 17, 2016 at 12:18 PM, Andrey Salnikov
<and...@breakoutcommerce.com> wrote:
>
> But actually I don't understand how to receive context inside callback from
> C-code. May be I'm wrong here but as I understand you mean that I have to
> identify instance of *A using callback parameters received from C-side. But
> what about if I'll receive only sum of two arguments a+b, I don't know the
> result until I'll receive it from C-side and I don't know which instance
> should be called if callback receive ex: 10 - should it be an instance which
> handle 5+5 or another one used for 2+8.

If I understand you correctly, you are saying that you have a *A on
the Go side, and you want it to call C code, and you want the C code
to call back into Go, and when you call back you want to have the same
*A you started with.

If that is accurate, then one way or another you need pass the *A from
Go to C. There is no magic way that you can call into C and then back
to Go and somehow know which *A you had to begin with, any more than
you could do it if you called from Go to Go without passing the *A.

Ian

andrey mirtchovski

unread,
Jun 17, 2016, 6:01:02 PM6/17/16
to Ian Lance Taylor, Andrey Salnikov, golang-nuts
If the library made no provision for the caller to give a unique token
which would help to identify it in the callback then that library does
not expect to have more than one caller-and-callback in play at any
one time, or, even worse, expects you to arrange some thread-local
storage in the caller to resolve the correct one. Without knowing more
about the library there isn't much to say, except that you should be
able to serialize all calls into it on the Go side, leaving only one
possible *A with an outstanding function call at a time. This is going
to be slow.

Andrey Salnikov

unread,
Jun 18, 2016, 5:05:56 AM6/18/16
to golang-nuts
Thank you all guys for your replies! it helps me to understand how it works! really helpful! :)
Reply all
Reply to author
Forward
0 new messages