]> Cypherpunks repositories - gostls13.git/commitdiff
io: fix PipeWriter.Close to wake up Writes
authorKirill Smelkov <kirr@nexedi.com>
Tue, 20 Dec 2016 09:02:39 +0000 (12:02 +0300)
committerRuss Cox <rsc@golang.org>
Wed, 21 Dec 2016 15:08:26 +0000 (15:08 +0000)
Since commit cc62bed0 (CL 994043) the pipe deadlock when doing
Read+Close or Write+Close on same end was fixed, alas with test for
Read+Close case only.

Then commit 6d6f3381 (CL 4252057) made a thinko: in the writer path
p.werr is checked for != nil and then err is set but there is no break
from waiting loop unlike break is there in similar condition for reader.
Together with having only Read+Close case tested that made it to leave
reintroduced Write+Close deadlock unnoticed.

Fix it.

Implicitly this also fixes net.Pipe to conform to semantic of net.Conn
interface where Close is documented to unblock any blocked Read or Write
operations.

No test added to net/ since net.Pipe tests are "Assuming that the
underlying io.Pipe implementation is solid and we're just testing the
net wrapping". The test added in this patch should be enough to cover
the breakage.

Fixes #18401
Updates #18170

Change-Id: I9e9460b3fd7d220bbe60b726accf86f352aed8d4
Reviewed-on: https://go-review.googlesource.com/34637
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
src/io/pipe.go
src/io/pipe_test.go

index 6145872391f8b59e4f6542a80261029db1f42e6c..b6e7755f64cc40cf6c461330fd3bbeba550da826 100644 (file)
@@ -85,6 +85,7 @@ func (p *pipe) write(b []byte) (n int, err error) {
                }
                if p.werr != nil {
                        err = ErrClosedPipe
+                       break
                }
                p.wwait.Wait()
        }
index b16e6530693578680d79fe5794ef7818a141d635..95930e86a4ebbd134da26b5f6f663bcfdb16c306 100644 (file)
@@ -247,6 +247,18 @@ func TestPipeWriteClose(t *testing.T) {
        }
 }
 
+// Test close on Write side during Write.
+func TestPipeWriteClose2(t *testing.T) {
+       c := make(chan int, 1)
+       _, w := Pipe()
+       go delayClose(t, w, c, pipeTest{})
+       n, err := w.Write(make([]byte, 64))
+       <-c
+       if n != 0 || err != ErrClosedPipe {
+               t.Errorf("write to closed pipe: %v, %v want %v, %v", n, err, 0, ErrClosedPipe)
+       }
+}
+
 func TestWriteEmpty(t *testing.T) {
        r, w := Pipe()
        go func() {