Fix HID read busy-spin: pass 250ms, not 250ns, to ReadWithTimeout
go-hid's ReadWithTimeout takes a time.Duration, so the bare 250 was 250ns, which truncates to a 0 ms hid_read_timeout. On both Linux (poll) and macOS (cond_timedwait) 0 ms means non-blocking, so the button loop spun continuously: ~1.2 cores and ~7.5k context switches/sec at idle, from startup. Pass 250*time.Millisecond and match hid.ErrTimeout with errors.Is ahead of the string fallback. Idle CPU drops to ~0%. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016yH8jHn1SNzNnL58CRwTi9
This commit is contained in:
@@ -3,6 +3,7 @@ package device
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/jpeg"
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/sstallion/go-hid"
|
||||
"golang.org/x/image/draw"
|
||||
@@ -167,8 +169,13 @@ func (sd *StreamDeck) ClearKey(keyIndex int) error {
|
||||
// Returns (nil, nil) on timeout — callers should check context and retry.
|
||||
func (sd *StreamDeck) ReadButtons() ([]bool, error) {
|
||||
data := make([]byte, readReportSize)
|
||||
n, err := sd.dev.ReadWithTimeout(data, 250)
|
||||
// ReadWithTimeout takes a time.Duration: a bare 250 would be 250ns, which
|
||||
// truncates to a 0 ms (non-blocking) hid_read_timeout and busy-spins the loop.
|
||||
n, err := sd.dev.ReadWithTimeout(data, 250*time.Millisecond)
|
||||
if err != nil {
|
||||
if errors.Is(err, hid.ErrTimeout) {
|
||||
return nil, nil
|
||||
}
|
||||
// Linux hidraw returns errors (not (0,nil)) for non-fatal conditions:
|
||||
// timeout waiting for data, or EINTR (signal interrupted).
|
||||
// macOS IOHIDManager usually returns (0, nil) on timeout, but may also
|
||||
|
||||
@@ -96,3 +96,4 @@ The biggest architectural difference is privileged commands:
|
||||
| Log location | `journalctl --user -u streamdeck-go` | `~/Library/Logs/streamdeck-go.log` |
|
||||
| Config path | `~/.config/streamdeck-go/` (XDG) | `~/.config/streamdeck-go/` (XDG — works fine on macOS for CLI tools) |
|
||||
| Sleep/wake | Handled by reconnect loop | Handled by reconnect loop (same code) |
|
||||
| HID read timeout | `hid_read_timeout` → `poll()`; 0 ms = non-blocking | `hid_read_timeout` → `pthread_cond_timedwait`; 0 ms = non-blocking. Same fix applies: pass `250*time.Millisecond` |
|
||||
|
||||
Reference in New Issue
Block a user