os, runtime: better EPIPE behavior for command line programs

Old behavior: 10 consecutive EPIPE errors on any descriptor cause the
program to exit with a SIGPIPE signal.

New behavior: an EPIPE error on file descriptors 1 or 2 cause the
program to raise a SIGPIPE signal.  If os/signal.Notify was not used to
catch SIGPIPE signals, this will cause the program to exit with SIGPIPE.
An EPIPE error on a file descriptor other than 1 or 2 will simply be
returned from Write.

Fixes #11845.
Update #9896.

Change-Id: Ic85d77e386a8bb0255dc4be1e4b3f55875d10f18
Reviewed-on: https://go-review.googlesource.com/18151
Reviewed-by: Russ Cox <rsc@golang.org>
This commit is contained in:
Ian Lance Taylor 2015-12-28 11:29:22 -08:00
parent a7d2b4d7ce
commit 58c73de7d0
4 changed files with 134 additions and 8 deletions

View file

@ -8,7 +8,6 @@ package os
import (
"runtime"
"sync/atomic"
"syscall"
)
@ -37,7 +36,6 @@ type file struct {
fd int
name string
dirinfo *dirInfo // nil unless directory being read
nepipe int32 // number of consecutive EPIPE in Write
}
// Fd returns the integer Unix file descriptor referencing the open file.
@ -67,13 +65,12 @@ type dirInfo struct {
bufp int // location of next record in buf.
}
// epipecheck raises SIGPIPE if we get an EPIPE error on standard
// output or standard error. See the SIGPIPE docs in os/signal, and
// issue 11845.
func epipecheck(file *File, e error) {
if e == syscall.EPIPE {
if atomic.AddInt32(&file.nepipe, 1) >= 10 {
sigpipe()
}
} else {
atomic.StoreInt32(&file.nepipe, 0)
if e == syscall.EPIPE && (file.fd == 1 || file.fd == 2) {
sigpipe()
}
}