aboutsummaryrefslogtreecommitdiffstats
path: root/utils/v4l2-compliance
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2018-05-11 14:49:33 +0200
committerHans Verkuil <hans.verkuil@cisco.com>2018-05-11 14:49:33 +0200
commit79d98edd1a27233667a6bc38d3d7f8958c2ec02c (patch)
tree851cf27cc6bb984819ec072503dd32e94b28a380 /utils/v4l2-compliance
parent03e763fd4b361b2082019032fc315b7606669335 (diff)
v4l2-compliance: test stream locking
When in a blocking wait for DQBUF it should be possible to call STREAMOFF from a forked process. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Diffstat (limited to 'utils/v4l2-compliance')
-rw-r--r--utils/v4l2-compliance/v4l2-compliance.cpp2
-rw-r--r--utils/v4l2-compliance/v4l2-compliance.h1
-rw-r--r--utils/v4l2-compliance/v4l2-test-buffers.cpp92
3 files changed, 95 insertions, 0 deletions
diff --git a/utils/v4l2-compliance/v4l2-compliance.cpp b/utils/v4l2-compliance/v4l2-compliance.cpp
index 75146caf..36c4c0a6 100644
--- a/utils/v4l2-compliance/v4l2-compliance.cpp
+++ b/utils/v4l2-compliance/v4l2-compliance.cpp
@@ -1014,6 +1014,8 @@ void testNode(struct node &node, struct node &expbuf_node, media_type type,
// Reopen after each streaming test to reset the streaming state
// in case of any errors in the preceeding test.
node.reopen();
+ printf("\ttest blocking wait: %s\n", ok(testBlockingWait(&node)));
+ node.reopen();
printf("\ttest MMAP: %s\n", ok(testMmap(&node, frame_count)));
node.reopen();
printf("\ttest USERPTR: %s\n", ok(testUserPtr(&node, frame_count)));
diff --git a/utils/v4l2-compliance/v4l2-compliance.h b/utils/v4l2-compliance/v4l2-compliance.h
index 00d341a2..3c791155 100644
--- a/utils/v4l2-compliance/v4l2-compliance.h
+++ b/utils/v4l2-compliance/v4l2-compliance.h
@@ -252,6 +252,7 @@ int testSubDevFrameInterval(struct node *node, unsigned pad);
int testReqBufs(struct node *node);
int testReadWrite(struct node *node);
int testExpBuf(struct node *node);
+int testBlockingWait(struct node *node);
int testMmap(struct node *node, unsigned frame_count);
int testUserPtr(struct node *node, unsigned frame_count);
int testDmaBuf(struct node *expbuf_node, struct node *node, unsigned frame_count);
diff --git a/utils/v4l2-compliance/v4l2-test-buffers.cpp b/utils/v4l2-compliance/v4l2-test-buffers.cpp
index 9b0933ef..3986435b 100644
--- a/utils/v4l2-compliance/v4l2-test-buffers.cpp
+++ b/utils/v4l2-compliance/v4l2-test-buffers.cpp
@@ -26,6 +26,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
+#include <sys/wait.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
@@ -1167,6 +1168,97 @@ int testDmaBuf(struct node *expbuf_node, struct node *node, unsigned frame_count
return 0;
}
+static int testBlockingDQBuf(struct node *node, cv4l_queue &q)
+{
+ int pid_dqbuf;
+ int pid_streamoff;
+ int pid;
+
+ fail_on_test(q.reqbufs(node, 2));
+ fail_on_test(node->streamon(q.g_type()));
+
+ /*
+ * This test checks if a blocking wait in VIDIOC_DQBUF doesn't block
+ * other ioctls.
+ */
+ pid_dqbuf = fork();
+ fail_on_test(pid_dqbuf == -1);
+
+ if (pid_dqbuf == 0) { // Child
+ /*
+ * In the child process we call VIDIOC_DQBUF and wait
+ * indefinitely since no buffers are queued.
+ */
+ cv4l_buffer buf(q.g_type(), V4L2_MEMORY_MMAP);
+
+ node->dqbuf(buf);
+ exit(0);
+ }
+
+ /* Wait for the child process to start and block */
+ usleep(100000);
+ pid = waitpid(pid_dqbuf, NULL, WNOHANG);
+ /* Check that it is really blocking */
+ fail_on_test(pid);
+
+ pid_streamoff = fork();
+ fail_on_test(pid_streamoff == -1);
+
+ if (pid_streamoff == 0) { // Child
+ /*
+ * In the second child call STREAMOFF: this shouldn't
+ * be blocked by the DQBUF!
+ */
+ node->streamoff(q.g_type());
+ exit(0);
+ }
+
+ int wstatus_streamoff = 0;
+
+ /* Wait for the second child to start and exit */
+ usleep(250000);
+ pid = waitpid(pid_streamoff, &wstatus_streamoff, WNOHANG);
+ kill(pid_dqbuf, SIGKILL);
+ fail_on_test(pid != pid_streamoff);
+ /* Test that the second child exited properly */
+ if (!pid || !WIFEXITED(wstatus_streamoff)) {
+ kill(pid_streamoff, SIGKILL);
+ fail_on_test(!pid || !WIFEXITED(wstatus_streamoff));
+ }
+
+ fail_on_test(node->streamoff(q.g_type()));
+ fail_on_test(q.reqbufs(node, 0));
+ return 0;
+}
+
+int testBlockingWait(struct node *node)
+{
+ bool can_stream = node->g_caps() & V4L2_CAP_STREAMING;
+ int type;
+
+ if (!can_stream || !node->valid_buftypes)
+ return ENOTTY;
+
+ buffer_info.clear();
+ for (type = 0; type <= V4L2_BUF_TYPE_LAST; type++) {
+ if (!(node->valid_buftypes & (1 << type)))
+ continue;
+ if (v4l_type_is_overlay(type))
+ continue;
+
+ cv4l_queue q(type, V4L2_MEMORY_MMAP);
+ cv4l_queue m2m_q(v4l_type_invert(type), V4L2_MEMORY_MMAP);
+
+ if (testSetupVbi(node, type))
+ continue;
+
+ fail_on_test(testBlockingDQBuf(node, q));
+ if (node->is_m2m)
+ fail_on_test(testBlockingDQBuf(node, m2m_q));
+ }
+ return 0;
+}
+
static void restoreCropCompose(struct node *node, __u32 field,
v4l2_selection &crop, v4l2_selection &compose)
{

Privacy Policy