]> Cypherpunks repositories - gostls13.git/commitdiff
net/rpc: clarify requirements for connections and codecs
authorDmitry Vyukov <dvyukov@google.com>
Tue, 26 Jun 2018 11:28:04 +0000 (13:28 +0200)
committerDmitry Vyukov <dvyukov@google.com>
Tue, 24 Jul 2018 09:23:08 +0000 (09:23 +0000)
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 <r@golang.org>
src/net/rpc/client.go
src/net/rpc/server.go

index f3da3ae3ee9ed4413158aa9505cf183ef24df1cb..cad2d45e7f8d4f4dcdc5f60e7c3d342db54860e6 100644 (file)
@@ -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}
index 96e6973c3a2e710591be25e01b124a73028e2fa9..7bb6476ffab596c6c297281912a6dafb40c3856e 100644 (file)
@@ -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)
 }