Commit 04f0d148 authored by Alex Brainman's avatar Alex Brainman

cmd/go: handle os signals

Ignore signals during "go run" and wait for running child
process to exit. Stop executing further tests during "go test",
wait for running tests to exit and report error exit code.

Original CL 6351053 by dfc.

Fixes #3572.
Fixes #3581.

R=golang-dev, dave, rsc
CC=golang-dev
https://golang.org/cl/6903061
parent cc5682dc
......@@ -1183,6 +1183,7 @@ static char *buildorder[] = {
"pkg/go/ast",
"pkg/go/parser",
"pkg/os/exec",
"pkg/os/signal",
"pkg/net/url",
"pkg/text/template/parse",
"pkg/text/template",
......
......@@ -548,7 +548,6 @@ func (b *builder) do(root *action) {
}
b.readySema = make(chan bool, len(all))
done := make(chan bool)
// Initialize per-action execution state.
for _, a := range all {
......@@ -596,10 +595,11 @@ func (b *builder) do(root *action) {
if a == root {
close(b.readySema)
done <- true
}
}
var wg sync.WaitGroup
// Kick off goroutines according to parallelism.
// If we are using the -n flag (just printing commands)
// drop the parallelism to 1, both to make the output
......@@ -609,19 +609,30 @@ func (b *builder) do(root *action) {
par = 1
}
for i := 0; i < par; i++ {
wg.Add(1)
go func() {
for _ = range b.readySema {
// Receiving a value from b.sema entitles
defer wg.Done()
for {
select {
case _, ok := <-b.readySema:
if !ok {
return
}
// Receiving a value from b.readySema entitles
// us to take from the ready queue.
b.exec.Lock()
a := b.ready.pop()
b.exec.Unlock()
handle(a)
case <-interrupted:
setExitStatus(1)
return
}
}
}()
}
<-done
wg.Wait()
}
// build is the action for building a single package or command.
......
......@@ -84,6 +84,7 @@ func runStdin(cmdargs ...interface{}) {
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
startSigHandlers()
if err := cmd.Run(); err != nil {
errorf("%v", err)
}
......
// 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.
package main
import (
"os"
"os/signal"
"sync"
)
// interrupted is closed, if go process is interrupted.
var interrupted = make(chan struct{})
// processSignals setups signal handler.
func processSignals() {
sig := make(chan os.Signal)
signal.Notify(sig, signalsToIgnore...)
go func() {
<-sig
close(interrupted)
}()
}
var onceProcessSignals sync.Once
// startSigHandlers start signal handlers.
func startSigHandlers() {
onceProcessSignals.Do(processSignals)
}
// 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.
// +build plan9 windows
package main
import (
"os"
)
var signalsToIgnore = []os.Signal{os.Interrupt}
// 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.
// +build darwin freebsd linux netbsd openbsd
package main
import (
"os"
"syscall"
)
var signalsToIgnore = []os.Signal{os.Interrupt, syscall.SIGQUIT}
......@@ -644,6 +644,7 @@ func (b *builder) runTest(a *action) error {
// running.
tick := time.NewTimer(testKillTimeout)
if err == nil {
startSigHandlers()
done := make(chan error)
go func() {
done <- cmd.Wait()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment