blob: 9b53d9035ca1e1478dd4604c9227d860ded827a9 [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: moby
* Issue or PR : https://github.com/moby/moby/pull/27782
* Buggy version: 18768fdc2e76ec6c600c8ab57d2d487ee7877794
* fix commit-id: a69a59ffc7e3d028a72d1195c2c1535f447eaa84
* Flaky: 2/100
*/
package main
import (
"errors"
"os"
"runtime"
"runtime/pprof"
"sync"
"time"
)
func init() {
register("Moby27782", Moby27782)
}
type Event_moby27782 struct {
Op Op_moby27782
}
type Op_moby27782 uint32
const (
Create_moby27782 Op_moby27782 = 1 << iota
Write_moby27782
Remove_moby27782
Rename_moby27782
Chmod_moby27782
)
func newEvent(op Op_moby27782) Event_moby27782 {
return Event_moby27782{op}
}
func (e *Event_moby27782) ignoreLinux(w *Watcher_moby27782) bool {
if e.Op != Write_moby27782 {
w.mu.Lock()
defer w.mu.Unlock()
w.cv.Broadcast()
return true
}
runtime.Gosched()
return false
}
type Watcher_moby27782 struct {
Events chan Event_moby27782
mu sync.Mutex // L1
cv *sync.Cond // C1
done chan struct{}
}
func NewWatcher_moby27782() *Watcher_moby27782 {
w := &Watcher_moby27782{
Events: make(chan Event_moby27782),
done: make(chan struct{}),
}
w.cv = sync.NewCond(&w.mu)
go w.readEvents() // G3
return w
}
func (w *Watcher_moby27782) readEvents() {
defer close(w.Events)
for {
if w.isClosed() {
return
}
event := newEvent(Write_moby27782) // MODIFY event
if !event.ignoreLinux(w) {
runtime.Gosched()
select {
case w.Events <- event:
case <-w.done:
return
}
}
}
}
func (w *Watcher_moby27782) isClosed() bool {
select {
case <-w.done:
return true
default:
return false
}
}
func (w *Watcher_moby27782) Close() {
if w.isClosed() {
return
}
close(w.done)
}
func (w *Watcher_moby27782) Remove() {
w.mu.Lock()
defer w.mu.Unlock()
exists := true
for exists {
w.cv.Wait()
runtime.Gosched()
}
}
type FileWatcher_moby27782 interface {
Events() <-chan Event_moby27782
Remove()
Close()
}
func New_moby27782() FileWatcher_moby27782 {
return NewEventWatcher_moby27782()
}
func NewEventWatcher_moby27782() FileWatcher_moby27782 {
return &fsNotifyWatcher_moby27782{NewWatcher_moby27782()}
}
type fsNotifyWatcher_moby27782 struct {
*Watcher_moby27782
}
func (w *fsNotifyWatcher_moby27782) Events() <-chan Event_moby27782 {
return w.Watcher_moby27782.Events
}
func watchFile_moby27782() FileWatcher_moby27782 {
fileWatcher := New_moby27782()
return fileWatcher
}
type LogWatcher_moby27782 struct {
closeOnce sync.Once
closeNotifier chan struct{}
}
func (w *LogWatcher_moby27782) Close() {
w.closeOnce.Do(func() {
close(w.closeNotifier)
})
}
func (w *LogWatcher_moby27782) WatchClose() <-chan struct{} {
return w.closeNotifier
}
func NewLogWatcher_moby27782() *LogWatcher_moby27782 {
return &LogWatcher_moby27782{
closeNotifier: make(chan struct{}),
}
}
func followLogs_moby27782(logWatcher *LogWatcher_moby27782) {
fileWatcher := watchFile_moby27782()
defer func() {
fileWatcher.Close()
}()
waitRead := func() {
runtime.Gosched()
select {
case <-fileWatcher.Events():
case <-logWatcher.WatchClose():
fileWatcher.Remove()
return
}
}
handleDecodeErr := func() {
waitRead()
}
handleDecodeErr()
}
type Container_moby27782 struct {
LogDriver *JSONFileLogger_moby27782
}
func (container *Container_moby27782) InitializeStdio() {
if err := container.startLogging(); err != nil {
container.Reset()
}
}
func (container *Container_moby27782) startLogging() error {
l := &JSONFileLogger_moby27782{
readers: make(map[*LogWatcher_moby27782]struct{}),
}
container.LogDriver = l
l.ReadLogs()
return errors.New("Some error")
}
func (container *Container_moby27782) Reset() {
if container.LogDriver != nil {
container.LogDriver.Close()
}
}
type JSONFileLogger_moby27782 struct {
mu sync.Mutex
readers map[*LogWatcher_moby27782]struct{}
}
func (l *JSONFileLogger_moby27782) ReadLogs() *LogWatcher_moby27782 {
logWatcher := NewLogWatcher_moby27782()
go l.readLogs(logWatcher) // G2
return logWatcher
}
func (l *JSONFileLogger_moby27782) readLogs(logWatcher *LogWatcher_moby27782) {
l.mu.Lock()
defer l.mu.Unlock()
l.readers[logWatcher] = struct{}{}
followLogs_moby27782(logWatcher)
}
func (l *JSONFileLogger_moby27782) Close() {
l.mu.Lock()
defer l.mu.Unlock()
for r := range l.readers {
r.Close()
delete(l.readers, r)
}
}
func Moby27782() {
prof := pprof.Lookup("goroutineleak")
defer func() {
time.Sleep(100 * time.Millisecond)
prof.WriteTo(os.Stdout, 2)
}()
for i := 0; i < 10000; i++ {
go (&Container_moby27782{}).InitializeStdio() // G1
}
}