umlaeute / v4l2loopback

v4l2-loopback device
GNU General Public License v2.0
3.73k stars 531 forks source link

poll() for readers fail if first call has readable state #601

Closed stephematician closed 1 week ago

stephematician commented 1 week ago

Essentially what the title says, a readers' poll will always hang (if there is no timeout) if the first call to poll was during readable state. Have identified where the problem occurs in a comment:

I believe this causes polling to fail if the first call to poll occurs when the system is in a readable state.

See e.g. this commit for v4l2: https://github.com/torvalds/linux/commit/726daf6bafe9d1d9e5c36e1e2a4008941fbc28bd

Originally posted by @stephematician in 64795fd

stephematician commented 1 week ago

The reason is explained in an (obscure) comment I found in V4L2 source code:

    /*
     * poll_wait() MUST be called on the first invocation on all the
     * potential queues of interest, even if we are not interested in their
     * events during this first call. Failure to do so will result in
     * queue's events to be ignored because the poll_table won't be capable
     * of adding new wait queues thereafter.
     */

Some further explanation is found in the commit attributed to when the comment was inserted:

media: v4l2-mem2mem: always call poll_wait() on queues
do_poll()/do_select() seem to set the _qproc member of poll_table to
NULL the first time they are called on a given table, making subsequent
calls of poll_wait() on that table no-ops. This is a problem for mem2mem
which calls poll_wait() on the V4L2 queues' waitqueues only when a
queue-related event is requested, which may not necessarily be the case
during the first poll.

For instance, a stateful decoder is typically only interested in
EPOLLPRI events when it starts, and will switch to listening to both
EPOLLPRI and EPOLLIN after receiving the initial resolution change event
and configuring the CAPTURE queue. However by the time that switch
happens and v4l2_m2m_poll_for_data() is called for the first time,
poll_wait() has become a no-op and the V4L2 queues waitqueues thus
cannot be registered.

Fix this by moving the registration to v4l2_m2m_poll() and do it whether
or not one of the queue-related events are requested.

Signed-off-by: Alexandre Courbot <gnurou@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>

Thank the stars for git and version control! 🧡