From 7c6325977b55385bc65f0a08f4da8ed6dfede52a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 19 May 2019 09:50:14 +0000 Subject: [PATCH] lib/ui/ui: use atomic instead of channel This makes it so an atomic `invalid` value is used instead of an unbuffered channel. When many invalidations kick in, a lot of values were sent to the channel. (Since OnInvalidate's callback can be run in any goroutine, we need to be careful about races here.) --- lib/ui/ui.go | 47 +++++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/lib/ui/ui.go b/lib/ui/ui.go index 91a26da..f04d3d8 100644 --- a/lib/ui/ui.go +++ b/lib/ui/ui.go @@ -14,8 +14,8 @@ type UI struct { ctx *Context screen tcell.Screen - tcEvents chan tcell.Event - invalidations chan interface{} + tcEvents chan tcell.Event + invalid int32 // access via atomic } func Initialize(conf *config.AercConfig, @@ -40,24 +40,22 @@ func Initialize(conf *config.AercConfig, ctx: NewContext(width, height, screen), screen: screen, - tcEvents: make(chan tcell.Event, 10), - invalidations: make(chan interface{}), + tcEvents: make(chan tcell.Event, 10), } + state.exit.Store(false) - go (func() { + go func() { for !state.ShouldExit() { state.tcEvents <- screen.PollEvent() } - })() - go (func() { - state.invalidations <- nil - })() + }() + + state.invalid = 1 content.OnInvalidate(func(_ Drawable) { - go (func() { - state.invalidations <- nil - })() + atomic.StoreInt32(&state.invalid, 1) }) content.Focus(true) + return &state, nil } @@ -74,6 +72,8 @@ func (state *UI) Close() { } func (state *UI) Tick() bool { + more := false + select { case event := <-state.tcEvents: switch event := event.(type) { @@ -84,21 +84,16 @@ func (state *UI) Tick() bool { state.Content.Invalidate() } state.Content.Event(event) - case <-state.invalidations: - for { - // Flush any other pending invalidations - select { - case <-state.invalidations: - break - default: - goto done - } - } - done: + more = true + default: + } + + wasInvalid := atomic.SwapInt32(&state.invalid, 0) + if wasInvalid != 0 { state.Content.Draw(state.ctx) state.screen.Show() - default: - return false + more = true } - return true + + return more }