David Chou @ Golang Taipei / Crescendo Lab
CC-BY-SA-3.0-TW
david74.chou @ gmail
david74.chou @ facebook
david74chou @ telegram
package main
/*
#include <stdlib.h>
*/
import "C"
import "fmt"
func Random() int {
r := C.random() // r is C.long
return int(r)
}
func Seed(i int) {
C.srandom(C.uint(i))
}
func main() {
Seed(0)
for i := 0; i < 10; i++ {
fmt.Printf("rand(%d): %d\n", i, Random())
}
}
// #cgo CFLAGS: -DPNG_DEBUG=1
// #cgo amd64 386 CFLAGS: -DX86=1
// #cgo LDFLAGS: -lpng
// #include <png.h>
import "C"
// #cgo pkg-config: png
// #cgo CFLAGS: -DPNG_DEBUG=1
// #include <png.h>
import "C"// #cgo LDFLAGS: -L${SRCDIR}/libs -lfoo
import "C"package native
/*
#cgo CFLAGS: -I${SRCDIR}/includes/
#cgo windows LDFLAGS: ${SRCDIR}/libs/winlibz.a
#cgo linux LDFLAGS: ${SRCDIR}/libs/linuxlibz.a
#cgo darwin LDFLAGS: ${SRCDIR}/libs/darwinlibz.a
*/
import "C".
├── cgo.go
├── libs
│ ├── darwinlibz.a
│ ├── linuxlibz.a
│ └── winlibz.a
└── includes
├── zconf.h
└── zlib.hfunc C.CString(string) *C.char
func C.CBytes([]byte) unsafe.Pointer
func C.free(unsafe.Pointer)func C.GoString(*C.char) string
func C.GoStringN(*C.char, C.int) string
func C.GoBytes(unsafe.Pointer, C.int) []byte/*
#include <stdlib.h>
char *get_string() {
return strdup("hello from C");
}
void release_string(char *s) {
free(s);
}
*/
import "C"
func main() {
cs := C.CString("Hello from go\n")
C.puts(cs)
C.free(unsafe.Pointer(cs))
cs = C.get_string()
gs := C.GoString(cs)
fmt.Printf("%s\n", gs)
C.release_string(cs)
}
Cgo is not Go - Rob Pike
//#include <unistd.h>
//void foo() { }
import "C"
//go:noinline
func foo() {}
func CallCgo(n int) {
for i := 0; i < n; i++ {
C.foo()
}
}
func CallGo(n int) {
for i := 0; i < n; i++ {
foo()
}
}foos := []C.struct_Foo{
{ a: C.int(1), b: C.int(2) },
{ a: C.int(3), b: C.int(4) },
}
C.pass_array((*C.struct_Foo)(unsafe.Pointer(&foos[0])), C.int(len(foos)))go build -ldflags='-extldflags "-static"'d := C.GoBytes([]byte{...})
C.foo(d) // <- if foo() takes the ownership
// C.free(d)
func Foo(payload []byte) {
p := (*C.uchar)(unsafe.Pointer(&payload[0]))
size := C.int(len(payload))
C.foo(p, size)
}
func Foo(str string) {
strHdr := (*reflect.StringHeader)(unsafe.Pointer(&str))
p := (*C.char)(unsafe.Pointer(strHdr.Data))
size := C.int(len(payload))
C.foo(p, size)
}
ZeroCopy (Go => C): []bytes
ZeroCopy (Go => C): string
// before 1.17
func toByteSlize(data unsafe.Pointer, size int) []byte {
return (*[1 << 30]byte)(data)[:size:size]
}
// after 1.17
func toByteSlize(data unsafe.Pointer, size int) []byte {
return unsafe.Slze(data, size)
}
ZeroCopy (C => Go): []bytes
func main() {
var wg sync.WaitGroup
wg.Add(1000)
for i := 0; i < 1000; i++ {
go func() {
time.Sleep(100 * time.Second)
wg.Done()
}()
}
wg.Wait()
}
func main() {
var wg sync.WaitGroup
wg.Add(1000)
for i := 0; i < 1000; i++ {
go func() {
time.Sleep(100 * time.Second)
wg.Done()
}()
}
wg.Wait()
}
// use 13 threads
// use 1004 threads
// Call from Go to C.
func cgocall(fn, arg unsafe.Pointer) int32 {
...
// Announce we are entering a system call
// so that the scheduler knows to create another
// M to run goroutines while we are in the
// foreign code.
//
entersyscall()
errno := asmcgocall(fn, arg)
exitsyscall()
...
}//export Add
func Add(arg1, arg2 int) int {...}extern int Add(int arg1, int arg2);func (c *MyCounter) Add(i int) {
c.count += i
}var mu sync.Mutex
var index int
var fns = make(map[int]func(int))
func register(fn func(int)) int {
mu.Lock()
defer mu.Unlock()
index++
for fns[index] != nil {
index++
}
fns[index] = fn
return index
}
func lookup(i int) func(int) { ... }
func unregister(i int) { ... }/*
extern void go_callback_int(
int foo,
int p1);
static inline void CallMyFunction(int foo) {
go_callback_int(foo, 5);
}
*/
import "C"
//export go_callback_int
func go_callback_int(idx C.int, p1 C.int) {
fn := lookup(int(idx))
fn(int(p1))
}
func (c *MyCounter) Add(i int) { ... }
func main() {
c := &MyCounter{count: 0}
i := register(c.Add)
C.CallMyFunction(C.int(i))
unregister(i)
}/*
extern void go_callback_int(
uintptr_t h,
int p1);
static inline void CallMyFunction(uintptr_t h) {
go_callback_int(h, 5);
}
*/
import "C"
//export go_callback_int
func go_callback_int(h C.uintptr_t, p C.int){
v := cgo.Handle(h).Value()
fn := v.(func(C.int))
fn(p)
}
func (c *MyCounter) Add(i int) { ... }
func main() {
c := &MyCounter{count: 0}
i := register(c.Add)
h := cgo.NewHandle(c.Add)
C.CallMyFunction(C.uintptr_t(h))
h.Delete()
}We are hiring now! Feel free to chat with us in Room TR 312 (研揚大樓 312室).