// 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. package main import ( "context" "io" "os" "runtime" "runtime/pprof" "sync" ) func init() { register("Etcd5509", Etcd5509) } var ErrConnClosed_etcd5509 error type Client_etcd5509 struct { mu sync.RWMutex ctx context.Context cancel context.CancelFunc } func (c *Client_etcd5509) Close() { c.mu.Lock() defer c.mu.Unlock() if c.cancel == nil { return } c.cancel() c.cancel = nil c.mu.Unlock() c.mu.Lock() } type remoteClient_etcd5509 struct { client *Client_etcd5509 mu sync.Mutex } func (r *remoteClient_etcd5509) acquire(ctx context.Context) error { for { r.client.mu.RLock() closed := r.client.cancel == nil r.mu.Lock() r.mu.Unlock() if closed { return ErrConnClosed_etcd5509 // Missing RUnlock before return } r.client.mu.RUnlock() } } type kv_etcd5509 struct { rc *remoteClient_etcd5509 } func (kv *kv_etcd5509) Get(ctx context.Context) error { return kv.Do(ctx) } func (kv *kv_etcd5509) Do(ctx context.Context) error { for { err := kv.do(ctx) if err == nil { return nil } return err } } func (kv *kv_etcd5509) do(ctx context.Context) error { err := kv.getRemote(ctx) return err } func (kv *kv_etcd5509) getRemote(ctx context.Context) error { return kv.rc.acquire(ctx) } type KV interface { Get(ctx context.Context) error Do(ctx context.Context) error } func NewKV_etcd5509(c *Client_etcd5509) KV { return &kv_etcd5509{rc: &remoteClient_etcd5509{ client: c, }} } func Etcd5509() { 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, _ := context.WithCancel(context.TODO()) cli := &Client_etcd5509{ ctx: ctx, } kv := NewKV_etcd5509(cli) donec := make(chan struct{}) go func() { defer close(donec) err := kv.Get(context.TODO()) if err != nil && err != ErrConnClosed_etcd5509 { io.Discard.Write([]byte("Expect ErrConnClosed")) } }() runtime.Gosched() cli.Close() <-donec }() }