using runtime cgo.Handle passing struct types

198 views
Skip to first unread message

Pavan

unread,
May 15, 2024, 1:36:39 AMMay 15
to golang-nuts
Hi, 
I need to pass value of struct type, which has C strings and functions to C function as void* argument.  C layer would provide this struct type data back to go function. Below is the sample program. It panics if the handle used is returned from getH function. It works fine if the handle is global. Can the handle be dynamically returned from getH and make it work. Please correct if i missed something..



package main

/*
struct dt {
  void *context;
};
typedef struct dt dt;

extern void MyGoPrint(void *context);
static inline void myprint(struct dt *a1) {
    MyGoPrint(a1->context);
}
*/
import "C"
import (
"context"
"runtime/cgo"
"unsafe"
)

//export MyGoPrint
func MyGoPrint(context unsafe.Pointer) {
h := *(*cgo.Handle)(context)
val := h.Value().(accessTokenCB)
println(val.id)
h.Delete()
}

type At struct {
Tok string
}

type accessTokenCB struct {
ctx         context.Context
callback    func(context.Context, *At) error
id          uint64
ctoken      *C.char
cprivateKey *C.char
}

func getH() cgo.Handle {
cb := func(ctx context.Context, tok *At) error {
tok.Tok = "123"
return nil
}
val := accessTokenCB{callback: cb, ctx: context.Background(), id: 32, ctoken: nil, cprivateKey: nil}
h := cgo.NewHandle(val)
return h

}

var h cgo.Handle

func main() {
var h cgo.Handle // commenting this line runs the program successfully else it panics. (cgo argument has Go pointer to unpinned Go pointer)
h = getH()
var poolCt C.dt
poolCt.context = unsafe.Pointer(&h)
C.myprint(&poolCt)
// Output: 32
}

Ian Lance Taylor

unread,
May 15, 2024, 7:58:55 PMMay 15
to Pavan, golang-nuts
You aren't following the pattern shown at
https://pkg.go.dev/runtime/cgo#Handle. Pass the cgo.Handle value to C
code, not the address of the cgo.Handle value. Catch the cgo.Handle
value as a uintptr_t in C. The point of using cgo.Handle is to avoid
difficulties passing pointers between Go and C. When you pass a
pointer to a cgo.Handle, you just get those difficulties back again.

Ian

Pavan

unread,
May 16, 2024, 3:56:42 AMMay 16
to golang-nuts
Thanks . Yes it works when C API takes uintptr_t. In my case, the C API expects void * which i can not change, so I was trying to make it work with the variant example stated above. 

Ian Lance Taylor

unread,
May 18, 2024, 7:07:31 PMMay 18
to Pavan, golang-nuts
On Thu, May 16, 2024 at 12:57 AM Pavan <sudars...@gmail.com> wrote:
>
> Thanks . Yes it works when C API takes uintptr_t. In my case, the C API expects void * which i can not change, so I was trying to make it work with the variant example stated above.

In C, unlike Go, you can convert between void* and uintptr_t. When
using cgo, one approach is a little wrapper function in the cgo
comment that takes a uintptr_t and calls the real function with a
conversion to void*.

Ian
> --
> 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.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/39afbb8b-8361-40a2-967f-0f462ef45994n%40googlegroups.com.

Sudarshan Soma

unread,
May 19, 2024, 2:37:23 AMMay 19
to Ian Lance Taylor, golang-nuts
Thanks Ian, Yes i followed a similar approach and it's working fine..
Reply all
Reply to author
Forward
0 new messages