I'm not sure if the Go pointer proposal has already been implemented,
but under the proposed restrictions allocating the callback struct in Go
and passing that pointer to a C function which keeps it after returning
is not allowed.
This patch allocates the struct in C and passes the pointer from Go to
C, which is fine.
--- /dev/null
+// Copyright © 2015, 2016 Hraban Luyat <hraban@0brg.net>
+//
+// License for use of this code is detailed in the LICENSE file
+
+// Allocate callback struct in C to ensure it's not managed by the Go GC. This
+// plays nice with the CGo rules and avoids any confusion.
+
+#include <opusfile.h>
+
+// Defined in Go. Uses the same signature as Go, no need for proxy function.
+int go_readcallback(void *p, unsigned char *buf, int nbytes);
+
+// Allocated once, never moved. Pointer to this is safe for passing around
+// between Go and C.
+struct OpusFileCallbacks callbacks = {
+ .read = go_readcallback,
+};
#include <opusfile.h>
#include <string.h>
-// Uses the same signature as Go, no need for proxy
-int go_readcallback(void *p, unsigned char *buf, int nbytes);
+extern struct OpusFileCallbacks callbacks;
*/
import "C"
return C.int(n)
}
-var callbacks = C.struct_OpusFileCallbacks{
- read: C.op_read_func(C.go_readcallback),
- seek: nil,
- tell: nil,
- close: nil,
-}
-
func NewStream(read io.Reader) (*Stream, error) {
var s Stream
err := s.Init(read)
oggfile := C.op_open_callbacks(
// "C code may not keep a copy of a Go pointer after the call returns."
unsafe.Pointer(s.id),
- &callbacks,
+ &C.callbacks,
nil,
0,
&errno)