blob: bc658b408d8c6b06748dca6277f504eb6c31f8d2 [file] [log] [blame]
// 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
* Issue or PR : https://github.com/grpc/grpc-go/pull/1460
* Buggy version: 7db1564ba1229bc42919bb1f6d9c4186f3aa8678
* fix commit-id: e605a1ecf24b634f94f4eefdab10a9ada98b70dd
* Flaky: 100/100
*/
package main
import (
"os"
"runtime"
"runtime/pprof"
"sync"
"time"
)
func init() {
register("Grpc1460", Grpc1460)
}
type Stream_grpc1460 struct{}
type http2Client_grpc1460 struct {
mu sync.Mutex
awakenKeepalive chan struct{}
activeStream []*Stream_grpc1460
}
func (t *http2Client_grpc1460) keepalive() {
t.mu.Lock()
if len(t.activeStream) < 1 {
<-t.awakenKeepalive
runtime.Gosched()
t.mu.Unlock()
} else {
t.mu.Unlock()
}
}
func (t *http2Client_grpc1460) NewStream() {
t.mu.Lock()
runtime.Gosched()
t.activeStream = append(t.activeStream, &Stream_grpc1460{})
if len(t.activeStream) == 1 {
select {
case t.awakenKeepalive <- struct{}{}:
default:
}
}
t.mu.Unlock()
}
///
/// G1 G2
/// client.keepalive()
/// client.NewStream()
/// t.mu.Lock()
/// <-t.awakenKeepalive
/// t.mu.Lock()
/// ---------------G1, G2 deadlock--------------
///
func Grpc1460() {
prof := pprof.Lookup("goroutineleak")
defer func() {
time.Sleep(100 * time.Millisecond)
prof.WriteTo(os.Stdout, 2)
}()
for i := 0; i < 1000; i++ {
go func() {
client := &http2Client_grpc1460{
awakenKeepalive: make(chan struct{}),
}
go client.keepalive() //G1
go client.NewStream() //G2
}()
}
}