Source file src/runtime/testdata/testgoroutineleakprofile/goker/etcd7492.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  /*
     6   * Project: etcd
     7   * Issue or PR  : https://github.com/etcd-io/etcd/pull/7492
     8   * Buggy version: 51939650057d602bb5ab090633138fffe36854dc
     9   * fix commit-id: 1b1fabef8ffec606909f01c3983300fff539f214
    10   * Flaky: 40/100
    11   */
    12  package main
    13  
    14  import (
    15  	"os"
    16  	"runtime"
    17  	"runtime/pprof"
    18  	"sync"
    19  	"time"
    20  )
    21  
    22  func init() {
    23  	register("Etcd7492", Etcd7492)
    24  }
    25  
    26  type TokenProvider_etcd7492 interface {
    27  	assign()
    28  	enable()
    29  	disable()
    30  }
    31  
    32  type simpleTokenTTLKeeper_etcd7492 struct {
    33  	tokens           map[string]time.Time
    34  	addSimpleTokenCh chan struct{}
    35  	stopCh           chan chan struct{}
    36  	deleteTokenFunc  func(string)
    37  }
    38  
    39  type authStore_etcd7492 struct {
    40  	tokenProvider TokenProvider_etcd7492
    41  }
    42  
    43  func (as *authStore_etcd7492) Authenticate() {
    44  	as.tokenProvider.assign()
    45  }
    46  
    47  func NewSimpleTokenTTLKeeper_etcd7492(deletefunc func(string)) *simpleTokenTTLKeeper_etcd7492 {
    48  	stk := &simpleTokenTTLKeeper_etcd7492{
    49  		tokens:           make(map[string]time.Time),
    50  		addSimpleTokenCh: make(chan struct{}, 1),
    51  		stopCh:           make(chan chan struct{}),
    52  		deleteTokenFunc:  deletefunc,
    53  	}
    54  	go stk.run() // G1
    55  	return stk
    56  }
    57  
    58  func (tm *simpleTokenTTLKeeper_etcd7492) run() {
    59  	tokenTicker := time.NewTicker(time.Nanosecond)
    60  	defer tokenTicker.Stop()
    61  	for {
    62  		select {
    63  		case <-tm.addSimpleTokenCh:
    64  			runtime.Gosched()
    65  			/// Make tm.tokens not empty is enough
    66  			tm.tokens["1"] = time.Now()
    67  		case <-tokenTicker.C:
    68  			runtime.Gosched()
    69  			for t, _ := range tm.tokens {
    70  				tm.deleteTokenFunc(t)
    71  				delete(tm.tokens, t)
    72  			}
    73  		case waitCh := <-tm.stopCh:
    74  			waitCh <- struct{}{}
    75  			return
    76  		}
    77  	}
    78  }
    79  
    80  func (tm *simpleTokenTTLKeeper_etcd7492) addSimpleToken() {
    81  	tm.addSimpleTokenCh <- struct{}{}
    82  	runtime.Gosched()
    83  }
    84  
    85  func (tm *simpleTokenTTLKeeper_etcd7492) stop() {
    86  	waitCh := make(chan struct{})
    87  	tm.stopCh <- waitCh
    88  	<-waitCh
    89  	close(tm.stopCh)
    90  }
    91  
    92  type tokenSimple_etcd7492 struct {
    93  	simpleTokenKeeper *simpleTokenTTLKeeper_etcd7492
    94  	simpleTokensMu    sync.RWMutex
    95  }
    96  
    97  func (t *tokenSimple_etcd7492) assign() {
    98  	t.assignSimpleTokenToUser()
    99  }
   100  
   101  func (t *tokenSimple_etcd7492) assignSimpleTokenToUser() {
   102  	t.simpleTokensMu.Lock()
   103  	runtime.Gosched()
   104  	t.simpleTokenKeeper.addSimpleToken()
   105  	t.simpleTokensMu.Unlock()
   106  }
   107  func newDeleterFunc(t *tokenSimple_etcd7492) func(string) {
   108  	return func(tk string) {
   109  		t.simpleTokensMu.Lock()
   110  		defer t.simpleTokensMu.Unlock()
   111  	}
   112  }
   113  
   114  func (t *tokenSimple_etcd7492) enable() {
   115  	t.simpleTokenKeeper = NewSimpleTokenTTLKeeper_etcd7492(newDeleterFunc(t))
   116  }
   117  
   118  func (t *tokenSimple_etcd7492) disable() {
   119  	if t.simpleTokenKeeper != nil {
   120  		t.simpleTokenKeeper.stop()
   121  		t.simpleTokenKeeper = nil
   122  	}
   123  	t.simpleTokensMu.Lock()
   124  	t.simpleTokensMu.Unlock()
   125  }
   126  
   127  func newTokenProviderSimple_etcd7492() *tokenSimple_etcd7492 {
   128  	return &tokenSimple_etcd7492{}
   129  }
   130  
   131  func setupAuthStore_etcd7492() (store *authStore_etcd7492, teardownfunc func()) {
   132  	as := &authStore_etcd7492{
   133  		tokenProvider: newTokenProviderSimple_etcd7492(),
   134  	}
   135  	as.tokenProvider.enable()
   136  	tearDown := func() {
   137  		as.tokenProvider.disable()
   138  	}
   139  	return as, tearDown
   140  }
   141  
   142  func Etcd7492() {
   143  	prof := pprof.Lookup("goroutineleak")
   144  	defer func() {
   145  		time.Sleep(100 * time.Millisecond)
   146  		prof.WriteTo(os.Stdout, 2)
   147  	}()
   148  	for i := 0; i < 100; i++ {
   149  		go func() {
   150  			as, tearDown := setupAuthStore_etcd7492()
   151  			defer tearDown()
   152  			var wg sync.WaitGroup
   153  			wg.Add(3)
   154  			for i := 0; i < 3; i++ {
   155  				go func() { // G2
   156  					as.Authenticate()
   157  					defer wg.Done()
   158  				}()
   159  			}
   160  			wg.Wait()
   161  		}()
   162  	}
   163  }
   164  

View as plain text