feat/data-dnd e05cb15

postring.go RawHistoryFolder

1package wayland
2
3import (
4	"sync"
5
6	"github.com/bnema/purego-libwayland/server"
7)
8
9// postRing carries values from producer goroutines to the display goroutine
10// without allocating. It is a transport queue, not window state: the mutex
11// guards only the slices and the pending flag. Values are never merged or
12// dropped, in order of arrival.
13//
14// It binds its drain once and posts it at most once per batch: Display.Post
15// is unbounded (a Post per value would let a fast producer grow the queue),
16// so one pending drain serves every value pushed before it runs.
17type postRing[T any] struct {
18	display *server.Display
19	apply   func(T)
20	drainFn func()
21	// space is signalled (never blocking) after each drain and after a push
22	// that left room, to wake blocked pushers one after the other.
23	space chan struct{}
24
25	mu          sync.Mutex
26	ring, spare []T
27	limit       int
28	pending     bool // a drain is posted and has not taken the ring yet
29}
30
31// newPostRing returns a ring of limit values whose values apply runs on the
32// display goroutine, in order. limit must be at least 1.
33func newPostRing[T any](d *server.Display, limit int, apply func(T)) *postRing[T] {
34	r := &postRing[T]{
35		display: d,
36		apply:   apply,
37		space:   make(chan struct{}, 1),
38		ring:    make([]T, 0, limit),
39		spare:   make([]T, 0, limit),
40		limit:   limit,
41	}
42	r.drainFn = r.drain
43	return r
44}
45
46// Push queues v for the display goroutine and wakes it. A full ring blocks
47// the caller, which must not be the display goroutine, until a drain made
48// room; it reports false, with v dropped, once the display has stopped.
49func (r *postRing[T]) Push(v T) bool {
50	for {
51		r.mu.Lock()
52		if len(r.ring) < r.limit {
53			r.ring = append(r.ring, v)
54			post := !r.pending
55			r.pending = true
56			room := len(r.ring) < r.limit
57			r.mu.Unlock()
58			if post {
59				r.display.Post(r.drainFn)
60			}
61			if room {
62				r.signal() // chain the wake to another blocked pusher
63			}
64			return true
65		}
66		r.mu.Unlock()
67		select {
68		case <-r.space:
69		case <-r.display.Stopped():
70			return false
71		}
72	}
73}
74
75func (r *postRing[T]) signal() {
76	select {
77	case r.space <- struct{}{}:
78	default:
79	}
80}
81
82// drain runs on the display goroutine and applies the batch in order.
83func (r *postRing[T]) drain() {
84	r.mu.Lock()
85	batch := r.ring
86	r.ring, r.spare = r.spare[:0], nil
87	r.pending = false
88	r.mu.Unlock()
89	r.signal()
90	for _, v := range batch {
91		r.apply(v)
92	}
93	// Do not retain what the values reference in the spare batch.
94	clear(batch)
95	r.mu.Lock()
96	r.spare = batch[:0]
97	r.mu.Unlock()
98}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 23

Tags 10

↑↓ moveenter openesc close