[libcamera-devel] [PATCH 5/5] v4l2: v4l2_compat: Add sockets to support polling

Paul Elder paul.elder at ideasonboard.com
Wed Jun 3 16:16:09 CEST 2020


To support polling, we need to be able to signal when data is available
to be read (POLLIN), as well as events (POLLPRI). To allow signaling
POLLPRI specifically, change eventfd to a pair of sockets.

After adding the socketpair, use the socketpair to signal POLLIN by
writing a byte to the socket, and read the byte away upon VIDIOC_DQBUF
to clear the handled POLLIN.

Although POLLPRI is not actually implemented, since we don't support
events, the facilities are in place. The implementation for signaling
and clearing POLLPRI is the same as for POLLIN, except that we would
send and receive an out-of-band byte through the socket.

Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>
---
 src/v4l2/v4l2_camera.cpp         | 13 +++++++++++++
 src/v4l2/v4l2_camera.h           |  3 +++
 src/v4l2/v4l2_camera_proxy.cpp   | 14 ++++++++++++++
 src/v4l2/v4l2_camera_proxy.h     |  4 ++++
 src/v4l2/v4l2_compat_manager.cpp | 22 ++++++++++++++++------
 5 files changed, 50 insertions(+), 6 deletions(-)

diff --git a/src/v4l2/v4l2_camera.cpp b/src/v4l2/v4l2_camera.cpp
index 4da01a45..ecbc87ec 100644
--- a/src/v4l2/v4l2_camera.cpp
+++ b/src/v4l2/v4l2_camera.cpp
@@ -8,6 +8,9 @@
 #include "v4l2_camera.h"
 
 #include <errno.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include "libcamera/internal/log.h"
 
@@ -51,6 +54,13 @@ void V4L2Camera::close()
 	bufferAllocator_ = nullptr;
 
 	camera_->release();
+
+	::close(sockfd_);
+}
+
+void V4L2Camera::bind(int sockfd)
+{
+	sockfd_ = sockfd;
 }
 
 void V4L2Camera::getStreamConfig(StreamConfiguration *streamConfig)
@@ -85,6 +95,9 @@ void V4L2Camera::requestComplete(Request *request)
 	bufferLock_.unlock();
 
 	bufferSema_.release();
+
+	char tmp = 0;
+	::send(sockfd_, &tmp, 1, 0);
 }
 
 int V4L2Camera::configure(StreamConfiguration *streamConfigOut,
diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h
index 303eda44..1ad040c1 100644
--- a/src/v4l2/v4l2_camera.h
+++ b/src/v4l2/v4l2_camera.h
@@ -39,6 +39,7 @@ public:
 
 	int open();
 	void close();
+	void bind(int sockfd);
 	void getStreamConfig(StreamConfiguration *streamConfig);
 	std::vector<Buffer> completedBuffers();
 
@@ -70,6 +71,8 @@ private:
 
 	std::deque<std::unique_ptr<Request>> pendingRequests_;
 	std::deque<std::unique_ptr<Buffer>> completedBuffers_;
+
+	int sockfd_;
 };
 
 #endif /* __V4L2_CAMERA_H__ */
diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp
index f84982a2..c9d7945a 100644
--- a/src/v4l2/v4l2_camera_proxy.cpp
+++ b/src/v4l2/v4l2_camera_proxy.cpp
@@ -13,6 +13,9 @@
 #include <linux/videodev2.h>
 #include <string.h>
 #include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include <libcamera/camera.h>
 #include <libcamera/object.h>
@@ -451,6 +454,11 @@ int V4L2CameraProxy::vidioc_dqbuf(struct v4l2_buffer *arg)
 
 	currentBuf_ = (currentBuf_ + 1) % bufferCount_;
 
+	char tmp;
+	int ret = ::recv(sockfd_, &tmp, 1, 0);
+	if (ret < 1)
+		return -EBUSY;
+
 	return 0;
 }
 
@@ -529,6 +537,12 @@ int V4L2CameraProxy::ioctl(unsigned long request, void *arg)
 	return ret;
 }
 
+void V4L2CameraProxy::bind(int sockfds[2])
+{
+	sockfd_ = sockfds[0];
+	vcam_->bind(sockfds[1]);
+}
+
 struct PixelFormatPlaneInfo {
 	unsigned int bitsPerPixel;
 	unsigned int hSubSampling;
diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h
index af9f9bbe..251b14a8 100644
--- a/src/v4l2/v4l2_camera_proxy.h
+++ b/src/v4l2/v4l2_camera_proxy.h
@@ -33,6 +33,8 @@ public:
 
 	int ioctl(unsigned long request, void *arg);
 
+	void bind(int sockfds[2]);
+
 private:
 	bool validateBufferType(uint32_t type);
 	bool validateMemoryType(uint32_t memory);
@@ -77,6 +79,8 @@ private:
 	std::map<void *, unsigned int> mmaps_;
 
 	std::unique_ptr<V4L2Camera> vcam_;
+
+	int sockfd_;
 };
 
 #endif /* __V4L2_CAMERA_PROXY_H__ */
diff --git a/src/v4l2/v4l2_compat_manager.cpp b/src/v4l2/v4l2_compat_manager.cpp
index 2338a0ee..b6e84866 100644
--- a/src/v4l2/v4l2_compat_manager.cpp
+++ b/src/v4l2/v4l2_compat_manager.cpp
@@ -12,8 +12,8 @@
 #include <map>
 #include <stdarg.h>
 #include <string.h>
-#include <sys/eventfd.h>
 #include <sys/mman.h>
+#include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/sysmacros.h>
 #include <sys/types.h>
@@ -155,15 +155,25 @@ int V4L2CompatManager::openat(int dirfd, const char *path, int oflag, mode_t mod
 	if (ret < 0)
 		return ret;
 
-	int efd = eventfd(0, oflag & (O_CLOEXEC | O_NONBLOCK));
-	if (efd < 0) {
+	int sockets[2];
+	ret = socketpair(AF_UNIX,
+			 SOCK_STREAM
+			 | ((oflag & O_CLOEXEC) ? SOCK_CLOEXEC : 0)
+			 | ((oflag & O_NONBLOCK) ? SOCK_NONBLOCK : 0),
+			 0, sockets);
+	if (ret) {
+		int err = errno;
 		proxy->close();
-		return efd;
+		errno = err;
+
+		return ret;
 	}
 
-	devices_.emplace(efd, proxy);
+	proxy->bind(sockets);
+
+	devices_.emplace(sockets[0], proxy);
 
-	return efd;
+	return sockets[0];
 }
 
 int V4L2CompatManager::dup(int oldfd)
-- 
2.20.1



More information about the libcamera-devel mailing list