1
0
mirror of https://github.com/cjbassi/gotop.git synced 2025-04-25 13:49:00 +08:00

Fix data race between rendering and updating

This commit is contained in:
Caleb Bassi 2019-01-19 20:34:19 -08:00
parent 523a190e66
commit 97f490be80
9 changed files with 61 additions and 39 deletions

57
main.go
View File

@ -10,6 +10,7 @@ import (
"path/filepath"
"sort"
"strconv"
"sync"
"syscall"
"time"
@ -46,6 +47,8 @@ var (
battery = false
statusbar = false
renderLock sync.RWMutex
cpu *w.CPU
batt *w.Batt
mem *w.Mem
@ -257,20 +260,26 @@ func widgetColors() {
}
func initWidgets() {
cpu = w.NewCPU(updateInterval, graphHorizontalScale, averageLoad, percpuLoad)
mem = w.NewMem(updateInterval, graphHorizontalScale)
proc = w.NewProc()
cpu = w.NewCPU(&renderLock, updateInterval, graphHorizontalScale, averageLoad, percpuLoad)
mem = w.NewMem(&renderLock, updateInterval, graphHorizontalScale)
proc = w.NewProc(&renderLock)
help = w.NewHelpMenu()
if !minimalMode {
if battery {
batt = w.NewBatt(graphHorizontalScale)
batt = w.NewBatt(&renderLock, graphHorizontalScale)
}
net = w.NewNet()
disk = w.NewDisk()
temp = w.NewTemp(fahrenheit)
net = w.NewNet(&renderLock)
disk = w.NewDisk(&renderLock)
temp = w.NewTemp(&renderLock, fahrenheit)
}
}
func render(drawable ...ui.Drawable) {
renderLock.Lock()
ui.Render(drawable...)
renderLock.Unlock()
}
func eventLoop() {
drawTicker := time.NewTicker(updateInterval).C
@ -288,7 +297,7 @@ func eventLoop() {
return
case <-drawTicker:
if !helpVisible {
ui.Render(grid)
render(grid)
}
case e := <-uiEvents:
switch e.ID {
@ -310,68 +319,68 @@ func eventLoop() {
ui.Render(help)
case "<Escape>":
helpVisible = false
ui.Render(grid)
render(grid)
case "<Resize>":
ui.Render(help)
}
} else {
switch e.ID {
case "?":
ui.Render(grid)
render(grid)
case "h":
graphHorizontalScale += graphHorizontalScaleDelta
cpu.HorizontalScale = graphHorizontalScale
mem.HorizontalScale = graphHorizontalScale
ui.Render(cpu, mem)
render(cpu, mem)
case "l":
if graphHorizontalScale > graphHorizontalScaleDelta {
graphHorizontalScale -= graphHorizontalScaleDelta
cpu.HorizontalScale = graphHorizontalScale
mem.HorizontalScale = graphHorizontalScale
ui.Render(cpu, mem)
render(cpu, mem)
}
case "<Resize>":
ui.Render(grid)
render(grid)
case "<MouseLeft>":
payload := e.Payload.(ui.Mouse)
proc.Click(payload.X, payload.Y)
ui.Render(proc)
render(proc)
case "k", "<Up>", "<MouseWheelUp>":
proc.Up()
ui.Render(proc)
render(proc)
case "j", "<Down>", "<MouseWheelDown>":
proc.Down()
ui.Render(proc)
render(proc)
case "g", "<Home>":
if previousKey == "g" {
proc.Top()
ui.Render(proc)
render(proc)
}
case "G", "<End>":
proc.Bottom()
ui.Render(proc)
render(proc)
case "<C-d>":
proc.HalfPageDown()
ui.Render(proc)
render(proc)
case "<C-u>":
proc.HalfPageUp()
ui.Render(proc)
render(proc)
case "<C-f>":
proc.PageDown()
ui.Render(proc)
render(proc)
case "<C-b>":
proc.PageUp()
ui.Render(proc)
render(proc)
case "d":
if previousKey == "d" {
proc.Kill()
}
case "<Tab>":
proc.Tab()
ui.Render(proc)
render(proc)
case "m", "c", "p":
proc.ChangeSort(e)
ui.Render(proc)
render(proc)
}
if previousKey == e.ID {

View File

@ -3,7 +3,6 @@ package termui
import (
"image"
"strings"
"sync"
. "github.com/gizak/termui"
)
@ -12,8 +11,6 @@ import (
type Table struct {
*Block
sync.Mutex
Header []string
Rows [][]string
@ -51,8 +48,6 @@ func (self *Table) ColResize() {
}
func (self *Table) Draw(buf *Buffer) {
self.Lock()
self.Block.Draw(buf)
self.ColResizer()
@ -128,7 +123,6 @@ func (self *Table) Draw(buf *Buffer) {
)
}
}
self.Unlock()
}
/////////////////////////////////////////////////////////////////////////////////

View File

@ -5,6 +5,7 @@ import (
"log"
"math"
"strconv"
"sync"
"time"
ui "github.com/cjbassi/gotop/src/termui"
@ -17,7 +18,7 @@ type Batt struct {
interval time.Duration
}
func NewBatt(horizontalScale int) *Batt {
func NewBatt(renderLock *sync.RWMutex, horizontalScale int) *Batt {
batts, err := battery.GetAll()
self := &Batt{
LineGraph: ui.NewLineGraph(),
@ -39,7 +40,9 @@ func NewBatt(horizontalScale int) *Batt {
go func() {
ticker := time.NewTicker(self.interval)
for range ticker.C {
renderLock.RLock()
self.update()
renderLock.RUnlock()
}
}()

View File

@ -3,6 +3,7 @@ package widgets
import (
"fmt"
"log"
"sync"
"time"
ui "github.com/cjbassi/gotop/src/termui"
@ -18,7 +19,7 @@ type CPU struct {
formatString string
}
func NewCPU(interval time.Duration, horizontalScale int, average bool, percpu bool) *CPU {
func NewCPU(renderLock *sync.RWMutex, interval time.Duration, horizontalScale int, average bool, percpu bool) *CPU {
count, err := psCPU.Counts(false)
if err != nil {
log.Printf("failed to get CPU count from gopsutil: %v", err)
@ -62,7 +63,9 @@ func NewCPU(interval time.Duration, horizontalScale int, average bool, percpu bo
go func() {
ticker := time.NewTicker(self.interval)
for range ticker.C {
renderLock.RLock()
self.update()
renderLock.RUnlock()
}
}()

View File

@ -5,6 +5,7 @@ import (
"log"
"sort"
"strings"
"sync"
"time"
ui "github.com/cjbassi/gotop/src/termui"
@ -29,7 +30,7 @@ type Disk struct {
Partitions map[string]*Partition
}
func NewDisk() *Disk {
func NewDisk(renderLock *sync.RWMutex) *Disk {
self := &Disk{
Table: ui.NewTable(),
interval: time.Second,
@ -45,7 +46,9 @@ func NewDisk() *Disk {
go func() {
ticker := time.NewTicker(self.interval)
for range ticker.C {
renderLock.RLock()
self.update()
renderLock.RUnlock()
}
}()

View File

@ -3,6 +3,7 @@ package widgets
import (
"fmt"
"log"
"sync"
"time"
ui "github.com/cjbassi/gotop/src/termui"
@ -15,7 +16,7 @@ type Mem struct {
interval time.Duration
}
func NewMem(interval time.Duration, horizontalScale int) *Mem {
func NewMem(renderLock *sync.RWMutex, interval time.Duration, horizontalScale int) *Mem {
self := &Mem{
LineGraph: ui.NewLineGraph(),
interval: interval,
@ -30,7 +31,9 @@ func NewMem(interval time.Duration, horizontalScale int) *Mem {
go func() {
ticker := time.NewTicker(self.interval)
for range ticker.C {
renderLock.RLock()
self.update()
renderLock.RUnlock()
}
}()

View File

@ -3,6 +3,7 @@ package widgets
import (
"fmt"
"log"
"sync"
"time"
ui "github.com/cjbassi/gotop/src/termui"
@ -18,7 +19,7 @@ type Net struct {
prevSentTotal uint64
}
func NewNet() *Net {
func NewNet(renderLock *sync.RWMutex) *Net {
recv := ui.NewSparkline()
recv.Data = []int{0}
@ -37,7 +38,9 @@ func NewNet() *Net {
go func() {
ticker := time.NewTicker(self.interval)
for range ticker.C {
renderLock.RLock()
self.update()
renderLock.RUnlock()
}
}()

View File

@ -6,6 +6,7 @@ import (
"os/exec"
"sort"
"strconv"
"sync"
"time"
ui "github.com/cjbassi/gotop/src/termui"
@ -38,7 +39,7 @@ type Proc struct {
group bool
}
func NewProc() *Proc {
func NewProc(renderLock *sync.RWMutex) *Proc {
cpuCount, err := psCPU.Counts(false)
if err != nil {
log.Printf("failed to get CPU count from gopsutil: %v", err)
@ -66,9 +67,9 @@ func NewProc() *Proc {
go func() {
ticker := time.NewTicker(self.interval)
for range ticker.C {
self.Lock()
renderLock.RLock()
self.update()
self.Unlock()
renderLock.RUnlock()
}
}()

View File

@ -7,6 +7,7 @@ import (
"fmt"
"image"
"sort"
"sync"
"time"
ui "github.com/gizak/termui"
@ -22,7 +23,7 @@ type Temp struct {
Fahrenheit bool
}
func NewTemp(fahrenheit bool) *Temp {
func NewTemp(renderLock *sync.RWMutex, fahrenheit bool) *Temp {
self := &Temp{
Block: ui.NewBlock(),
interval: time.Second * 5,
@ -41,7 +42,9 @@ func NewTemp(fahrenheit bool) *Temp {
go func() {
ticker := time.NewTicker(self.interval)
for range ticker.C {
renderLock.RLock()
self.update()
renderLock.RUnlock()
}
}()