Never read sysfs through Go's poller, and a GPU that stops answering is skipped
On grid the sampler sat 42 minutes in runtime_pollWait on the Arc A380's hwmon fan1_input: kernfs accepts epoll, so os.ReadFile made the fd non-blocking, i915 answered EAGAIN once, and the poller waited for a readiness kernfs only signals on sysfs_notify. Every graph on the machine froze while the API carried on. readStr now reads with plain blocking syscalls. Each GPU's sysfs reads run under a three-second deadline; a device that does not answer is marked stalled, logged, and left alone until restart, with the box saying so. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
a8f4655c83
commit
b5cecce435
@@ -1352,12 +1352,32 @@ func Signal(pid int, sig syscall.Signal) error {
|
||||
|
||||
// ---- small helpers ----
|
||||
|
||||
// readStr reads a /proc or /sys file whole, with plain blocking syscalls and never through
|
||||
// the runtime poller. os.ReadFile would hand a sysfs file to the poller — kernfs accepts
|
||||
// epoll — and a driver that answers a non-blocking read with EAGAIN (i915's fan attribute
|
||||
// did, on grid, 2026-10-02) then leaves the reader waiting for a readiness kernfs only
|
||||
// signals on sysfs_notify: never. The sampler sat in that wait for 42 minutes.
|
||||
func readStr(p string) string {
|
||||
b, err := os.ReadFile(p)
|
||||
fd, err := syscall.Open(p, syscall.O_RDONLY|syscall.O_CLOEXEC, 0)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(b)
|
||||
defer syscall.Close(fd)
|
||||
var out []byte
|
||||
buf := make([]byte, 4096)
|
||||
for {
|
||||
n, err := syscall.Read(fd, buf)
|
||||
if n > 0 {
|
||||
out = append(out, buf[:n]...)
|
||||
}
|
||||
if err == syscall.EINTR {
|
||||
continue
|
||||
}
|
||||
if err != nil || n == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
|
||||
func readInt(p string) (int64, bool) {
|
||||
|
||||
Reference in New Issue
Block a user