// Copyright 2025 The Go Authors. All rights reserved. // Use of this source code is governed by a MIT // license that can be found in the LICENSE file. /* * Project: grpc-go * Issue or PR : https://github.com/grpc/grpc-go/pull/862 * Buggy version: d8f4ebe77f6b7b6403d7f98626de8a534f9b93a7 * fix commit-id: dd5645bebff44f6b88780bb949022a09eadd7dae * Flaky: 100/100 */ package main import ( "context" "os" "runtime" "runtime/pprof" "time" ) func init() { register("Grpc862", Grpc862) } type ClientConn_grpc862 struct { ctx context.Context cancel context.CancelFunc conns []*addrConn_grpc862 } func (cc *ClientConn_grpc862) Close() { cc.cancel() conns := cc.conns cc.conns = nil for _, ac := range conns { ac.tearDown() } } func (cc *ClientConn_grpc862) resetAddrConn() { ac := &addrConn_grpc862{ cc: cc, } cc.conns = append(cc.conns, ac) ac.ctx, ac.cancel = context.WithCancel(cc.ctx) ac.resetTransport() } type addrConn_grpc862 struct { cc *ClientConn_grpc862 ctx context.Context cancel context.CancelFunc } func (ac *addrConn_grpc862) resetTransport() { for retries := 1; ; retries++ { _ = 2 * time.Nanosecond * time.Duration(retries) timeout := 10 * time.Nanosecond _, cancel := context.WithTimeout(ac.ctx, timeout) _ = time.Now() cancel() <-ac.ctx.Done() return } } func (ac *addrConn_grpc862) tearDown() { ac.cancel() } func DialContext_grpc862(ctx context.Context) (conn *ClientConn_grpc862) { cc := &ClientConn_grpc862{} cc.ctx, cc.cancel = context.WithCancel(context.Background()) defer func() { select { case <-ctx.Done(): if conn != nil { conn.Close() } conn = nil default: } }() go func() { // G2 cc.resetAddrConn() }() return conn } func Grpc862() { prof := pprof.Lookup("goroutineleak") defer func() { // Yield several times to allow the child goroutine to run. for i := 0; i < yieldCount; i++ { runtime.Gosched() } prof.WriteTo(os.Stdout, 2) }() go func() { ctx, cancel := context.WithCancel(context.Background()) go DialContext_grpc862(ctx) // G1 go cancel() // helper goroutine }() }