v0.2.0 c616855

syncobj.go RawHistoryFolder

1// Package syncobj wraps the few DRM syncobj ioctls the bar needs: one acquire
2// timeline signaled from the CPU, and one release timeline per buffer whose
3// points the compositor signals and an eventfd reports.
4package syncobj
5
6import (
7	"fmt"
8	"unsafe"
9
10	"golang.org/x/sys/unix"
11)
12
13// ioctl numbers of DRM_IOCTL_SYNCOBJ_* (Linux drm.h, type 'd').
14const (
15	ioctlCreate      = uintptr(0xc00864bf)
16	ioctlDestroy     = uintptr(0xc00864c0)
17	ioctlHandleToFD  = uintptr(0xc01864c1)
18	ioctlQuery       = uintptr(0xc01864cb)
19	ioctlTimelineSig = uintptr(0xc01864cd)
20	ioctlEventFD     = uintptr(0xc01864cf)
21)
22
23type createArg struct{ Handle, Flags uint32 }
24type destroyArg struct{ Handle, Pad uint32 }
25type handleArg struct {
26	Handle, Flags uint32
27	FD            int32
28	Pad           uint32
29	Point         uint64
30}
31type arrayArg struct { // drm_syncobj_timeline_array
32	Handles, Points uint64
33	Count, Flags    uint32
34}
35type eventFDArg struct {
36	Handle, Flags uint32
37	Point         uint64
38	FD            int32
39	Pad           uint32
40}
41
42// Node owns a DRM render node fd. It is used from one goroutine; its scratch
43// fields live in the heap object so the addresses embedded in ioctl arguments
44// stay valid and no call allocates.
45type Node struct {
46	fd int
47
48	handle uint32
49	point  uint64
50	array  arrayArg
51}
52
53// Open opens a render node such as /dev/dri/renderD128.
54func Open(path string) (*Node, error) {
55	fd, err := unix.Open(path, unix.O_RDWR|unix.O_CLOEXEC, 0)
56	if err != nil {
57		return nil, fmt.Errorf("syncobj: open %s: %w", path, err)
58	}
59	return &Node{fd: fd}, nil
60}
61
62// Close closes the render node.
63func (n *Node) Close() error {
64	if n.fd < 0 {
65		return nil
66	}
67	err := unix.Close(n.fd)
68	n.fd = -1
69	return err
70}
71
72func (n *Node) ioctl(request uintptr, arg unsafe.Pointer) error {
73	if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(n.fd), request, uintptr(arg)); errno != 0 {
74		return fmt.Errorf("syncobj: ioctl %#x: %w", request, errno)
75	}
76	return nil
77}
78
79// Create returns a new syncobj handle.
80func (n *Node) Create() (uint32, error) {
81	var a createArg
82	if err := n.ioctl(ioctlCreate, unsafe.Pointer(&a)); err != nil {
83		return 0, err
84	}
85	return a.Handle, nil
86}
87
88// Destroy releases a handle.
89func (n *Node) Destroy(handle uint32) error {
90	a := destroyArg{Handle: handle}
91	return n.ioctl(ioctlDestroy, unsafe.Pointer(&a))
92}
93
94// Export returns a new owned syncobj fd for handle; the caller closes it.
95func (n *Node) Export(handle uint32) (int, error) {
96	a := handleArg{Handle: handle, FD: -1}
97	if err := n.ioctl(ioctlHandleToFD, unsafe.Pointer(&a)); err != nil {
98		return -1, err
99	}
100	return int(a.FD), nil
101}
102
103// Signal signals one timeline point from the CPU.
104func (n *Node) Signal(handle uint32, point uint64) error {
105	n.handle, n.point = handle, point
106	n.array = arrayArg{
107		Handles: uint64(uintptr(unsafe.Pointer(&n.handle))),
108		Points:  uint64(uintptr(unsafe.Pointer(&n.point))),
109		Count:   1,
110	}
111	return n.ioctl(ioctlTimelineSig, unsafe.Pointer(&n.array))
112}
113
114// Query returns the last signaled point of a timeline.
115func (n *Node) Query(handle uint32) (uint64, error) {
116	n.handle, n.point = handle, 0
117	n.array = arrayArg{
118		Handles: uint64(uintptr(unsafe.Pointer(&n.handle))),
119		Points:  uint64(uintptr(unsafe.Pointer(&n.point))),
120		Count:   1,
121	}
122	if err := n.ioctl(ioctlQuery, unsafe.Pointer(&n.array)); err != nil {
123		return 0, err
124	}
125	return n.point, nil
126}
127
128// EventFD arms efd to become readable once point is signaled. The registration
129// is one-shot and returns at once; the point need not be submitted yet.
130func (n *Node) EventFD(handle uint32, point uint64, efd int) error {
131	a := eventFDArg{Handle: handle, Point: point, FD: int32(efd)}
132	return n.ioctl(ioctlEventFD, unsafe.Pointer(&a))
133}

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 5

Tags 4

↑↓ moveenter openesc close