Skip to content

Commit 04f0d14

Browse files
committed
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
1 parent cc5682d commit 04f0d14

File tree

7 files changed

+82
-10
lines changed

7 files changed

+82
-10
lines changed

src/cmd/dist/build.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,6 +1183,7 @@ static char *buildorder[] = {
11831183
"pkg/go/ast",
11841184
"pkg/go/parser",
11851185
"pkg/os/exec",
1186+
"pkg/os/signal",
11861187
"pkg/net/url",
11871188
"pkg/text/template/parse",
11881189
"pkg/text/template",

src/cmd/go/build.go

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,6 @@ func (b *builder) do(root *action) {
548548
}
549549

550550
b.readySema = make(chan bool, len(all))
551-
done := make(chan bool)
552551

553552
// Initialize per-action execution state.
554553
for _, a := range all {
@@ -596,10 +595,11 @@ func (b *builder) do(root *action) {
596595

597596
if a == root {
598597
close(b.readySema)
599-
done <- true
600598
}
601599
}
602600

601+
var wg sync.WaitGroup
602+
603603
// Kick off goroutines according to parallelism.
604604
// If we are using the -n flag (just printing commands)
605605
// drop the parallelism to 1, both to make the output
@@ -609,19 +609,30 @@ func (b *builder) do(root *action) {
609609
par = 1
610610
}
611611
for i := 0; i < par; i++ {
612+
wg.Add(1)
612613
go func() {
613-
for _ = range b.readySema {
614-
// Receiving a value from b.sema entitles
615-
// us to take from the ready queue.
616-
b.exec.Lock()
617-
a := b.ready.pop()
618-
b.exec.Unlock()
619-
handle(a)
614+
defer wg.Done()
615+
for {
616+
select {
617+
case _, ok := <-b.readySema:
618+
if !ok {
619+
return
620+
}
621+
// Receiving a value from b.readySema entitles
622+
// us to take from the ready queue.
623+
b.exec.Lock()
624+
a := b.ready.pop()
625+
b.exec.Unlock()
626+
handle(a)
627+
case <-interrupted:
628+
setExitStatus(1)
629+
return
630+
}
620631
}
621632
}()
622633
}
623634

624-
<-done
635+
wg.Wait()
625636
}
626637

627638
// build is the action for building a single package or command.

src/cmd/go/run.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ func runStdin(cmdargs ...interface{}) {
8484
cmd.Stdin = os.Stdin
8585
cmd.Stdout = os.Stdout
8686
cmd.Stderr = os.Stderr
87+
startSigHandlers()
8788
if err := cmd.Run(); err != nil {
8889
errorf("%v", err)
8990
}

src/cmd/go/signal.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2012 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import (
8+
"os"
9+
"os/signal"
10+
"sync"
11+
)
12+
13+
// interrupted is closed, if go process is interrupted.
14+
var interrupted = make(chan struct{})
15+
16+
// processSignals setups signal handler.
17+
func processSignals() {
18+
sig := make(chan os.Signal)
19+
signal.Notify(sig, signalsToIgnore...)
20+
go func() {
21+
<-sig
22+
close(interrupted)
23+
}()
24+
}
25+
26+
var onceProcessSignals sync.Once
27+
28+
// startSigHandlers start signal handlers.
29+
func startSigHandlers() {
30+
onceProcessSignals.Do(processSignals)
31+
}

src/cmd/go/signal_notunix.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2012 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// +build plan9 windows
6+
7+
package main
8+
9+
import (
10+
"os"
11+
)
12+
13+
var signalsToIgnore = []os.Signal{os.Interrupt}

src/cmd/go/signal_unix.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2012 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// +build darwin freebsd linux netbsd openbsd
6+
7+
package main
8+
9+
import (
10+
"os"
11+
"syscall"
12+
)
13+
14+
var signalsToIgnore = []os.Signal{os.Interrupt, syscall.SIGQUIT}

src/cmd/go/test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,7 @@ func (b *builder) runTest(a *action) error {
644644
// running.
645645
tick := time.NewTimer(testKillTimeout)
646646
if err == nil {
647+
startSigHandlers()
647648
done := make(chan error)
648649
go func() {
649650
done <- cmd.Wait()

0 commit comments

Comments
 (0)