[{"id":5108,"web_url":"https://patchwork.libcamera.org/comment/5108/","msgid":"<20200607164124.GC22208@pendragon.ideasonboard.com>","date":"2020-06-07T16:41:24","subject":"Re: [libcamera-devel] [PATCH v3 3/5] libcamera: camera_manager:\n\tIntroduce signals when a camera is added/removed","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Umang,\n\nThank you for the patch.\n\nOn Thu, May 21, 2020 at 01:54:25PM +0000, Umang Jain wrote:\n> Emit 'newCameraAdded' and 'cameraRemoved' from CameraManager to enable\n> hotplug and hot-unplug support in appplication like QCam.\n> \n> To avoid use-after-free race between the CameraManager and the\n> application, emit the 'cameraRemoved' with the shared_ptr version\n> of <Camera *>. This requires to change the function signature of\n> CameraManager::removeCamera() API.\n> \n> Signed-off-by: Umang Jain <email@uajain.com>\n> ---\n>  include/libcamera/camera_manager.h |  6 ++++-\n>  src/libcamera/camera_manager.cpp   | 36 +++++++++++++++++++++++++++---\n>  src/libcamera/pipeline_handler.cpp |  2 +-\n>  3 files changed, 39 insertions(+), 5 deletions(-)\n> \n> diff --git a/include/libcamera/camera_manager.h b/include/libcamera/camera_manager.h\n> index 079f848..365e286 100644\n> --- a/include/libcamera/camera_manager.h\n> +++ b/include/libcamera/camera_manager.h\n> @@ -13,6 +13,7 @@\n>  #include <vector>\n>  \n>  #include <libcamera/object.h>\n> +#include <libcamera/signal.h>\n>  \n>  namespace libcamera {\n>  \n> @@ -35,13 +36,16 @@ public:\n>  \tstd::shared_ptr<Camera> get(dev_t devnum);\n>  \n>  \tvoid addCamera(std::shared_ptr<Camera> camera, dev_t devnum);\n> -\tvoid removeCamera(Camera *camera);\n> +\tvoid removeCamera(std::shared_ptr<Camera> camera);\n\nThis may not be strictly required, as we could use\ncamera->shared_from_this() in removeCamera(), but I think it's cleaner\nto pass the shared_ptr.\n\n>  \n>  \tstatic const std::string &version() { return version_; }\n>  \n>  \tvoid setEventDispatcher(std::unique_ptr<EventDispatcher> dispatcher);\n>  \tEventDispatcher *eventDispatcher();\n>  \n> +\tSignal<std::shared_ptr<Camera>> newCameraAdded;\n\nFor symmetry, should this be called cameraAdded ?\n\n> +\tSignal<std::shared_ptr<Camera>> cameraRemoved;\n> +\n>  private:\n>  \tstatic const std::string version_;\n>  \tstatic CameraManager *self_;\n> diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp\n> index 27064d2..bdd78f5 100644\n> --- a/src/libcamera/camera_manager.cpp\n> +++ b/src/libcamera/camera_manager.cpp\n> @@ -185,7 +185,7 @@ void CameraManager::Private::addCamera(std::shared_ptr<Camera> &camera,\n>  \t\t}\n>  \t}\n>  \n> -\tcameras_.push_back(std::move(camera));\n> +\tcameras_.push_back(camera);\n\nCould we keep the std::move here, and turn the &camera argument into\ncamera ? Passing a non-const reference and having the caller rely on\nthis function not modifying the reference is a bit fragile. If we pass a\ncopy of the shared_ptr to the function, it's clear from the caller point\nof view that the pointer within the caller will still be valid after\nthis function returns.\n\nWith those two small issues addressed,\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\n>  \n>  \tif (devnum) {\n>  \t\tunsigned int index = cameras_.size() - 1;\n> @@ -375,6 +375,34 @@ std::shared_ptr<Camera> CameraManager::get(dev_t devnum)\n>  \treturn iter->second.lock();\n>  }\n>  \n> +/**\n> + * \\var CameraManager::newCameraAdded\n> + * \\brief Notify of a new camera added to the system\n> + *\n> + * This signal is emitted when a new camera is detected and successfully handled\n> + * by the camera manager. The notification occurs alike for cameras detected\n> + * when the manager is started with start() or when new cameras are later\n> + * connected to the system. When the signal is emitted the new camera is already\n> + * available from the list of cameras().\n> + *\n> + * The signal is emitted from the CameraManager thread. Applications shall\n> + * minimize the time spent in the signal handler and shall in particular not\n> + * perform any blocking operation.\n> + */\n> +\n> +/**\n> + * \\var CameraManager::cameraRemoved\n> + * \\brief Notify of a new camera removed from the system\n> + *\n> + * This signal is emitted when a camera is removed from the system. When the\n> + * signal is emitted the camera is not available from the list of cameras()\n> + * anymore.\n> + *\n> + * The signal is emitted from the CameraManager thread. Applications shall\n> + * minimize the time spent in the signal handler and shall in particular not\n> + * perform any blocking operation.\n> + */\n> +\n>  /**\n>   * \\brief Add a camera to the camera manager\n>   * \\param[in] camera The camera to be added\n> @@ -394,6 +422,7 @@ void CameraManager::addCamera(std::shared_ptr<Camera> camera, dev_t devnum)\n>  \tASSERT(Thread::current() == p_.get());\n>  \n>  \tp_->addCamera(camera, devnum);\n> +\tnewCameraAdded.emit(camera);\n>  }\n>  \n>  /**\n> @@ -406,11 +435,12 @@ void CameraManager::addCamera(std::shared_ptr<Camera> camera, dev_t devnum)\n>   *\n>   * \\context This function shall be called from the CameraManager thread.\n>   */\n> -void CameraManager::removeCamera(Camera *camera)\n> +void CameraManager::removeCamera(std::shared_ptr<Camera> camera)\n>  {\n>  \tASSERT(Thread::current() == p_.get());\n>  \n> -\tp_->removeCamera(camera);\n> +\tp_->removeCamera(camera.get());\n> +\tcameraRemoved.emit(camera);\n>  }\n>  \n>  /**\n> diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\n> index 53aeebd..9a1e6ff 100644\n> --- a/src/libcamera/pipeline_handler.cpp\n> +++ b/src/libcamera/pipeline_handler.cpp\n> @@ -555,7 +555,7 @@ void PipelineHandler::disconnect()\n>  \t\t\tcontinue;\n>  \n>  \t\tcamera->disconnect();\n> -\t\tmanager_->removeCamera(camera.get());\n> +\t\tmanager_->removeCamera(camera);\n>  \t}\n>  \n>  \tcameras_.clear();","headers":{"Return-Path":"<laurent.pinchart@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 02FF6600F7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun,  7 Jun 2020 18:41:44 +0200 (CEST)","from pendragon.ideasonboard.com (81-175-216-236.bb.dnainternet.fi\n\t[81.175.216.236])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 7FADB2C9;\n\tSun,  7 Jun 2020 18:41:43 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"BKlg+GEe\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1591548103;\n\tbh=0uUe6+OEeqy2PgkmjSQcos0+fSJLAhZahLvgMTrmJ4M=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=BKlg+GEedsmwKcJRAtw5KHPlsS31x11i+aJW6oHVDbzwSl8S5RxUWIvx+8DW9ThQk\n\tlSy4vHEQpI4XTHcYgnp1cPA5JO7XCTUVMipIHX7MTg4ObWrHOXMAqB+IJ1vSGIYrop\n\tisoo9lYsVOlYDOn+PICCUdjmfGOwq3Wu4SZT8ft4=","Date":"Sun, 7 Jun 2020 19:41:24 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Umang Jain <email@uajain.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20200607164124.GC22208@pendragon.ideasonboard.com>","References":"<20200521135416.13685-1-email@uajain.com>\n\t<20200521135416.13685-4-email@uajain.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20200521135416.13685-4-email@uajain.com>","Subject":"Re: [libcamera-devel] [PATCH v3 3/5] libcamera: camera_manager:\n\tIntroduce signals when a camera is added/removed","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>","X-List-Received-Date":"Sun, 07 Jun 2020 16:41:44 -0000"}}]