From: Dmitry Vyukov Date: Tue, 26 Jun 2018 11:28:04 +0000 (+0200) Subject: net/rpc: clarify requirements for connections and codecs X-Git-Tag: go1.11beta3~94 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=08ab820437229f68fe5f7dad1c9b4940c674e206;p=gostls13.git net/rpc: clarify requirements for connections and codecs 1. Connections and codecs need to be partially safe for concurrent use. Namely, read side is serialized by one mutex, and writing side is serialized by another. Current comment says that they need to be fully thread-safe, which makes the default implementations (gobClientCodec/gobServerCodec) non-conforming. 2. Say that ServerCodec.Close can be called multiple times and must be idempotent. Server requires this and gobServerCodec accounts for this, but the requirement is not documented. Change-Id: Ie877e37891fed28056e3d9d1722edaed8e154067 Reviewed-on: https://go-review.googlesource.com/120818 Reviewed-by: Rob Pike --- diff --git a/src/net/rpc/client.go b/src/net/rpc/client.go index f3da3ae3ee..cad2d45e7f 100644 --- a/src/net/rpc/client.go +++ b/src/net/rpc/client.go @@ -59,8 +59,8 @@ type Client struct { // connection. ReadResponseBody may be called with a nil // argument to force the body of the response to be read and then // discarded. +// See NewClient's comment for information about concurrent access. type ClientCodec interface { - // WriteRequest must be safe for concurrent use by multiple goroutines. WriteRequest(*Request, interface{}) error ReadResponseHeader(*Response) error ReadResponseBody(interface{}) error @@ -185,6 +185,11 @@ func (call *Call) done() { // set of services at the other end of the connection. // It adds a buffer to the write side of the connection so // the header and payload are sent as a unit. +// +// The read and write halves of the connection are serialized independently, +// so no interlocking is required. However each half may be accessed +// concurrently so the implementation of conn should protect against +// concurrent reads or concurrent writes. func NewClient(conn io.ReadWriteCloser) *Client { encBuf := bufio.NewWriter(conn) client := &gobClientCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(encBuf), encBuf} diff --git a/src/net/rpc/server.go b/src/net/rpc/server.go index 96e6973c3a..7bb6476ffa 100644 --- a/src/net/rpc/server.go +++ b/src/net/rpc/server.go @@ -444,6 +444,7 @@ func (c *gobServerCodec) Close() error { // The caller typically invokes ServeConn in a go statement. // ServeConn uses the gob wire format (see package gob) on the // connection. To use an alternate codec, use ServeCodec. +// See NewClient's comment for information about concurrent access. func (server *Server) ServeConn(conn io.ReadWriteCloser) { buf := bufio.NewWriter(conn) srv := &gobServerCodec{ @@ -653,12 +654,13 @@ func RegisterName(name string, rcvr interface{}) error { // write a response back. The server calls Close when finished with the // connection. ReadRequestBody may be called with a nil // argument to force the body of the request to be read and discarded. +// See NewClient's comment for information about concurrent access. type ServerCodec interface { ReadRequestHeader(*Request) error ReadRequestBody(interface{}) error - // WriteResponse must be safe for concurrent use by multiple goroutines. WriteResponse(*Response, interface{}) error + // Close can be called multiple times and must be idempotent. Close() error } @@ -667,6 +669,7 @@ type ServerCodec interface { // The caller typically invokes ServeConn in a go statement. // ServeConn uses the gob wire format (see package gob) on the // connection. To use an alternate codec, use ServeCodec. +// See NewClient's comment for information about concurrent access. func ServeConn(conn io.ReadWriteCloser) { DefaultServer.ServeConn(conn) }