Source file src/runtime/testdata/testgoroutineleakprofile/goker/etcd5509.go

     1  // Copyright 2025 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a MIT
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"context"
     9  	"io"
    10  	"os"
    11  	"runtime"
    12  	"runtime/pprof"
    13  	"sync"
    14  )
    15  
    16  func init() {
    17  	register("Etcd5509", Etcd5509)
    18  }
    19  
    20  var ErrConnClosed_etcd5509 error
    21  
    22  type Client_etcd5509 struct {
    23  	mu     sync.RWMutex
    24  	ctx    context.Context
    25  	cancel context.CancelFunc
    26  }
    27  
    28  func (c *Client_etcd5509) Close() {
    29  	c.mu.Lock()
    30  	defer c.mu.Unlock()
    31  	if c.cancel == nil {
    32  		return
    33  	}
    34  	c.cancel()
    35  	c.cancel = nil
    36  	c.mu.Unlock()
    37  	c.mu.Lock()
    38  }
    39  
    40  type remoteClient_etcd5509 struct {
    41  	client *Client_etcd5509
    42  	mu     sync.Mutex
    43  }
    44  
    45  func (r *remoteClient_etcd5509) acquire(ctx context.Context) error {
    46  	for {
    47  		r.client.mu.RLock()
    48  		closed := r.client.cancel == nil
    49  		r.mu.Lock()
    50  		r.mu.Unlock()
    51  		if closed {
    52  			return ErrConnClosed_etcd5509 // Missing RUnlock before return
    53  		}
    54  		r.client.mu.RUnlock()
    55  	}
    56  }
    57  
    58  type kv_etcd5509 struct {
    59  	rc *remoteClient_etcd5509
    60  }
    61  
    62  func (kv *kv_etcd5509) Get(ctx context.Context) error {
    63  	return kv.Do(ctx)
    64  }
    65  
    66  func (kv *kv_etcd5509) Do(ctx context.Context) error {
    67  	for {
    68  		err := kv.do(ctx)
    69  		if err == nil {
    70  			return nil
    71  		}
    72  		return err
    73  	}
    74  }
    75  
    76  func (kv *kv_etcd5509) do(ctx context.Context) error {
    77  	err := kv.getRemote(ctx)
    78  	return err
    79  }
    80  
    81  func (kv *kv_etcd5509) getRemote(ctx context.Context) error {
    82  	return kv.rc.acquire(ctx)
    83  }
    84  
    85  type KV interface {
    86  	Get(ctx context.Context) error
    87  	Do(ctx context.Context) error
    88  }
    89  
    90  func NewKV_etcd5509(c *Client_etcd5509) KV {
    91  	return &kv_etcd5509{rc: &remoteClient_etcd5509{
    92  		client: c,
    93  	}}
    94  }
    95  
    96  func Etcd5509() {
    97  	prof := pprof.Lookup("goroutineleak")
    98  	defer func() {
    99  		// Yield several times to allow the child goroutine to run.
   100  		for i := 0; i < yieldCount; i++ {
   101  			runtime.Gosched()
   102  		}
   103  		prof.WriteTo(os.Stdout, 2)
   104  	}()
   105  
   106  	go func() {
   107  		ctx, _ := context.WithCancel(context.TODO())
   108  		cli := &Client_etcd5509{
   109  			ctx: ctx,
   110  		}
   111  		kv := NewKV_etcd5509(cli)
   112  		donec := make(chan struct{})
   113  		go func() {
   114  			defer close(donec)
   115  			err := kv.Get(context.TODO())
   116  			if err != nil && err != ErrConnClosed_etcd5509 {
   117  				io.Discard.Write([]byte("Expect ErrConnClosed"))
   118  			}
   119  		}()
   120  
   121  		runtime.Gosched()
   122  		cli.Close()
   123  
   124  		<-donec
   125  	}()
   126  }
   127  

View as plain text