<div dir="ltr">Hi all,<br><br>On Tue, 23 Jan 2024 at 14:43, Laurent Pinchart <<a href="mailto:laurent.pinchart@ideasonboard.com">laurent.pinchart@ideasonboard.com</a>> wrote:<br>><br>> On Tue, Jan 23, 2024 at 03:34:53PM +0200, Laurent Pinchart wrote:<br>> > On Sat, Jan 13, 2024 at 10:45:14PM +0000, -dev wrote:<br>> > > Quoting Hans de Goede via libcamera-devel (2024-01-13 14:22:05)<br>> > > > From: Dennis Bonke <<a href="mailto:admin@dennisbonke.com">admin@dennisbonke.com</a>><br>> > > ><br>> > > > Document the SharedMemObject class.<br>> > > ><br>> > > > Signed-off-by: Dennis Bonke <<a href="mailto:admin@dennisbonke.com">admin@dennisbonke.com</a>><br>> > > > Signed-off-by: Hans de Goede <<a href="mailto:hdegoede@redhat.com">hdegoede@redhat.com</a>><br>> > > > Tested-by: Bryan O'Donoghue <<a href="mailto:bryan.odonoghue@linaro.org">bryan.odonoghue@linaro.org</a>> # sc8280xp Lenovo x13s<br>> > > > Tested-by: Pavel Machek <<a href="mailto:pavel@ucw.cz">pavel@ucw.cz</a>><br>> > > > ---<br>> > > >  .../libcamera/internal/shared_mem_object.h    | 53 +++++++++++++++++++<br>> > > >  1 file changed, 53 insertions(+)<br>> > > ><br>> > > > diff --git a/include/libcamera/internal/shared_mem_object.h b/include/libcamera/internal/shared_mem_object.h<br>> > > > index bfb639ee..e862ce48 100644<br>> > > > --- a/include/libcamera/internal/shared_mem_object.h<br>> > > > +++ b/include/libcamera/internal/shared_mem_object.h<br>> > > > @@ -19,10 +19,20 @@<br>> > > > <br>> > > >  namespace libcamera {<br>> > > > <br>> > > > +/**<br>> > > > + * \class SharedMemObject<br>> > > > + * \brief Helper class for shared memory allocations.<br>> > > > + *<br>> > > > + * Takes a template T which is used to indicate the<br>> > > > + * data type of the object stored.<br>> > ><br>> > > I'd wrap this to the usual 80 chars. Not critical though.<br>> ><br>> > Not critical, but no reason not to do so :-)<br>> ><br>> > > It might be nice to explain here what the class is doing, as the code<br>> > > may not be visible to the reader.<br>> > ><br>> > > The only part I'd add is perhaps something like:<br>> > ><br>> > > """<br>> > > Memory is allocated and exposed as a SharedFD for use across IPC<br>> > > boundaries.<br>> > > """<br>> ><br>> > I would like more documentation too, with an explanation of how this is<br>> > supposed to be used.<br>> ><br>> > > But either way,<br>> > ><br>> > > Reviewed-by: Kieran Bingham <<a href="mailto:kieran.bingham@ideasonboard.com">kieran.bingham@ideasonboard.com</a>><br>> ><br>> > Documentation goes to .cpp files. The documentation should also come in<br>> > the same patch as the one that adds the class.<br>><br>> Just to be clear, as there's no .cpp file yet, I think most of the<br>> SharedMemObject constructor should go to a separate init(size_t size)<br>> function moved to a .cpp file, as it doesn't otherwise depend on the<br>> type T or arguments Args.<br>><br>><br>> The way we create a single memfd for every SharedMemObject isn't very<br>> nice, as it could cause lots of fd allocations if callers are not aware<br>> that they should create a single large object instead. This should be at<br>> the very least clearly explained in the documentation. Ideally the<br>> class should be refactored to make it possible to allocate multiple<br>> objects within a single shared memory segment, but that's out of scope<br>> for this series.<br>><br>> As for squashing documentation with the patch that introduces the class,<br>> I hadn't realized that the class had simply be moved from the rpi code.<br>> I'm OK keeping the two patches separate.<br><br><br>Admittedly I've not been following this series, so apologies if I get some of the details below wrong.<br><br>The RPi Pi implementation of SharedMemObject is exactly what we want as per Laurent's description above, i.e. a single FD per object instance allocated and constructed through "placement new".  This is why the SharedMemObject constructor takes the var-args list for the wrapped object constructor.  There are only ever 2 SharedMemObject instances (backend and frontend) at runtime shared between the IPA and pipeline handler.<br><br>I agree with Laurent that this same mechanism may not be entirely appropriate if there are a large number of objects being allocated in shared memory, resulting in a large number of FDs.  In such cases, perhaps SharedMemObject() is not the right tool, and the underlying memfd allocations may need to be wrapped differently.  Or maybe SharedMemObject can be used as-is, but the object it allocates is a superset of many smaller sub-objects...?<br><br>Regards,<br>Naush<br><br>><br>> > > > + */<br>> > > >  template<class T><br>> > > >  class SharedMemObject<br>> > > >  {<br>> > > >  public:<br>> > > > +       /**<br>> > > > +        * \brief The size of the object that is going to be stored here.<br>> > > > +        */<br>> > > >         static constexpr std::size_t SIZE = sizeof(T);<br>><br>> We don't use all uppercase constants. You can name this kSize or size.<br>><br>> > > > <br>> > > >         SharedMemObject()<br>> > > > @@ -30,6 +40,11 @@ public:<br>> > > >         {<br>> > > >         }<br>> > > > <br>> > > > +       /**<br>> > > > +        * \brief Contstructor for the SharedMemObject.<br>> > > > +        * \param[in] name The requested name.<br>> > > > +        * \param[in] args Any additional args.<br>> > > > +        */<br>><br>> You need to expand the documentation. Consider the point of view of a<br>> reader who hasn't seen the code. They can't tell from the documentation<br>> what the name and args are for.<br>><br>> Also, I'd like unit tests.<br>><br>> > > >         template<class... Args><br>> > > >         SharedMemObject(const std::string &name, Args &&...args)<br>> > > >                 : name_(name), obj_(nullptr)<br>> > > > @@ -57,6 +72,10 @@ public:<br>> > > >                 obj_ = new (mem) T(std::forward<Args>(args)...);<br>> > > >         }<br>> > > > <br>> > > > +       /**<br>> > > > +        * \brief Move constructor for SharedMemObject.<br>> > > > +        * \param[in] rhs The object to move.<br>> > > > +        */<br>> > > >         SharedMemObject(SharedMemObject<T> &&rhs)<br>> > > >         {<br>> > > >                 this->name_ = std::move(rhs.name_);<br>> > > > @@ -76,6 +95,10 @@ public:<br>> > > >         /* Make SharedMemObject non-copyable for now. */<br>> > > >         LIBCAMERA_DISABLE_COPY(SharedMemObject)<br>> > > > <br>> > > > +       /**<br>> > > > +        * \brief Operator= for SharedMemObject.<br>> > > > +        * \param[in] rhs The SharedMemObject object to take the data from.<br>> > > > +        */<br>> > > >         SharedMemObject<T> &operator=(SharedMemObject<T> &&rhs)<br>> > > >         {<br>> > > >                 this->name_ = std::move(rhs.name_);<br>> > > > @@ -85,31 +108,61 @@ public:<br>> > > >                 return *this;<br>> > > >         }<br>> > > > <br>> > > > +       /**<br>> > > > +        * \brief Operator-> for SharedMemObject.<br>> > > > +        *<br>> > > > +        * \return the object.<br>> > > > +        */<br>> > > >         T *operator->()<br>> > > >         {<br>> > > >                 return obj_;<br>> > > >         }<br>> > > > <br>> > > > +       /**<br>> > > > +        * \brief Operator-> for SharedMemObject.<br>> > > > +        *<br>> > > > +        * \return the object.<br>> > > > +        */<br>> > > >         const T *operator->() const<br>> > > >         {<br>> > > >                 return obj_;<br>> > > >         }<br>> > > > <br>> > > > +       /**<br>> > > > +        * \brief Operator* for SharedMemObject.<br>> > > > +        *<br>> > > > +        * \return the object.<br>> > > > +        */<br>> > > >         T &operator*()<br>> > > >         {<br>> > > >                 return *obj_;<br>> > > >         }<br>> > > > <br>> > > > +       /**<br>> > > > +        * \brief Operator* for SharedMemObject.<br>> > > > +        *<br>> > > > +        * \return the object.<br>> > > > +        */<br>> > > >         const T &operator*() const<br>> > > >         {<br>> > > >                 return *obj_;<br>> > > >         }<br>> > > > <br>> > > > +       /**<br>> > > > +        * \brief Gets the file descriptor for the underlaying storage file.<br>> > > > +        *<br>> > > > +        * \return the file descriptor.<br>> > > > +        */<br>> > > >         const SharedFD &fd() const<br>> > > >         {<br>> > > >                 return fd_;<br>> > > >         }<br>> > > > <br>> > > > +       /**<br>> > > > +        * \brief Operator bool() for SharedMemObject.<br>> > > > +        *<br>> > > > +        * \return true if the object is not null, false otherwise.<br>> > > > +        */<br>> > > >         explicit operator bool() const<br>> > > >         {<br>> > > >                 return !!obj_;<br>><br>> --<br>> Regards,<br>><br>> Laurent Pinchart</div>