v0.1.0 d9218d6

syncdev.go RawHistoryFolder

1package wayland
2
3import (
4	"fmt"
5	"os"
6	"runtime"
7	"unsafe"
8
9	"golang.org/x/sys/unix"
10)
11
12// syncobjDevice is the DRM syncobj interface of a render node: explicit
13// sync timelines clients import (wp_linux_drm_syncobj_v1).
14type syncobjDevice interface {
15	// fdToHandle imports a timeline syncobj fd.
16	fdToHandle(fd int) (uint32, error)
17	// exportSyncFile returns a sync file of a timeline point's fence.
18	exportSyncFile(h uint32, point uint64) (*os.File, error)
19	// signal signals a timeline point (a release point).
20	signal(h uint32, point uint64) error
21	// eventfd writes efd once the point has a fence (WAIT_AVAILABLE).
22	eventfd(h uint32, point uint64, efd int) error
23	destroy(h uint32) error
24}
25
26const (
27	ioctlSyncobjDestroy        = 0xC00864C0 // DRM_IOWR(0xC0, struct drm_syncobj_destroy)
28	ioctlSyncobjHandleToFD     = 0xC01864C1 // DRM_IOWR(0xC1, struct drm_syncobj_handle)
29	ioctlSyncobjFDToHandle     = 0xC01864C2 // DRM_IOWR(0xC2, struct drm_syncobj_handle)
30	ioctlSyncobjTimelineSignal = 0xC01864CD // DRM_IOWR(0xCD, struct drm_syncobj_timeline_array)
31	ioctlSyncobjEventfd        = 0xC01864CF // DRM_IOWR(0xCF, struct drm_syncobj_eventfd)
32	ioctlGetCap                = 0xC010640C // DRM_IOWR(0x0C, struct drm_get_cap)
33
34	syncobjExportSyncFile = 1 << 0
35	syncobjTimeline       = 1 << 1
36	syncobjWaitAvailable  = 1 << 2
37	capSyncobjTimeline    = 0x14
38)
39
40type syncobjHandle struct {
41	handle, flags uint32
42	fd            int32
43	pad           uint32
44	point         uint64
45}
46
47type syncobjDestroy struct{ handle, pad uint32 }
48
49type syncobjTimelineArray struct {
50	handles, points uint64
51	count, flags    uint32
52}
53
54type syncobjEventfd struct {
55	handle, flags uint32
56	point         uint64
57	fd            int32
58	pad           uint32
59}
60
61type drmCap struct{ capability, value uint64 }
62
63// renderNode is a DRM render node opened for syncobj ioctls.
64type renderNode struct{ fd int }
65
66// openSyncobj opens a render node that supports timeline syncobjs.
67func openSyncobj(path string) (*renderNode, error) {
68	fd, err := unix.Open(path, unix.O_RDWR|unix.O_CLOEXEC, 0)
69	if err != nil {
70		return nil, err
71	}
72	c := drmCap{capability: capSyncobjTimeline}
73	if ioctl(fd, ioctlGetCap, unsafe.Pointer(&c)) != nil || c.value == 0 {
74		unix.Close(fd)
75		return nil, fmt.Errorf("%s: no timeline syncobjs", path)
76	}
77	return &renderNode{fd: fd}, nil
78}
79
80func (n *renderNode) close() { unix.Close(n.fd) }
81
82func ioctl(fd int, req uintptr, arg unsafe.Pointer) error {
83	for {
84		_, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), req, uintptr(arg))
85		if errno == unix.EINTR || errno == unix.EAGAIN {
86			continue
87		}
88		if errno != 0 {
89			return errno
90		}
91		return nil
92	}
93}
94
95func (n *renderNode) fdToHandle(fd int) (uint32, error) {
96	a := syncobjHandle{fd: int32(fd)}
97	if err := ioctl(n.fd, ioctlSyncobjFDToHandle, unsafe.Pointer(&a)); err != nil {
98		return 0, err
99	}
100	return a.handle, nil
101}
102
103func (n *renderNode) exportSyncFile(h uint32, point uint64) (*os.File, error) {
104	a := syncobjHandle{handle: h, flags: syncobjExportSyncFile | syncobjTimeline, fd: -1, point: point}
105	if err := ioctl(n.fd, ioctlSyncobjHandleToFD, unsafe.Pointer(&a)); err != nil {
106		return nil, err
107	}
108	return os.NewFile(uintptr(a.fd), "acquire-fence"), nil
109}
110
111func (n *renderNode) signal(h uint32, point uint64) error {
112	handles, points := [1]uint32{h}, [1]uint64{point}
113	a := syncobjTimelineArray{handles: uint64(uintptr(unsafe.Pointer(&handles))), points: uint64(uintptr(unsafe.Pointer(&points))), count: 1}
114	err := ioctl(n.fd, ioctlSyncobjTimelineSignal, unsafe.Pointer(&a))
115	runtime.KeepAlive(&handles)
116	runtime.KeepAlive(&points)
117	return err
118}
119
120func (n *renderNode) eventfd(h uint32, point uint64, efd int) error {
121	a := syncobjEventfd{handle: h, flags: syncobjWaitAvailable, point: point, fd: int32(efd)}
122	return ioctl(n.fd, ioctlSyncobjEventfd, unsafe.Pointer(&a))
123}
124
125func (n *renderNode) destroy(h uint32) error {
126	a := syncobjDestroy{handle: h}
127	return ioctl(n.fd, ioctlSyncobjDestroy, unsafe.Pointer(&a))
128}

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 26

Tags 10

↑↓ moveenter openesc close