| // 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: moby |
| * Issue or PR : https://github.com/moby/moby/pull/21233 |
| * Buggy version: cc12d2bfaae135e63b1f962ad80e6943dd995337 |
| * fix commit-id: 2f4aa9658408ac72a598363c6e22eadf93dbb8a7 |
| * Flaky:100/100 |
| */ |
| package main |
| |
| import ( |
| "math/rand" |
| "os" |
| "runtime/pprof" |
| "sync" |
| "time" |
| ) |
| |
| func init() { |
| register("Moby21233", Moby21233) |
| } |
| |
| type Progress_moby21233 struct{} |
| |
| type Output_moby21233 interface { |
| WriteProgress(Progress_moby21233) error |
| } |
| |
| type chanOutput_moby21233 chan<- Progress_moby21233 |
| |
| type TransferManager_moby21233 struct { |
| mu sync.Mutex |
| } |
| |
| type Transfer_moby21233 struct { |
| mu sync.Mutex |
| } |
| |
| type Watcher_moby21233 struct { |
| signalChan chan struct{} |
| releaseChan chan struct{} |
| running chan struct{} |
| } |
| |
| func ChanOutput_moby21233(progressChan chan<- Progress_moby21233) Output_moby21233 { |
| return chanOutput_moby21233(progressChan) |
| } |
| func (out chanOutput_moby21233) WriteProgress(p Progress_moby21233) error { |
| out <- p |
| return nil |
| } |
| func NewTransferManager_moby21233() *TransferManager_moby21233 { |
| return &TransferManager_moby21233{} |
| } |
| func NewTransfer_moby21233() *Transfer_moby21233 { |
| return &Transfer_moby21233{} |
| } |
| func (t *Transfer_moby21233) Release(watcher *Watcher_moby21233) { |
| t.mu.Lock() |
| t.mu.Unlock() |
| close(watcher.releaseChan) |
| <-watcher.running |
| } |
| func (t *Transfer_moby21233) Watch(progressOutput Output_moby21233) *Watcher_moby21233 { |
| t.mu.Lock() |
| defer t.mu.Unlock() |
| lastProgress := Progress_moby21233{} |
| w := &Watcher_moby21233{ |
| releaseChan: make(chan struct{}), |
| signalChan: make(chan struct{}), |
| running: make(chan struct{}), |
| } |
| go func() { // G2 |
| defer func() { |
| close(w.running) |
| }() |
| done := false |
| for { |
| t.mu.Lock() |
| t.mu.Unlock() |
| if rand.Int31n(2) >= 1 { |
| progressOutput.WriteProgress(lastProgress) |
| } |
| if done { |
| return |
| } |
| select { |
| case <-w.signalChan: |
| case <-w.releaseChan: |
| done = true |
| } |
| } |
| }() |
| return w |
| } |
| func (tm *TransferManager_moby21233) Transfer(progressOutput Output_moby21233) (*Transfer_moby21233, *Watcher_moby21233) { |
| tm.mu.Lock() |
| defer tm.mu.Unlock() |
| t := NewTransfer_moby21233() |
| return t, t.Watch(progressOutput) |
| } |
| |
| func testTransfer_moby21233() { // G1 |
| tm := NewTransferManager_moby21233() |
| progressChan := make(chan Progress_moby21233) |
| progressDone := make(chan struct{}) |
| go func() { // G3 |
| time.Sleep(1 * time.Millisecond) |
| for p := range progressChan { /// Chan consumer |
| if rand.Int31n(2) >= 1 { |
| return |
| } |
| _ = p |
| } |
| close(progressDone) |
| }() |
| time.Sleep(1 * time.Millisecond) |
| ids := []string{"id1", "id2", "id3"} |
| xrefs := make([]*Transfer_moby21233, len(ids)) |
| watchers := make([]*Watcher_moby21233, len(ids)) |
| for i := range ids { |
| xrefs[i], watchers[i] = tm.Transfer(ChanOutput_moby21233(progressChan)) /// Chan producer |
| time.Sleep(2 * time.Millisecond) |
| } |
| |
| for i := range xrefs { |
| xrefs[i].Release(watchers[i]) |
| } |
| |
| close(progressChan) |
| <-progressDone |
| } |
| |
| func Moby21233() { |
| prof := pprof.Lookup("goroutineleak") |
| defer func() { |
| time.Sleep(100 * time.Millisecond) |
| prof.WriteTo(os.Stdout, 2) |
| }() |
| for i := 0; i < 100; i++ { |
| go testTransfer_moby21233() // G1 |
| } |
| } |