From 5eb007dedeb59a52a3000202dcb162a3677a384b Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 27 Mar 2012 12:22:19 -0400 Subject: [PATCH] runtime: work around false negative in deadlock detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not a complete fix for issue 3342, but fixes the trivial case. There may still be a race in the instants before and after a scavenger-induced garbage collection. Intended to be "obviously safe": a call to runtime·gosched before main.main is no different than a call to runtime.Gosched at the beginning of main.main, and it is (or had better be) safe to call runtime.Gosched at any point during main. Update #3342. R=iant CC=golang-dev https://golang.org/cl/5919052 --- src/pkg/runtime/proc.c | 19 +++++++++++++++++++ test/fixedbugs/bug429.go | 13 +++++++++++++ test/golden.out | 3 +++ 3 files changed, 35 insertions(+) create mode 100644 test/fixedbugs/bug429.go diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c index 962f748ce86..04a9926283b 100644 --- a/src/pkg/runtime/proc.c +++ b/src/pkg/runtime/proc.c @@ -236,6 +236,11 @@ runtime·main(void) if(!runtime·sched.lockmain) runtime·UnlockOSThread(); + // The deadlock detection has false negatives. + // Let scvg start up, to eliminate the false negative + // for the trivial program func main() { select{} }. + runtime·gosched(); + main·main(); runtime·exit(0); for(;;) @@ -591,6 +596,20 @@ top: } // Look for deadlock situation. + // There is a race with the scavenger that causes false negatives: + // if the scavenger is just starting, then we have + // scvg != nil && grunning == 0 && gwait == 0 + // and we do not detect a deadlock. It is possible that we should + // add that case to the if statement here, but it is too close to Go 1 + // to make such a subtle change. Instead, we work around the + // false negative in trivial programs by calling runtime.gosched + // from the main goroutine just before main.main. + // See runtime·main above. + // + // On a related note, it is also possible that the scvg == nil case is + // wrong and should include gwait, but that does not happen in + // standard Go programs, which all start the scavenger. + // if((scvg == nil && runtime·sched.grunning == 0) || (scvg != nil && runtime·sched.grunning == 1 && runtime·sched.gwait == 0 && (scvg->status == Grunning || scvg->status == Gsyscall))) { diff --git a/test/fixedbugs/bug429.go b/test/fixedbugs/bug429.go new file mode 100644 index 00000000000..c1bd1d4bb99 --- /dev/null +++ b/test/fixedbugs/bug429.go @@ -0,0 +1,13 @@ +// $G $D/$F.go && $L $F.$A && ! ./$A.out || echo BUG: bug429 + +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Should print deadlock message, not hang. + +package main + +func main() { + select {} +} diff --git a/test/golden.out b/test/golden.out index 764f561969d..376af8e53cc 100644 --- a/test/golden.out +++ b/test/golden.out @@ -15,6 +15,9 @@ == fixedbugs/ +=========== fixedbugs/bug429.go +throw: all goroutines are asleep - deadlock! + == bugs/ =========== bugs/bug395.go