Patch Detail
Show a patch.
GET /api/1.1/patches/2506/?format=api
{ "id": 2506, "url": "https://patchwork.libcamera.org/api/1.1/patches/2506/?format=api", "web_url": "https://patchwork.libcamera.org/patch/2506/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api", "name": "libcamera", "link_name": "libcamera", "list_id": "libcamera_core", "list_email": "libcamera-devel@lists.libcamera.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20200104050947.7673-11-laurent.pinchart@ideasonboard.com>", "date": "2020-01-04T05:09:43", "name": "[libcamera-devel,10/14] libcamera: bound_method: Propagate method return value", "commit_ref": "3d1d2081714f316483dddf573105682910b026bc", "pull_url": null, "state": "accepted", "archived": false, "hash": "4a7e618889010e1341503aee7e75dde59e2b3a14", "submitter": { "id": 2, "url": "https://patchwork.libcamera.org/api/1.1/people/2/?format=api", "name": "Laurent Pinchart", "email": "laurent.pinchart@ideasonboard.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/2506/mbox/", "series": [ { "id": 600, "url": "https://patchwork.libcamera.org/api/1.1/series/600/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=600", "date": "2020-01-04T05:09:33", "name": "object: Propagate return value of invoked method", "version": 1, "mbox": "https://patchwork.libcamera.org/series/600/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/2506/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/2506/checks/", "tags": {}, "headers": { "Return-Path": "<laurent.pinchart@ideasonboard.com>", "Received": [ "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 5393760607\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 4 Jan 2020 06:10:06 +0100 (CET)", "from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi\n\t[81.175.216.236])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id D8CD1A58\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 4 Jan 2020 06:10:05 +0100 (CET)" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1578114606;\n\tbh=LHL/mAZ8wgV9cylqoYiZojUEgXcwoSor7hup2mIBjUE=;\n\th=From:To:Subject:Date:In-Reply-To:References:From;\n\tb=caa2XxcPYZxh32QatAOnJsrFePN5SXZr7/dJ0/Ke0V1WnpTugrrMPfKwOXilEbH7Q\n\t9I7ui8XIzWIUk6CDznEh0BStEx8J273rubAl0mog8uDLa1bfhAx2ezjoWkBtwQE8k5\n\tt6NCYSikGRZT4lw3ZNCIKCoXpIt1YjoHt8aYQeBk=", "From": "Laurent Pinchart <laurent.pinchart@ideasonboard.com>", "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", "Content-Transfer-Encoding": "8bit", "Subject": "[libcamera-devel] [PATCH 10/14] libcamera: bound_method: Propagate\n\tmethod return value", "X-BeenThere": "libcamera-devel@lists.libcamera.org", "X-Mailman-Version": "2.1.29", "Precedence": "list", "List-Id": "<libcamera-devel.lists.libcamera.org>", "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>", "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>", "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>", "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>", "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>", "X-List-Received-Date": "Sat, 04 Jan 2020 05:10:08 -0000" }, "content": "Propagate the return value of the bound method all the way to the caller\nof activate(). The value is stored in the arguments pack for indirect\ninvocation.\n\nAs C++ doesn't allow instantiating a variable of type void, we need to\nspecialize the template class BoundMethodPack for methods returning\nvoid. This in turn requires template specialization for the\nBoundMethodArgs class in order to store the return value in the pack,\nand for the BoundMemberMethod class to extract the return value from the\npack.\n\nSigned-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n---\n include/libcamera/bound_method.h | 99 +++++++++++++++++++++++++++-----\n include/libcamera/object.h | 6 +-\n src/libcamera/bound_method.cpp | 23 ++++++--\n src/libcamera/object.cpp | 6 +-\n 4 files changed, 113 insertions(+), 21 deletions(-)", "diff": "diff --git a/include/libcamera/bound_method.h b/include/libcamera/bound_method.h\nindex a74d2c503cdb..0a91f44a2054 100644\n--- a/include/libcamera/bound_method.h\n+++ b/include/libcamera/bound_method.h\n@@ -28,7 +28,7 @@ public:\n \tvirtual ~BoundMethodPackBase() {}\n };\n \n-template<typename... Args>\n+template<typename R, typename... Args>\n class BoundMethodPack : public BoundMethodPackBase\n {\n public:\n@@ -37,6 +37,19 @@ public:\n \t{\n \t}\n \n+\tstd::tuple<typename std::remove_reference<Args>::type...> args_;\n+\tR ret_;\n+};\n+\n+template<typename... Args>\n+class BoundMethodPack<void, Args...> : public BoundMethodPackBase\n+{\n+public:\n+\tBoundMethodPack(const Args &... args)\n+\t\t: args_(args...)\n+\t{\n+\t}\n+\n \tstd::tuple<typename std::remove_reference<Args>::type...> args_;\n };\n \n@@ -77,7 +90,7 @@ protected:\n \t};\n #endif\n \n-\tvoid activatePack(std::shared_ptr<BoundMethodPackBase> pack,\n+\tbool activatePack(std::shared_ptr<BoundMethodPackBase> pack,\n \t\t\t bool deleteMethod);\n \n \tvoid *obj_;\n@@ -91,7 +104,34 @@ template<typename R, typename... Args>\n class BoundMethodArgs : public BoundMethodBase\n {\n public:\n-\tusing PackType = BoundMethodPack<Args...>;\n+\tusing PackType = BoundMethodPack<R, Args...>;\n+\n+private:\n+\ttemplate<int... S>\n+\tvoid invokePack(BoundMethodPackBase *pack, BoundMethodBase::sequence<S...>)\n+\t{\n+\t\tPackType *args = static_cast<PackType *>(pack);\n+\t\targs->ret_ = invoke(std::get<S>(args->args_)...);\n+\t}\n+\n+public:\n+\tBoundMethodArgs(void *obj, Object *object, ConnectionType type)\n+\t\t: BoundMethodBase(obj, object, type) {}\n+\n+\tvoid invokePack(BoundMethodPackBase *pack) override\n+\t{\n+\t\tinvokePack(pack, typename BoundMethodBase::generator<sizeof...(Args)>::type());\n+\t}\n+\n+\tvirtual R activate(Args... args, bool deleteMethod = false) = 0;\n+\tvirtual R invoke(Args... args) = 0;\n+};\n+\n+template<typename... Args>\n+class BoundMethodArgs<void, Args...> : public BoundMethodBase\n+{\n+public:\n+\tusing PackType = BoundMethodPack<void, Args...>;\n \n private:\n \ttemplate<int... S>\n@@ -129,15 +169,45 @@ public:\n \n \tbool match(R (T::*func)(Args...)) const { return func == func_; }\n \n+\tR activate(Args... args, bool deleteMethod = false) override\n+\t{\n+\t\tif (!this->object_)\n+\t\t\treturn (static_cast<T *>(this->obj_)->*func_)(args...);\n+\n+\t\tauto pack = std::make_shared<PackType>(args...);\n+\t\tbool sync = BoundMethodBase::activatePack(pack, deleteMethod);\n+\t\treturn sync ? pack->ret_ : R();\n+\t}\n+\n+\tR invoke(Args... args) override\n+\t{\n+\t\treturn (static_cast<T *>(this->obj_)->*func_)(args...);\n+\t}\n+\n+private:\n+\tR (T::*func_)(Args...);\n+};\n+\n+template<typename T, typename... Args>\n+class BoundMemberMethod<T, void, Args...> : public BoundMethodArgs<void, Args...>\n+{\n+public:\n+\tusing PackType = typename BoundMethodArgs<void *, Args...>::PackType;\n+\n+\tBoundMemberMethod(T *obj, Object *object, void (T::*func)(Args...),\n+\t\t\t ConnectionType type = ConnectionTypeAuto)\n+\t\t: BoundMethodArgs<void, Args...>(obj, object, type), func_(func)\n+\t{\n+\t}\n+\n+\tbool match(void (T::*func)(Args...)) const { return func == func_; }\n+\n \tvoid activate(Args... args, bool deleteMethod = false) override\n \t{\n-\t\tif (!this->object_) {\n-\t\t\t(static_cast<T *>(this->obj_)->*func_)(args...);\n-\t\t\treturn;\n-\t\t}\n+\t\tif (!this->object_)\n+\t\t\treturn (static_cast<T *>(this->obj_)->*func_)(args...);\n \n-\t\tstd::shared_ptr<BoundMethodPackBase> pack =\n-\t\t\tstd::make_shared<typename BoundMemberMethod<T, R, Args...>::PackType>(args...);\n+\t\tauto pack = std::make_shared<PackType>(args...);\n \t\tBoundMethodBase::activatePack(pack, deleteMethod);\n \t}\n \n@@ -147,7 +217,7 @@ public:\n \t}\n \n private:\n-\tR (T::*func_)(Args...);\n+\tvoid (T::*func_)(Args...);\n };\n \n template<typename R, typename... Args>\n@@ -162,12 +232,15 @@ public:\n \n \tbool match(R (*func)(Args...)) const { return func == func_; }\n \n-\tvoid activate(Args... args, bool deleteMethod = false) override\n+\tR activate(Args... args, bool deleteMethod = false) override\n \t{\n-\t\t(*func_)(args...);\n+\t\treturn (*func_)(args...);\n \t}\n \n-\tvoid invoke(Args...) override {}\n+\tR invoke(Args...) override\n+\t{\n+\t\treturn R();\n+\t}\n \n private:\n \tR (*func_)(Args...);\ndiff --git a/include/libcamera/object.h b/include/libcamera/object.h\nindex 586c2cf6fc70..04aa18394d55 100644\n--- a/include/libcamera/object.h\n+++ b/include/libcamera/object.h\n@@ -31,12 +31,12 @@ public:\n \n \ttemplate<typename T, typename R, typename... FuncArgs, typename... Args,\n \t\t typename std::enable_if<std::is_base_of<Object, T>::value>::type * = nullptr>\n-\tvoid invokeMethod(R (T::*func)(FuncArgs...), ConnectionType type,\n-\t\t\t Args... args)\n+\tR invokeMethod(R (T::*func)(FuncArgs...), ConnectionType type,\n+\t\t Args... args)\n \t{\n \t\tT *obj = static_cast<T *>(this);\n \t\tauto *method = new BoundMemberMethod<T, R, FuncArgs...>(obj, this, func, type);\n-\t\tmethod->activate(args..., true);\n+\t\treturn method->activate(args..., true);\n \t}\n \n \tThread *thread() const { return thread_; }\ndiff --git a/src/libcamera/bound_method.cpp b/src/libcamera/bound_method.cpp\nindex 82339b7e9c95..8e95c7eec92c 100644\n--- a/src/libcamera/bound_method.cpp\n+++ b/src/libcamera/bound_method.cpp\n@@ -48,7 +48,22 @@ namespace libcamera {\n * deadlock will occur.\n */\n \n-void BoundMethodBase::activatePack(std::shared_ptr<BoundMethodPackBase> pack,\n+/**\n+ * \\brief Invoke the bound method with packed arguments\n+ * \\param[in] pack Packed arguments\n+ * \\param[in] deleteMethod True to delete \\a this bound method instance when\n+ * method invocation completes\n+ *\n+ * The bound method stores its return value, if any, in the arguments \\a pack.\n+ * For direct and blocking invocations, this is performed synchronously, and\n+ * the return value contained in the pack may be used. For queued invocations,\n+ * the return value is stored at an undefined point of time and shall thus not\n+ * be used by the caller.\n+ *\n+ * \\return True if the return value contained in the \\a pack may be used by the\n+ * caller, false otherwise\n+ */\n+bool BoundMethodBase::activatePack(std::shared_ptr<BoundMethodPackBase> pack,\n \t\t\t\t bool deleteMethod)\n {\n \tConnectionType type = connectionType_;\n@@ -65,13 +80,13 @@ void BoundMethodBase::activatePack(std::shared_ptr<BoundMethodPackBase> pack,\n \t\tinvokePack(pack.get());\n \t\tif (deleteMethod)\n \t\t\tdelete this;\n-\t\tbreak;\n+\t\treturn true;\n \n \tcase ConnectionTypeQueued: {\n \t\tstd::unique_ptr<Message> msg =\n \t\t\tutils::make_unique<InvokeMessage>(this, pack, nullptr, deleteMethod);\n \t\tobject_->postMessage(std::move(msg));\n-\t\tbreak;\n+\t\treturn false;\n \t}\n \n \tcase ConnectionTypeBlocking: {\n@@ -82,7 +97,7 @@ void BoundMethodBase::activatePack(std::shared_ptr<BoundMethodPackBase> pack,\n \t\tobject_->postMessage(std::move(msg));\n \n \t\tsemaphore.acquire();\n-\t\tbreak;\n+\t\treturn true;\n \t}\n \t}\n }\ndiff --git a/src/libcamera/object.cpp b/src/libcamera/object.cpp\nindex e76faf48b8ed..21aad5652b38 100644\n--- a/src/libcamera/object.cpp\n+++ b/src/libcamera/object.cpp\n@@ -143,7 +143,7 @@ void Object::message(Message *msg)\n }\n \n /**\n- * \\fn void Object::invokeMethod()\n+ * \\fn R Object::invokeMethod()\n * \\brief Invoke a method asynchronously on an Object instance\n * \\param[in] func The object method to invoke\n * \\param[in] type Connection type for method invocation\n@@ -156,6 +156,10 @@ void Object::message(Message *msg)\n * Arguments \\a args passed by value or reference are copied, while pointers\n * are passed untouched. The caller shall ensure that any pointer argument\n * remains valid until the method is invoked.\n+ *\n+ * \\return For connection types ConnectionTypeDirect and\n+ * ConnectionTypeBlocking, return the return value of the invoked method. For\n+ * connection type ConnectionTypeQueued, return a default-constructed R value.\n */\n \n /**\n", "prefixes": [ "libcamera-devel", "10/14" ] }