场景如下
package mainimport "fmt"/*#define JUMP_PARENT 0x00#define JUMP_CHILD 0xA0#define _GNU_SOURCE#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sched.h>#include <setjmp.h>char child_stack[4096] __attribute__ ((aligned(16)));int child_func(void *arg) {jmp_buf* env = (jmp_buf*)arg;longjmp(*env, JUMP_CHILD);}__attribute__((constructor)) void init(void) {printf("init...\n");jmp_buf env;switch(setjmp(env)) {case JUMP_PARENT:printf("JUMP_PARENT\n");int child_pid = clone(child_func, child_stack, CLONE_PARENT, env);printf("CHILD_PID: %d\n", child_pid);exit(0);case JUMP_CHILD:printf("JUMP_CHILD\n");return;}}*/import "C"func main() {fmt.Println("main...")}
使用Cgo在进入Go runtime之前先执行一段C代码。正常情况下child进程应该打印完JUMP_CHILD后开始执行main函数。
但是在执行完init函数后,无法回到main函数,child进程会阻塞在一个地方。
[root@localhost cgo-practive]# go build .[root@localhost cgo-practive]# lscgo-practive main.go[root@localhost cgo-practive]# ./cgo-practiveinit...JUMP_PARENTCHILD_PID: 14348[root@localhost cgo-practive]# JUMP_CHILD
使用GDB查看stack:
(gdb) list28 exit(0);29 case JUMP_CHILD:30 printf("JUMP_CHILD\n");31 return;32 }33 }34 */35 import "C"3637 func main() {(gdb) info stack#0 0x00007efd6f9684ed in __lll_lock_wait () from /lib64/libpthread.so.0#1 0x00007efd6f966170 in pthread_cond_broadcast@@GLIBC_2.3.2 () from /lib64/libpthread.so.0#2 0x00000000004862e6 in x_cgo_notify_runtime_init_done (dummy=<optimized out>) at gcc_libinit.c:69#3 0x0000000000451070 in runtime.asmcgocall () at /usr/local/go/src/runtime/asm_amd64.s:637#4 0x00007ffdec4b5c30 in ?? ()#5 0x000000000044efd1 in runtime.malg.func1 () at /usr/local/go/src/runtime/proc.go:3289#6 0x000000000044f886 in runtime.systemstack () at /usr/local/go/src/runtime/asm_amd64.s:351#7 0x000000000042c5b0 in ?? () at /usr/local/go/src/runtime/proc.go:1146#8 0x000000000044f719 in runtime.rt0_go () at /usr/local/go/src/runtime/asm_amd64.s:201#9 0x0000000000000000 in ?? ()
查看Cgo的源码:
// /usr/local/Cellar/go/1.11.5/libexec/src/runtime/cgo/gcc_libinit.cvoidx_cgo_notify_runtime_init_done(void* dummy) {pthread_mutex_lock(&runtime_init_mu);runtime_init_done = 1;pthread_cond_broadcast(&runtime_init_cond); // 阻塞在此处pthread_mutex_unlock(&runtime_init_mu);}
