From patchwork Sat Jan 4 05:09:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 2506 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5393760607 for ; Sat, 4 Jan 2020 06:10:06 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id D8CD1A58 for ; Sat, 4 Jan 2020 06:10:05 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1578114606; bh=LHL/mAZ8wgV9cylqoYiZojUEgXcwoSor7hup2mIBjUE=; h=From:To:Subject:Date:In-Reply-To:References:From; b=caa2XxcPYZxh32QatAOnJsrFePN5SXZr7/dJ0/Ke0V1WnpTugrrMPfKwOXilEbH7Q 9I7ui8XIzWIUk6CDznEh0BStEx8J273rubAl0mog8uDLa1bfhAx2ezjoWkBtwQE8k5 t6NCYSikGRZT4lw3ZNCIKCoXpIt1YjoHt8aYQeBk= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 4 Jan 2020 07:09:43 +0200 Message-Id: <20200104050947.7673-11-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200104050947.7673-1-laurent.pinchart@ideasonboard.com> References: <20200104050947.7673-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 10/14] libcamera: bound_method: Propagate method return value X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 04 Jan 2020 05:10:08 -0000 Propagate the return value of the bound method all the way to the caller of activate(). The value is stored in the arguments pack for indirect invocation. As C++ doesn't allow instantiating a variable of type void, we need to specialize the template class BoundMethodPack for methods returning void. This in turn requires template specialization for the BoundMethodArgs class in order to store the return value in the pack, and for the BoundMemberMethod class to extract the return value from the pack. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- include/libcamera/bound_method.h | 99 +++++++++++++++++++++++++++----- include/libcamera/object.h | 6 +- src/libcamera/bound_method.cpp | 23 ++++++-- src/libcamera/object.cpp | 6 +- 4 files changed, 113 insertions(+), 21 deletions(-) diff --git a/include/libcamera/bound_method.h b/include/libcamera/bound_method.h index a74d2c503cdb..0a91f44a2054 100644 --- a/include/libcamera/bound_method.h +++ b/include/libcamera/bound_method.h @@ -28,7 +28,7 @@ public: virtual ~BoundMethodPackBase() {} }; -template +template class BoundMethodPack : public BoundMethodPackBase { public: @@ -37,6 +37,19 @@ public: { } + std::tuple::type...> args_; + R ret_; +}; + +template +class BoundMethodPack : public BoundMethodPackBase +{ +public: + BoundMethodPack(const Args &... args) + : args_(args...) + { + } + std::tuple::type...> args_; }; @@ -77,7 +90,7 @@ protected: }; #endif - void activatePack(std::shared_ptr pack, + bool activatePack(std::shared_ptr pack, bool deleteMethod); void *obj_; @@ -91,7 +104,34 @@ template class BoundMethodArgs : public BoundMethodBase { public: - using PackType = BoundMethodPack; + using PackType = BoundMethodPack; + +private: + template + void invokePack(BoundMethodPackBase *pack, BoundMethodBase::sequence) + { + PackType *args = static_cast(pack); + args->ret_ = invoke(std::get(args->args_)...); + } + +public: + BoundMethodArgs(void *obj, Object *object, ConnectionType type) + : BoundMethodBase(obj, object, type) {} + + void invokePack(BoundMethodPackBase *pack) override + { + invokePack(pack, typename BoundMethodBase::generator::type()); + } + + virtual R activate(Args... args, bool deleteMethod = false) = 0; + virtual R invoke(Args... args) = 0; +}; + +template +class BoundMethodArgs : public BoundMethodBase +{ +public: + using PackType = BoundMethodPack; private: template @@ -129,15 +169,45 @@ public: bool match(R (T::*func)(Args...)) const { return func == func_; } + R activate(Args... args, bool deleteMethod = false) override + { + if (!this->object_) + return (static_cast(this->obj_)->*func_)(args...); + + auto pack = std::make_shared(args...); + bool sync = BoundMethodBase::activatePack(pack, deleteMethod); + return sync ? pack->ret_ : R(); + } + + R invoke(Args... args) override + { + return (static_cast(this->obj_)->*func_)(args...); + } + +private: + R (T::*func_)(Args...); +}; + +template +class BoundMemberMethod : public BoundMethodArgs +{ +public: + using PackType = typename BoundMethodArgs::PackType; + + BoundMemberMethod(T *obj, Object *object, void (T::*func)(Args...), + ConnectionType type = ConnectionTypeAuto) + : BoundMethodArgs(obj, object, type), func_(func) + { + } + + bool match(void (T::*func)(Args...)) const { return func == func_; } + void activate(Args... args, bool deleteMethod = false) override { - if (!this->object_) { - (static_cast(this->obj_)->*func_)(args...); - return; - } + if (!this->object_) + return (static_cast(this->obj_)->*func_)(args...); - std::shared_ptr pack = - std::make_shared::PackType>(args...); + auto pack = std::make_shared(args...); BoundMethodBase::activatePack(pack, deleteMethod); } @@ -147,7 +217,7 @@ public: } private: - R (T::*func_)(Args...); + void (T::*func_)(Args...); }; template @@ -162,12 +232,15 @@ public: bool match(R (*func)(Args...)) const { return func == func_; } - void activate(Args... args, bool deleteMethod = false) override + R activate(Args... args, bool deleteMethod = false) override { - (*func_)(args...); + return (*func_)(args...); } - void invoke(Args...) override {} + R invoke(Args...) override + { + return R(); + } private: R (*func_)(Args...); diff --git a/include/libcamera/object.h b/include/libcamera/object.h index 586c2cf6fc70..04aa18394d55 100644 --- a/include/libcamera/object.h +++ b/include/libcamera/object.h @@ -31,12 +31,12 @@ public: template::value>::type * = nullptr> - void invokeMethod(R (T::*func)(FuncArgs...), ConnectionType type, - Args... args) + R invokeMethod(R (T::*func)(FuncArgs...), ConnectionType type, + Args... args) { T *obj = static_cast(this); auto *method = new BoundMemberMethod(obj, this, func, type); - method->activate(args..., true); + return method->activate(args..., true); } Thread *thread() const { return thread_; } diff --git a/src/libcamera/bound_method.cpp b/src/libcamera/bound_method.cpp index 82339b7e9c95..8e95c7eec92c 100644 --- a/src/libcamera/bound_method.cpp +++ b/src/libcamera/bound_method.cpp @@ -48,7 +48,22 @@ namespace libcamera { * deadlock will occur. */ -void BoundMethodBase::activatePack(std::shared_ptr pack, +/** + * \brief Invoke the bound method with packed arguments + * \param[in] pack Packed arguments + * \param[in] deleteMethod True to delete \a this bound method instance when + * method invocation completes + * + * The bound method stores its return value, if any, in the arguments \a pack. + * For direct and blocking invocations, this is performed synchronously, and + * the return value contained in the pack may be used. For queued invocations, + * the return value is stored at an undefined point of time and shall thus not + * be used by the caller. + * + * \return True if the return value contained in the \a pack may be used by the + * caller, false otherwise + */ +bool BoundMethodBase::activatePack(std::shared_ptr pack, bool deleteMethod) { ConnectionType type = connectionType_; @@ -65,13 +80,13 @@ void BoundMethodBase::activatePack(std::shared_ptr pack, invokePack(pack.get()); if (deleteMethod) delete this; - break; + return true; case ConnectionTypeQueued: { std::unique_ptr msg = utils::make_unique(this, pack, nullptr, deleteMethod); object_->postMessage(std::move(msg)); - break; + return false; } case ConnectionTypeBlocking: { @@ -82,7 +97,7 @@ void BoundMethodBase::activatePack(std::shared_ptr pack, object_->postMessage(std::move(msg)); semaphore.acquire(); - break; + return true; } } } diff --git a/src/libcamera/object.cpp b/src/libcamera/object.cpp index e76faf48b8ed..21aad5652b38 100644 --- a/src/libcamera/object.cpp +++ b/src/libcamera/object.cpp @@ -143,7 +143,7 @@ void Object::message(Message *msg) } /** - * \fn void Object::invokeMethod() + * \fn R Object::invokeMethod() * \brief Invoke a method asynchronously on an Object instance * \param[in] func The object method to invoke * \param[in] type Connection type for method invocation @@ -156,6 +156,10 @@ void Object::message(Message *msg) * Arguments \a args passed by value or reference are copied, while pointers * are passed untouched. The caller shall ensure that any pointer argument * remains valid until the method is invoked. + * + * \return For connection types ConnectionTypeDirect and + * ConnectionTypeBlocking, return the return value of the invoked method. For + * connection type ConnectionTypeQueued, return a default-constructed R value. */ /**