From 5685a176747711d0330f1251ad297b13e0621a37 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 27 Apr 2019 16:47:59 +0000 Subject: lib/ui: introduce Invalidatable Many Drawable implementations have their own Invalidate and OnInvalidate functions, with an unexported onInvalidate field. However OnInvalidate and Invalidate are usually not called in the same goroutine. This results in a race on this field, e.g.: Read at 0x00c000094748 by goroutine 7: git.sr.ht/~sircmpwn/aerc2/widgets.NewDirectoryList.func1() /home/simon/src/aerc2/widgets/dirlist.go:85 +0x56 git.sr.ht/~sircmpwn/aerc2/widgets.(*Spinner).Start.func1() /home/simon/src/aerc2/widgets/spinner.go:93 +0x1bb Previous write at 0x00c000094748 by main goroutine: [failed to restore the stack] Goroutine 7 (running) created at: git.sr.ht/~sircmpwn/aerc2/widgets.(*Spinner).Start() /home/simon/src/aerc2/widgets/spinner.go:46 +0x8f git.sr.ht/~sircmpwn/aerc2/widgets.NewDirectoryList() /home/simon/src/aerc2/widgets/dirlist.go:37 +0x286 git.sr.ht/~sircmpwn/aerc2/widgets.NewAccountView() /home/simon/src/aerc2/widgets/account.go:50 +0x5ca git.sr.ht/~sircmpwn/aerc2/widgets.NewAerc() /home/simon/src/aerc2/widgets/aerc.go:60 +0x800 main.main() /home/simon/src/aerc2/aerc.go:65 +0x33e To fix this, introduce a new type, Invalidatable, which protects the field. Unfortunately the Drawable must be passed to the callback function in Invalidate, so we still need to re-implement this in each Invalidatable user. --- widgets/terminal.go | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) (limited to 'widgets/terminal.go') diff --git a/widgets/terminal.go b/widgets/terminal.go index 84f80e3..63c105f 100644 --- a/widgets/terminal.go +++ b/widgets/terminal.go @@ -88,20 +88,20 @@ func init() { } type Terminal struct { - closed bool - cmd *exec.Cmd - colors map[tcell.Color]tcell.Color - ctx *ui.Context - cursorPos vterm.Pos - cursorShown bool - damage []vterm.Rect - destroyed bool - err error - focus bool - onInvalidate func(d ui.Drawable) - pty *os.File - start chan interface{} - vterm *vterm.VTerm + ui.Invalidatable + closed bool + cmd *exec.Cmd + colors map[tcell.Color]tcell.Color + ctx *ui.Context + cursorPos vterm.Pos + cursorShown bool + damage []vterm.Rect + destroyed bool + err error + focus bool + pty *os.File + start chan interface{} + vterm *vterm.VTerm OnClose func(err error) OnStart func() @@ -225,10 +225,6 @@ func (term *Terminal) Destroy() { term.destroyed = true } -func (term *Terminal) OnInvalidate(cb func(d ui.Drawable)) { - term.onInvalidate = cb -} - func (term *Terminal) Invalidate() { if term.vterm != nil { width, height := term.vterm.Size() @@ -239,9 +235,7 @@ func (term *Terminal) Invalidate() { } func (term *Terminal) invalidate() { - if term.onInvalidate != nil { - term.onInvalidate(term) - } + term.DoInvalidate(term) } func (term *Terminal) Draw(ctx *ui.Context) { -- cgit v1.2.3