blackjack / webcam

Golang webcam library for Linux
MIT License
411 stars 90 forks source link

v4l2.go / waitForFrame panics on "large" fds. #65

Closed dezi closed 10 months ago

dezi commented 10 months ago

waitForFrame panics on "large" fd value.

panic: runtime error: index out of range [19] with length 16

goroutine 410912 [running]:
golang.org/x/sys/unix.(*FdSet).Set(...)
        /home/dezi/go/src/golang.org/x/sys/unix/fdset.go:12
github.com/blackjack/webcam.waitForFrame(0x4e2, 0x5)
        /home/dezi/go/src/github.com/blackjack/webcam/v4l2.go:563 +0x165
github.com/blackjack/webcam.(*Webcam).WaitForFrame(0xc0157a4c90?, 0x4f9ebf?)
        /home/dezi/go/src/github.com/blackjack/webcam/webcam.go:289 +0x1c

Referring to unix manpage of select, this can only handle fds beeing less than some limit. This leads to unpredictable panics.

The solution is to replace "select" with "poll":

func waitForFrame(fd uintptr, timeout uint32) (count int, err error) {

    for {
        //fds := &unix.FdSet{}
        //fds.Set(int(fd))

        //var oneSecInNsec int64 = 1e9
        //timeoutNsec := int64(timeout) * oneSecInNsec
        //nativeTimeVal := unix.NsecToTimeval(timeoutNsec)
        //tv := &nativeTimeVal

        //count, err = unix.Select(int(fd+1), fds, nil, nil, tv)

        pollFds := []unix.PollFd{{Fd: int32(fd), Events: unix.POLLIN}}
        count, err = unix.Poll(pollFds, int(timeout*1000))

        if count < 0 && err == unix.EINTR {
            continue
        }
        return
    }
}

I have tested this, and it works. If desired, I can provide a pull request.

Regards, dezi

edaniels commented 10 months ago

Hey Dezi! I'm working on this now (well on a flight so it's slow going). I just want to take a quick look at perf considerations for tight loop slice allocations

edaniels commented 10 months ago

@dezi this should be fixed now. Thank you for the work!