diff options
-rw-r--r-- | include/libcamera/internal/message.h | 1 | ||||
-rw-r--r-- | include/libcamera/object.h | 2 | ||||
-rw-r--r-- | src/libcamera/message.cpp | 2 | ||||
-rw-r--r-- | src/libcamera/object.cpp | 48 |
4 files changed, 53 insertions, 0 deletions
diff --git a/include/libcamera/internal/message.h b/include/libcamera/internal/message.h index 92ea64a5..f1b133bf 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, UserMessage = 1000, }; diff --git a/include/libcamera/object.h b/include/libcamera/object.h index 9a3dd070..a1882f05 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/message.cpp b/src/libcamera/message.cpp index e9b3e73f..bc985c07 100644 --- a/src/libcamera/message.cpp +++ b/src/libcamera/message.cpp @@ -49,6 +49,8 @@ std::atomic_uint Message::nextUserType_{ Message::UserMessage }; * \brief Asynchronous method invocation across threads * \var Message::ThreadMoveMessage * \brief Object is being moved to a different thread + * \var Message::DeferredDelete + * \brief Object is scheduled for deletion * \var Message::UserMessage * \brief First value available for user-defined messages */ diff --git a/src/libcamera/object.cpp b/src/libcamera/object.cpp index 1544a23e..647ccda7 100644 --- a/src/libcamera/object.cpp +++ b/src/libcamera/object.cpp @@ -73,6 +73,10 @@ Object::Object(Object *parent) * Deleting an Object automatically disconnects all signals from the Object's * slots. All the Object's children are made orphan, but stay bound to their * current thread. + * + * 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. */ Object::~Object() { @@ -99,6 +103,46 @@ Object::~Object() } /** + * \brief Schedule deletion of the instance in the thread it belongs to + * + * 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. + * + * 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<MyObject> 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 + * + * \context This function is \threadsafe. + */ +void Object::deleteLater() +{ + postMessage(std::make_unique<Message>(Message::DeferredDelete)); +} + +/** * \brief Post a message to the object's thread * \param[in] msg The message * @@ -144,6 +188,10 @@ void Object::message(Message *msg) break; } + case Message::DeferredDelete: + delete this; + break; + default: break; } |