]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/tls: use context.AfterFunc in handshakeContext
authordatabase64128 <free122448@hotmail.com>
Fri, 29 Aug 2025 09:52:54 +0000 (17:52 +0800)
committerSean Liao <sean@liao.dev>
Sat, 6 Sep 2025 09:20:36 +0000 (02:20 -0700)
This saves a goroutine when ctx can be canceled but is not canceled
during the handshakeContext call.

Use ctx consistently, because in this path (c.quic == nil) handshakeCtx
will only be canceled when ctx is canceled.

Change-Id: I7f4565119f30d589dce026b0d7ef3c324220525a
Reviewed-on: https://go-review.googlesource.com/c/go/+/699895
Reviewed-by: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Daniel McCarney <daniel@binaryparadox.net>
Reviewed-by: Michael Pratt <mpratt@google.com>
src/crypto/tls/conn.go

index b36fcaa64830d2ba230b153c4300f56b8d27537b..d4d68c0744daa830a88e55d91405f5238b6123fd 100644 (file)
@@ -1524,7 +1524,7 @@ func (c *Conn) handshakeContext(ctx context.Context) (ret error) {
        }
 
        handshakeCtx, cancel := context.WithCancel(ctx)
-       // Note: defer this before starting the "interrupter" goroutine
+       // Note: defer this before calling context.AfterFunc
        // so that we can tell the difference between the input being canceled and
        // this cancellation. In the former case, we need to close the connection.
        defer cancel()
@@ -1533,28 +1533,14 @@ func (c *Conn) handshakeContext(ctx context.Context) (ret error) {
                c.quic.cancelc = handshakeCtx.Done()
                c.quic.cancel = cancel
        } else if ctx.Done() != nil {
-               // Start the "interrupter" goroutine, if this context might be canceled.
-               // (The background context cannot).
-               //
-               // The interrupter goroutine waits for the input context to be done and
-               // closes the connection if this happens before the function returns.
-               done := make(chan struct{})
-               interruptRes := make(chan error, 1)
+               // Close the connection if ctx is canceled before the function returns.
+               stop := context.AfterFunc(ctx, func() {
+                       _ = c.conn.Close()
+               })
                defer func() {
-                       close(done)
-                       if ctxErr := <-interruptRes; ctxErr != nil {
+                       if !stop() {
                                // Return context error to user.
-                               ret = ctxErr
-                       }
-               }()
-               go func() {
-                       select {
-                       case <-handshakeCtx.Done():
-                               // Close the connection, discarding the error
-                               _ = c.conn.Close()
-                               interruptRes <- handshakeCtx.Err()
-                       case <-done:
-                               interruptRes <- nil
+                               ret = ctx.Err()
                        }
                }()
        }