-
Notifications
You must be signed in to change notification settings - Fork 18k
runtime: crash on Windows-created thread calling Go code during CPU profiling #17165
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
You already emailed golang-nuts for help and that thread is active, so let's keep it there instead of the bug tracker until a bug has been identified. Also, please |
@bradfitz on the thread I asked the OP to open a bug report with a reproduction case. |
Does Anyone have the same result? |
How do I build c.dll? Alex |
@alexbrainman |
I do not know how to use your "solution". Alex |
Anyone can give a explanation? |
I think this thread is the my answer:https://github.com/golang/go/issues/14599 |
Issue #14599 is fixed in 1.7.1, so whatever you are encountering is unlikely to be the same problem. |
@ianlancetaylor |
I don't use Windows, so I have not tried to reproduce this problem. alexbrainman tried to reproduce it, ran into a problem, and asked you a question that you have not answered. See above: he asked "How do I build c.dll?" |
@supernow Why you take an address of callback pointer? I don't reproduce with following code. test0001.c #include <process.h>
#include <stdio.h>
typedef void (*callback) (int, int, char*);
callback goCallback;
void
timeProc(void *p) {
for (;;) {
goCallback(1, 2, "Hello");
}
}
void
init(void* p) {
goCallback = p;
printf("init success!\n");
_beginthread(&timeProc, 0, 0);
printf("End \n");
} test.go package main
import (
"C"
"fmt"
"net/http"
_ "net/http/pprof"
"os"
"runtime/pprof"
"syscall"
"time"
)
var (
times = 0
dll = syscall.NewLazyDLL("test0001.dll")
proc = dll.NewProc("init")
)
func main() {
proc.Call(syscall.NewCallback(goCbStr))
f, _ := os.Create("cpu.prof")
err := pprof.StartCPUProfile(f)
if err != nil {
fmt.Println("pprof.StartCPUProfile:", err)
}
defer pprof.StopCPUProfile()
go func() {
fmt.Println(http.ListenAndServe("localhost:54321", nil))
}()
for {
time.Sleep(time.Second)
}
}
func goCbStr(callId int, funtype int, str *C.char) uintptr {
times++
fmt.Println(times, callId, funtype, C.GoString(str))
return uintptr(0)
} |
@mattn @alexbrainman |
@mattn I use you golang program to call my dll, It just output:
There is no func goCbStr calleback. I change your golang program line
to
It have the same the error with mine! Thank you for repro my error! |
Windows7 64bit. @ianlancetaylor I'm not sure, the address given from |
@mattn
my dll code is
When I rewrite it like you: BTW, What's your golang edition? Is it 1.7.1 edition? |
It's not safe to take the address of a value, convert the address to In this case I don't understand why the code is written that way. |
So I guess this is not a bug. |
Thank you for the link. Unfortunately this needs some MS build tool to create the DLL, and I do not have that. So I will try to comment your code without actually running it. So I could be wrong about many things. Your golang test.cpp:15 (init function) starts new thread, and new thread (timeProc function) calls Go callback. That will not work. The syscall.NewCallback can only be called by the no-Go code that is called by syscall.Syscall (or syscall.(*Proc).Call) before it return back to Go. Also your DLL functions must use standard calling conventions: stdcall on 386 and "whatever Windows uses" on amd64. Your C build tool must generate appropriate code for both init and goCallback. Also syscall.Syscall and syscall.NewCallback both align its parameters and return value on 4 bytes for 386 and 8 bytes for amd64. Does your C build tool does the same? You need to make sure it does. I hope it helps. Alex |
Thank you for replies.
As far as I understand, in this scenario I can not callback golang func. However , If I want to create a new thread that can callback Go Code, what need I do? BTW, In my program, when I remove code
The program run well. I think the CPU profile have the effect on the callback |
To call Go code from a new non-Go thread, use cgo (https://golang.org/cmd/cgo). |
I do not know. Maybe try what Ian suggested, but I have not done that myself.
I am not sure why. Maybe you are just lucky. Alex |
@alexbrainman, why do you say that a syscall.NewCallback-created callback can't be invoked on a new Windows-created thread? I think that should work, and it clearly mostly works. @ianlancetaylor, syscall.NewCallback returns a Windows callback that can be used to invoke the Go code. Underneath it translates to the usual cgo entry points. In particular, when the callback is invoked, it ends up in cgocallback_gofunc (on the stack above), which will take care of borrowing an M appropriately. But the borrowing of M's and the profiling of M's by the CPU profiler seem not synchronized enough. This code implements the CPU profiler on Windows:
A borrowed M may migrate between threads. Between the atomic.Loaduintptr(&mp.thread) and the SuspendThread, mp may have moved to a new thread, so that it's in active use. In particular it might be calling malloc, as in the crash stack trace. If so, the mp.mallocing++ in sigprof would provoke the crash. Those lines are trying to guard against allocation during sigprof. But on Windows, mp is the thread being traced, not the current thread. Those lines should really be using getg().m.mallocing, which is the same on Unix but not on Windows. With that change, it's possible the race on the actual thread is not a problem: the traceback would get confused and eventually return an error, but that's fine. The code expects that possibility. It would be nice if we could reproduce the problem, though. It might suffice just to turn on CPU profiling and make a bunch of callbacks from multiple threads simultaneously. |
See issue #6751. I did not look at this for a while, so it could be well fixed now. Anyway we use syscall.NewCallback mainly for GUI. And there all callbacks happen on the same thread. Alex |
CL https://golang.org/cl/33132 mentions this issue. |
Please answer these questions before submitting your issue. Thanks!
the same topic and attachment is in https://groups.google.com/forum/#!topic/golang-nuts/2YpUrnjiY6k
What version of Go are you using (
go version
)?go version go1.7.1 windows/amd64
What operating system and processor architecture are you using (
go env
)?set GOARCH=amd64
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOOS=windows
my env is win10, visual studio 2015
What did you do?
If possible, provide a recipe for reproducing the error.
A complete runnable program is good.
A link on play.golang.org is best.
my golang is:
my c.dll program is:
What did you expect to see?
C can call into golang func (goCbStr).
What did you see instead?
The text was updated successfully, but these errors were encountered: