From cc3ae13d9edf36473fb0c4c78b9490c355ce0096 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 10 Jul 2019 14:47:30 +0300 Subject: libcamera: signal: Support cross-thread signals MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Niklas Söderlund --- src/libcamera/include/message.h | 14 ++++++++++++++ src/libcamera/message.cpp | 22 ++++++++++++++++++++++ src/libcamera/object.cpp | 15 +++++++++++++++ src/libcamera/signal.cpp | 26 ++++++++++++++++++++++++++ 4 files changed, 77 insertions(+) (limited to 'src') 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 #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 msg) */ void Object::message(Message *msg) { + switch (msg->type()) { + case Message::SignalMessage: { + SignalMessage *smsg = static_cast(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 +#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(obj_); + + if (Thread::current() == obj->thread()) { + invokePack(pack); + } else { + std::unique_ptr msg = + utils::make_unique(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 -- cgit v1.2.1