diff options
author | Jesse Duffield <jessedduffield@gmail.com> | 2022-08-07 09:44:50 +1000 |
---|---|---|
committer | Jesse Duffield <jessedduffield@gmail.com> | 2022-08-07 11:16:14 +1000 |
commit | 755ae0ef846d6a42678d0b8cb2c37108f79a0458 (patch) | |
tree | 8ef20b395f85fa174c122665ca46eb2d7d9b7ff4 | |
parent | 7410acd1aaa97f678295a328264360802346b33a (diff) |
add deadlock mutex package
write to deadlock stderr after closing gocui
more deadlock checking
44 files changed, 1635 insertions, 57 deletions
@@ -30,6 +30,7 @@ require ( github.com/sahilm/fuzzy v0.1.0 github.com/samber/lo v1.10.1 github.com/sanity-io/litter v1.5.2 + github.com/sasha-s/go-deadlock v0.3.1 github.com/sirupsen/logrus v1.4.2 github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad github.com/stretchr/testify v1.7.0 @@ -58,6 +59,7 @@ require ( github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/onsi/ginkgo v1.10.3 // indirect github.com/onsi/gomega v1.7.1 // indirect + github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect github.com/rivo/uniseg v0.3.4 // indirect github.com/sergi/go-diff v1.1.0 // indirect github.com/xanzy/ssh-agent v0.2.1 // indirect @@ -125,6 +125,8 @@ github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= +github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -140,6 +142,8 @@ github.com/samber/lo v1.10.1 h1:0D3h7i0U3hRAbaCeQ82DLe67n0A7Bbl0/cEoWqFGp+U= github.com/samber/lo v1.10.1/go.mod h1:2I7tgIv8Q1SG2xEIkRq0F2i2zgxVpnyPOP0d3Gj2r+A= github.com/sanity-io/litter v1.5.2 h1:AnC8s9BMORWH5a4atZ4D6FPVvKGzHcnc5/IVTa87myw= github.com/sanity-io/litter v1.5.2/go.mod h1:5Z71SvaYy5kcGtyglXOC9rrUi3c1E8CamFWjQsazTh0= +github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= +github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= diff --git a/pkg/commands/git.go b/pkg/commands/git.go index 64f0455b7..2176077d4 100644 --- a/pkg/commands/git.go +++ b/pkg/commands/git.go @@ -5,9 +5,9 @@ import ( "os" "path/filepath" "strings" - "sync" "github.com/go-errors/errors" + "github.com/sasha-s/go-deadlock" gogit "github.com/jesseduffield/go-git/v5" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" @@ -57,7 +57,7 @@ func NewGitCommand( cmn *common.Common, osCommand *oscommands.OSCommand, gitConfig git_config.IGitConfig, - syncMutex *sync.Mutex, + syncMutex *deadlock.Mutex, ) (*GitCommand, error) { if err := navigateToRepoRootDirectory(os.Stat, os.Chdir); err != nil { return nil, err @@ -89,7 +89,7 @@ func NewGitCommandAux( gitConfig git_config.IGitConfig, dotGitDir string, repo *gogit.Repository, - syncMutex *sync.Mutex, + syncMutex *deadlock.Mutex, ) *GitCommand { cmd := NewGitCmdObjBuilder(cmn.Log, osCommand.Cmd) diff --git a/pkg/commands/git_commands/common.go b/pkg/commands/git_commands/common.go index 85f0d2118..09694110d 100644 --- a/pkg/commands/git_commands/common.go +++ b/pkg/commands/git_commands/common.go @@ -1,11 +1,10 @@ package git_commands import ( - "sync" - gogit "github.com/jesseduffield/go-git/v5" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/common" + "github.com/sasha-s/go-deadlock" ) type GitCommon struct { @@ -16,7 +15,7 @@ type GitCommon struct { repo *gogit.Repository config *ConfigCommands // mutex for doing things like push/pull/fetch - syncMutex *sync.Mutex + syncMutex *deadlock.Mutex } func NewGitCommon( @@ -26,7 +25,7 @@ func NewGitCommon( dotGitDir string, repo *gogit.Repository, config *ConfigCommands, - syncMutex *sync.Mutex, + syncMutex *deadlock.Mutex, ) *GitCommon { return &GitCommon{ Common: cmn, diff --git a/pkg/commands/git_test.go b/pkg/commands/git_test.go index a36a5c6fe..3531f14ca 100644 --- a/pkg/commands/git_test.go +++ b/pkg/commands/git_test.go @@ -3,7 +3,6 @@ package commands import ( "fmt" "os" - "sync" "testing" "time" @@ -12,6 +11,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/git_config" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/utils" + "github.com/sasha-s/go-deadlock" "github.com/stretchr/testify/assert" ) @@ -220,7 +220,7 @@ func TestNewGitCommand(t *testing.T) { NewGitCommand(utils.NewDummyCommon(), oscommands.NewDummyOSCommand(), git_config.NewFakeGitConfig(nil), - &sync.Mutex{}, + &deadlock.Mutex{}, )) }) } diff --git a/pkg/commands/oscommands/cmd_obj.go b/pkg/commands/oscommands/cmd_obj.go index 7960bfa99..1a801c6fe 100644 --- a/pkg/commands/oscommands/cmd_obj.go +++ b/pkg/commands/oscommands/cmd_obj.go @@ -2,7 +2,8 @@ package oscommands import ( "os/exec" - "sync" + + "github.com/sasha-s/go-deadlock" ) // A command object is a general way to represent a command to be run on the @@ -51,8 +52,8 @@ type ICmdObj interface { PromptOnCredentialRequest() ICmdObj FailOnCredentialRequest() ICmdObj - WithMutex(mutex *sync.Mutex) ICmdObj - Mutex() *sync.Mutex + WithMutex(mutex *deadlock.Mutex) ICmdObj + Mutex() *deadlock.Mutex GetCredentialStrategy() CredentialStrategy } @@ -76,7 +77,7 @@ type CmdObj struct { credentialStrategy CredentialStrategy // can be set so that we don't run certain commands simultaneously - mutex *sync.Mutex + mutex *deadlock.Mutex } type CredentialStrategy int @@ -139,11 +140,11 @@ func (self *CmdObj) IgnoreEmptyError() ICmdObj { return self } -func (self *CmdObj) Mutex() *sync.Mutex { +func (self *CmdObj) Mutex() *deadlock.Mutex { return self.mutex } -func (self *CmdObj) WithMutex(mutex *sync.Mutex) ICmdObj { +func (self *CmdObj) WithMutex(mutex *deadlock.Mutex) ICmdObj { self.mutex = mutex return self diff --git a/pkg/commands/oscommands/cmd_obj_runner_win.go b/pkg/commands/oscommands/cmd_obj_runner_win.go index e4098ddc9..6893a2535 100644 --- a/pkg/commands/oscommands/cmd_obj_runner_win.go +++ b/pkg/commands/oscommands/cmd_obj_runner_win.go @@ -13,7 +13,7 @@ import ( type Buffer struct { b bytes.Buffer - m sync.Mutex + m deadlock.Mutex } func (b *Buffer) Read(p []byte) (n int, err error) { diff --git a/pkg/gui/app_status_manager.go b/pkg/gui/app_status_manager.go index 21cf353a4..c2d72c5ac 100644 --- a/pkg/gui/app_status_manager.go +++ b/pkg/gui/app_status_manager.go @@ -1,11 +1,11 @@ package gui import ( - "sync" "time" "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/utils" + "github.com/sasha-s/go-deadlock" ) // statusManager's job is to handle rendering of loading states and toast notifications @@ -13,7 +13,7 @@ import ( type statusManager struct { statuses []appStatus nextId int - mutex sync.Mutex + mutex deadlock.Mutex } type appStatus struct { diff --git a/pkg/gui/context/merge_conflicts_context.go b/pkg/gui/context/merge_conflicts_context.go index b49bf2c65..4d02d452e 100644 --- a/pkg/gui/context/merge_conflicts_context.go +++ b/pkg/gui/context/merge_conflicts_context.go @@ -2,7 +2,6 @@ package context import ( "math" - "sync" "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/gui/mergeconflicts" @@ -14,7 +13,7 @@ type MergeConflictsContext struct { types.Context viewModel *ConflictsViewModel c *types.HelperCommon - mutex *sync.Mutex + mutex *deadlock.Mutex } type ConflictsViewModel struct { @@ -40,7 +39,7 @@ func NewMergeConflictsContext( return &MergeConflictsContext{ viewModel: viewModel, - mutex: &sync.Mutex{}, + mutex: &deadlock.Mutex{}, Context: NewSimpleContext( NewBaseContext(NewBaseContextOpts{ Kind: types.MAIN_CONTEXT, @@ -64,7 +63,7 @@ func (self *MergeConflictsContext) SetState(state *mergeconflicts.State) { self.viewModel.state = state } -func (self *MergeConflictsContext) GetMutex() *sync.Mutex { +func (self *MergeConflictsContext) GetMutex() *deadlock.Mutex { return self.mutex } diff --git a/pkg/gui/context/patch_explorer_context.go b/pkg/gui/context/patch_explorer_context.go index a8ad45bbb..3e13b8539 100644 --- a/pkg/gui/context/patch_explorer_context.go +++ b/pkg/gui/context/patch_explorer_context.go @@ -1,11 +1,10 @@ package context import ( - "sync" - "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/gui/patch_exploring" "github.com/jesseduffield/lazygit/pkg/gui/types" + deadlock "github.com/sasha-s/go-deadlock" ) type PatchExplorerContext struct { @@ -15,7 +14,7 @@ type PatchExplorerContext struct { viewTrait *ViewTrait getIncludedLineIndices func() []int c *types.HelperCommon - mutex *sync.Mutex + mutex *deadlock.Mutex } var _ types.IPatchExplorerContext = (*PatchExplorerContext)(nil) @@ -35,7 +34,7 @@ func NewPatchExplorerContext( state: nil, viewTrait: NewViewTrait(view), c: c, - mutex: &sync.Mutex{}, + mutex: &deadlock.Mutex{}, getIncludedLineIndices: getIncludedLineIndices, SimpleContext: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ View: view, @@ -124,6 +123,6 @@ func (self *PatchExplorerContext) NavigateTo(isFocused bool, selectedLineIdx int return self.RenderAndFocus(isFocused) } -func (self *PatchExplorerContext) GetMutex() *sync.Mutex { +func (self *PatchExplorerContext) GetMutex() *deadlock.Mutex { return self.mutex } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 6b5f129af..bb5821a57 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -35,6 +35,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/theme" "github.com/jesseduffield/lazygit/pkg/updates" "github.com/jesseduffield/lazygit/pkg/utils" + "github.com/sasha-s/go-deadlock" "gopkg.in/ozeidan/fuzzy-patricia.v3/patricia" ) @@ -358,13 +359,13 @@ func NewGui( // sake of backwards compatibility. We're making use of short circuiting here ShowExtrasWindow: cmn.UserConfig.Gui.ShowCommandLog && !config.GetAppState().HideCommandLog, Mutexes: types.Mutexes{ - RefreshingFilesMutex: &sync.Mutex{}, - RefreshingStatusMutex: &sync.Mutex{}, - SyncMutex: &sync.Mutex{}, - LocalCommitsMutex: &sync.Mutex{}, - SubprocessMutex: &sync.Mutex{}, - PopupMutex: &sync.Mutex{}, - PtyMutex: &sync.Mutex{}, + RefreshingFilesMutex: &deadlock.Mutex{}, + RefreshingStatusMutex: &deadlock.Mutex{}, + SyncMutex: &deadlock.Mutex{}, + LocalCommitsMutex: &deadlock.Mutex{}, + SubprocessMutex: &deadlock.Mutex{}, + PopupMutex: &deadlock.Mutex{}, + PtyMutex: &deadlock.Mutex{}, }, InitialDir: initialDir, } diff --git a/pkg/gui/popup/popup_handler.go b/pkg/gui/popup/popup_handler.go index de892437f..26b886fb7 100644 --- a/pkg/gui/popup/popup_handler.go +++ b/pkg/gui/popup/popup_handler.go @@ -2,7 +2,6 @@ package popup import ( "strings" - "sync" "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/common" @@ -10,12 +9,13 @@ import ( "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" + "github.com/sasha-s/go-deadlock" ) type PopupHandler struct { *common.Common index int - sync.Mutex + deadlock.Mutex createPopupPanelFn func(types.CreatePopupPanelOpts) error onErrorFn func() error popContextFn func() error diff --git a/pkg/gui/presentation/commits.go b/pkg/gui/presentation/commits.go index 6ddbd5045..f9bdaee47 100644 --- a/pkg/gui/presentation/commits.go +++ b/pkg/gui/presentation/commits.go @@ -2,7 +2,6 @@ package presentation import ( "strings" - "sync" "github.com/jesseduffield/generics/set" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" @@ -14,6 +13,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/theme" "github.com/jesseduffield/lazygit/pkg/utils" "github.com/kyokomi/emoji/v2" + "github.com/sasha-s/go-deadlock" ) type pipeSetCacheKey struct { @@ -23,7 +23,7 @@ type pipeSetCacheKey struct { var ( pipeSetCache = make(map[pipeSetCacheKey][][]*graph.Pipe) - mutex sync.Mutex + mutex deadlock.Mutex ) type bisectBounds struct { diff --git a/pkg/gui/types/common.go b/pkg/gui/types/common.go index 156d8ae8f..dba7ba7f4 100644 --- a/pkg/gui/types/common.go +++ b/pkg/gui/types/common.go @@ -1,13 +1,12 @@ package types import ( - "sync" - "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/common" "github.com/jesseduffield/lazygit/pkg/config" + "github.com/sasha-s/go-deadlock" "gopkg.in/ozeidan/fuzzy-patricia.v3/patricia" ) @@ -160,11 +159,11 @@ type Model struct { // if you add a new mutex here be sure to instantiate it. We're using pointers to // mutexes so that we can pass the mutexes to controllers. type Mutexes struct { - RefreshingFilesMutex *sync.Mutex - RefreshingStatusMutex *sync.Mutex - SyncMutex *sync.Mutex - LocalCommitsMutex *sync.Mutex - SubprocessMutex *sync.Mutex - PopupMutex *sync.Mutex - PtyMutex *sync.Mutex + RefreshingFilesMutex *deadlock.Mutex + RefreshingStatusMutex *deadlock.Mutex + SyncMutex *deadlock.Mutex + LocalCommitsMutex *deadlock.Mutex + SubprocessMutex *deadlock.Mutex + PopupMutex *deadlock.Mutex + PtyMutex *deadlock.Mutex } diff --git a/pkg/gui/types/context.go b/pkg/gui/types/context.go index fa4a01b9e..e88d0d0f9 100644 --- a/pkg/gui/types/context.go +++ b/pkg/gui/types/context.go @@ -1,11 +1,10 @@ package types import ( - "sync" - "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui/patch_exploring" + "github.com/sasha-s/go-deadlock" ) type ContextKind int @@ -106,7 +105,7 @@ type IPatchExplorerContext interface { Focus() error GetContentToRender(isFocused bool) string NavigateTo(isFocused bool, selectedLineIdx int) error - GetMutex() *sync.Mutex + GetMutex() *deadlock.Mutex } type IViewTrait interface { diff --git a/pkg/tasks/async_handler.go b/pkg/tasks/async_handler.go index 897efb0e2..c277a1184 100644 --- a/pkg/tasks/async_handler.go +++ b/pkg/tasks/async_handler.go @@ -1,9 +1,8 @@ package tasks import ( - "sync" - "github.com/jesseduffield/lazygit/pkg/utils" + "github.com/sasha-s/go-deadlock" ) // the purpose of an AsyncHandler is to ensure that if we have multiple long-running @@ -17,13 +16,13 @@ import ( type AsyncHandler struct { currentId int lastId int - mutex sync.Mutex + mutex deadlock.Mutex onReject func() } func NewAsyncHandler() *AsyncHandler { return &AsyncHandler{ - mutex: sync.Mutex{}, + mutex: deadlock.Mutex{}, } } diff --git a/pkg/tasks/tasks.go b/pkg/tasks/tasks.go index a4b7b6098..448857fca 100644 --- a/pkg/tasks/tasks.go +++ b/pkg/tasks/tasks.go @@ -11,6 +11,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/utils" + "github.com/sasha-s/go-deadlock" "github.com/sirupsen/logrus" ) @@ -34,8 +35,8 @@ type ViewBufferManager struct { // this is what we write the output of the task to. It's typically a view writer io.Writer - waitingMutex sync.Mutex - taskIDMutex sync.Mutex + waitingMutex deadlock.Mutex + taskIDMutex deadlock.Mutex Log *logrus.Entry newTaskID int readLines chan int @@ -126,7 +127,7 @@ func (self *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), p } }) - loadingMutex := sync.Mutex{} + loadingMutex := deadlock.Mutex{} // not sure if it's the right move to redefine this or not self.readLines = make(chan int, 1024) diff --git a/pkg/utils/once_writer.go b/pkg/utils/once_writer.go new file mode 100644 index 000000000..aecf20369 --- /dev/null +++ b/pkg/utils/once_writer.go @@ -0,0 +1,31 @@ +package utils + +import ( + "io" + "sync" +) + +// 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) +} diff --git a/pkg/utils/once_writer_test.go b/pkg/utils/once_writer_test.go new file mode 100644 index 000000000..47f64bb61 --- /dev/null +++ b/pkg/utils/once_writer_test.go @@ -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) + } +} diff --git a/vendor/github.com/petermattis/goid/.gitignore b/vendor/github.com/petermattis/goid/.gitignore new file mode 100644 index 000000000..2b9d6b552 --- /dev/null +++ b/vendor/github.com/petermattis/goid/.gitignore @@ -0,0 +1,4 @@ +*~ +*.test +.*.swp +.DS_Store |