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:
parent
523a190e66
commit
97f490be80
57
main.go
57
main.go
@ -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 {
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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()
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}()
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user