diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2019-07-10 14:47:30 +0300 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2019-07-11 11:57:37 +0300 |
commit | cc3ae13d9edf36473fb0c4c78b9490c355ce0096 (patch) | |
tree | 5216f22dd8eda2975bc41fc6ea9d504892a62f3f /include | |
parent | 01b930964acdd9475d46044c459396f8c3cf8a79 (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 'include')
-rw-r--r-- | include/libcamera/signal.h | 67 |
1 files changed, 59 insertions, 8 deletions
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 <list> +#include <tuple> +#include <type_traits> #include <vector> #include <libcamera/object.h> @@ -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<typename... Args> class SlotArgs : public SlotBase { +private: +#ifndef __DOXYGEN__ + /* + * This is a cheap partial implementation of std::integer_sequence<> + * from C++14. + */ + template<int...> + struct sequence { + }; + + template<int N, int... S> + struct generator : generator<N-1, N-1, S...> { + }; + + template<int... S> + struct generator<0, S...> { + typedef sequence<S...> type; + }; +#endif + + using PackType = std::tuple<typename std::remove_reference<Args>::type...>; + + template<int... S> + void invokePack(void *pack, sequence<S...>) + { + PackType *args = static_cast<PackType *>(pack); + invoke(std::get<S>(*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<sizeof...(Args)>::type()); + } -protected: - friend class Signal<Args...>; + virtual void activate(Args... args) = 0; + virtual void invoke(Args... args) = 0; }; template<typename T, typename... Args> class SlotMember : public SlotArgs<Args...> { public: + using PackType = std::tuple<typename std::remove_reference<Args>::type...>; + SlotMember(T *obj, bool isObject, void (T::*func)(Args...)) : SlotArgs<Args...>(obj, isObject), func_(func) {} - void invoke(Args... args) { (static_cast<T *>(this->obj_)->*func_)(args...); } + void activate(Args... args) + { + if (this->isObject_) + SlotBase::activatePack(new PackType{ args... }); + else + (static_cast<T *>(this->obj_)->*func_)(args...); + } + + void invoke(Args... args) + { + (static_cast<T *>(this->obj_)->*func_)(args...); + } private: friend class Signal<Args...>; @@ -66,7 +117,8 @@ public: SlotStatic(void (*func)(Args...)) : SlotArgs<Args...>(nullptr, false), func_(func) {} - void invoke(Args... args) { (*func_)(args...); } + void activate(Args... args) { (*func_)(args...); } + void invoke(Args... args) {} private: friend class Signal<Args...>; @@ -186,9 +238,8 @@ public: * disconnect operation, invalidating the iterator. */ std::vector<SlotBase *> slots{ slots_.begin(), slots_.end() }; - for (SlotBase *slot : slots) { - static_cast<SlotArgs<Args...> *>(slot)->invoke(args...); - } + for (SlotBase *slot : slots) + static_cast<SlotArgs<Args...> *>(slot)->activate(args...); } }; |