[libcamera-devel] [PATCH 4/4] libcamera: camera: Handle camera objects through shared pointers
Ricky Liang
jcliang at chromium.org
Tue Jan 22 04:19:01 CET 2019
Hi Laurent,
On Sat, Jan 19, 2019 at 6:51 AM Laurent Pinchart
<laurent.pinchart at ideasonboard.com> wrote:
>
> Hi Ricky,
>
> On Sat, Jan 19, 2019 at 01:39:35AM +0800, Ricky Liang wrote:
> > On Fri, Jan 18, 2019 at 7:59 AM Laurent Pinchart
> > <laurent.pinchart at ideasonboard.com> wrote:
> > >
> > > The Camera class is explicitly reference-counted to manage the lifetime
> > > of camera objects. Replace this open-coded implementation with usage of
> > > the std::shared_ptr<> class.
> > >
> > > Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> > > ---
> > > include/libcamera/camera.h | 13 +++++----
> > > include/libcamera/camera_manager.h | 8 +++---
> > > src/libcamera/camera.cpp | 46 +++++++++++++++++-------------
> > > src/libcamera/camera_manager.cpp | 20 ++++++-------
> > > src/libcamera/pipeline/vimc.cpp | 2 +-
> > > test/list-cameras.cpp | 2 +-
> > > 6 files changed, 50 insertions(+), 41 deletions(-)
> > >
> > > diff --git a/include/libcamera/camera.h b/include/libcamera/camera.h
> > > index 9a7579d61fa3..ef0a794e3a82 100644
> > > --- a/include/libcamera/camera.h
> > > +++ b/include/libcamera/camera.h
> > > @@ -7,6 +7,7 @@
> > > #ifndef __LIBCAMERA_CAMERA_H__
> > > #define __LIBCAMERA_CAMERA_H__
> > >
> > > +#include <memory>
> > > #include <string>
> > >
> > > namespace libcamera {
> > > @@ -14,15 +15,17 @@ namespace libcamera {
> > > class Camera
> > > {
> > > public:
> > > - Camera(const std::string &name);
> > > + static std::shared_ptr<Camera> create(const std::string &name);
> > > +
> > > + Camera(const Camera &) = delete;
> > > + void operator=(const Camera &) = delete;
> >
> > We probably want to delete the implicit constructor as well:
> >
> > Camera() = delete;
>
> The compiler only creates an implicit constructor when no explicit
> constructor is specified. As we define Camera(const std::string &name),
> there's no need to delete the implicit constructor.
Ack.
>
> > >
> > > const std::string &name() const;
> > > - void get();
> > > - void put();
> > >
> > > private:
> > > - virtual ~Camera() { };
> > > - int ref_;
> > > + Camera(const std::string &name);
> >
> > Can we add the 'explicit' specifier for constructor with only one
> > argument? Not super important for this patch as it's a private
> > constructor here, but may be a good general guideline.
>
> Good point, I'll do that.
>
> > > + ~Camera();
> > > +
> > > std::string name_;
> > > };
> > >
> > > diff --git a/include/libcamera/camera_manager.h b/include/libcamera/camera_manager.h
> > > index 4b941fd9183b..738b13f4cfb1 100644
> > > --- a/include/libcamera/camera_manager.h
> > > +++ b/include/libcamera/camera_manager.h
> > > @@ -24,10 +24,10 @@ public:
> > > int start();
> > > void stop();
> > >
> > > - const std::vector<Camera *> &cameras() const { return cameras_; }
> > > - Camera *get(const std::string &name);
> > > + const std::vector<std::shared_ptr<Camera>> &cameras() const { return cameras_; }
> > > + std::shared_ptr<Camera> get(const std::string &name);
> >
> > Some high level design questions:
> >
> > 1. Who are the callers of these getter methods?
>
> These methods are meant to be called by applications. I expect the API
> to change as we continue developing though, but the general idea will
> stay the same.
>
> > 2. What's the threading model that we plan to use for exercising the
> > Camera objects?
>
> We don't support multiple threads yet. This will be fixed down the road,
> but not all details have been decided yet.
>
> > While making Camera objects as shared pointers makes the coding
> > easier, it may also be hard to track the ownership of the objects once
> > the code base gets large. In some cases it may lead to memory/fd leaks
> > that are hard to debug, e.g. a singleton object holding a shared
> > pointer reference to an object and never releases the reference.
> >
> > I tend to agree that fundamental objects like Camera has the necessity
> > to be shared pointers, but would also like to know if it's possible to
> > design the threading model such that CameraManager is the main owner
> > of the Camera objects. For example, if we can design it such that all
> > the access to Camera objects is serialized on a thread,
>
> I think they will, possibly with the exception of request queuing and
> request completion handling. This remains to be decided. In any case, I
> don't think we should support camera lookup from multiple threads.
>
> > then we probably don't need to use shared pointers. Or, we can achieve
> > concurrency by storing Camera objects as std::shared_ptr in
> > CameraManager and only giving out std::weak_ptr of the Camera objects.
>
> It's not just a concurrency issue. Support for hot-pluggable cameras
> will be added in the future, and we'll need to track users of camera
> objects in order to delete the camera only when no users are left. This
> doesn't require std::shared_ptr<>, a manual reference count would work
> too (and it exists today, this patch is replacing it), but I think it's
> better to use std::shared_ptr<> rather than reinventing (and
> open-coding) the wheel.
I'd imagine in the hot-pluggable camera case, the action of actually
removing the camera (e.g. un-plugging the USB camera) would make the
camera no longer usable and what we need would be to handle the
exception gracefully.
Or, do you mean hot-pluggable in the software sense, like the
bind/unbind in kernel drivers? Most of the camera devices allow only
one active user at a time. Do we plan to design the APIs to allow
concurrent access to a camera?
>
> Giving out weak pointers would I think cause more issues than it would
> solve, as any user of a camera instance would need to be prepared for
> the pointer becoming null at any time when the camera is unplugged.
Ack.
>
> > > - void addCamera(Camera *camera);
> > > + void addCamera(std::shared_ptr<Camera> &camera);
> >
> > We can pass by value here so that we provide the caller with the
> > freedom to pass its own shared ownership to the callee through
> > std::move().
>
> In the typical use case the caller will likely retain a shared pointer
> to the camera. I can pass by value and use std::move() in the
> addCamera() function.
>
> > >
> > > static CameraManager *instance();
> > >
> > > @@ -42,7 +42,7 @@ private:
> > >
> > > std::unique_ptr<DeviceEnumerator> enumerator_;
> > > std::vector<PipelineHandler *> pipes_;
> > > - std::vector<Camera *> cameras_;
> > > + std::vector<std::shared_ptr<Camera>> cameras_;
> >
> > If the camera name is required to be unique then perhaps we can store
> > the cameras as
> >
> > std::unordered_map<std::string, std::shared_ptr<Camera>> cameras_;
>
> We used to store them in a std::map<>, but it make it cumbersome to
> retrieve the list of all cameras. As I expect the camera lookup API to
> change anyway I think we can revisit this later.
Ack.
>
> > >
> > > std::unique_ptr<EventDispatcher> dispatcher_;
> > > };
>
> --
> Regards,
>
> Laurent Pinchart
More information about the libcamera-devel
mailing list