mirror of
https://github.com/golang/go
synced 2024-11-12 08:10:21 -07:00
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
This commit is contained in:
parent
cd81db8299
commit
7edd13355f
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user