v0.2.0 13c6a90

reads.go RawHistoryFolder

1package drm
2
3import (
4	"os"
5	"time"
6
7	"golang.org/x/sys/unix"
8)
9
10// Fence holds: client buffers the GPU may still read.
11
12// dupFences duplicates the non-nil fences.
13func dupFences(fs ...*os.File) []*os.File {
14	var out []*os.File
15	for _, f := range fs {
16		if d := dupFence(f); d != nil {
17			out = append(out, d)
18		}
19	}
20	return out
21}
22
23// signalled reports whether every fence signalled (readable); an fd that
24// cannot be polled counts as signalled.
25func signalled(fs []*os.File) bool {
26	if len(fs) == 0 {
27		return true
28	}
29	pfds := make([]unix.PollFd, len(fs))
30	for i, f := range fs {
31		pfds[i] = unix.PollFd{Fd: int32(f.Fd()), Events: unix.POLLIN}
32	}
33	if _, err := unix.Poll(pfds, 0); err != nil {
34		return true
35	}
36	for _, p := range pfds {
37		if p.Revents == 0 {
38			return false
39		}
40	}
41	return true
42}
43
44// holdRead keeps the fences of a frame that was not committed.
45func (o *Output) holdRead(fs ...*os.File) {
46	o.readFences = append(o.readFences, dupFences(fs...)...)
47}
48
49// readDone reports whether no uncommitted frame may still read client
50// buffers, closing the fences that signalled.
51func (o *Output) readDone() bool {
52	kept := o.readFences[:0]
53	for _, f := range o.readFences {
54		if signalled([]*os.File{f}) {
55			f.Close()
56			continue
57		}
58		kept = append(kept, f)
59	}
60	clear(o.readFences[len(kept):])
61	o.readFences = kept
62	return len(kept) == 0
63}
64
65// dropRead closes the fences of uncommitted frames.
66func (o *Output) dropRead() {
67	for _, f := range o.readFences {
68		f.Close()
69	}
70	o.readFences = nil
71}
72
73// expire applies a lifecycle deadline and reports whether KMS needs a modeset.
74// Fence polling and logging stay at the output boundary, not in the value
75// transition; the lifecycle owns the decision and closes pending fences.
76func (o *Output) expire() bool {
77	now := time.Now()
78	serial, frame, age, busy, fences := o.frame.deadlineInfo(now)
79	ready := serial == 0 || !o.frame.deadlineReached(now) || signalled(fences)
80	switch o.frame.timeout(now, ready) {
81	case timeoutFence:
82		o.log.Warn().Str("connector", o.conn.name).Uint64("serial", serial).Dur("age", age).Msg("frame waits for GPU fence")
83	case timeoutBusy:
84		o.log.Warn().Str("connector", o.conn.name).Str("kind", "busy").Dur("age", busy).Msg("commits refused as busy; modeset")
85		return true
86	case timeoutMissing:
87		kind := "state"
88		if frame {
89			kind = "frame"
90		}
91		o.log.Warn().Str("connector", o.conn.name).Uint64("serial", serial).Str("kind", kind).Dur("age", age).Msg("commit event missing; modeset")
92		return true
93	}
94	return false
95}

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 25

Tags 10

↑↓ moveenter openesc close