]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go: handle os signals
authorAlex Brainman <alex.brainman@gmail.com>
Fri, 14 Dec 2012 06:33:59 +0000 (17:33 +1100)
committerAlex Brainman <alex.brainman@gmail.com>
Fri, 14 Dec 2012 06:33:59 +0000 (17:33 +1100)
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

src/cmd/dist/build.c
src/cmd/go/build.go
src/cmd/go/run.go
src/cmd/go/signal.go [new file with mode: 0644]
src/cmd/go/signal_notunix.go [new file with mode: 0644]
src/cmd/go/signal_unix.go [new file with mode: 0644]
src/cmd/go/test.go

index fca668ceb882f6726052500b99bfc917c63f9d57..13dbe0e81da149a69449f4d88b7af29dd3bd4c0c 100644 (file)
@@ -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",
index 7e3d2f496ded920275a99056da8e824eb4cc0fbb..5f91227f151a79618673e1cfafba5a990f6e9ee6 100644 (file)
@@ -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
-                               // us to take from the ready queue.
-                               b.exec.Lock()
-                               a := b.ready.pop()
-                               b.exec.Unlock()
-                               handle(a)
+                       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.
index 0f41fa61be7e9270548cec90aa8c6cc67b25448f..88f57617e4e31fc62d68429e9bc9b791c1892cc7 100644 (file)
@@ -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)
        }
diff --git a/src/cmd/go/signal.go b/src/cmd/go/signal.go
new file mode 100644 (file)
index 0000000..e8ba0d3
--- /dev/null
@@ -0,0 +1,31 @@
+// 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)
+}
diff --git a/src/cmd/go/signal_notunix.go b/src/cmd/go/signal_notunix.go
new file mode 100644 (file)
index 0000000..ef13c19
--- /dev/null
@@ -0,0 +1,13 @@
+// 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}
diff --git a/src/cmd/go/signal_unix.go b/src/cmd/go/signal_unix.go
new file mode 100644 (file)
index 0000000..489a73b
--- /dev/null
@@ -0,0 +1,14 @@
+// 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}
index efd14609aa0c502b3f7cb1e2d735e0c78597b7f4..555c6f50eddeb69ced9064bbd840b7f241ac1a89 100644 (file)
@@ -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()