Fail loudly on a drm read instead of leaving the panel frozen on its last frame
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sync/atomic"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
@@ -49,6 +50,9 @@ type framebuffer struct {
|
|||||||
// One token per completed flip. The render loop waits on this rather than on
|
// One token per completed flip. The render loop waits on this rather than on
|
||||||
// a timer, so drawing is paced by the panel instead of by a guess at its rate.
|
// a timer, so drawing is paced by the panel instead of by a guess at its rate.
|
||||||
flips chan struct{}
|
flips chan struct{}
|
||||||
|
|
||||||
|
// Set before the fd goes, so the event reader can tell shutdown from failure.
|
||||||
|
closing atomic.Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fb *framebuffer) offset(x, y int) int {
|
func (fb *framebuffer) offset(x, y int) int {
|
||||||
@@ -275,18 +279,30 @@ func openFramebuffer() (*framebuffer, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Flip completions arrive on the drm fd as a stream of length-prefixed events.
|
// Flip completions arrive on the drm fd as a stream of length-prefixed events.
|
||||||
|
// Nothing else feeds fb.flips, so returning early here freezes the panel on its
|
||||||
|
// last frame while everything else goes on running.
|
||||||
func (fb *framebuffer) readEvents() {
|
func (fb *framebuffer) readEvents() {
|
||||||
buf := make([]byte, 4096)
|
buf := make([]byte, 4096)
|
||||||
for {
|
for {
|
||||||
n, err := unix.Read(fb.fd, buf)
|
n, err := unix.Read(fb.fd, buf)
|
||||||
if n <= 0 || err != nil {
|
if fb.closing.Load() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if err == unix.EINTR || err == unix.EAGAIN {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("reading drm events: %v", err))
|
||||||
|
}
|
||||||
|
if n == 0 {
|
||||||
|
panic("drm fd reported end of file")
|
||||||
|
}
|
||||||
for off := 0; off+8 <= n; {
|
for off := 0; off+8 <= n; {
|
||||||
typ := binary.LittleEndian.Uint32(buf[off:])
|
typ := binary.LittleEndian.Uint32(buf[off:])
|
||||||
length := int(binary.LittleEndian.Uint32(buf[off+4:]))
|
length := int(binary.LittleEndian.Uint32(buf[off+4:]))
|
||||||
if length < 8 || off+length > n {
|
if length < 8 || off+length > n {
|
||||||
return
|
panic(fmt.Sprintf("drm event at offset %d claims %d bytes of %d read",
|
||||||
|
off, length, n))
|
||||||
}
|
}
|
||||||
if typ == drm.EventFlipComplete {
|
if typ == drm.EventFlipComplete {
|
||||||
select {
|
select {
|
||||||
@@ -300,6 +316,7 @@ func (fb *framebuffer) readEvents() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (fb *framebuffer) close() {
|
func (fb *framebuffer) close() {
|
||||||
|
fb.closing.Store(true)
|
||||||
for i := range fb.bufs {
|
for i := range fb.bufs {
|
||||||
if fb.bufs[i].mem != nil {
|
if fb.bufs[i].mem != nil {
|
||||||
unix.Munmap(fb.bufs[i].mem)
|
unix.Munmap(fb.bufs[i].mem)
|
||||||
|
|||||||
Reference in New Issue
Block a user