mirror of
https://github.com/golang/go
synced 2024-11-26 07:57:57 -07:00
runtime: detect deadlocks in programs using cgo
When cgo is used, runtime creates an additional M to handle callbacks on threads not created by Go. This effectively disabled deadlock detection, which is a right thing, because Go program can be blocked and only serve callbacks on external threads. This also disables deadlock detection under race detector, because it happens to use cgo. With this change the additional M is created lazily on first cgo call. So deadlock detector works for programs that import "C", "net" or "net/http/pprof" but do not use them in fact. Also fixes deadlock detector under race detector. It should be fine to create the M later, because C code can not call into Go before first cgo call, because C code does not know when Go initialization has completed. So a Go program need to call into C first either to create an external thread, or notify a thread created in global ctor that Go initialization has completed. Fixes #4973. Fixes #5475. R=golang-dev, minux.ma, iant CC=golang-dev https://golang.org/cl/9303046
This commit is contained in:
parent
a3393e1750
commit
34c67eb24e
@ -12,3 +12,4 @@
|
||||
#include "../runtime.h"
|
||||
|
||||
bool runtime·iscgo = 1;
|
||||
uint32 runtime·needextram = 1; // create an extra M on first cgo call
|
||||
|
@ -126,6 +126,10 @@ runtime·cgocall(void (*fn)(void*), void *arg)
|
||||
if(raceenabled)
|
||||
runtime·racereleasemerge(&cgosync);
|
||||
|
||||
// Create an extra M for callbacks on threads not created by Go on first cgo call.
|
||||
if(runtime·needextram && runtime·cas(&runtime·needextram, 1, 0))
|
||||
runtime·newextram();
|
||||
|
||||
m->ncgocall++;
|
||||
|
||||
/*
|
||||
|
@ -60,6 +60,7 @@ enum { MaxGomaxprocs = 1<<8 };
|
||||
|
||||
Sched runtime·sched;
|
||||
int32 runtime·gomaxprocs;
|
||||
uint32 runtime·needextram;
|
||||
bool runtime·singleproc;
|
||||
bool runtime·iscgo;
|
||||
uint32 runtime·gcwaiting;
|
||||
@ -475,11 +476,8 @@ runtime·mstart(void)
|
||||
|
||||
// Install signal handlers; after minit so that minit can
|
||||
// prepare the thread to be able to handle the signals.
|
||||
if(m == &runtime·m0) {
|
||||
if(m == &runtime·m0)
|
||||
runtime·initsig();
|
||||
if(runtime·iscgo)
|
||||
runtime·newextram();
|
||||
}
|
||||
|
||||
if(m->mstartfn)
|
||||
m->mstartfn();
|
||||
@ -587,6 +585,14 @@ runtime·needm(byte x)
|
||||
{
|
||||
M *mp;
|
||||
|
||||
if(runtime·needextram) {
|
||||
// Can happen if C/C++ code calls Go from a global ctor.
|
||||
// Can not throw, because scheduler is not initialized yet.
|
||||
runtime·write(2, "fatal error: cgo callback before cgo call\n",
|
||||
sizeof("fatal error: cgo callback before cgo call\n")-1);
|
||||
runtime·exit(1);
|
||||
}
|
||||
|
||||
// Lock extra list, take head, unlock popped list.
|
||||
// nilokay=false is safe here because of the invariant above,
|
||||
// that the extra list always contains or will soon contain
|
||||
|
@ -657,6 +657,7 @@ extern G* runtime·lastg;
|
||||
extern M* runtime·allm;
|
||||
extern P** runtime·allp;
|
||||
extern int32 runtime·gomaxprocs;
|
||||
extern uint32 runtime·needextram;
|
||||
extern bool runtime·singleproc;
|
||||
extern uint32 runtime·panicking;
|
||||
extern uint32 runtime·gcwaiting; // gc is waiting to run
|
||||
|
Loading…
Reference in New Issue
Block a user