英文:
How to debug C-shared library (written in Go) - it hangs on net call
问题
使用http.Post()的Go代码。如果我构建exe,一切正常。如果我构建C共享库-buildmode=c-shared,它会在https.Post()上挂起。
我尝试了strace -fp PID:
futex(0x7f618b2c1cd0, FUTEX_WAKE, 1) = 0
futex(0xc820022110, FUTEX_WAIT, 0, NULL
我尝试添加分析器:
http.ListenAndServe("localhost:6060", nil)
http.Post()
但是它仍然在http.Post上挂起,分析器也被阻塞了(它在监听,但是没有从6060端口返回响应)。我发送了SIGQUIT信号-堆栈跟踪:
SIGQUIT: quit
PC=0x7f0cad5c9081 m=1
goroutine 0 [idle]:
runtime.futex(0xc820022110, 0x0, 0x0, 0x0, 0x7f0c00000000, 0x7f0cad577879, 0x0, 0x0, 0x7f0cad577ae8, 0xc820022110, ...)
/usr/local/go/src/runtime/sys_linux_amd64.s:288 +0x21
runtime.futexsleep(0xc820022110, 0xc800000000, 0xffffffffffffffff)
/usr/local/go/src/runtime/os1_linux.go:39 +0x53
runtime.notesleep(0xc820022110)
/usr/local/go/src/runtime/lock_futex.go:142 +0xa8
runtime.stoplockedm()
/usr/local/go/src/runtime/proc1.go:1268 +0xb2
runtime.schedule()
/usr/local/go/src/runtime/proc1.go:1590 +0x72
runtime.park_m(0xc820000600)
/usr/local/go/src/runtime/proc1.go:1698 +0x191
runtime.mcall(0x7f0cad5c722a)
/usr/local/go/src/runtime/asm_amd64.s:204 +0x53
goroutine 17 [IO wait, locked to thread]:
runtime.gopark(0x7f0cada4a878, 0x7f0ca594b198, 0x7f0cad993b20, 0x7, 0x1b, 0x5)
/usr/local/go/src/runtime/proc.go:185 +0x169 fp=0xc820041868 sp=0xc820041840
runtime.netpollblock(0x7f0ca594b170, 0x72, 0x7f0cac21e050)
/usr/local/go/src/runtime/netpoll.go:338 +0x160 fp=0xc8200418b0 sp=0xc820041868
net.runtime_pollWait(0x7f0ca594b170, 0x72, 0xc82000a1c0)
/usr/local/go/src/runtime/netpoll.go:157 +0x62 fp=0xc8200418d0 sp=0xc8200418b0
net.(*pollDesc).Wait(0xc82011c140, 0x72, 0x0, 0x0)
/usr/local/go/src/net/fd_poll_runtime.go:73 +0x3c fp=0xc8200418f0 sp=0xc8200418d0
net.(*pollDesc).WaitRead(0xc82011c140, 0x0, 0x0)
/usr/local/go/src/net/fd_poll_runtime.go:78 +0x38 fp=0xc820041918 sp=0xc8200418f0
net.(*netFD).accept(0xc82011c0e0, 0x0, 0x7f0ca594b268, 0xc8200b4440)
/usr/local/go/src/net/fd_unix.go:408 +0x27e fp=0xc820041a18 sp=0xc820041918
net.(*TCPListener).AcceptTCP(0xc8200b8050, 0xc820041ab0, 0x0, 0x0)
/usr/local/go/src/net/tcpsock_posix.go:254 +0x4f fp=0xc820041a78 sp=0xc820041a18
net/http.tcpKeepAliveListener.Accept(0xc8200b8050, 0x0, 0x0, 0x0, 0x0)
/usr/local/go/src/net/http/server.go:2135 +0x43 fp=0xc820041ab0 sp=0xc820041a78
net/http.(*Server).Serve(0xc8200b20c0, 0x7f0ca594b230, 0xc8200b8050, 0x0, 0x0)
/usr/local/go/src/net/http/server.go:1887 +0xb5 fp=0xc820041b98 sp=0xc820041ab0
net/http.(*Server).ListenAndServe(0xc8200b20c0, 0x0, 0x0)
/usr/local/go/src/net/http/server.go:1877 +0x138 fp=0xc820041c28 sp=0xc820041b98
net/http.ListenAndServe(0x7f0cad9a6ae0, 0xe, 0x0, 0x0, 0x0, 0x0)
/usr/local/go/src/net/http/server.go:1967 +0x91 fp=0xc820041c50 sp=0xc820041c28
main.Code(0xc8201122a0, 0x0, 0x0, 0x0, 0x0)
/opt/gopath/src/github.com/jangaraj/zabbix-module/zabbix_module.go:152 +0x94 fp=0xc820041d58 sp=0xc820041c50
github.com/cavaliercoder/g2z.route_item(0x7ffe7bc803e0, 0x7ffe7bc80c90, 0x0)
/opt/gopath/src/github.com/cavaliercoder/g2z/router.go:65 +0xc2a fp=0xc820041ed0 sp=0xc820041d58
runtime.call32(0x0, 0x7ffe7bc802d8, 0x7ffe7bc80360, 0x18)
/usr/local/go/src/runtime/asm_amd64.s:437 +0x40 fp=0xc820041ef8 sp=0xc820041ed0
runtime.cgocallbackg1()
/usr/local/go/src/runtime/cgocall.go:252 +0x110 fp=0xc820041f30 sp=0xc820041ef8
runtime.cgocallbackg()
/usr/local/go/src/runtime/cgocall.go:177 +0xd9 fp=0xc820041f90 sp=0xc820041f30
runtime.cgocallback_gofunc(0x0, 0x0, 0x0)
/usr/local/go/src/runtime/asm_amd64.s:801 +0x5d fp=0xc820041fa0 sp=0xc820041f90
runtime.goexit()
/usr/local/go/src/runtime/asm_amd64.s:1696 +0x1 fp=0xc820041fa8 sp=0xc820041fa0
goroutine 18 [syscall, locked to thread]:
runtime.goexit()
/usr/local/go/src/runtime/asm_amd64.s:1696 +0x1
goroutine 5 [chan receive]:
github.com/golang/glog.(*loggingT).flushDaemon(0x7f0cadd99bc0)
/opt/gopath/src/github.com/golang/glog/glog.go:882 +0x69
created by github.com/golang/glog.init.1
/opt/gopath/src/github.com/golang/glog/glog.go:410 +0x299
rax 0xca
rbx 0x0
rcx 0xffffffffffffffff
rdx 0x0
rdi 0xc820022110
rsi 0x0
rbp 0x1
rsp 0x7ffe7bc801a8
r8 0x0
r9 0x0
r10 0x0
r11 0x286
r12 0x4
r13 0x7f0cada47090
r14 0xd
r15 0x8
rip 0x7f0cad5c9081
rflags 0x286
cs 0x33
fs 0x0
gs 0x0
如何调试/解决这个问题?代码看起来没问题-标准可执行二进制文件返回正确的值。只有C共享库版本有一些问题。另外,不使用http.post()/net.Dial()的共享库中的其他方法都没问题。
原始问题:https://github.com/cavaliercoder/g2z/issues/5
英文:
Go code with http.Post(). If I build exe, it's OK. If I build C shared library -buildmode=c-shared, it hangs on https.Post().
I've tried strace -fp PID:
futex(0x7f618b2c1cd0, FUTEX_WAKE, 1) = 0
futex(0xc820022110, FUTEX_WAIT, 0, NULL
I've tried to add profiler:
http.ListenAndServe("localhost:6060", nil)
http.Post()
But again it hangs on http.Post and profiler was blocked as well (it was listening, but not response from 6060 port). I've sent SIGQUIT signal - stack trace:
SIGQUIT: quit
PC=0x7f0cad5c9081 m=1
goroutine 0 [idle]:
runtime.futex(0xc820022110, 0x0, 0x0, 0x0, 0x7f0c00000000, 0x7f0cad577879, 0x0, 0x0, 0x7f0cad577ae8, 0xc820022110, ...)
/usr/local/go/src/runtime/sys_linux_amd64.s:288 +0x21
runtime.futexsleep(0xc820022110, 0xc800000000, 0xffffffffffffffff)
/usr/local/go/src/runtime/os1_linux.go:39 +0x53
runtime.notesleep(0xc820022110)
/usr/local/go/src/runtime/lock_futex.go:142 +0xa8
runtime.stoplockedm()
/usr/local/go/src/runtime/proc1.go:1268 +0xb2
runtime.schedule()
/usr/local/go/src/runtime/proc1.go:1590 +0x72
runtime.park_m(0xc820000600)
/usr/local/go/src/runtime/proc1.go:1698 +0x191
runtime.mcall(0x7f0cad5c722a)
/usr/local/go/src/runtime/asm_amd64.s:204 +0x53
goroutine 17 [IO wait, locked to thread]:
runtime.gopark(0x7f0cada4a878, 0x7f0ca594b198, 0x7f0cad993b20, 0x7, 0x1b, 0x5)
/usr/local/go/src/runtime/proc.go:185 +0x169 fp=0xc820041868 sp=0xc820041840
runtime.netpollblock(0x7f0ca594b170, 0x72, 0x7f0cac21e050)
/usr/local/go/src/runtime/netpoll.go:338 +0x160 fp=0xc8200418b0 sp=0xc820041868
net.runtime_pollWait(0x7f0ca594b170, 0x72, 0xc82000a1c0)
/usr/local/go/src/runtime/netpoll.go:157 +0x62 fp=0xc8200418d0 sp=0xc8200418b0
net.(*pollDesc).Wait(0xc82011c140, 0x72, 0x0, 0x0)
/usr/local/go/src/net/fd_poll_runtime.go:73 +0x3c fp=0xc8200418f0 sp=0xc8200418d0
net.(*pollDesc).WaitRead(0xc82011c140, 0x0, 0x0)
/usr/local/go/src/net/fd_poll_runtime.go:78 +0x38 fp=0xc820041918 sp=0xc8200418f0
net.(*netFD).accept(0xc82011c0e0, 0x0, 0x7f0ca594b268, 0xc8200b4440)
/usr/local/go/src/net/fd_unix.go:408 +0x27e fp=0xc820041a18 sp=0xc820041918
net.(*TCPListener).AcceptTCP(0xc8200b8050, 0xc820041ab0, 0x0, 0x0)
/usr/local/go/src/net/tcpsock_posix.go:254 +0x4f fp=0xc820041a78 sp=0xc820041a18
net/http.tcpKeepAliveListener.Accept(0xc8200b8050, 0x0, 0x0, 0x0, 0x0)
/usr/local/go/src/net/http/server.go:2135 +0x43 fp=0xc820041ab0 sp=0xc820041a78
net/http.(*Server).Serve(0xc8200b20c0, 0x7f0ca594b230, 0xc8200b8050, 0x0, 0x0)
/usr/local/go/src/net/http/server.go:1887 +0xb5 fp=0xc820041b98 sp=0xc820041ab0
net/http.(*Server).ListenAndServe(0xc8200b20c0, 0x0, 0x0)
/usr/local/go/src/net/http/server.go:1877 +0x138 fp=0xc820041c28 sp=0xc820041b98
net/http.ListenAndServe(0x7f0cad9a6ae0, 0xe, 0x0, 0x0, 0x0, 0x0)
/usr/local/go/src/net/http/server.go:1967 +0x91 fp=0xc820041c50 sp=0xc820041c28
main.Code(0xc8201122a0, 0x0, 0x0, 0x0, 0x0)
/opt/gopath/src/github.com/jangaraj/zabbix-module/zabbix_module.go:152 +0x94 fp=0xc820041d58 sp=0xc820041c50
github.com/cavaliercoder/g2z.route_item(0x7ffe7bc803e0, 0x7ffe7bc80c90, 0x0)
/opt/gopath/src/github.com/cavaliercoder/g2z/router.go:65 +0xc2a fp=0xc820041ed0 sp=0xc820041d58
runtime.call32(0x0, 0x7ffe7bc802d8, 0x7ffe7bc80360, 0x18)
/usr/local/go/src/runtime/asm_amd64.s:437 +0x40 fp=0xc820041ef8 sp=0xc820041ed0
runtime.cgocallbackg1()
/usr/local/go/src/runtime/cgocall.go:252 +0x110 fp=0xc820041f30 sp=0xc820041ef8
runtime.cgocallbackg()
/usr/local/go/src/runtime/cgocall.go:177 +0xd9 fp=0xc820041f90 sp=0xc820041f30
runtime.cgocallback_gofunc(0x0, 0x0, 0x0)
/usr/local/go/src/runtime/asm_amd64.s:801 +0x5d fp=0xc820041fa0 sp=0xc820041f90
runtime.goexit()
/usr/local/go/src/runtime/asm_amd64.s:1696 +0x1 fp=0xc820041fa8 sp=0xc820041fa0
goroutine 18 [syscall, locked to thread]:
runtime.goexit()
/usr/local/go/src/runtime/asm_amd64.s:1696 +0x1
goroutine 5 [chan receive]:
github.com/golang/glog.(*loggingT).flushDaemon(0x7f0cadd99bc0)
/opt/gopath/src/github.com/golang/glog/glog.go:882 +0x69
created by github.com/golang/glog.init.1
/opt/gopath/src/github.com/golang/glog/glog.go:410 +0x299
rax 0xca
rbx 0x0
rcx 0xffffffffffffffff
rdx 0x0
rdi 0xc820022110
rsi 0x0
rbp 0x1
rsp 0x7ffe7bc801a8
r8 0x0
r9 0x0
r10 0x0
r11 0x286
r12 0x4
r13 0x7f0cada47090
r14 0xd
r15 0x8
rip 0x7f0cad5c9081
rflags 0x286
cs 0x33
fs 0x0
gs 0x0
How to debug/solve this problem? Code looks OK - standard executable binary returns correct value. Only C shared library version has some issue. Another methods from shared library, which don't use http.post()/net.Dial() are OK.
Original issue: https://github.com/cavaliercoder/g2z/issues/5
答案1
得分: 5
好的,我为您翻译如下:
好的,我解决了我的使用情况,你可能处于类似的情况。
当你将Go的c-shared库链接到你的C或C++应用程序时,当你启动应用程序时,Go运行时会被加载(你可以验证这一点,例如在func init()
中,它在你启动应用程序时直接被调用)。然后,如果你fork一个进程并使用Go库,你将会有不可预测的行为。
基本上,在fork之后,你必须在加载Go共享库,并且不能依赖它。使用dlopen
和dlsym
将允许你控制何时加载Go运行时。
英文:
Ok I solved this for my use case, you might be in a similar situation.
When you link your Go c-shared library to your C or C++ application, the Go runtime is loaded when you start the application (you can verify this, in func init()
for example, it's called directly when you start your app). Then, if you fork a process and use the Go library, you will have unpredictable behaviour.
Basically, you must load the Go shared library after fork and can't rely on it once you forked. Using dlopen
and dlsym
will allow you to control when the Go runtime get loaded.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论