• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pomerium / pomerium / 21647993278

03 Feb 2026 09:10PM UTC coverage: 44.408% (-0.07%) from 44.475%
21647993278

push

github

web-flow
ssh tui: fix data races related to model updates (#6077)

This fixes several data races related to concurrent rendering and model
updating. Some model callbacks were changed to be propagated using
tea.Msg instead, and the top level model uses a new double-buffer
drawable to ensure View() is always called from the same thread as
Update.

0 of 248 new or added lines in 15 files covered. (0.0%)

33 existing lines in 11 files now uncovered.

31413 of 70737 relevant lines covered (44.41%)

115.64 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/pkg/ssh/tui/core/double_buffer.go
1
package core
2

3
import (
4
        "sync"
5
        "sync/atomic"
6

7
        uv "github.com/charmbracelet/ultraviolet"
8
)
9

10
type buffer struct {
11
        uv.ScreenBuffer
12
        width, height int
13
        mu            sync.Mutex
14
        _             [24]byte // pad to cache line
15
}
16

17
type DoubleBuffer struct {
18
        buffers [2]buffer
19
        back    *buffer
20
        front   atomic.Pointer[buffer]
21
}
22

NEW
23
func NewDoubleBuffer() *DoubleBuffer {
×
NEW
24
        db := &DoubleBuffer{
×
NEW
25
                buffers: [2]buffer{
×
NEW
26
                        {
×
NEW
27
                                ScreenBuffer: uv.NewScreenBuffer(0, 0),
×
NEW
28
                        },
×
NEW
29
                        {
×
NEW
30
                                ScreenBuffer: uv.NewScreenBuffer(0, 0),
×
NEW
31
                        },
×
NEW
32
                },
×
NEW
33
        }
×
NEW
34
        db.back = &db.buffers[0]
×
NEW
35
        db.back.mu.Lock()
×
NEW
36
        db.front.Store(&db.buffers[1])
×
NEW
37
        return db
×
NEW
38
}
×
39

NEW
40
func (db *DoubleBuffer) UpdateView(width, height int, drawable uv.Drawable) {
×
NEW
41
        back := db.back
×
NEW
42
        if back.width != width || back.height != height {
×
NEW
43
                back.width = width
×
NEW
44
                back.height = height
×
NEW
45
                back.ScreenBuffer = uv.NewScreenBuffer(width, height)
×
NEW
46
        }
×
NEW
47
        drawable.Draw(back, uv.Rect(0, 0, back.width, back.height))
×
NEW
48
        db.swap()
×
49
}
50

NEW
51
func (db *DoubleBuffer) Draw(scr uv.Screen, area uv.Rectangle) {
×
NEW
52
        front := db.front.Load()
×
NEW
53
        front.mu.Lock()
×
NEW
54
        defer front.mu.Unlock()
×
NEW
55
        front.Draw(scr, area)
×
NEW
56
}
×
57

NEW
58
func (db *DoubleBuffer) swap() {
×
NEW
59
        db.back.mu.Unlock()              // unlock the current back buffer
×
NEW
60
        db.back = db.front.Swap(db.back) // swap the front and back buffers
×
NEW
61
        db.back.mu.Lock()                // wait for the previous frame to finish rendering
×
NEW
62
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc