Patch Detail
Show a patch.
GET /api/patches/18462/?format=api
{ "id": 18462, "url": "https://patchwork.libcamera.org/api/patches/18462/?format=api", "web_url": "https://patchwork.libcamera.org/patch/18462/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/projects/1/?format=api", "name": "libcamera", "link_name": "libcamera", "list_id": "libcamera_core", "list_email": "libcamera-devel@lists.libcamera.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20230325122410.575584-1-dorota.czaplejewicz@puri.sm>", "date": "2023-03-25T12:29:38", "name": "[libcamera-devel] camera_manager: Formalize shared ownership", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "bea494b79f8d683b64ae3e0adfc7f91a0d5dd164", "submitter": { "id": 96, "url": "https://patchwork.libcamera.org/api/people/96/?format=api", "name": "Dorota Czaplejewicz", "email": "dorota.czaplejewicz@puri.sm" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/18462/mbox/", "series": [ { "id": 3816, "url": "https://patchwork.libcamera.org/api/series/3816/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=3816", "date": "2023-03-25T12:29:38", "name": "[libcamera-devel] camera_manager: Formalize shared ownership", "version": 1, "mbox": "https://patchwork.libcamera.org/series/3816/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/18462/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/18462/checks/", "tags": {}, "headers": { "Return-Path": "<libcamera-devel-bounces@lists.libcamera.org>", "X-Original-To": "parsemail@patchwork.libcamera.org", "Delivered-To": "parsemail@patchwork.libcamera.org", "Received": [ "from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id E1DA8C0F2A\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSat, 25 Mar 2023 12:30:01 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id D9300626D7;\n\tSat, 25 Mar 2023 13:30:00 +0100 (CET)", "from comms.puri.sm (comms.puri.sm [159.203.221.185])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id B20DD603A8\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 25 Mar 2023 13:29:58 +0100 (CET)", "from localhost (localhost [127.0.0.1])\n\tby comms.puri.sm (Postfix) with ESMTP id D420BFD54F\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 25 Mar 2023 05:29:56 -0700 (PDT)", "from comms.puri.sm ([127.0.0.1])\n\tby localhost (comms.puri.sm [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id xN4rapFsCpdI for <libcamera-devel@lists.libcamera.org>; \n\tSat, 25 Mar 2023 05:29:54 -0700 (PDT)" ], "DKIM-Signature": [ "v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1679747400;\n\tbh=T7Xolcbk5yqmidv3+52WZEHNt/e8yJ6wD817I0zFdvY=;\n\th=Date:To:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post:\n\tList-Help:List-Subscribe:From:Reply-To:From;\n\tb=CG0lhvPRvx3/KySK3LAmYE0r3Mj8eWFuBDjqSEbcpQ0PLdAZI0YcgxfupaeynIi+p\n\tNLL8GjzNgoV+g17Cc+2IGPWBp3v22MBQ/QiJETTjLIZl9yj1kLe89v5qYxYbbYi37X\n\ti5tDttBR0hG9zssdvJ5YpPD6SNAFBU0Rk6NM9d6dkamUzdPaxRBIBZ534k8X3HYVhO\n\tOz5fqEpoVa+sVZpNIJloYjGCpasv/vQAZXt5nff2xUWwKFRmYuanzt8PIHf7/3sdaC\n\tdrAjocRwQJ5QzLhzR+cv57D3wKLwNzkPSCwO5WMuSWaNM7/CPV8iDZzO4FWIgmJVCQ\n\tTClC4d7can8wA==", "v=1; a=rsa-sha256; c=relaxed/simple; d=puri.sm; s=comms;\n\tt=1679747394; bh=T7Xolcbk5yqmidv3+52WZEHNt/e8yJ6wD817I0zFdvY=;\n\th=Date:From:To:Subject:From;\n\tb=oL0xC4y5nlqoCjUUxyVuxVXR9S14hsfCCbZSpMNMmTVeRhyTXL+YYT6s2U2tsexhC\n\tydMhDI7r+Z+PKQbeN1y8TLr7/v/F2wEoEScbSbZN1EfPcqe0AMamHewI2MTpqiPBvF\n\tTrxCNlex8W+OKlZ0KWKF2Ed6RPva/Wyc3JuXKOc9lYPG91t9lQ+2krPNUiu19uskNU\n\tbnbs2hWiC1LwylSltl4eAIjEzI4cQTwMVPZTkRXMEhTroy9uwXPxDx7fdGdZgCHnmW\n\t6oRl0rst/NH74hK5sf4AzMgdsd6q8uomtk0mjRgGNfJzNVqaJhUg9W/5JuJRUOS6hx\n\tl6gmJP7isHsHA==" ], "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (2048-bit key; \n\tunprotected) header.d=puri.sm header.i=@puri.sm\n\theader.b=\"oL0xC4y5\"; dkim-atps=neutral", "Date": "Sat, 25 Mar 2023 13:29:38 +0100", "To": "libcamera-devel@lists.libcamera.org", "Message-ID": "<20230325122410.575584-1-dorota.czaplejewicz@puri.sm>", "Organization": "Purism", "MIME-Version": "1.0", "Content-Type": "multipart/signed; boundary=\"Sig_/s_boOum08WWfpOm1tPleWKq\";\n\tprotocol=\"application/pgp-signature\"; micalg=pgp-sha256", "Subject": "[libcamera-devel] [PATCH] camera_manager: Formalize shared ownership", "X-BeenThere": "libcamera-devel@lists.libcamera.org", "X-Mailman-Version": "2.1.29", "Precedence": "list", "List-Id": "<libcamera-devel.lists.libcamera.org>", "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>", "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>", "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>", "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>", "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>", "From": "Dorota Czaplejewicz via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>", "Reply-To": "Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>", "Errors-To": "libcamera-devel-bounces@lists.libcamera.org", "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>" }, "content": "This change corrects the violation of the Ownership rules by making the shared part of CameraManager useable in a shared manner. In practice, this takes over the task of tracking CameraManager memory away from the public API users. In particular, releasing the CameraManager no longer causes undefined behaviour.\n\nBefore this change, libcamera kept references to CameraManager via the PipelineHandler Camera::Private::pipe_, through its manager_ field.\nThis field gets populated via a sequence of calls:\n\nCameraManager::start() calls PipelineHandler::match, which calls Camera::Private(this).\n\nThis sequence is unavoidable because Camera::Private constructor is `Private(PipelineHandler *pipe)`.\n\nAs a result, Camera owns a reference to PipelineHandler, which owns a signal which holds a reference to CameraManager. Thus, CameraManager is referenced by each camera, as well as the user.\n\nThis is in violation of the Object Ownership rules on Single Owner Objects:\n\n> When borrowing from caller to callee for the duration of a function call, this implies that the callee shall not keep any stored reference after it returns. These rules apply to the callee and all the functions it calls, directly or indirectly.\n\nbecause CameraManager::start() indirectly retains a reference to CameraManager beyond duration of the call.\n\nThe solution presented here turns CameraManager data into a shared object, allowing the previous sequence of calls to operate safely.\n\nThe shared portion of CameraManager is extracted and turned into a singleton class CamerasList. The public CameraManager class itself becomes an on-demand reference to this CamerasList object.\n---\nHello,\n\ndespite the previous discussion, I managed to find a way to prevent CameraManager mistakes without wrapping it in a shared_ptr.\n\nA bug reproducer, leading to crashes/hangs can be seen in my copy of simple_cam here:\n\nhttps://source.puri.sm/dorota.czaplejewicz/simplecam/-/merge_requests/new?merge_request%5Bsource_branch%5D=manager\n\nThe breakage comes at Camera::configure(), and it's gone after this change.\n\nRegards,\nDorota Czaplejewicz\n\n include/libcamera/camera_manager.h | 2 +-\n include/libcamera/internal/camera_manager.h | 60 +++++++++\n include/libcamera/internal/pipeline_handler.h | 11 +-\n src/libcamera/camera_manager.cpp | 124 +++++++++---------\n src/libcamera/pipeline/imx8-isi/imx8-isi.cpp | 4 +-\n src/libcamera/pipeline/ipu3/ipu3.cpp | 4 +-\n .../pipeline/raspberrypi/raspberrypi.cpp | 4 +-\n src/libcamera/pipeline/rkisp1/rkisp1.cpp | 4 +-\n src/libcamera/pipeline/simple/simple.cpp | 4 +-\n src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 4 +-\n src/libcamera/pipeline/vimc/vimc.cpp | 4 +-\n src/libcamera/pipeline_handler.cpp | 7 +-\n 12 files changed, 145 insertions(+), 87 deletions(-)\n create mode 100644 include/libcamera/internal/camera_manager.h", "diff": "diff --git a/include/libcamera/camera_manager.h b/include/libcamera/camera_manager.h\nindex 4b1fb756..3d5bf1ea 100644\n--- a/include/libcamera/camera_manager.h\n+++ b/include/libcamera/camera_manager.h\n@@ -16,6 +16,7 @@\n #include <libcamera/base/object.h>\n #include <libcamera/base/signal.h>\n \n+\n namespace libcamera {\n \n class Camera;\n@@ -47,7 +48,6 @@ private:\n \tLIBCAMERA_DISABLE_COPY(CameraManager)\n \n \tstatic const std::string version_;\n-\tstatic CameraManager *self_;\n };\n \n } /* namespace libcamera */\ndiff --git a/include/libcamera/internal/camera_manager.h b/include/libcamera/internal/camera_manager.h\nnew file mode 100644\nindex 00000000..ec1d625b\n--- /dev/null\n+++ b/include/libcamera/internal/camera_manager.h\n@@ -0,0 +1,60 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2018, Google Inc.\n+ *\n+ * camera_manager.h - Camera management\n+ */\n+\n+#pragma once\n+\n+\n+#include <map>\n+#include <memory>\n+#include <vector>\n+#include <libcamera/base/mutex.h>\n+#include <libcamera/base/thread.h>\n+#include <libcamera/camera.h>\n+#include \"libcamera/internal/device_enumerator.h\"\n+\n+namespace libcamera {\n+\n+class CamerasList : public Thread\n+{\n+public:\n+\tCamerasList();\n+\t~CamerasList();\n+\n+\tint start();\n+\tvoid stop();\n+\tvoid addCamera(std::shared_ptr<Camera> camera,\n+\t\t const std::vector<dev_t> &devnums) LIBCAMERA_TSA_EXCLUDES(mutex_);\n+\tvoid removeCamera(Camera *camera) LIBCAMERA_TSA_EXCLUDES(mutex_);\n+\n+\t/*\n+\t * This mutex protects\n+\t *\n+\t * - initialized_ and status_ during initialization\n+\t * - cameras_ and camerasByDevnum_ after initialization\n+\t */\n+\tmutable Mutex mutex_;\n+\tstd::vector<std::shared_ptr<Camera>> cameras_ LIBCAMERA_TSA_GUARDED_BY(mutex_);\n+\tstd::map<dev_t, std::weak_ptr<Camera>> camerasByDevnum_ LIBCAMERA_TSA_GUARDED_BY(mutex_);\n+\tstatic std::weak_ptr<CamerasList> singleton_;\n+\n+\tvoid createPipelineHandlers();\n+\tvoid cleanup() LIBCAMERA_TSA_EXCLUDES(mutex_);\n+\tvoid prepare(std::shared_ptr<CamerasList> self);\n+\n+protected:\n+\tvoid run() override;\n+\n+private:\n+\tint init();\n+\tConditionVariable cv_;\n+\tbool initialized_ LIBCAMERA_TSA_GUARDED_BY(mutex_);\n+\tint status_ LIBCAMERA_TSA_GUARDED_BY(mutex_);\n+\n+\tstd::unique_ptr<DeviceEnumerator> enumerator_;\n+};\n+\n+}\n\\ No newline at end of file\ndiff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h\nindex 4c4dfe62..fd07ceda 100644\n--- a/include/libcamera/internal/pipeline_handler.h\n+++ b/include/libcamera/internal/pipeline_handler.h\n@@ -27,6 +27,7 @@ namespace libcamera {\n class Camera;\n class CameraConfiguration;\n class CameraManager;\n+class CamerasList;\n class DeviceEnumerator;\n class DeviceMatch;\n class FrameBuffer;\n@@ -38,7 +39,7 @@ class PipelineHandler : public std::enable_shared_from_this<PipelineHandler>,\n \t\t\tpublic Object\n {\n public:\n-\tPipelineHandler(CameraManager *manager);\n+\tPipelineHandler(std::shared_ptr<CamerasList> manager);\n \tvirtual ~PipelineHandler();\n \n \tvirtual bool match(DeviceEnumerator *enumerator) = 0;\n@@ -79,7 +80,7 @@ protected:\n \n \tvirtual void releaseDevice(Camera *camera);\n \n-\tCameraManager *manager_;\n+\tstd::shared_ptr<CamerasList> manager_;\n \n private:\n \tvoid unlockMediaDevices();\n@@ -109,7 +110,7 @@ public:\n \tPipelineHandlerFactoryBase(const char *name);\n \tvirtual ~PipelineHandlerFactoryBase() = default;\n \n-\tstd::shared_ptr<PipelineHandler> create(CameraManager *manager) const;\n+\tstd::shared_ptr<PipelineHandler> create(std::shared_ptr<CamerasList> manager) const;\n \n \tconst std::string &name() const { return name_; }\n \n@@ -119,7 +120,7 @@ private:\n \tstatic void registerType(PipelineHandlerFactoryBase *factory);\n \n \tvirtual std::unique_ptr<PipelineHandler>\n-\tcreateInstance(CameraManager *manager) const = 0;\n+\tcreateInstance(std::shared_ptr<CamerasList> manager) const = 0;\n \n \tstd::string name_;\n };\n@@ -134,7 +135,7 @@ public:\n \t}\n \n \tstd::unique_ptr<PipelineHandler>\n-\tcreateInstance(CameraManager *manager) const override\n+\tcreateInstance(std::shared_ptr<CamerasList> manager) const override\n \t{\n \t\treturn std::make_unique<_PipelineHandler>(manager);\n \t}\ndiff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp\nindex c1edefda..85eca629 100644\n--- a/src/libcamera/camera_manager.cpp\n+++ b/src/libcamera/camera_manager.cpp\n@@ -16,6 +16,7 @@\n #include <libcamera/base/thread.h>\n #include <libcamera/base/utils.h>\n \n+#include \"libcamera/internal/camera_manager.h\"\n #include \"libcamera/internal/device_enumerator.h\"\n #include \"libcamera/internal/ipa_manager.h\"\n #include \"libcamera/internal/pipeline_handler.h\"\n@@ -33,52 +34,46 @@ namespace libcamera {\n \n LOG_DEFINE_CATEGORY(Camera)\n \n-class CameraManager::Private : public Extensible::Private, public Thread\n+\n+class CameraManager::Private : public Extensible::Private\n {\n \tLIBCAMERA_DECLARE_PUBLIC(CameraManager)\n \n public:\n-\tPrivate();\n-\n \tint start();\n-\tvoid addCamera(std::shared_ptr<Camera> camera,\n-\t\t const std::vector<dev_t> &devnums) LIBCAMERA_TSA_EXCLUDES(mutex_);\n-\tvoid removeCamera(Camera *camera) LIBCAMERA_TSA_EXCLUDES(mutex_);\n-\n-\t/*\n-\t * This mutex protects\n-\t *\n-\t * - initialized_ and status_ during initialization\n-\t * - cameras_ and camerasByDevnum_ after initialization\n-\t */\n-\tmutable Mutex mutex_;\n-\tstd::vector<std::shared_ptr<Camera>> cameras_ LIBCAMERA_TSA_GUARDED_BY(mutex_);\n-\tstd::map<dev_t, std::weak_ptr<Camera>> camerasByDevnum_ LIBCAMERA_TSA_GUARDED_BY(mutex_);\n-\n-protected:\n-\tvoid run() override;\n-\n+\tstd::shared_ptr<CamerasList> cl_;\n private:\n-\tint init();\n-\tvoid createPipelineHandlers();\n-\tvoid cleanup() LIBCAMERA_TSA_EXCLUDES(mutex_);\n-\n-\tConditionVariable cv_;\n-\tbool initialized_ LIBCAMERA_TSA_GUARDED_BY(mutex_);\n-\tint status_ LIBCAMERA_TSA_GUARDED_BY(mutex_);\n-\n-\tstd::unique_ptr<DeviceEnumerator> enumerator_;\n-\n \tIPAManager ipaManager_;\n \tProcessManager processManager_;\n };\n \n-CameraManager::Private::Private()\n+std::weak_ptr<CamerasList> CamerasList::singleton_;\n+\n+int CameraManager::Private::start()\n+{\n+\tif (CamerasList::singleton_.use_count() > 0) {\n+\t\tcl_ = CamerasList::singleton_.lock();\n+\t\tif (cl_->isRunning()) {\n+\t\t\treturn 0;\n+\t\t}\n+\t} else {\n+\t\tcl_ = std::make_shared<CamerasList>();\n+\t\tcl_->prepare(cl_);\n+\t}\n+\treturn cl_->start();\n+}\n+\n+CamerasList::CamerasList()\n \t: initialized_(false)\n {\n }\n \n-int CameraManager::Private::start()\n+CamerasList::~CamerasList()\n+{\n+\tstop();\n+}\n+\n+int CamerasList::start()\n {\n \tint status;\n \n@@ -103,8 +98,9 @@ int CameraManager::Private::start()\n \treturn 0;\n }\n \n-void CameraManager::Private::run()\n+void CamerasList::run()\n {\n+\tASSERT(singleton_.use_count() > 0);\n \tLOG(Camera, Debug) << \"Starting camera manager\";\n \n \tint ret = init();\n@@ -124,21 +120,28 @@ void CameraManager::Private::run()\n \tcleanup();\n }\n \n-int CameraManager::Private::init()\n+void CamerasList::prepare(std::shared_ptr<CamerasList> self)\n+{\n+\tsingleton_ = self;\n+}\n+\n+int CamerasList::init()\n {\n \tenumerator_ = DeviceEnumerator::create();\n \tif (!enumerator_ || enumerator_->enumerate())\n \t\treturn -ENODEV;\n \n \tcreatePipelineHandlers();\n-\tenumerator_->devicesAdded.connect(this, &Private::createPipelineHandlers);\n+\t// It's safe to add signals directly through a pointer\n+\t// because enumerator (and its signals) can not outlive CamerasList.\n+\tenumerator_->devicesAdded.connect(this, &CamerasList::createPipelineHandlers);\n \n \treturn 0;\n }\n \n-void CameraManager::Private::createPipelineHandlers()\n+void CamerasList::createPipelineHandlers()\n {\n-\tCameraManager *const o = LIBCAMERA_O_PTR();\n+\tstd::shared_ptr<CamerasList> const o = singleton_.lock();\n \n \t/*\n \t * \\todo Try to read handlers and order from configuration\n@@ -168,10 +171,9 @@ void CameraManager::Private::createPipelineHandlers()\n \t}\n }\n \n-void CameraManager::Private::cleanup()\n+void CamerasList::cleanup()\n {\n \tenumerator_->devicesAdded.disconnect(this);\n-\n \t/*\n \t * Release all references to cameras to ensure they all get destroyed\n \t * before the device enumerator deletes the media devices. Cameras are\n@@ -189,7 +191,7 @@ void CameraManager::Private::cleanup()\n \tenumerator_.reset(nullptr);\n }\n \n-void CameraManager::Private::addCamera(std::shared_ptr<Camera> camera,\n+void CamerasList::addCamera(std::shared_ptr<Camera> camera,\n \t\t\t\t const std::vector<dev_t> &devnums)\n {\n \tMutexLocker locker(mutex_);\n@@ -210,7 +212,7 @@ void CameraManager::Private::addCamera(std::shared_ptr<Camera> camera,\n \t\tcamerasByDevnum_[devnum] = cameras_[index];\n }\n \n-void CameraManager::Private::removeCamera(Camera *camera)\n+void CamerasList::removeCamera(Camera *camera)\n {\n \tMutexLocker locker(mutex_);\n \n@@ -234,6 +236,13 @@ void CameraManager::Private::removeCamera(Camera *camera)\n \tcameras_.erase(iter);\n }\n \n+void CamerasList::stop()\n+{\n+\texit();\n+\twait();\n+}\n+\n+\n /**\n * \\class CameraManager\n * \\brief Provide access and manage all cameras in the system\n@@ -244,9 +253,7 @@ void CameraManager::Private::removeCamera(Camera *camera)\n * handles hot-plugging and hot-unplugging to manage the lifetime of cameras.\n *\n * To interact with libcamera, an application starts by creating a camera\n- * manager instance. Only a single instance of the camera manager may exist at\n- * a time. Attempting to create a second instance without first deleting the\n- * existing instance results in undefined behaviour.\n+ * manager instance.\n *\n * The manager is initially stopped, and shall be started with start(). This\n * will enumerate all the cameras present in the system, which can then be\n@@ -258,29 +265,19 @@ void CameraManager::Private::removeCamera(Camera *camera)\n * references it held to cameras, the camera manager can be stopped with\n * stop().\n */\n-\n-CameraManager *CameraManager::self_ = nullptr;\n-\n CameraManager::CameraManager()\n \t: Extensible(std::make_unique<CameraManager::Private>())\n {\n-\tif (self_)\n-\t\tLOG(Camera, Fatal)\n-\t\t\t<< \"Multiple CameraManager objects are not allowed\";\n-\n-\tself_ = this;\n }\n \n /**\n * \\brief Destroy the camera manager\n *\n- * Destroying the camera manager stops it if it is currently running.\n+ * Destroying the camera manager stops it if it is currently running\n+ * and none of its cameras exist.\n */\n CameraManager::~CameraManager()\n {\n-\tstop();\n-\n-\tself_ = nullptr;\n }\n \n /**\n@@ -317,9 +314,8 @@ int CameraManager::start()\n */\n void CameraManager::stop()\n {\n-\tPrivate *const d = _d();\n-\td->exit();\n-\td->wait();\n+\tauto *const d = _d()->cl_.get();\n+\td->stop();\n }\n \n /**\n@@ -335,7 +331,7 @@ void CameraManager::stop()\n */\n std::vector<std::shared_ptr<Camera>> CameraManager::cameras() const\n {\n-\tconst Private *const d = _d();\n+\tconst auto *const d = _d()->cl_.get();\n \n \tMutexLocker locker(d->mutex_);\n \n@@ -355,7 +351,7 @@ std::vector<std::shared_ptr<Camera>> CameraManager::cameras() const\n */\n std::shared_ptr<Camera> CameraManager::get(const std::string &id)\n {\n-\tPrivate *const d = _d();\n+\tauto *const d = _d()->cl_.get();\n \n \tMutexLocker locker(d->mutex_);\n \n@@ -385,7 +381,7 @@ std::shared_ptr<Camera> CameraManager::get(const std::string &id)\n */\n std::shared_ptr<Camera> CameraManager::get(dev_t devnum)\n {\n-\tPrivate *const d = _d();\n+\tauto *const d = _d()->cl_.get();\n \n \tMutexLocker locker(d->mutex_);\n \n@@ -441,7 +437,7 @@ std::shared_ptr<Camera> CameraManager::get(dev_t devnum)\n void CameraManager::addCamera(std::shared_ptr<Camera> camera,\n \t\t\t const std::vector<dev_t> &devnums)\n {\n-\tPrivate *const d = _d();\n+\tauto *const d = _d()->cl_.get();\n \n \tASSERT(Thread::current() == d);\n \n@@ -461,7 +457,7 @@ void CameraManager::addCamera(std::shared_ptr<Camera> camera,\n */\n void CameraManager::removeCamera(std::shared_ptr<Camera> camera)\n {\n-\tPrivate *const d = _d();\n+\tauto *const d = _d()->cl_.get();\n \n \tASSERT(Thread::current() == d);\n \ndiff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\nindex 0c67e35d..f57316bf 100644\n--- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n+++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n@@ -107,7 +107,7 @@ private:\n class PipelineHandlerISI : public PipelineHandler\n {\n public:\n-\tPipelineHandlerISI(CameraManager *manager);\n+\tPipelineHandlerISI(std::shared_ptr<CamerasList> manager);\n \n \tbool match(DeviceEnumerator *enumerator) override;\n \n@@ -564,7 +564,7 @@ CameraConfiguration::Status ISICameraConfiguration::validate()\n * Pipeline Handler\n */\n \n-PipelineHandlerISI::PipelineHandlerISI(CameraManager *manager)\n+PipelineHandlerISI::PipelineHandlerISI(std::shared_ptr<CamerasList> manager)\n \t: PipelineHandler(manager)\n {\n }\ndiff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\nindex 355cb0cb..b789ccc0 100644\n--- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n@@ -132,7 +132,7 @@ public:\n \t\tIPU3PipeModeStillCapture = 1,\n \t};\n \n-\tPipelineHandlerIPU3(CameraManager *manager);\n+\tPipelineHandlerIPU3(std::shared_ptr<CamerasList> manager);\n \n \tstd::unique_ptr<CameraConfiguration> generateConfiguration(Camera *camera,\n \t\tconst StreamRoles &roles) override;\n@@ -384,7 +384,7 @@ CameraConfiguration::Status IPU3CameraConfiguration::validate()\n \treturn status;\n }\n \n-PipelineHandlerIPU3::PipelineHandlerIPU3(CameraManager *manager)\n+PipelineHandlerIPU3::PipelineHandlerIPU3(std::shared_ptr<CamerasList> manager)\n \t: PipelineHandler(manager), cio2MediaDev_(nullptr), imguMediaDev_(nullptr)\n {\n }\ndiff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp\nindex 00600441..4ddea305 100644\n--- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp\n+++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp\n@@ -364,7 +364,7 @@ private:\n class PipelineHandlerRPi : public PipelineHandler\n {\n public:\n-\tPipelineHandlerRPi(CameraManager *manager);\n+\tPipelineHandlerRPi(std::shared_ptr<CamerasList> manager);\n \n \tstd::unique_ptr<CameraConfiguration> generateConfiguration(Camera *camera,\n \t\tconst StreamRoles &roles) override;\n@@ -661,7 +661,7 @@ CameraConfiguration::Status RPiCameraConfiguration::validate()\n \treturn status;\n }\n \n-PipelineHandlerRPi::PipelineHandlerRPi(CameraManager *manager)\n+PipelineHandlerRPi::PipelineHandlerRPi(std::shared_ptr<CamerasList> manager)\n \t: PipelineHandler(manager)\n {\n }\ndiff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\nindex 8a30fe06..ef6d92b2 100644\n--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n@@ -145,7 +145,7 @@ private:\n class PipelineHandlerRkISP1 : public PipelineHandler\n {\n public:\n-\tPipelineHandlerRkISP1(CameraManager *manager);\n+\tPipelineHandlerRkISP1(std::shared_ptr<CamerasList> manager);\n \n \tstd::unique_ptr<CameraConfiguration> generateConfiguration(Camera *camera,\n \t\tconst StreamRoles &roles) override;\n@@ -602,7 +602,7 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()\n * Pipeline Operations\n */\n \n-PipelineHandlerRkISP1::PipelineHandlerRkISP1(CameraManager *manager)\n+PipelineHandlerRkISP1::PipelineHandlerRkISP1(std::shared_ptr<CamerasList> manager)\n \t: PipelineHandler(manager), hasSelfPath_(true)\n {\n }\ndiff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp\nindex 2423ec10..a6e4cfca 100644\n--- a/src/libcamera/pipeline/simple/simple.cpp\n+++ b/src/libcamera/pipeline/simple/simple.cpp\n@@ -309,7 +309,7 @@ private:\n class SimplePipelineHandler : public PipelineHandler\n {\n public:\n-\tSimplePipelineHandler(CameraManager *manager);\n+\tSimplePipelineHandler(std::shared_ptr<CamerasList> manager);\n \n \tstd::unique_ptr<CameraConfiguration> generateConfiguration(Camera *camera,\n \t\tconst StreamRoles &roles) override;\n@@ -1032,7 +1032,7 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate()\n * Pipeline Handler\n */\n \n-SimplePipelineHandler::SimplePipelineHandler(CameraManager *manager)\n+SimplePipelineHandler::SimplePipelineHandler(std::shared_ptr<CamerasList> manager)\n \t: PipelineHandler(manager), converter_(nullptr)\n {\n }\ndiff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\nindex 277465b7..1dad59d7 100644\n--- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n+++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n@@ -72,7 +72,7 @@ private:\n class PipelineHandlerUVC : public PipelineHandler\n {\n public:\n-\tPipelineHandlerUVC(CameraManager *manager);\n+\tPipelineHandlerUVC(std::shared_ptr<CamerasList> manager);\n \n \tstd::unique_ptr<CameraConfiguration> generateConfiguration(Camera *camera,\n \t\tconst StreamRoles &roles) override;\n@@ -173,7 +173,7 @@ CameraConfiguration::Status UVCCameraConfiguration::validate()\n \treturn status;\n }\n \n-PipelineHandlerUVC::PipelineHandlerUVC(CameraManager *manager)\n+PipelineHandlerUVC::PipelineHandlerUVC(std::shared_ptr<CamerasList> manager)\n \t: PipelineHandler(manager)\n {\n }\ndiff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp\nindex 204f5ad7..e4c34586 100644\n--- a/src/libcamera/pipeline/vimc/vimc.cpp\n+++ b/src/libcamera/pipeline/vimc/vimc.cpp\n@@ -82,7 +82,7 @@ private:\n class PipelineHandlerVimc : public PipelineHandler\n {\n public:\n-\tPipelineHandlerVimc(CameraManager *manager);\n+\tPipelineHandlerVimc(std::shared_ptr<CamerasList> manager);\n \n \tstd::unique_ptr<CameraConfiguration> generateConfiguration(Camera *camera,\n \t\tconst StreamRoles &roles) override;\n@@ -184,7 +184,7 @@ CameraConfiguration::Status VimcCameraConfiguration::validate()\n \treturn status;\n }\n \n-PipelineHandlerVimc::PipelineHandlerVimc(CameraManager *manager)\n+PipelineHandlerVimc::PipelineHandlerVimc(std::shared_ptr<CamerasList> manager)\n \t: PipelineHandler(manager)\n {\n }\ndiff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\nindex f72613b8..07ab284a 100644\n--- a/src/libcamera/pipeline_handler.cpp\n+++ b/src/libcamera/pipeline_handler.cpp\n@@ -20,6 +20,7 @@\n #include <libcamera/framebuffer.h>\n \n #include \"libcamera/internal/camera.h\"\n+#include \"libcamera/internal/camera_manager.h\"\n #include \"libcamera/internal/device_enumerator.h\"\n #include \"libcamera/internal/framebuffer.h\"\n #include \"libcamera/internal/media_device.h\"\n@@ -67,7 +68,7 @@ LOG_DEFINE_CATEGORY(Pipeline)\n * PipelineHandler instances shall never be constructed manually, but always\n * through the PipelineHandlerFactoryBase::create() function.\n */\n-PipelineHandler::PipelineHandler(CameraManager *manager)\n+PipelineHandler::PipelineHandler(std::shared_ptr<CamerasList> manager)\n \t: manager_(manager), useCount_(0)\n {\n }\n@@ -691,7 +692,7 @@ void PipelineHandler::disconnect()\n \t\t\tcontinue;\n \n \t\tcamera->disconnect();\n-\t\tmanager_->removeCamera(camera);\n+\t\tmanager_->removeCamera(camera.get());\n \t}\n }\n \n@@ -743,7 +744,7 @@ PipelineHandlerFactoryBase::PipelineHandlerFactoryBase(const char *name)\n * \\return A shared pointer to a new instance of the PipelineHandler subclass\n * corresponding to the factory\n */\n-std::shared_ptr<PipelineHandler> PipelineHandlerFactoryBase::create(CameraManager *manager) const\n+std::shared_ptr<PipelineHandler> PipelineHandlerFactoryBase::create(std::shared_ptr<CamerasList> manager) const\n {\n \tstd::unique_ptr<PipelineHandler> handler = createInstance(manager);\n \thandler->name_ = name_.c_str();\n", "prefixes": [ "libcamera-devel" ] }