crypto/tls: use context.AfterFunc in handshakeContext

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>
This commit is contained in:
yuhan6665
2026-09-08 21:33:46 -04:00
parent 72e8b6c674
commit c8bbf33334
+7 -21
View File
@@ -1591,7 +1591,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()
@@ -1600,28 +1600,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()
}
}()
}