widgets/terminal: fix damage race condition
Terminal.damage is accessed when drawing and when invalidating the widget. For this reason we need to protect it with a mutex. This seems to fix various damage issues I've been experiencing (where some regions of the terminal weren't correctly repainted). Race detector trace: Read at 0x00c0000c6670 by main goroutine: git.sr.ht/~sircmpwn/aerc/widgets.(*Terminal).Draw() /home/simon/src/aerc/widgets/terminal.go:292 +0x191 git.sr.ht/~sircmpwn/aerc/lib/ui.(*Grid).Draw() /home/simon/src/aerc/lib/ui/grid.go:117 +0x575 git.sr.ht/~sircmpwn/aerc/lib/ui.(*Grid).Draw() /home/simon/src/aerc/lib/ui/grid.go:117 +0x575 git.sr.ht/~sircmpwn/aerc/widgets.(*MessageViewer).Draw() /home/simon/src/aerc/widgets/msgviewer.go:231 +0x253 git.sr.ht/~sircmpwn/aerc/lib/ui.(*TabContent).Draw() /home/simon/src/aerc/lib/ui/tab.go:124 +0x12e git.sr.ht/~sircmpwn/aerc/lib/ui.(*Grid).Draw() /home/simon/src/aerc/lib/ui/grid.go:117 +0x575 git.sr.ht/~sircmpwn/aerc/widgets.(*Aerc).Draw() /home/simon/src/aerc/widgets/aerc.go:95 +0x5a git.sr.ht/~sircmpwn/aerc/lib/ui.(*UI).Tick() /home/simon/src/aerc/lib/ui/ui.go:93 +0x1dd main.main() /home/simon/src/aerc/aerc.go:105 +0x539 Previous write at 0x00c0000c6670 by goroutine 37: git.sr.ht/~sircmpwn/aerc/widgets.(*Terminal).onDamage-fm() /home/simon/src/aerc/widgets/terminal.go:429 +0x131 git.sr.ht/~sircmpwn/go-libvterm._go_handle_damage() /home/simon/go/pkg/mod/git.sr.ht/~sircmpwn/go-libvterm@v0.0.0-20190421201021-3184f6f13687/vterm.go:481 +0xf9 git.sr.ht/~sircmpwn/go-libvterm._cgoexpwrap_5e22200b58b7__go_handle_damage() _cgo_gotypes.go:731 +0x58 runtime.call32() /usr/lib/go/src/runtime/asm_amd64.s:519 +0x3a git.sr.ht/~sircmpwn/go-libvterm.(*VTerm).Write.func1() /home/simon/go/pkg/mod/git.sr.ht/~sircmpwn/go-libvterm@v0.0.0-20190421201021-3184f6f13687/vterm.go:329 +0x9d git.sr.ht/~sircmpwn/go-libvterm.(*VTerm).Write() /home/simon/go/pkg/mod/git.sr.ht/~sircmpwn/go-libvterm@v0.0.0-20190421201021-3184f6f13687/vterm.go:329 +0x7f git.sr.ht/~sircmpwn/aerc/widgets.NewTerminal.func1() /home/simon/src/aerc/widgets/terminal.go:131 +0x18c Goroutine 37 (running) created at: git.sr.ht/~sircmpwn/aerc/widgets.NewTerminal() /home/simon/src/aerc/widgets/terminal.go:121 +0x23f git.sr.ht/~sircmpwn/aerc/widgets.NewMessageViewer() /home/simon/src/aerc/widgets/msgviewer.go:147 +0xfbe git.sr.ht/~sircmpwn/aerc/commands/account.ViewMessage() /home/simon/src/aerc/commands/account/view-message.go:26 +0x4a4 git.sr.ht/~sircmpwn/aerc/commands.(*Commands).ExecuteCommand() /home/simon/src/aerc/commands/commands.go:47 +0x1f0 main.main.func1() /home/simon/src/aerc/aerc.go:76 +0x205 git.sr.ht/~sircmpwn/aerc/widgets.(*Aerc).BeginExCommand.func1() /home/simon/src/aerc/widgets/aerc.go:262 +0x89 git.sr.ht/~sircmpwn/aerc/widgets.(*ExLine).Event() /home/simon/src/aerc/widgets/exline.go:47 +0x222 git.sr.ht/~sircmpwn/aerc/widgets.(*Aerc).Event() /home/simon/src/aerc/widgets/aerc.go:133 +0x83c git.sr.ht/~sircmpwn/aerc/widgets.(*Aerc).simulate() /home/simon/src/aerc/widgets/aerc.go:126 +0x12a git.sr.ht/~sircmpwn/aerc/widgets.(*Aerc).Event() /home/simon/src/aerc/widgets/aerc.go:148 +0x766 git.sr.ht/~sircmpwn/aerc/lib/ui.(*UI).Tick() /home/simon/src/aerc/lib/ui/ui.go:86 +0x11b main.main() /home/simon/src/aerc/aerc.go:105 +0x539
This commit is contained in:
parent
ca2cd00fe7
commit
1da3239345
|
@ -4,6 +4,7 @@ import (
|
|||
gocolor "image/color"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sync"
|
||||
|
||||
"git.sr.ht/~sircmpwn/aerc/lib/ui"
|
||||
|
||||
|
@ -95,7 +96,6 @@ type Terminal struct {
|
|||
ctx *ui.Context
|
||||
cursorPos vterm.Pos
|
||||
cursorShown bool
|
||||
damage []vterm.Rect
|
||||
destroyed bool
|
||||
err error
|
||||
focus bool
|
||||
|
@ -103,6 +103,9 @@ type Terminal struct {
|
|||
start chan interface{}
|
||||
vterm *vterm.VTerm
|
||||
|
||||
damage []vterm.Rect // protected by mutex
|
||||
mutex sync.Mutex
|
||||
|
||||
OnClose func(err error)
|
||||
OnEvent func(event tcell.Event) bool
|
||||
OnStart func()
|
||||
|
@ -230,7 +233,9 @@ func (term *Terminal) Invalidate() {
|
|||
if term.vterm != nil {
|
||||
width, height := term.vterm.Size()
|
||||
rect := vterm.NewRect(0, width, 0, height)
|
||||
term.mutex.Lock()
|
||||
term.damage = append(term.damage, *rect)
|
||||
term.mutex.Unlock()
|
||||
}
|
||||
term.invalidate()
|
||||
}
|
||||
|
@ -274,7 +279,9 @@ func (term *Terminal) Draw(ctx *ui.Context) {
|
|||
pty.Setsize(term.pty, &winsize)
|
||||
term.vterm.SetSize(ctx.Height(), ctx.Width())
|
||||
rect := vterm.NewRect(0, ctx.Width(), 0, ctx.Height())
|
||||
term.mutex.Lock()
|
||||
term.damage = append(term.damage, *rect)
|
||||
term.mutex.Unlock()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -289,6 +296,7 @@ func (term *Terminal) Draw(ctx *ui.Context) {
|
|||
// naive optimization
|
||||
visited := make(map[coords]interface{})
|
||||
|
||||
term.mutex.Lock()
|
||||
for _, rect := range term.damage {
|
||||
for x := rect.StartCol(); x < rect.EndCol() && x < ctx.Width(); x += 1 {
|
||||
|
||||
|
@ -311,6 +319,7 @@ func (term *Terminal) Draw(ctx *ui.Context) {
|
|||
}
|
||||
|
||||
term.damage = nil
|
||||
term.mutex.Unlock()
|
||||
|
||||
if term.focus && !term.closed {
|
||||
if !term.cursorShown {
|
||||
|
@ -426,7 +435,9 @@ func (term *Terminal) styleFromCell(cell *vterm.ScreenCell) tcell.Style {
|
|||
}
|
||||
|
||||
func (term *Terminal) onDamage(rect *vterm.Rect) int {
|
||||
term.mutex.Lock()
|
||||
term.damage = append(term.damage, *rect)
|
||||
term.mutex.Unlock()
|
||||
term.invalidate()
|
||||
return 1
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue