|
|
Descriptionos/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 issue 6270.
Patch Set 1 #Patch Set 2 : diff -r 21a81bde7dc9 https://code.google.com/p/go #Patch Set 3 : diff -r 21a81bde7dc9 https://code.google.com/p/go #
Total comments: 5
Patch Set 4 : diff -r 21a81bde7dc9 https://code.google.com/p/go #
Total comments: 6
Patch Set 5 : diff -r 4f4edc2ddd93 https://code.google.com/p/go #Patch Set 6 : diff -r 318540e7857f https://code.google.com/p/go #MessagesTotal messages: 24
Hello golang-dev@googlegroups.com, I'd like you to review this change to https://code.google.com/p/go
Sign in to reply to this message.
Confirmed that the new test triggers a race condition with "go test -race" before the fix, and that the race is gone after.
Sign in to reply to this message.
LGTM but wait for bradfitz. https://codereview.appspot.com/13329043/diff/6001/src/pkg/os/exec/exec.go File src/pkg/os/exec/exec.go (right): https://codereview.appspot.com/13329043/diff/6001/src/pkg/os/exec/exec.go#new... src/pkg/os/exec/exec.go:16: "sync" this is a new fundamental dependency. is it ok? (i think it is) confirmed: yes it is. sync is in L0, exec is not leveled. https://codereview.appspot.com/13329043/diff/6001/src/pkg/os/exec/exec.go#new... src/pkg/os/exec/exec.go:360: // standard input when the command starts. // If the returned WriteCloser is not closed before Wait is called, Wait will close it.
Sign in to reply to this message.
Fixes issue 6270.
Sign in to reply to this message.
Le 28 août 2013 07:40, <adg@golang.org> a écrit : > > Reviewers: golang-dev1, > > Message: > Hello golang-dev@googlegroups.com, > > I'd like you to review this change to > https://code.google.com/p/go > > > Description: > 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. > > Please review this at https://codereview.appspot.com/13329043/ > > Affected files: > M src/pkg/os/exec/exec.go > M src/pkg/os/exec/exec_test.go > > > Index: src/pkg/os/exec/exec.go > =================================================================== > --- a/src/pkg/os/exec/exec.go > +++ b/src/pkg/os/exec/exec.go > @@ -13,6 +13,7 @@ > "io" > "os" > "strconv" > + "sync" > "syscall" > ) > > @@ -370,8 +371,21 @@ > } > c.Stdin = pr > c.closeAfterStart = append(c.closeAfterStart, pr) > - c.closeAfterWait = append(c.closeAfterWait, pw) > - return pw, nil > + wc := &closeOnce{WriteCloser: pw} > + c.closeAfterWait = append(c.closeAfterWait, wc) > + return wc, nil > +} > + > +type closeOnce struct { > + io.WriteCloser > + close sync.Once > +} > + > +func (c *closeOnce) Close() (err error) { > + c.close.Do(func() { > + err = c.WriteCloser.Close() > + }) > + return > } > Only one caller can get the error if you do that. Is it the intended behaviour? Rémy.
Sign in to reply to this message.
https://codereview.appspot.com/13329043/diff/6001/src/pkg/os/exec/exec.go File src/pkg/os/exec/exec.go (right): https://codereview.appspot.com/13329043/diff/6001/src/pkg/os/exec/exec.go#new... src/pkg/os/exec/exec.go:387: }) rémy points out this means only the first caller gets the error. errors on close are totally stupid of course (what am i supposed to do? close it again?) but it's easy to get it right, so get it right.
Sign in to reply to this message.
PTAL https://codereview.appspot.com/13329043/diff/6001/src/pkg/os/exec/exec.go File src/pkg/os/exec/exec.go (right): https://codereview.appspot.com/13329043/diff/6001/src/pkg/os/exec/exec.go#new... src/pkg/os/exec/exec.go:16: "sync" Ack. https://codereview.appspot.com/13329043/diff/6001/src/pkg/os/exec/exec.go#new... src/pkg/os/exec/exec.go:387: }) On 2013/08/28 06:13:06, r wrote: > rémy points out this means only the first caller gets the error. > > errors on close are totally stupid of course (what am i supposed to do? close it > again?) but it's easy to get it right, so get it right. > Done.
Sign in to reply to this message.
LGTM but wait for badboyfitz
Sign in to reply to this message.
https://codereview.appspot.com/13329043/diff/16001/src/pkg/os/exec/exec.go File src/pkg/os/exec/exec.go (right): https://codereview.appspot.com/13329043/diff/16001/src/pkg/os/exec/exec.go#ne... src/pkg/os/exec/exec.go:376: wc := &closeOnce{WriteCloser: pw} This was proposed and rejected previously because it changes the underlying type of the io.WriteCloser from an *os.File (from which you can get its Fd). Are we okay with that change? It might break programs. That was the concern before. https://codereview.appspot.com/13329043/diff/16001/src/pkg/os/exec/exec.go#ne... src/pkg/os/exec/exec.go:387: func (c *closeOnce) Close() (err error) { not sure why this is named result https://codereview.appspot.com/13329043/diff/16001/src/pkg/os/exec/exec.go#ne... src/pkg/os/exec/exec.go:388: c.close.Do(func() { if you use a method value here, I believe you save an allocation. func (c *closeOnce) Close() error { c.close.Do(c.close) return c.closeErr } func (c *closeOnce) close() { c.closeErr = c.WriteCloser.Close() }
Sign in to reply to this message.
Would it mitigate enough if we embed the *os.File? -rob
Sign in to reply to this message.
If *os.File were an interface, yes. Unfortunately it is not and that thwarts this approach I believe. Perhaps it needs to be a new method. On 29 Aug 2013 08:21, "Rob Pike" <r@golang.org> wrote: > Would it mitigate enough if we embed the *os.File? > > -rob >
Sign in to reply to this message.
On Wed, Aug 28, 2013 at 3:21 PM, Rob Pike <r@golang.org> wrote: > Would it mitigate enough if we embed the *os.File? > Not my call. It would permit access to the Fd() uintptr and all the other methods, though. But I imagine most code does: foo.(*os.File).Fd() or anyway, and not gracefully testing for a specific method.
Sign in to reply to this message.
Perhaps we go back to plan B then, and introduce new methods that work and discourage the old. -rob
Sign in to reply to this message.
The whole point of StdinPipe returning interfaces is that it *doesn't* promise that it's an *os.File. It doesn't document that it's an *os.File. If people are making such assumptions then I don't feel bad if their code breaks. It'll at least break in a very obvious way. I'm pretty sure we've made other similar changes elsewhere in the standard library since Go 1.0.
Sign in to reply to this message.
All right, you've convinced me. It's an io.WriteCloser. If someone asserts that to something else, they're trusting promises that aren't made. Let's go with what's here. -rob
Sign in to reply to this message.
https://codereview.appspot.com/13329043/diff/16001/src/pkg/os/exec/exec.go File src/pkg/os/exec/exec.go (right): https://codereview.appspot.com/13329043/diff/16001/src/pkg/os/exec/exec.go#ne... src/pkg/os/exec/exec.go:388: c.close.Do(func() { a method value is an allocation too. i don't care about one allocation like this, and i think it's clearer as written, but if you want it as a method value that's fine with me.
Sign in to reply to this message.
I'm fine changing it too. But I still think it'd be prudent to embed the *os.File so we have an answer to breakage questions that works with Go 1, 1.1, or 1.2. On Wed, Aug 28, 2013 at 8:13 PM, Rob Pike <r@golang.org> wrote: > All right, you've convinced me. It's an io.WriteCloser. If someone > asserts that to something else, they're trusting promises that aren't > made. > > Let's go with what's here. > > -rob >
Sign in to reply to this message.
PTAL Now with embedded *os.File. https://codereview.appspot.com/13329043/diff/16001/src/pkg/os/exec/exec.go File src/pkg/os/exec/exec.go (right): https://codereview.appspot.com/13329043/diff/16001/src/pkg/os/exec/exec.go#ne... src/pkg/os/exec/exec.go:387: func (c *closeOnce) Close() (err error) { On 2013/08/28 16:23:31, bradfitz wrote: > not sure why this is named result It needn't be; a holdover from a previous revision https://codereview.appspot.com/13329043/diff/16001/src/pkg/os/exec/exec.go#ne... src/pkg/os/exec/exec.go:388: c.close.Do(func() { On 2013/08/29 03:15:18, r wrote: > a method value is an allocation too. > > i don't care about one allocation like this, and i think it's clearer as > written, but if you want it as a method value that's fine with me. I would prefer to leave it as written.
Sign in to reply to this message.
LGTM but again wait for the fitzoid
Sign in to reply to this message.
Document (with issue link) and test the embedding? On Aug 28, 2013 9:26 PM, <adg@golang.org> wrote: > PTAL > > Now with embedded *os.File. > > > https://codereview.appspot.**com/13329043/diff/16001/src/** > pkg/os/exec/exec.go<https://codereview.appspot.com/13329043/diff/16001/src/pkg/os/exec/exec.go> > File src/pkg/os/exec/exec.go (right): > > https://codereview.appspot.**com/13329043/diff/16001/src/** > pkg/os/exec/exec.go#newcode387<https://codereview.appspot.com/13329043/diff/16001/src/pkg/os/exec/exec.go#newcode387> > src/pkg/os/exec/exec.go:387: func (c *closeOnce) Close() (err error) { > On 2013/08/28 16:23:31, bradfitz wrote: > >> not sure why this is named result >> > > It needn't be; a holdover from a previous revision > > https://codereview.appspot.**com/13329043/diff/16001/src/** > pkg/os/exec/exec.go#newcode388<https://codereview.appspot.com/13329043/diff/16001/src/pkg/os/exec/exec.go#newcode388> > src/pkg/os/exec/exec.go:388: c.close.Do(func() { > On 2013/08/29 03:15:18, r wrote: > >> a method value is an allocation too. >> > > i don't care about one allocation like this, and i think it's clearer >> > as > >> written, but if you want it as a method value that's fine with me. >> > > I would prefer to leave it as written. > > https://codereview.appspot.**com/13329043/<https://codereview.appspot.com/133... >
Sign in to reply to this message.
LGTM modulo the things raised by the fitzoid.
Sign in to reply to this message.
LGTM after test/comment addition. I'm off now. Don't wait for me to submit. On Aug 28, 2013 9:31 PM, "Brad Fitzpatrick" <bradfitz@golang.org> wrote: > Document (with issue link) and test the embedding? > On Aug 28, 2013 9:26 PM, <adg@golang.org> wrote: > >> PTAL >> >> Now with embedded *os.File. >> >> >> https://codereview.appspot.**com/13329043/diff/16001/src/** >> pkg/os/exec/exec.go<https://codereview.appspot.com/13329043/diff/16001/src/pkg/os/exec/exec.go> >> File src/pkg/os/exec/exec.go (right): >> >> https://codereview.appspot.**com/13329043/diff/16001/src/** >> pkg/os/exec/exec.go#newcode387<https://codereview.appspot.com/13329043/diff/16001/src/pkg/os/exec/exec.go#newcode387> >> src/pkg/os/exec/exec.go:387: func (c *closeOnce) Close() (err error) { >> On 2013/08/28 16:23:31, bradfitz wrote: >> >>> not sure why this is named result >>> >> >> It needn't be; a holdover from a previous revision >> >> https://codereview.appspot.**com/13329043/diff/16001/src/** >> pkg/os/exec/exec.go#newcode388<https://codereview.appspot.com/13329043/diff/16001/src/pkg/os/exec/exec.go#newcode388> >> src/pkg/os/exec/exec.go:388: c.close.Do(func() { >> On 2013/08/29 03:15:18, r wrote: >> >>> a method value is an allocation too. >>> >> >> i don't care about one allocation like this, and i think it's clearer >>> >> as >> >>> written, but if you want it as a method value that's fine with me. >>> >> >> I would prefer to leave it as written. >> >> https://codereview.appspot.**com/13329043/<https://codereview.appspot.com/133... >> >
Sign in to reply to this message.
*** Submitted as https://code.google.com/p/go/source/detail?r=ef345053cf89 *** 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 issue 6270. R=golang-dev, r, remyoudompheng, bradfitz, dsymonds CC=golang-dev https://codereview.appspot.com/13329043
Sign in to reply to this message.
|