Commit 7edd1335 authored by Roger Peppe's avatar Roger Peppe

net/rpc: avoid racy use of closing flag.

It's accessed without mutex protection
in a different goroutine from the one that
sets it.

Also make sure that Client.Call after Client.Close
will reliably return ErrShutdown, and that clients
see ErrShutdown rather than io.EOF when appropriate.

Suggestions welcome for a way to reliably test
the mutex issue.

R=r, iant
CC=golang-dev
https://golang.org/cl/7338045
parent cd81db82
......@@ -71,7 +71,7 @@ func (client *Client) send(call *Call) {
// Register this call.
client.mutex.Lock()
if client.shutdown {
if client.shutdown || client.closing {
call.Error = ErrShutdown
client.mutex.Unlock()
call.done()
......@@ -105,9 +105,6 @@ func (client *Client) input() {
response = Response{}
err = client.codec.ReadResponseHeader(&response)
if err != nil {
if err == io.EOF && !client.closing {
err = io.ErrUnexpectedEOF
}
break
}
seq := response.Seq
......@@ -150,6 +147,13 @@ func (client *Client) input() {
client.mutex.Lock()
client.shutdown = true
closing := client.closing
if err == io.EOF {
if closing {
err = ErrShutdown
} else {
err = io.ErrUnexpectedEOF
}
}
for _, call := range client.pending {
call.Error = err
call.done()
......
......@@ -524,6 +524,23 @@ func TestTCPClose(t *testing.T) {
}
}
func TestErrorAfterClientClose(t *testing.T) {
once.Do(startServer)
client, err := dialHTTP()
if err != nil {
t.Fatalf("dialing: %v", err)
}
err = client.Close()
if err != nil {
t.Fatal("close error:", err)
}
err = client.Call("Arith.Add", &Args{7, 9}, new(Reply))
if err != ErrShutdown {
t.Errorf("Forever: expected ErrShutdown got %v", err)
}
}
func benchmarkEndToEnd(dial func() (*Client, error), b *testing.B) {
b.StopTimer()
once.Do(startServer)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment