Source file src/runtime/testdata/testgoroutineleakprofile/goker/istio17860.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  	"os"
    10  	"runtime/pprof"
    11  
    12  	"sync"
    13  	"time"
    14  )
    15  
    16  func init() {
    17  	register("Istio17860", Istio17860)
    18  }
    19  
    20  type Proxy_istio17860 interface {
    21  	IsLive() bool
    22  }
    23  
    24  type TestProxy_istio17860 struct {
    25  	live func() bool
    26  }
    27  
    28  func (tp TestProxy_istio17860) IsLive() bool {
    29  	if tp.live == nil {
    30  		return true
    31  	}
    32  	return tp.live()
    33  }
    34  
    35  type Agent_istio17860 interface {
    36  	Run(ctx context.Context)
    37  	Restart()
    38  }
    39  
    40  type exitStatus_istio17860 int
    41  
    42  type agent_istio17860 struct {
    43  	proxy        Proxy_istio17860
    44  	mu           *sync.Mutex
    45  	statusCh     chan exitStatus_istio17860
    46  	currentEpoch int
    47  	activeEpochs map[int]struct{}
    48  }
    49  
    50  func (a *agent_istio17860) Run(ctx context.Context) {
    51  	for {
    52  		select {
    53  		case status := <-a.statusCh:
    54  			a.mu.Lock()
    55  			delete(a.activeEpochs, int(status))
    56  			active := len(a.activeEpochs)
    57  			a.mu.Unlock()
    58  			if active == 0 {
    59  				return
    60  			}
    61  		case <-ctx.Done():
    62  			return
    63  		}
    64  	}
    65  }
    66  
    67  func (a *agent_istio17860) Restart() {
    68  	a.mu.Lock()
    69  	defer a.mu.Unlock()
    70  
    71  	a.waitUntilLive()
    72  	a.currentEpoch++
    73  	a.activeEpochs[a.currentEpoch] = struct{}{}
    74  
    75  	go a.runWait(a.currentEpoch)
    76  }
    77  
    78  func (a *agent_istio17860) runWait(epoch int) {
    79  	a.statusCh <- exitStatus_istio17860(epoch)
    80  }
    81  
    82  func (a *agent_istio17860) waitUntilLive() {
    83  	if len(a.activeEpochs) == 0 {
    84  		return
    85  	}
    86  
    87  	interval := time.NewTicker(30 * time.Nanosecond)
    88  	timer := time.NewTimer(100 * time.Nanosecond)
    89  	defer func() {
    90  		interval.Stop()
    91  		timer.Stop()
    92  	}()
    93  
    94  	if a.proxy.IsLive() {
    95  		return
    96  	}
    97  
    98  	for {
    99  		select {
   100  		case <-timer.C:
   101  			return
   102  		case <-interval.C:
   103  			if a.proxy.IsLive() {
   104  				return
   105  			}
   106  		}
   107  	}
   108  }
   109  
   110  func NewAgent_istio17860(proxy Proxy_istio17860) Agent_istio17860 {
   111  	return &agent_istio17860{
   112  		proxy:        proxy,
   113  		mu:           &sync.Mutex{},
   114  		statusCh:     make(chan exitStatus_istio17860),
   115  		activeEpochs: make(map[int]struct{}),
   116  	}
   117  }
   118  
   119  func Istio17860() {
   120  	prof := pprof.Lookup("goroutineleak")
   121  	defer func() {
   122  		time.Sleep(100 * time.Millisecond)
   123  		prof.WriteTo(os.Stdout, 2)
   124  	}()
   125  
   126  	for i := 0; i < 100; i++ {
   127  		go func() {
   128  			ctx, cancel := context.WithCancel(context.Background())
   129  			defer cancel()
   130  
   131  			neverLive := func() bool {
   132  				return false
   133  			}
   134  
   135  			a := NewAgent_istio17860(TestProxy_istio17860{live: neverLive})
   136  			go func() { a.Run(ctx) }()
   137  
   138  			a.Restart()
   139  			go a.Restart()
   140  
   141  			time.Sleep(200 * time.Nanosecond)
   142  		}()
   143  	}
   144  }
   145  

View as plain text