From patchwork Mon Aug 12 12:46:28 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1782 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6232760E38 for ; Mon, 12 Aug 2019 14:46:50 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E130D327 for ; Mon, 12 Aug 2019 14:46:49 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1565614010; bh=n9M1fZ+58duTiTj7ajfnt8ZHBoYWVcO9iMDMQoQ/2c0=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Q9o49AhAz2mnl/WLIXiS00IMDKNr5CiSBag8ecitSlQWYk3d3K9j1ZrQWECPsoONH hOGiapfbjshGrEJk4dV2NJE0SmSUZtKIbJ/KNI8p7ZtEK0hm91HlxP3/8Tnt4CZpAx 4UNcIApzK/77RJbdqNaqPzYYqbG/r2rt/d1T1ekE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 12 Aug 2019 15:46:28 +0300 Message-Id: <20190812124642.24287-5-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> References: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 04/18] libcamera: signal: Split Slot implementation to reusable classes X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Aug 2019 12:46:50 -0000 Move the Slot* classes to bound_method.{h,cpp} and rename them to Bound*Method*. They will be reused to implement asynchronous method invocation similar to cross-thread signal delivery. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- Documentation/Doxyfile.in | 10 +-- include/libcamera/bound_method.h | 131 ++++++++++++++++++++++++++++ include/libcamera/meson.build | 1 + include/libcamera/object.h | 5 +- include/libcamera/signal.h | 145 ++++--------------------------- src/libcamera/bound_method.cpp | 33 +++++++ src/libcamera/include/message.h | 8 +- src/libcamera/meson.build | 1 + src/libcamera/message.cpp | 4 +- src/libcamera/object.cpp | 2 +- src/libcamera/signal.cpp | 23 ----- 11 files changed, 197 insertions(+), 166 deletions(-) create mode 100644 include/libcamera/bound_method.h create mode 100644 src/libcamera/bound_method.cpp diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in index 3d94623a4b8f..a9596c2a32d8 100644 --- a/Documentation/Doxyfile.in +++ b/Documentation/Doxyfile.in @@ -865,11 +865,11 @@ EXCLUDE_PATTERNS = # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* -EXCLUDE_SYMBOLS = libcamera::SignalBase \ - libcamera::SlotArgs \ - libcamera::SlotBase \ - libcamera::SlotMember \ - libcamera::SlotStatic \ +EXCLUDE_SYMBOLS = libcamera::BoundMemberMethod \ + libcamera::BoundMethodArgs \ + libcamera::BoundMethodBase \ + libcamera::BoundStaticMethod \ + libcamera::SignalBase \ std::* # The EXAMPLE_PATH tag can be used to specify one or more files or directories diff --git a/include/libcamera/bound_method.h b/include/libcamera/bound_method.h new file mode 100644 index 000000000000..38c44b923ba1 --- /dev/null +++ b/include/libcamera/bound_method.h @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * bound_method.h - Method bind and invocation + */ +#ifndef __LIBCAMERA_BOUND_METHOD_H__ +#define __LIBCAMERA_BOUND_METHOD_H__ + +#include +#include + +namespace libcamera { + +class Object; +template +class Signal; +class SignalBase; + +class BoundMethodBase +{ +public: + BoundMethodBase(void *obj, Object *object) + : obj_(obj), object_(object) {} + virtual ~BoundMethodBase() {} + + template::value>::type * = nullptr> + bool match(T *obj) { return obj == obj_; } + bool match(Object *object) { return object == object_; } + + void disconnect(SignalBase *signal); + + void activatePack(void *pack); + virtual void invokePack(void *pack) = 0; + +protected: + void *obj_; + Object *object_; +}; + +template +class BoundMethodArgs : public BoundMethodBase +{ +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: + BoundMethodArgs(void *obj, Object *object) + : BoundMethodBase(obj, object) {} + + void invokePack(void *pack) override + { + invokePack(pack, typename generator::type()); + } + + virtual void activate(Args... args) = 0; + virtual void invoke(Args... args) = 0; +}; + +template +class BoundMemberMethod : public BoundMethodArgs +{ +public: + using PackType = std::tuple::type...>; + + BoundMemberMethod(T *obj, Object *object, void (T::*func)(Args...)) + : BoundMethodArgs(obj, object), func_(func) {} + + void activate(Args... args) + { + if (this->object_) + BoundMethodBase::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; + void (T::*func_)(Args...); +}; + +template +class BoundStaticMethod : public BoundMethodArgs +{ +public: + BoundStaticMethod(void (*func)(Args...)) + : BoundMethodArgs(nullptr, nullptr), func_(func) {} + + void activate(Args... args) { (*func_)(args...); } + void invoke(Args... args) {} + +private: + friend class Signal; + void (*func_)(Args...); +}; + +}; /* namespace libcamera */ + +#endif /* __LIBCAMERA_BOUND_METHOD_H__ */ diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build index 920eb5fcbfd1..a8a38a9b1db7 100644 --- a/include/libcamera/meson.build +++ b/include/libcamera/meson.build @@ -1,4 +1,5 @@ libcamera_api = files([ + 'bound_method.h', 'buffer.h', 'camera.h', 'camera_manager.h', diff --git a/include/libcamera/object.h b/include/libcamera/object.h index 3d08d69a9044..e3b39cf547b0 100644 --- a/include/libcamera/object.h +++ b/include/libcamera/object.h @@ -10,13 +10,14 @@ #include #include +#include + namespace libcamera { class Message; template class Signal; class SignalBase; -class SlotBase; class Thread; class Object @@ -36,7 +37,7 @@ protected: private: template friend class Signal; - friend class SlotBase; + friend class BoundMethodBase; friend class Thread; void connect(SignalBase *signal); diff --git a/include/libcamera/signal.h b/include/libcamera/signal.h index 8f6db700cd80..3b6de30f7d35 100644 --- a/include/libcamera/signal.h +++ b/include/libcamera/signal.h @@ -8,127 +8,14 @@ #define __LIBCAMERA_SIGNAL_H__ #include -#include #include #include +#include #include namespace libcamera { -template -class Signal; -class SignalBase; - -class SlotBase -{ -public: - SlotBase(void *obj, Object *object) - : obj_(obj), object_(object) {} - virtual ~SlotBase() {} - - template::value>::type * = nullptr> - bool match(T *obj) { return obj == obj_; } - bool match(Object *object) { return object == object_; } - - void disconnect(SignalBase *signal); - - void activatePack(void *pack); - virtual void invokePack(void *pack) = 0; - -protected: - void *obj_; - Object *object_; -}; - -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, Object *object) - : SlotBase(obj, object) {} - - void invokePack(void *pack) override - { - invokePack(pack, typename generator::type()); - } - - 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, Object *object, void (T::*func)(Args...)) - : SlotArgs(obj, object), func_(func) {} - - void activate(Args... args) - { - if (this->object_) - 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; - void (T::*func_)(Args...); -}; - -template -class SlotStatic : public SlotArgs -{ -public: - SlotStatic(void (*func)(Args...)) - : SlotArgs(nullptr, nullptr), func_(func) {} - - void activate(Args... args) { (*func_)(args...); } - void invoke(Args... args) {} - -private: - friend class Signal; - void (*func_)(Args...); -}; - class SignalBase { public: @@ -136,7 +23,7 @@ public: void disconnect(T *obj) { for (auto iter = slots_.begin(); iter != slots_.end(); ) { - SlotBase *slot = *iter; + BoundMethodBase *slot = *iter; if (slot->match(obj)) { iter = slots_.erase(iter); delete slot; @@ -148,7 +35,7 @@ public: protected: friend class Object; - std::list slots_; + std::list slots_; }; template @@ -158,7 +45,7 @@ public: Signal() {} ~Signal() { - for (SlotBase *slot : slots_) { + for (BoundMethodBase *slot : slots_) { slot->disconnect(this); delete slot; } @@ -170,7 +57,7 @@ public: { Object *object = static_cast(obj); object->connect(this); - slots_.push_back(new SlotMember(obj, object, func)); + slots_.push_back(new BoundMemberMethod(obj, object, func)); } template::value>::type * = nullptr> @@ -179,17 +66,17 @@ public: #endif void connect(T *obj, void (T::*func)(Args...)) { - slots_.push_back(new SlotMember(obj, nullptr, func)); + slots_.push_back(new BoundMemberMethod(obj, nullptr, func)); } void connect(void (*func)(Args...)) { - slots_.push_back(new SlotStatic(func)); + slots_.push_back(new BoundStaticMethod(func)); } void disconnect() { - for (SlotBase *slot : slots_) + for (BoundMethodBase *slot : slots_) delete slot; slots_.clear(); } @@ -204,15 +91,15 @@ public: void disconnect(T *obj, void (T::*func)(Args...)) { for (auto iter = slots_.begin(); iter != slots_.end(); ) { - SlotArgs *slot = static_cast *>(*iter); + BoundMethodArgs *slot = static_cast *>(*iter); /* * If the object matches the slot, the slot is * guaranteed to be a member slot, so we can safely - * cast it to SlotMember and access its + * cast it to BoundMemberMethod and access its * func_ member. */ if (slot->match(obj) && - static_cast *>(slot)->func_ == func) { + static_cast *>(slot)->func_ == func) { iter = slots_.erase(iter); delete slot; } else { @@ -224,9 +111,9 @@ public: void disconnect(void (*func)(Args...)) { for (auto iter = slots_.begin(); iter != slots_.end(); ) { - SlotArgs *slot = *iter; + BoundMethodArgs *slot = *iter; if (slot->match(nullptr) && - static_cast *>(slot)->func_ == func) { + static_cast *>(slot)->func_ == func) { iter = slots_.erase(iter); delete slot; } else { @@ -241,9 +128,9 @@ public: * Make a copy of the slots list as the slot could call the * disconnect operation, invalidating the iterator. */ - std::vector slots{ slots_.begin(), slots_.end() }; - for (SlotBase *slot : slots) - static_cast *>(slot)->activate(args...); + std::vector slots{ slots_.begin(), slots_.end() }; + for (BoundMethodBase *slot : slots) + static_cast *>(slot)->activate(args...); } }; diff --git a/src/libcamera/bound_method.cpp b/src/libcamera/bound_method.cpp new file mode 100644 index 000000000000..0a2d61a6c805 --- /dev/null +++ b/src/libcamera/bound_method.cpp @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * bound_method.cpp - Method bind and invocation + */ + +#include + +#include "message.h" +#include "thread.h" +#include "utils.h" + +namespace libcamera { + +void BoundMethodBase::disconnect(SignalBase *signal) +{ + if (object_) + object_->disconnect(signal); +} + +void BoundMethodBase::activatePack(void *pack) +{ + if (Thread::current() == object_->thread()) { + invokePack(pack); + } else { + std::unique_ptr msg = + utils::make_unique(this, pack); + object_->postMessage(std::move(msg)); + } +} + +} /* namespace libcamera */ diff --git a/src/libcamera/include/message.h b/src/libcamera/include/message.h index 416fe74b10ad..b4670c0eab76 100644 --- a/src/libcamera/include/message.h +++ b/src/libcamera/include/message.h @@ -11,8 +11,8 @@ namespace libcamera { +class BoundMethodBase; class Object; -class SlotBase; class Thread; class Message @@ -44,12 +44,12 @@ private: class SignalMessage : public Message { public: - SignalMessage(SlotBase *slot, void *pack) - : Message(Message::SignalMessage), slot_(slot), pack_(pack) + SignalMessage(BoundMethodBase *method, void *pack) + : Message(Message::SignalMessage), method_(method), pack_(pack) { } - SlotBase *slot_; + BoundMethodBase *method_; void *pack_; }; diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 7d5d3c04fba0..c5d8f116ffc6 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -1,4 +1,5 @@ libcamera_sources = files([ + 'bound_method.cpp', 'buffer.cpp', 'camera.cpp', 'camera_manager.cpp', diff --git a/src/libcamera/message.cpp b/src/libcamera/message.cpp index d44d2a4c73a8..8d3376d8a533 100644 --- a/src/libcamera/message.cpp +++ b/src/libcamera/message.cpp @@ -114,12 +114,12 @@ Message::Type Message::registerMessageType() /** * \fn SignalMessage::SignalMessage() * \brief Construct a SignalMessage - * \param[in] slot The slot that the signal targets + * \param[in] method The slot that the signal targets * \param[in] pack The signal arguments */ /** - * \var SignalMessage::slot_ + * \var SignalMessage::method_ * \brief The slot that the signal targets */ diff --git a/src/libcamera/object.cpp b/src/libcamera/object.cpp index 61787fadac0b..0adbc203add8 100644 --- a/src/libcamera/object.cpp +++ b/src/libcamera/object.cpp @@ -90,7 +90,7 @@ void Object::message(Message *msg) switch (msg->type()) { case Message::SignalMessage: { SignalMessage *smsg = static_cast(msg); - smsg->slot_->invokePack(smsg->pack_); + smsg->method_->invokePack(smsg->pack_); break; } diff --git a/src/libcamera/signal.cpp b/src/libcamera/signal.cpp index ab7dba508dfb..6ee348acc8d4 100644 --- a/src/libcamera/signal.cpp +++ b/src/libcamera/signal.cpp @@ -7,10 +7,6 @@ #include -#include "message.h" -#include "thread.h" -#include "utils.h" - /** * \file signal.h * \brief Signal & slot implementation @@ -57,25 +53,6 @@ namespace libcamera { * passed through the signal will remain valid after the signal is emitted. */ -void SlotBase::disconnect(SignalBase *signal) -{ - if (object_) - object_->disconnect(signal); -} - -void SlotBase::activatePack(void *pack) -{ - Object *obj = static_cast(object_); - - 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