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 --- include/libcamera/signal.h | 67 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 8 deletions(-) (limited to 'include/libcamera/signal.h') diff --git a/include/libcamera/signal.h b/include/libcamera/signal.h index c8f3243e..11ffb857 100644 --- a/include/libcamera/signal.h +++ b/include/libcamera/signal.h @@ -8,6 +8,8 @@ #define __LIBCAMERA_SIGNAL_H__ #include +#include +#include #include #include @@ -27,6 +29,9 @@ public: void *obj() { return obj_; } bool isObject() const { return isObject_; } + void activatePack(void *pack); + virtual void invokePack(void *pack) = 0; + protected: void *obj_; bool isObject_; @@ -35,24 +40,70 @@ protected: template class SlotArgs : public SlotBase { +private: +#ifndef __DOXYGEN__ + /* + * This is a cheap partial implementation of std::integer_sequence<> + * from C++14. + */ + template + struct sequence { + }; + + template + struct generator : generator { + }; + + template + struct generator<0, S...> { + typedef sequence type; + }; +#endif + + using PackType = std::tuple::type...>; + + template + void invokePack(void *pack, sequence) + { + PackType *args = static_cast(pack); + invoke(std::get(*args)...); + delete args; + } + public: SlotArgs(void *obj, bool isObject) : SlotBase(obj, isObject) {} - virtual void invoke(Args... args) = 0; + void invokePack(void *pack) override + { + invokePack(pack, typename generator::type()); + } -protected: - friend class Signal; + virtual void activate(Args... args) = 0; + virtual void invoke(Args... args) = 0; }; template class SlotMember : public SlotArgs { public: + using PackType = std::tuple::type...>; + SlotMember(T *obj, bool isObject, void (T::*func)(Args...)) : SlotArgs(obj, isObject), func_(func) {} - void invoke(Args... args) { (static_cast(this->obj_)->*func_)(args...); } + void activate(Args... args) + { + if (this->isObject_) + SlotBase::activatePack(new PackType{ args... }); + else + (static_cast(this->obj_)->*func_)(args...); + } + + void invoke(Args... args) + { + (static_cast(this->obj_)->*func_)(args...); + } private: friend class Signal; @@ -66,7 +117,8 @@ public: SlotStatic(void (*func)(Args...)) : SlotArgs(nullptr, false), func_(func) {} - void invoke(Args... args) { (*func_)(args...); } + void activate(Args... args) { (*func_)(args...); } + void invoke(Args... args) {} private: friend class Signal; @@ -186,9 +238,8 @@ public: * disconnect operation, invalidating the iterator. */ std::vector slots{ slots_.begin(), slots_.end() }; - for (SlotBase *slot : slots) { - static_cast *>(slot)->invoke(args...); - } + for (SlotBase *slot : slots) + static_cast *>(slot)->activate(args...); } }; -- cgit v1.2.1