summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2019-07-10 14:47:30 +0300
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2019-07-11 11:57:37 +0300
commitcc3ae13d9edf36473fb0c4c78b9490c355ce0096 (patch)
tree5216f22dd8eda2975bc41fc6ea9d504892a62f3f /src
parent01b930964acdd9475d46044c459396f8c3cf8a79 (diff)
libcamera: signal: Support cross-thread signals
Allow signals to cross thread boundaries by posting them to the recipient through messages instead of calling the slot directly when the recipient lives in a different thread. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
Diffstat (limited to 'src')
-rw-r--r--src/libcamera/include/message.h14
-rw-r--r--src/libcamera/message.cpp22
-rw-r--r--src/libcamera/object.cpp15
-rw-r--r--src/libcamera/signal.cpp26
4 files changed, 77 insertions, 0 deletions
diff --git a/src/libcamera/include/message.h b/src/libcamera/include/message.h
index 97c9b80e..db17d647 100644
--- a/src/libcamera/include/message.h
+++ b/src/libcamera/include/message.h
@@ -10,6 +10,7 @@
namespace libcamera {
class Object;
+class SlotBase;
class Thread;
class Message
@@ -17,6 +18,7 @@ class Message
public:
enum Type {
None = 0,
+ SignalMessage = 1,
};
Message(Type type);
@@ -32,6 +34,18 @@ private:
Object *receiver_;
};
+class SignalMessage : public Message
+{
+public:
+ SignalMessage(SlotBase *slot, void *pack)
+ : Message(Message::SignalMessage), slot_(slot), pack_(pack)
+ {
+ }
+
+ SlotBase *slot_;
+ void *pack_;
+};
+
} /* namespace libcamera */
#endif /* __LIBCAMERA_MESSAGE_H__ */
diff --git a/src/libcamera/message.cpp b/src/libcamera/message.cpp
index 5bb17ae2..0580c105 100644
--- a/src/libcamera/message.cpp
+++ b/src/libcamera/message.cpp
@@ -68,4 +68,26 @@ Message::~Message()
* \return The message receiver
*/
+/**
+ * \class SignalMessage
+ * \brief A message carrying a Signal across threads
+ */
+
+/**
+ * \fn SignalMessage::SignalMessage()
+ * \brief Construct a SignalMessage
+ * \param[in] slot The slot that the signal targets
+ * \param[in] pack The signal arguments
+ */
+
+/**
+ * \var SignalMessage::slot_
+ * \brief The slot that the signal targets
+ */
+
+/**
+ * \var SignalMessage::pack_
+ * \brief The signal arguments
+ */
+
}; /* namespace libcamera */
diff --git a/src/libcamera/object.cpp b/src/libcamera/object.cpp
index fa228483..61787fad 100644
--- a/src/libcamera/object.cpp
+++ b/src/libcamera/object.cpp
@@ -10,6 +10,7 @@
#include <libcamera/signal.h>
#include "log.h"
+#include "message.h"
#include "thread.h"
/**
@@ -32,6 +33,10 @@ namespace libcamera {
* 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
+ * in another thread.
+ *
* \sa Message, Signal, Thread
*/
@@ -82,6 +87,16 @@ void Object::postMessage(std::unique_ptr<Message> msg)
*/
void Object::message(Message *msg)
{
+ switch (msg->type()) {
+ case Message::SignalMessage: {
+ SignalMessage *smsg = static_cast<SignalMessage *>(msg);
+ smsg->slot_->invokePack(smsg->pack_);
+ break;
+ }
+
+ default:
+ break;
+ }
}
/**
diff --git a/src/libcamera/signal.cpp b/src/libcamera/signal.cpp
index 4cb85ecb..53c18535 100644
--- a/src/libcamera/signal.cpp
+++ b/src/libcamera/signal.cpp
@@ -7,6 +7,10 @@
#include <libcamera/signal.h>
+#include "message.h"
+#include "thread.h"
+#include "utils.h"
+
/**
* \file signal.h
* \brief Signal & slot implementation
@@ -42,8 +46,30 @@ namespace libcamera {
* to the same slot. Duplicate connections between a signal and a slot are
* allowed and result in the slot being called multiple times for the same
* signal emission.
+ *
+ * When a slot belongs to an instance of the Object class, the slot is called
+ * in the context of the thread that the object is bound to. If the signal is
+ * emitted from the same thread, the slot will be called synchronously, before
+ * Signal::emit() returns. If the signal is emitted from a different thread,
+ * the slot will be called asynchronously from the object's thread's event
+ * loop, after the Signal::emit() method returns, with a copy of the signal's
+ * arguments. The emitter shall thus ensure that any pointer or reference
+ * passed through the signal will remain valid after the signal is emitted.
*/
+void SlotBase::activatePack(void *pack)
+{
+ Object *obj = static_cast<Object *>(obj_);
+
+ if (Thread::current() == obj->thread()) {
+ invokePack(pack);
+ } else {
+ std::unique_ptr<Message> msg =
+ utils::make_unique<SignalMessage>(this, pack);
+ obj->postMessage(std::move(msg));
+ }
+}
+
/**
* \fn Signal::connect(T *object, void(T::*func)(Args...))
* \brief Connect the signal to a member function slot