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>
This commit is contained in:
Laurent Pinchart
2019-08-12 14:19:06 +03:00
parent 4d9f1a0efc
commit 2b25819ec0
4 changed files with 81 additions and 13 deletions
+2
View File
@@ -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_;
+61 -11
View File
@@ -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);
+11 -1
View File
@@ -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 */