cgo callbacks

802 views
Skip to first unread message

Ian Lance Taylor

unread,
Apr 9, 2010, 5:45:05 PM4/9/10
to golan...@googlegroups.com
I've added a new facility to the cgo program: you can now mark a Go
function as callable from C. To do this, write a comment

//export NAME

as part of the comments which appear immediately before the function.
Your C code can then call the function under the specified name.

When any //export comments appear in the cgo input, cgo will create
two new files: _cgo_export.h and _cgo_export.c. The .h file declares
the Go functions in C syntax, and the intent is that your C code will
#include it in order to see the declarations that it can call. The
_cgo_export.c file contains the function wrappers; the file must be
compiled with gcc and linked with your C code.

There is an example in misc/cgo/life.


I implemented this as part of my ongoing work adding support for Go to
SWIG. Implementing SWIG's director feature requires the ability to
call back from C/C++ to Go, so I wrote that. I added support to cgo
in order to test the new feature.

Ian

Ostsol

unread,
Apr 10, 2010, 12:29:28 PM4/10/10
to golang-nuts
On Apr 9, 3:45 pm, Ian Lance Taylor <i...@google.com> wrote:
> When any //export comments appear in the cgo input, cgo will create
> two new files: _cgo_export.h and _cgo_export.c.  The .h file declares
> the Go functions in C syntax, and the intent is that your C code will
> #include it in order to see the declarations that it can call.  The
> _cgo_export.c file contains the function wrappers; the file must be
> compiled with gcc and linked with your C code.

So this means that one cannot simply pass a pointer to a Go function
to C? Based on this I wrote a test program that involved a wrapper
written in C (and using the new export functionality), that is passed
to a C function in another library, all of which is called via a
function defined in the comments above 'import "C"':

package callback

// #include "callgo.h"
// #include "funcwrap.h"
// void _call_go_add() {
// call_go(&wrap_GoAdd);
// }
import "C"

func Run() {
C._call_go_add()
}

//export GoAdd
func GoAdd(a, b int) int {
return a + b
}

Quite cumbersome. . . Will we be able to pass a Go function directly
in the future?

-Daniel

Ian Lance Taylor

unread,
Apr 12, 2010, 12:57:15 PM4/12/10
to Ostsol, golang-nuts
Ostsol <ost...@gmail.com> writes:

> On Apr 9, 3:45 pm, Ian Lance Taylor <i...@google.com> wrote:
>> When any //export comments appear in the cgo input, cgo will create
>> two new files: _cgo_export.h and _cgo_export.c.  The .h file declares
>> the Go functions in C syntax, and the intent is that your C code will
>> #include it in order to see the declarations that it can call.  The
>> _cgo_export.c file contains the function wrappers; the file must be
>> compiled with gcc and linked with your C code.
>
> So this means that one cannot simply pass a pointer to a Go function
> to C?

That is correct.

> Quite cumbersome. . . Will we be able to pass a Go function directly
> in the future?

6g/8g and gcc use different calling conventions and the functions run
on different stacks. That means that passing a function pointer
either from Go to C or from C to Go will always require wrapping at
some level. It's possible that cgo could be taught to create that
wrapping automatically. I don't plan to work on that myself, but it
could be an interesting project for somebody else.

Ian

Tony Worm

unread,
Jun 11, 2012, 1:10:59 PM6/11/12
to golan...@googlegroups.com, Ostsol
Is this still the convention for callbacks from C to Go

for example I need to pass function pointers to a nonlinear least squares solver:

extern int dlevmar_der(
      void (*func)(double *p, double *hx, int m, int n, void *adata),
      void (*jacf)(double *p, double *j, int m, int n, void *adata),
      double *p, double *x, int m, int n, int itmax, double *opts,
      double *info, double *work, double *covar, void *adata);


 /* Rosenbrock function */
    m=2; n=2;
    p[0]=-1.2; p[1]=1.0;
    for(i=0; i<n; i++) x[i]=0.0;
    ret=dlevmar_der(ros, jacros, p, x, m, n, 1000, opts, info, NULL, NULL, NULL); // with analytic Jacobian


these are where I'd like to call Go functions: (for analytic expression evaluation on some data points)

void ros(double *p, double *x, int m, int n, void *data)
{
register int i;

  for(i=0; i<n; ++i)
    x[i]=((1.0-p[0])*(1.0-p[0]) + ROSD*(p[1]-p[0]*p[0])*(p[1]-p[0]*p[0]));
}

void jacros(double *p, double *jac, int m, int n, void *data)
{
register int i, j;

  for(i=j=0; i<n; ++i){
    jac[j++]=(-2 + 2*p[0]-4*ROSD*(p[1]-p[0]*p[0])*p[0]);
    jac[j++]=(2*ROSD*(p[1]-p[0]*p[0]));
  }
}


On Monday, April 12, 2010 12:57:15 PM UTC-4, Ian Lance Taylor wrote:
Ostsol writes:

> On Apr 9, 3:45 pm, Ian Lance Taylor wrote:

Kyle Lemons

unread,
Jun 11, 2012, 5:57:29 PM6/11/12
to Tony Worm, golan...@googlegroups.com, Ostsol
You can //export a Go function to be callable from C, and these can be used in callbacks that run from a go-owned thread.  Be aware that these function calls can be something like 50x slower than a normal function call last time I benchmarked.

Tony Worm

unread,
Jun 11, 2012, 6:08:26 PM6/11/12
to golan...@googlegroups.com, Tony Worm, Ostsol
would this 50x be just for the callback?

I am thinking of something like the comparison of the following:

big_loop {
    data[i] = callback()
}

versus

callback() {
  big_loop {
     data = eval()
  }
}

On Monday, June 11, 2012 5:57:29 PM UTC-4, Kyle Lemons wrote:
You can //export a Go function to be callable from C, and these can be used in callbacks that run from a go-owned thread.  Be aware that these function calls can be something like 50x slower than a normal function call last time I benchmarked.

Kyle Lemons

unread,
Jun 11, 2012, 6:10:37 PM6/11/12
to Tony Worm, golan...@googlegroups.com, Ostsol
When you call from C into Go, there's a lot of work that goes on in the runtime (from my understanding) beyond simply jumping to a new location in memory.  The overhead is for the function call from C into Go.

On Mon, Jun 11, 2012 at 3:08 PM, Tony Worm <verd...@gmail.com> wrote:
would this 50x be just for the callback?

I am thinking of something like the comparison of the following:

big_loop {
    data[i] = callback()
}

versus

callback() {
  big_loop {
     data = eval()
  }
}

The second would do a lot to amortize the cost of the callback, yes.
Reply all
Reply to author
Forward
0 new messages