[libcamera-devel] [PATCH 15/18] libcamera: object: Create parent-child relationships

Laurent Pinchart laurent.pinchart at ideasonboard.com
Thu Aug 15 12:21:18 CEST 2019


Hi Jacopo,

On Thu, Aug 15, 2019 at 11:56:47AM +0200, Jacopo Mondi wrote:
> On Mon, Aug 12, 2019 at 03:46:39PM +0300, Laurent Pinchart wrote:
> > 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 at ideasonboard.com>
> > ---
> >  include/libcamera/object.h     |  8 ++++-
> >  src/libcamera/include/thread.h |  2 ++
> >  src/libcamera/object.cpp       | 65 ++++++++++++++++++++++++++++------
> >  src/libcamera/thread.cpp       | 12 ++++++-
> >  4 files changed, 74 insertions(+), 13 deletions(-)
> >
> > diff --git a/include/libcamera/object.h b/include/libcamera/object.h
> > index 14b939a9bd3d..4a0a272b875a 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);
> > @@ -42,6 +43,8 @@ public:
> >  	Thread *thread() const { return thread_; }
> >  	void moveToThread(Thread *thread);
> >
> > +	Object *parent() const { return parent_; }
> 
> maybe const Object * ?

There's a need to call non-const function of the parent, so we need a
non-const pointer. I could add two versions of this method, const Object
*parent() const and Object *parent(), but I don't think that's needed.
The parent isn't part of the child, so modifying it doesn't modify the
state of the child.

> > +
> >  protected:
> >  	virtual void message(Message *msg);
> >
> > @@ -58,6 +61,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 630abb49534f..37edd4f5138b 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 7c68ec01f78c..57cd6fefe20f 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,10 +46,20 @@ 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);
> >  }
> >
> >  Object::~Object()
> > @@ -54,6 +69,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;
> >  }
> >
> >  /**
> > @@ -143,16 +168,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)
> >  {
> > @@ -161,6 +189,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);
> > @@ -170,8 +204,17 @@ void Object::notifyThreadMove()
> >  {
> >  	Message msg(Message::ThreadMoveMessage);
> >  	sendMessage(&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 24422f7b7bd0..872ad1bd9d69 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 */
> > --
> > Regards,
> >
> > Laurent Pinchart
> >
> > _______________________________________________
> > libcamera-devel mailing list
> > libcamera-devel at lists.libcamera.org
> > https://lists.libcamera.org/listinfo/libcamera-devel



-- 
Regards,

Laurent Pinchart


More information about the libcamera-devel mailing list