about summary refs log tree commit diff stats
path: root/lib/ui/grid.go
diff options
context:
space:
mode:
authorSimon Ser <contact@emersion.fr>2019-04-27 16:47:59 +0000
committerDrew DeVault <sir@cmpwn.com>2019-04-27 14:30:28 -0400
commit5685a176747711d0330f1251ad297b13e0621a37 (patch)
treed338db2be97f5ac412a427776167d21b04abdf99 /lib/ui/grid.go
parent9ef2a57b51601cc0e18824bbfe8026891da1a38d (diff)
downloadaerc-5685a176747711d0330f1251ad297b13e0621a37.tar.gz
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.
Diffstat (limited to 'lib/ui/grid.go')
-rw-r--r--lib/ui/grid.go14
1 files changed, 3 insertions, 11 deletions
diff --git a/lib/ui/grid.go b/lib/ui/grid.go
index 87b94bd..3ac43a4 100644
--- a/lib/ui/grid.go
+++ b/lib/ui/grid.go
@@ -6,12 +6,12 @@ import (
 )
 
 type Grid struct {
+	Invalidatable
 	rows         []GridSpec
 	rowLayout    []gridLayout
 	columns      []GridSpec
 	columnLayout []gridLayout
 	cells        []*GridCell
-	onInvalidate func(d Drawable)
 	invalid      bool
 }
 
@@ -141,9 +141,7 @@ func (grid *Grid) reflow(ctx *Context) {
 
 func (grid *Grid) invalidateLayout() {
 	grid.invalid = true
-	if grid.onInvalidate != nil {
-		grid.onInvalidate(grid)
-	}
+	grid.DoInvalidate(grid)
 }
 
 func (grid *Grid) Invalidate() {
@@ -153,10 +151,6 @@ func (grid *Grid) Invalidate() {
 	}
 }
 
-func (grid *Grid) OnInvalidate(onInvalidate func(d Drawable)) {
-	grid.onInvalidate = onInvalidate
-}
-
 func (grid *Grid) AddChild(content Drawable) *GridCell {
 	cell := &GridCell{
 		RowSpan: 1,
@@ -193,7 +187,5 @@ func (grid *Grid) cellInvalidated(drawable Drawable) {
 		panic(fmt.Errorf("Attempted to invalidate unknown cell"))
 	}
 	cell.invalid = true
-	if grid.onInvalidate != nil {
-		grid.onInvalidate(grid)
-	}
+	grid.DoInvalidate(grid)
 }