summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2019-08-12 14:19:06 +0300
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2019-08-17 18:47:17 +0300
commit2b25819ec07e8de0b4be658c7d46f6c1c495766d (patch)
tree984c9c1785413b75bbe4825eca2895c6848f09e0
parent4d9f1a0efc038e12b5cfdb53cb89fad9976fccb2 (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.h8
-rw-r--r--src/libcamera/include/thread.h2
-rw-r--r--src/libcamera/object.cpp72
-rw-r--r--src/libcamera/thread.cpp12
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 */