This is an automatic generated email to let you know that the following patch 
were queued at the 
http://git.linuxtv.org/cgit.cgi/v4l-utils.git tree:

Subject: v4l2-ctl: process events before queues in stateful_m2m()
Author:  Alexandre Courbot <gnu...@gmail.com>
Date:    Fri Jan 24 20:56:06 2025 +0900

Events can change the streaming state and affect our ability (or
willingness) to further dequeue/requeue buffers.

For instance, a V4L2_EVENT_EOS means that we will stop streaming, so we
shouldn't process the OUTPUT queue any further once we receive it.
However, the current code processes the queues before the events, and
this can lead to issues such as an OUTPUT buffer dequeue attempt being
performed even though there is no buffer currently queued, resulting in
an indefinitely blocking DQBUF.

The issue was difficult to spot because (I assume) this usecase has been
mostly tested with software drivers like vicodec, which publish their
side-effects (notably in terms of events) before the ioctl that caused
them returns. But as far as I can tell this is not a requirement, and
events can also be sent asynchronously. In this case, a race condition
can cause the decoding loop to iterate one extra time and perform the
unfortunate DQBUF.

The fix is simple: process events before queues, so that the latter are
immediately affected by the result of published events instead of on the
next iteration of the loop. Events are supposed to be higher priority
anyway, and this is already done in that order in streaming_set_cap(),
so this sounds reasonable to do in any case.

Signed-off-by: Alexandre Courbot <gnu...@gmail.com>
Signed-off-by: Hans Verkuil <hverk...@xs4all.nl>

 utils/v4l2-ctl/v4l2-ctl-streaming.cpp | 54 +++++++++++++++++------------------
 1 file changed, 27 insertions(+), 27 deletions(-)

---

http://git.linuxtv.org/cgit.cgi/v4l-utils.git/commit/?id=7fa4b1f4388051de9103a13eaab1298368431f0a
diff --git a/utils/v4l2-ctl/v4l2-ctl-streaming.cpp 
b/utils/v4l2-ctl/v4l2-ctl-streaming.cpp
index 1068ef2e6559..a565628d3b73 100644
--- a/utils/v4l2-ctl/v4l2-ctl-streaming.cpp
+++ b/utils/v4l2-ctl/v4l2-ctl-streaming.cpp
@@ -2460,6 +2460,33 @@ static void stateful_m2m(cv4l_fd &fd, cv4l_queue &in, 
cv4l_queue &out,
                        return;
                }
 
+               if (ex_fds && FD_ISSET(fd.g_fd(), ex_fds)) {
+                       struct v4l2_event ev;
+
+                       while (!fd.dqevent(ev)) {
+                               if (ev.type == V4L2_EVENT_EOS) {
+                                       wr_fds = nullptr;
+                                       if (!verbose)
+                                               stderr_info("\n");
+                                       stderr_info("EOS EVENT\n");
+                                       fflush(stderr);
+                               } else if (ev.type == V4L2_EVENT_SOURCE_CHANGE) 
{
+                                       if (!verbose)
+                                               stderr_info("\n");
+                                       stderr_info("SOURCE CHANGE EVENT\n");
+                                       in_source_change_event = true;
+
+                                       /*
+                                        * if capture is not streaming, the
+                                        * driver will not send a last buffer so
+                                        * we set it here
+                                        */
+                                       if (!cap_streaming)
+                                               last_buffer = true;
+                               }
+                       }
+               }
+
                if (rd_fds && FD_ISSET(fd.g_fd(), rd_fds)) {
                        r = do_handle_cap(fd, in, fin, nullptr,
                                          count[CAP], fps_ts[CAP], fmt_in,
@@ -2495,33 +2522,6 @@ static void stateful_m2m(cv4l_fd &fd, cv4l_queue &in, 
cv4l_queue &out,
                        }
                }
 
-               if (ex_fds && FD_ISSET(fd.g_fd(), ex_fds)) {
-                       struct v4l2_event ev;
-
-                       while (!fd.dqevent(ev)) {
-                               if (ev.type == V4L2_EVENT_EOS) {
-                                       wr_fds = nullptr;
-                                       if (!verbose)
-                                               stderr_info("\n");
-                                       stderr_info("EOS EVENT\n");
-                                       fflush(stderr);
-                               } else if (ev.type == V4L2_EVENT_SOURCE_CHANGE) 
{
-                                       if (!verbose)
-                                               stderr_info("\n");
-                                       stderr_info("SOURCE CHANGE EVENT\n");
-                                       in_source_change_event = true;
-
-                                       /*
-                                        * if capture is not streaming, the
-                                        * driver will not send a last buffer so
-                                        * we set it here
-                                        */
-                                       if (!cap_streaming)
-                                               last_buffer = true;
-                               }
-                       }
-               }
-
                if (last_buffer) {
                        if (in_source_change_event) {
                                struct v4l2_control ctrl = {

Reply via email to