[RFC,v1,11/20] libcamera: camera_manager: Marshal work onto the camera manager thread
diff mbox series

Message ID 20260918080734.1228227-12-naush@raspberrypi.com
State New
Headers show
Series
  • libcamera: New enumeration API
Related show

Commit Message

Naushir Patuck Sept. 18, 2026, 7:59 a.m. UTC
The upcoming enumerate() and initialize() interfaces are called from the
application thread, but the device enumerator, pipeline handlers and
media devices they operate on are all bound to the camera manager
thread, so their work must be marshalled onto it.

CameraManager::Private is a Thread and not an Object, so it cannot be
the target of Object::invokeMethod(). Derive it from Object as well and
move it to its own thread on construction.

Changes in future commits can then start the thread and invoke work on
it regardless of the order in which they are called. notify_all()
replaces notify_one() as more than one caller can now be waiting in
startThread() for the same initialisation.

Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
---
 include/libcamera/internal/camera_manager.h |  6 ++-
 src/libcamera/camera_manager.cpp            | 44 +++++++++++++++++++--
 2 files changed, 45 insertions(+), 5 deletions(-)

Patch
diff mbox series

diff --git a/include/libcamera/internal/camera_manager.h b/include/libcamera/internal/camera_manager.h
index e6df676bb655..ed90d1d471a0 100644
--- a/include/libcamera/internal/camera_manager.h
+++ b/include/libcamera/internal/camera_manager.h
@@ -15,6 +15,7 @@ 
 
 #include <libcamera/base/class.h>
 #include <libcamera/base/mutex.h>
+#include <libcamera/base/object.h>
 #include <libcamera/base/thread.h>
 #include <libcamera/base/thread_annotations.h>
 
@@ -30,7 +31,7 @@  class MediaDevice;
 class PipelineHandler;
 class PipelineHandlerFactoryBase;
 
-class CameraManager::Private : public Extensible::Private, public Thread
+class CameraManager::Private : public Extensible::Private, public Thread, public Object
 {
 	LIBCAMERA_DECLARE_PUBLIC(CameraManager)
 
@@ -54,6 +55,7 @@  protected:
 private:
 	int init();
 	std::vector<const PipelineHandlerFactoryBase *> pipelineFactories() const;
+	int startThread() LIBCAMERA_TSA_EXCLUDES(mutex_);
 	void createPipelineHandlers();
 	void pipelineFactoryMatch(const PipelineHandlerFactoryBase *factory);
 	std::shared_ptr<PipelineHandler> findMatchingHandler(const MediaDevice *media);
@@ -72,6 +74,8 @@  private:
 	bool initialized_ LIBCAMERA_TSA_GUARDED_BY(mutex_);
 	int status_ LIBCAMERA_TSA_GUARDED_BY(mutex_);
 
+	bool started_ LIBCAMERA_TSA_GUARDED_BY(mutex_) = false;
+
 	std::unique_ptr<DeviceEnumerator> enumerator_;
 
 	/*
diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp
index 55cf650b8e66..55532179a61c 100644
--- a/src/libcamera/camera_manager.cpp
+++ b/src/libcamera/camera_manager.cpp
@@ -41,14 +41,45 @@  LOG_DEFINE_CATEGORY(Camera)
 CameraManager::Private::Private()
 	: Thread("CameraManager"), initialized_(false)
 {
+	/*
+	 * Bind this Object to its own thread, so that work can be marshalled
+	 * onto the camera manager thread with invokeMethod().
+	 */
+	moveToThread(this);
 }
 
 int CameraManager::Private::start()
 {
-	int status;
+	return startThread();
+}
+
+/*
+ * Start the camera manager thread if not started yet, and wait for its
+ * initialization to complete. Returns the initialization status.
+ */
+int CameraManager::Private::startThread()
+{
+	bool start = false;
+
+	{
+		MutexLocker locker(mutex_);
 
-	/* Start the thread and wait for initialization to complete. */
-	Thread::start();
+		if (!started_) {
+			started_ = true;
+			initialized_ = false;
+			start = true;
+		}
+	}
+
+	if (start)
+		Thread::start();
+
+	/*
+	 * Wait for initialization to complete, whether this call started the
+	 * thread or another one did, as the caller may otherwise proceed before
+	 * the thread is ready.
+	 */
+	int status;
 
 	{
 		MutexLocker locker(mutex_);
@@ -78,7 +109,7 @@  void CameraManager::Private::run()
 	status_ = ret;
 	initialized_ = true;
 	mutex_.unlock();
-	cv_.notify_one();
+	cv_.notify_all();
 
 	if (ret < 0) {
 		cleanup();
@@ -228,6 +259,11 @@  void CameraManager::Private::cleanup()
 {
 	enumerator_->devicesAdded.disconnect(this);
 
+	{
+		MutexLocker locker(mutex_);
+		started_ = false;
+	}
+
 	/*
 	 * Release all references to cameras to ensure they all get destroyed
 	 * before the device enumerator deletes the media devices. Cameras are