add deadlock detection for debug mode

This commit is contained in:
Jesse Duffield
2022-11-09 21:21:35 +11:00
parent 9b58b8188a
commit aab8bcfbcc
35 changed files with 1645 additions and 12 deletions
+2 -2
View File
@@ -7,10 +7,10 @@ import (
"sort"
"strconv"
"strings"
"sync"
"github.com/docker/docker/api/types/container"
"github.com/samber/lo"
"github.com/sasha-s/go-deadlock"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
@@ -45,7 +45,7 @@ type Container struct {
DockerCommand LimitedDockerCommand
Tr *i18n.TranslationSet
StatsMutex sync.Mutex
StatsMutex deadlock.Mutex
}
// TODO: move this stuff into a presentation layer
+3 -3
View File
@@ -9,7 +9,6 @@ import (
ogLog "log"
"os/exec"
"strings"
"sync"
"time"
"github.com/docker/docker/api/types"
@@ -19,6 +18,7 @@ import (
"github.com/jesseduffield/lazydocker/pkg/config"
"github.com/jesseduffield/lazydocker/pkg/i18n"
"github.com/jesseduffield/lazydocker/pkg/utils"
"github.com/sasha-s/go-deadlock"
"github.com/sirupsen/logrus"
)
@@ -35,8 +35,8 @@ type DockerCommand struct {
Client *client.Client
InDockerComposeProject bool
ErrorChan chan error
ContainerMutex sync.Mutex
ServiceMutex sync.Mutex
ContainerMutex deadlock.Mutex
ServiceMutex deadlock.Mutex
Closers []io.Closer
}
+14 -3
View File
@@ -2,8 +2,8 @@ package gui
import (
"context"
"os"
"strings"
"sync"
"time"
"github.com/docker/docker/api/types"
@@ -16,6 +16,8 @@ import (
"github.com/jesseduffield/lazydocker/pkg/config"
"github.com/jesseduffield/lazydocker/pkg/i18n"
"github.com/jesseduffield/lazydocker/pkg/tasks"
"github.com/jesseduffield/lazydocker/pkg/utils"
"github.com/sasha-s/go-deadlock"
"github.com/sirupsen/logrus"
)
@@ -57,8 +59,8 @@ type Panels struct {
}
type Mutexes struct {
SubprocessMutex sync.Mutex
ViewStackMutex sync.Mutex
SubprocessMutex deadlock.Mutex
ViewStackMutex deadlock.Mutex
}
type mainPanelState struct {
@@ -139,6 +141,9 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand
gui.CyclableViews = gui.sideViewNames()
deadlock.Opts.Disable = !gui.Config.Debug
deadlock.Opts.DeadlockTimeout = 5 * time.Second
return gui, nil
}
@@ -185,6 +190,12 @@ func (gui *Gui) Run() error {
gui.g = g // TODO: always use gui.g rather than passing g around everywhere
// if the deadlock package wants to report a deadlock, we first need to
// close the gui so that we can actually read what it prints.
deadlock.Opts.LogBuf = utils.NewOnceWriter(os.Stderr, func() {
gui.g.Close()
})
if err := gui.SetColorScheme(); err != nil {
return err
}
+4 -4
View File
@@ -2,17 +2,17 @@ package tasks
import (
"fmt"
"sync"
"time"
"github.com/jesseduffield/lazydocker/pkg/i18n"
"github.com/sasha-s/go-deadlock"
"github.com/sirupsen/logrus"
)
type TaskManager struct {
currentTask *Task
waitingMutex sync.Mutex
taskIDMutex sync.Mutex
waitingMutex deadlock.Mutex
taskIDMutex deadlock.Mutex
Log *logrus.Entry
Tr *i18n.TranslationSet
newTaskId int
@@ -21,7 +21,7 @@ type TaskManager struct {
type Task struct {
stop chan struct{}
stopped bool
stopMutex sync.Mutex
stopMutex deadlock.Mutex
notifyStopped chan struct{}
Log *logrus.Entry
f func(chan struct{})
+32
View File
@@ -0,0 +1,32 @@
package utils
import (
"io"
"sync"
)
// TODO: extract into lazycore repo.
// This wraps a writer and ensures that before we actually write anything we call a given function first
type OnceWriter struct {
writer io.Writer
once sync.Once
f func()
}
var _ io.Writer = &OnceWriter{}
func NewOnceWriter(writer io.Writer, f func()) *OnceWriter {
return &OnceWriter{
writer: writer,
f: f,
}
}
func (self *OnceWriter) Write(p []byte) (n int, err error) {
self.once.Do(func() {
self.f()
})
return self.writer.Write(p)
}
+19
View File
@@ -0,0 +1,19 @@
package utils
import (
"bytes"
"testing"
)
func TestOnceWriter(t *testing.T) {
innerWriter := bytes.NewBuffer(nil)
counter := 0
onceWriter := NewOnceWriter(innerWriter, func() {
counter += 1
})
_, _ = onceWriter.Write([]byte("hello"))
_, _ = onceWriter.Write([]byte("hello"))
if counter != 1 {
t.Errorf("expected counter to be 1, got %d", counter)
}
}