1
0
mirror of https://github.com/golang/go synced 2024-11-23 10:30:03 -07:00

runtime: fix exit status when killed by signal

Previously, when a program died because of a SIGHUP, SIGINT, or SIGTERM
signal it would exit with status 2.  This CL fixes the runtime to exit
with a status indicating that the program was killed by a signal.

Change-Id: Ic2982a2562857edfdccaf68856e0e4df532af136
Reviewed-on: https://go-review.googlesource.com/18156
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
Ian Lance Taylor 2016-01-01 15:44:12 -08:00
parent 81b35117d9
commit 2c67c8c303
10 changed files with 58 additions and 11 deletions

View File

@ -133,3 +133,21 @@ func loop(i int, c chan bool) {
}
}
`
func TestSignalExitStatus(t *testing.T) {
testenv.MustHaveGoBuild(t)
exe, err := buildTestProg(t, "testprog")
if err != nil {
t.Fatal(err)
}
err = testEnv(exec.Command(exe, "SignalExitStatus")).Run()
if err == nil {
t.Error("test program succeeded unexpectedly")
} else if ee, ok := err.(*exec.ExitError); !ok {
t.Errorf("error (%v) has type %T; expected exec.ExitError", err, err)
} else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok {
t.Errorf("error.Sys (%v) has type %T; expected syscall.WaitStatus", ee.Sys(), ee.Sys())
} else if !ws.Signaled() || ws.Signal() != syscall.SIGTERM {
t.Errorf("got %v; expected SIGTERM", ee)
}
}

View File

@ -45,6 +45,10 @@ func os_sigpipe() {
throw("too many writes on closed pipe")
}
func dieFromSignal(sig int32) {
exit(2)
}
func sigpanic() {
g := getg()
if !canpanic(g) {

View File

@ -142,8 +142,18 @@ func sigpipe() {
if sigsend(_SIGPIPE) {
return
}
setsig(_SIGPIPE, _SIG_DFL, false)
raise(_SIGPIPE)
dieFromSignal(_SIGPIPE)
}
// dieFromSignal kills the program with a signal.
// This provides the expected exit status for the shell.
// This is only called with fatal signals expected to kill the process.
func dieFromSignal(sig int32) {
setsig(sig, _SIG_DFL, false)
updatesigmask(sigmask{})
raise(sig)
// That should have killed us; call exit just in case.
exit(2)
}
// raisebadsignal is called when a signal is received on a non-Go
@ -196,9 +206,7 @@ func crash() {
}
}
updatesigmask(sigmask{})
setsig(_SIGABRT, _SIG_DFL, false)
raise(_SIGABRT)
dieFromSignal(_SIGABRT)
}
// ensureSigM starts one global, sleeping thread to make sure at least one thread

View File

@ -108,7 +108,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
}
if flags&_SigKill != 0 {
exit(2)
dieFromSignal(int32(sig))
}
if flags&_SigThrow == 0 {

View File

@ -140,7 +140,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
}
if flags&_SigKill != 0 {
exit(2)
dieFromSignal(int32(sig))
}
if flags&_SigThrow == 0 {

View File

@ -100,7 +100,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
}
if flags&_SigKill != 0 {
exit(2)
dieFromSignal(int32(sig))
}
if flags&_SigThrow == 0 {

View File

@ -116,7 +116,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
}
if flags&_SigKill != 0 {
exit(2)
dieFromSignal(int32(sig))
}
if flags&_SigThrow == 0 {

View File

@ -118,7 +118,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
}
if flags&_SigKill != 0 {
exit(2)
dieFromSignal(int32(sig))
}
if flags&_SigThrow == 0 {

View File

@ -122,7 +122,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
}
if flags&_SigKill != 0 {
exit(2)
dieFromSignal(int32(sig))
}
if flags&_SigThrow == 0 {

17
src/runtime/testdata/testprog/signal.go vendored Normal file
View File

@ -0,0 +1,17 @@
// Copyright 2015 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 !windows,!plan9,!nacl
package main
import "syscall"
func init() {
register("SignalExitStatus", SignalExitStatus)
}
func SignalExitStatus() {
syscall.Kill(syscall.Getpid(), syscall.SIGTERM)
}