mirror of
https://github.com/jesseduffield/lazydocker.git
synced 2026-09-28 01:56:07 -04:00
add deadlock detection for debug mode
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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{})
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user