aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/os/exec/exec.go
diff options
context:
space:
mode:
authorAndrew Gerrand <adg@golang.org>2013-08-29 14:41:44 +1000
committerAndrew Gerrand <adg@golang.org>2013-08-29 14:41:44 +1000
commit10e2ffdf2ca657567fc1708f6387fef69a8445b6 (patch)
treec2644859a14680a2557f5a8628fe800768982c7e /src/pkg/os/exec/exec.go
parent466001d05d366cbc97edfb65dc6f5cb883df0498 (diff)
downloadgo-10e2ffdf2ca657567fc1708f6387fef69a8445b6.tar.xz
os/exec: return idempotent Closer from StdinPipe
Before this fix, it was always an error to use the Close method on the io.WriteCloser obtained from Cmd.StdinPipe, as it would race with the Close performed by Cmd.Wait. Fixes #6270. R=golang-dev, r, remyoudompheng, bradfitz, dsymonds CC=golang-dev https://golang.org/cl/13329043
Diffstat (limited to 'src/pkg/os/exec/exec.go')
-rw-r--r--src/pkg/os/exec/exec.go22
1 files changed, 20 insertions, 2 deletions
diff --git a/src/pkg/os/exec/exec.go b/src/pkg/os/exec/exec.go
index a3bbcf3005..582930f2c4 100644
--- a/src/pkg/os/exec/exec.go
+++ b/src/pkg/os/exec/exec.go
@@ -13,6 +13,7 @@ import (
"io"
"os"
"strconv"
+ "sync"
"syscall"
)
@@ -357,6 +358,8 @@ func (c *Cmd) CombinedOutput() ([]byte, error) {
// StdinPipe returns a pipe that will be connected to the command's
// standard input when the command starts.
+// If the returned WriteCloser is not closed before Wait is called,
+// Wait will close it.
func (c *Cmd) StdinPipe() (io.WriteCloser, error) {
if c.Stdin != nil {
return nil, errors.New("exec: Stdin already set")
@@ -370,8 +373,23 @@ func (c *Cmd) StdinPipe() (io.WriteCloser, error) {
}
c.Stdin = pr
c.closeAfterStart = append(c.closeAfterStart, pr)
- c.closeAfterWait = append(c.closeAfterWait, pw)
- return pw, nil
+ wc := &closeOnce{File: pw}
+ c.closeAfterWait = append(c.closeAfterWait, wc)
+ return wc, nil
+}
+
+type closeOnce struct {
+ *os.File
+
+ close sync.Once
+ closeErr error
+}
+
+func (c *closeOnce) Close() error {
+ c.close.Do(func() {
+ c.closeErr = c.File.Close()
+ })
+ return c.closeErr
}
// StdoutPipe returns a pipe that will be connected to the command's