1
0
mirror of https://github.com/golang/go synced 2024-11-26 10:28:19 -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:
Dmitriy Vyukov 2013-05-22 22:57:47 +04:00
parent a3393e1750
commit 34c67eb24e
4 changed files with 16 additions and 4 deletions

View File

@ -12,3 +12,4 @@
#include "../runtime.h"
bool runtime·iscgo = 1;
uint32 runtime·needextram = 1; // create an extra M on first cgo call

View File

@ -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++;
/*

View File

@ -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

View File

@ -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