[libcamera-devel] [PATCH 1/2] libcamera: object: Add deleteLater() support
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Tue Jul 28 17:24:01 CEST 2020
Hi Umang,
Thank you for the patch.
On Tue, Jul 28, 2020 at 10:57:24AM +0000, Umang Jain wrote:
> This commit adds support to schedule the deletion of an Object to the
> thread it is bound to (similar to [1]). An Object getting destroyed
> by a different thread, is considered as a violation as per the
s/thread,/thread/
> threading model.
s/threading model/libcamera threading model/
> This will be useful for an Object where its ownership is shared via
> shared pointers in different threads. If the thread which drops the
> last reference of the Object is a different thread, the destructors
> get called in that particular thread, not the one Object is bound to.
> Hence, in order to resolve this kind of situation, the creation of
> shared pointer can be accompanied by a custom deleter which in turns
> use deleteLater() to ensure the Object is destroyed in its own thread.
>
> [1] https://doc.qt.io/qt-5/qobject.html#deleteLater
>
> Signed-off-by: Umang Jain <email at uajain.com>
> ---
> include/libcamera/internal/message.h | 1 +
> include/libcamera/object.h | 2 ++
> src/libcamera/object.cpp | 20 ++++++++++++++++++++
> 3 files changed, 23 insertions(+)
>
> diff --git a/include/libcamera/internal/message.h b/include/libcamera/internal/message.h
> index 92ea64a..f1b133b 100644
> --- a/include/libcamera/internal/message.h
> +++ b/include/libcamera/internal/message.h
> @@ -25,6 +25,7 @@ public:
> None = 0,
> InvokeMessage = 1,
> ThreadMoveMessage = 2,
> + DeferredDelete = 3,
This needs to be documented in message.cpp. Just "Object is scheduled
for deletion" should be enough.
> UserMessage = 1000,
> };
>
> diff --git a/include/libcamera/object.h b/include/libcamera/object.h
> index 9a3dd07..a1882f0 100644
> --- a/include/libcamera/object.h
> +++ b/include/libcamera/object.h
> @@ -27,6 +27,8 @@ public:
> Object(Object *parent = nullptr);
> virtual ~Object();
>
> + void deleteLater();
> +
> void postMessage(std::unique_ptr<Message> msg);
>
> template<typename T, typename R, typename... FuncArgs, typename... Args,
> diff --git a/src/libcamera/object.cpp b/src/libcamera/object.cpp
> index 1544a23..93e683a 100644
> --- a/src/libcamera/object.cpp
> +++ b/src/libcamera/object.cpp
> @@ -98,6 +98,22 @@ Object::~Object()
> child->parent_ = nullptr;
> }
>
> +/**
> + * \brief Defer the deletion of Object instance to their thread
Being a bit pendantic, the function doesn't defer the deletion of the
object (as there's no pending deletion before it's called), but
schedules a deferred deletion. Maybe "Schedule deletion of the instance
in the thread it belongs to" ?
> + *
> + * Schedule deletion of the Object in the thread to which they are bound.
> + * This will prevent destroying the Object from a different thread, which is
> + * not allowed by the threading model.
I think we should mention the event loop here to give a bit more
information about when the object will be deleted exactly. Maybe
* This function schedules deletion of the Object when control returns to the
* event loop that the object belongs to. This ensures the object is destroyed
* from the right context, as required by the libcamera threading model.
*
* If this function is called before the thread's event loop is started, the
* object will be deleted when the event loop starts.
I think we also have an issue if the object belongs to a thread that
doesn't have an event loop. We can fix that later, just adding
* \todo Handle scheduled deletion when the thread doesn't have an event loop
for now.
> + *
> + * It will typically be used with a custom deleter when creating a shared
> + * pointer. It can then be ensured that the Object is deleted in its
> + * own thread even if its last reference is dropped in a different thread.
Even though this is our first use case, I'm not sure it would be the
most typical one. Maybe we can mention it as just an example instead ?
* Deferred deletion can be used to control the destruction context with shared
* pointers. An object managed with shared pointers is deleted when the last
* reference is destroyed, which makes difficult to ensure through software
* design which context the deletion will take place in. With a custom deleter
* for the shared pointer using deleteLater(), the deletion can be guaranteed to
* happen in the thread the object is bound to.
*
* \code{.cpp}
* std::shared_ptr<MyObjet> createObject()
* {
* struct Deleter : std::default_delete<MyObject> {
* void operator()(MyObject *obj)
* {
* delete obj;
* }
* };
*
* MyObject *obj = new MyObject();
*
* return std::shared_ptr<MyObject>(obj, Deleter());
* }
* \endcode
And you should add
* \context This function is \threadsafe.
> + */
While at it, should we add
* Object instances shall be destroyed from the thread they are bound to,
* otherwise undefined behaviour may occur. If deletion of an Object needs to
* be scheduled from a different thread, deleteLater() shall be used.
to the Object::~Object() documentation ?
> +void Object::deleteLater()
> +{
> + postMessage(std::make_unique<Message>(Message::DeferredDelete));
> +}
> +
> /**
> * \brief Post a message to the object's thread
> * \param[in] msg The message
> @@ -143,6 +159,10 @@ void Object::message(Message *msg)
>
> break;
> }
A blank line here would be nice.
> + case Message::DeferredDelete: {
> + delete this;
> + break;
> + }
No need for the curly braces.
Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
>
> default:
> break;
--
Regards,
Laurent Pinchart
More information about the libcamera-devel
mailing list