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:
@@ -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
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user