diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2019-08-12 14:19:06 +0300 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2019-08-17 18:47:17 +0300 |
commit | 2b25819ec07e8de0b4be658c7d46f6c1c495766d (patch) | |
tree | 984c9c1785413b75bbe4825eca2895c6848f09e0 | |
parent | 4d9f1a0efc038e12b5cfdb53cb89fad9976fccb2 (diff) |
libcamera: object: Create parent-child relationships
Add a parent Object to Object instances, and track the parent-children
relationships. Children are bound to the same thread as their parent,
and moving an Object to a thread automatically moves all its children.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
-rw-r--r-- | include/libcamera/object.h | 8 | ||||
-rw-r--r-- | src/libcamera/include/thread.h | 2 | ||||
-rw-r--r-- | src/libcamera/object.cpp | 72 | ||||
-rw-r--r-- | src/libcamera/thread.cpp | 12 |
4 files changed, 81 insertions, 13 deletions
diff --git a/include/libcamera/object.h b/include/libcamera/object.h index e128c75e..3308330a 100644 --- a/include/libcamera/object.h +++ b/include/libcamera/object.h @@ -9,6 +9,7 @@ #include <list> #include <memory> +#include <vector> #include <libcamera/bound_method.h> @@ -23,7 +24,7 @@ class Thread; class Object { public: - Object(); + Object(Object *parent = nullptr); virtual ~Object(); void postMessage(std::unique_ptr<Message> msg); @@ -41,6 +42,8 @@ public: Thread *thread() const { return thread_; } void moveToThread(Thread *thread); + Object *parent() const { return parent_; } + protected: virtual void message(Message *msg); @@ -57,6 +60,9 @@ private: void connect(SignalBase *signal); void disconnect(SignalBase *signal); + Object *parent_; + std::vector<Object *> children_; + Thread *thread_; std::list<SignalBase *> signals_; unsigned int pendingMessages_; diff --git a/src/libcamera/include/thread.h b/src/libcamera/include/thread.h index 630abb49..37edd4f5 100644 --- a/src/libcamera/include/thread.h +++ b/src/libcamera/include/thread.h @@ -61,6 +61,8 @@ private: friend class ThreadMain; void moveObject(Object *object); + void moveObject(Object *object, ThreadData *currentData, + ThreadData *targetData); std::thread thread_; ThreadData *data_; diff --git a/src/libcamera/object.cpp b/src/libcamera/object.cpp index bbb28f26..98aa0af2 100644 --- a/src/libcamera/object.cpp +++ b/src/libcamera/object.cpp @@ -7,6 +7,8 @@ #include <libcamera/object.h> +#include <algorithm> + #include <libcamera/signal.h> #include "log.h" @@ -21,6 +23,8 @@ namespace libcamera { +LOG_DEFINE_CATEGORY(Object) + /** * \class Object * \brief Base object to support automatic signal disconnection @@ -29,10 +33,11 @@ namespace libcamera { * slots. By inheriting from Object, an object is automatically disconnected * from all connected signals when it gets destroyed. * - * Object instances are bound to the thread in which they're created. When a - * message is posted to an object, its handler will run in the object's thread. - * This allows implementing easy message passing between threads by inheriting - * from the Object class. + * Object instances are bound to the thread of their parent, or the thread in + * which they're created when they have no parent. When a message is posted to + * an object, its handler will run in the object's thread. This allows + * implementing easy message passing between threads by inheriting from the + * Object class. * * Object slots connected to signals will also run in the context of the * object's thread, regardless of whether the signal is emitted in the same or @@ -41,12 +46,29 @@ namespace libcamera { * \sa Message, Signal, Thread */ -Object::Object() - : pendingMessages_(0) +/** + * \brief Construct an Object instance + * \param[in] parent The object parent + * + * The new Object instance is bound to the thread of its \a parent, or to the + * current thread if the \a parent is nullptr. + */ +Object::Object(Object *parent) + : parent_(parent), pendingMessages_(0) { - thread_ = Thread::current(); + thread_ = parent ? parent->thread() : Thread::current(); + + if (parent) + parent->children_.push_back(this); } +/** + * \brief Destroy an Object instance + * + * 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::~Object() { for (SignalBase *signal : signals_) @@ -54,6 +76,16 @@ Object::~Object() if (pendingMessages_) thread()->removeMessages(this); + + if (parent_) { + auto it = std::find(parent_->children_.begin(), + parent_->children_.end(), this); + ASSERT(it != parent_->children_.end()); + parent_->children_.erase(it); + } + + for (auto child : children_) + child->parent_ = nullptr; } /** @@ -129,16 +161,19 @@ void Object::invokeMethod(BoundMethodBase *method, void *args) */ /** - * \brief Move the object to a different thread + * \brief Move the object and all its children to a different thread * \param[in] thread The target thread * - * This method moves the object from the current thread to the new \a thread. - * It shall be called from the thread in which the object currently lives, - * otherwise the behaviour is undefined. + * This method moves the object and all its children from the current thread to + * the new \a thread. It shall be called from the thread in which the object + * currently lives, otherwise the behaviour is undefined. * * Before the object is moved, a Message::ThreadMoveMessage message is sent to * it. The message() method can be reimplement in derived classes to be notified * of the upcoming thread move and perform any required processing. + * + * Moving an object that has a parent is not allowed, and causes undefined + * behaviour. */ void Object::moveToThread(Thread *thread) { @@ -147,6 +182,12 @@ void Object::moveToThread(Thread *thread) if (thread_ == thread) return; + if (parent_) { + LOG(Object, Error) + << "Moving object to thread with a parent is not permitted"; + return; + } + notifyThreadMove(); thread->moveObject(this); @@ -156,8 +197,17 @@ void Object::notifyThreadMove() { Message msg(Message::ThreadMoveMessage); message(&msg); + + for (auto child : children_) + child->notifyThreadMove(); } +/** + * \fn Object::parent() + * \brief Retrieve the object's parent + * \return The object's parent + */ + void Object::connect(SignalBase *signal) { signals_.push_back(signal); diff --git a/src/libcamera/thread.cpp b/src/libcamera/thread.cpp index 24422f7b..872ad1bd 100644 --- a/src/libcamera/thread.cpp +++ b/src/libcamera/thread.cpp @@ -448,7 +448,7 @@ void Thread::dispatchMessages() } /** - * \brief Move an \a object to the thread + * \brief Move an \a object and all its children to the thread * \param[in] object The object */ void Thread::moveObject(Object *object) @@ -460,6 +460,12 @@ void Thread::moveObject(Object *object) MutexLocker lockerTo(targetData->mutex_, std::defer_lock); std::lock(lockerFrom, lockerTo); + moveObject(object, currentData, targetData); +} + +void Thread::moveObject(Object *object, ThreadData *currentData, + ThreadData *targetData) +{ /* Move pending messages to the message queue of the new thread. */ if (object->pendingMessages_) { unsigned int movedMessages = 0; @@ -483,6 +489,10 @@ void Thread::moveObject(Object *object) } object->thread_ = this; + + /* Move all children. */ + for (auto child : object->children_) + moveObject(child, currentData, targetData); } }; /* namespace libcamera */ |