Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(412)

Unified Diff: ipc/ipc_message_templates.h

Issue 1532053002: use variadic macros/templates in IPC message implementation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix ipc_fuzzer build again Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ipc/ipc_message_templates.h
diff --git a/ipc/ipc_message_templates.h b/ipc/ipc_message_templates.h
new file mode 100644
index 0000000000000000000000000000000000000000..207d77928d28214782bc266ecd081ed696c0096f
--- /dev/null
+++ b/ipc/ipc_message_templates.h
@@ -0,0 +1,207 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_IPC_MESSAGE_TEMPLATES_H_
+#define IPC_IPC_MESSAGE_TEMPLATES_H_
+
+#include <stdint.h>
+
+#include <type_traits>
+
+#include "base/logging.h"
+#include "base/tuple.h"
+#include "build/build_config.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_message_utils.h"
+
+namespace IPC {
+
+// This function is for all the async IPCs that don't pass an extra parameter
+// using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM.
+template <typename ObjT, typename Method, typename P, typename Tuple>
+void DispatchToMethod(ObjT* obj, Method method, P*, const Tuple& tuple) {
+ base::DispatchToMethod(obj, method, tuple);
+}
+
+template <typename ObjT,
+ typename Method,
+ typename P,
+ typename Tuple,
+ size_t... Ns>
+void DispatchToMethodImpl(ObjT* obj,
+ Method method,
+ P* parameter,
+ const Tuple& tuple,
+ base::IndexSequence<Ns...>) {
+ // TODO(mdempsky): Apply UnwrapTraits like base::DispatchToMethod?
+ (obj->*method)(parameter, base::get<Ns>(tuple)...);
+}
+
+// The following function is for async IPCs which have a dispatcher with an
+// extra parameter specified using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM.
+template <typename ObjT, typename P, typename... Args, typename... Ts>
+typename std::enable_if<sizeof...(Args) == sizeof...(Ts)>::type
+DispatchToMethod(ObjT* obj,
+ void (ObjT::*method)(P*, Args...),
+ P* parameter,
+ const base::Tuple<Ts...>& tuple) {
+ DispatchToMethodImpl(obj, method, parameter, tuple,
+ base::MakeIndexSequence<sizeof...(Ts)>());
+}
+
+enum class MessageKind {
+ CONTROL,
+ ROUTED,
+};
+
+// Routing is a helper struct so MessageT's private common constructor has a
+// different type signature than the public "int32_t routing_id" one.
+struct Routing {
+ int32_t id;
+};
+
+// We want to restrict MessageT's constructors so that a routing_id is always
+// provided for ROUTED messages and never provided for CONTROL messages, so
+// use the SFINAE technique from N4387's "Implementation Hint" section.
+#if defined(COMPILER_MSVC)
+// MSVC 2013 doesn't support default arguments for template member functions
+// of templated classes, so there we have to rely on the DCHECKs instead.
+// TODO(mdempsky): Reevaluate once MSVC 2015.
vmpstr 2016/02/04 23:43:27 I'm not really up to date, but is MSVC2015 here? O
mdempsky 2016/02/05 00:32:32 No idea.
danakj 2016/02/05 00:41:04 https://groups.google.com/a/chromium.org/forum/#!t
vmpstr 2016/02/05 01:24:31 My point was simply that this seems to already wor
mdempsky 2016/02/05 02:06:10 Understood. I'm going to lean towards something m
+#define IPC_MESSAGET_SFINAE(x)
+#else
+#define IPC_MESSAGET_SFINAE(x) \
+ template <bool X = (x), typename std::enable_if<X, bool>::type = false>
vmpstr 2016/02/04 23:43:27 Is the extra bool X = (x) just convenience? Or doe
mdempsky 2016/02/05 00:32:32 I'm pretty sure it's necessary. I think it's beca
vmpstr 2016/02/05 01:24:31 I guess my initial concern was that if one explici
mdempsky 2016/02/05 02:06:10 I did too, but alas, that's not what the C++ commi
+#endif
+
+// MessageT is the common template used for all user-defined message types.
+// It's intended to be used via the macros defined in ipc_message_macros.h.
+template <typename Meta,
+ typename InTuple = typename Meta::InTuple,
+ typename OutTuple = typename Meta::OutTuple>
+class MessageT;
+
+// Asynchronous message partial specialization.
+template <typename Meta, typename... Ins>
+class MessageT<Meta, base::Tuple<Ins...>, void> : public Message {
+ public:
+ using Param = base::Tuple<Ins...>;
+ enum { ID = Meta::ID };
+
+ // TODO(mdempsky): Remove.
vmpstr 2016/02/04 23:43:27 Can you elaborate on this todo?
mdempsky 2016/02/05 00:32:32 Done.
+ using Schema = MessageT;
+
+ IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL)
+ MessageT(const Ins&... ins) : MessageT(Routing{MSG_ROUTING_CONTROL}, ins...) {
vmpstr 2016/02/04 23:43:27 Is this syntax allowed? I keep being confused betw
mdempsky 2016/02/05 00:32:32 Blah, looks like still no. Done.
+ DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName;
+ }
+
+ IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED)
+ MessageT(int32_t routing_id, const Ins&... ins)
+ : MessageT(Routing{routing_id}, ins...) {
+ DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName;
+ }
+
+ static bool Read(const Message* msg, Param* p);
+ static void Log(std::string* name, const Message* msg, std::string* l);
+
+ template <class T, class S, class P, class Method>
+ static bool Dispatch(const Message* msg,
+ T* obj,
+ S* sender,
+ P* parameter,
+ Method func) {
+ Param p;
+ if (Read(msg, &p)) {
+ DispatchToMethod(obj, func, parameter, p);
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ MessageT(Routing routing, const Ins&... ins);
+};
+
+// Synchronous message partial specialization.
+template <typename Meta, typename... Ins, typename... Outs>
+class MessageT<Meta, base::Tuple<Ins...>, base::Tuple<Outs...>>
+ : public SyncMessage {
+ public:
+ using SendParam = base::Tuple<Ins...>;
+ using ReplyParam = base::Tuple<Outs...>;
+ enum { ID = Meta::ID };
+
+ // TODO(mdempsky): Remove.
+ using Schema = MessageT;
+
+ IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL)
+ MessageT(const Ins&... ins, Outs*... outs)
+ : MessageT(Routing{MSG_ROUTING_CONTROL}, ins..., outs...) {
+ DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName;
+ }
+
+ IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED)
+ MessageT(int32_t routing_id, const Ins&... ins, Outs*... outs)
+ : MessageT(Routing{routing_id}, ins..., outs...) {
+ DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName;
+ }
+
+ static bool ReadSendParam(const Message* msg, SendParam* p);
+ static bool ReadReplyParam(const Message* msg, ReplyParam* p);
+ static void WriteReplyParams(Message* reply, const Outs&... outs);
+ static void Log(std::string* name, const Message* msg, std::string* l);
+
+ template <class T, class S, class P, class Method>
+ static bool Dispatch(const Message* msg,
+ T* obj,
+ S* sender,
+ P* parameter,
+ Method func) {
+ SendParam send_params;
+ bool ok = ReadSendParam(msg, &send_params);
+ Message* reply = SyncMessage::GenerateReply(msg);
+ if (ok) {
+ ReplyParam reply_params;
+ base::DispatchToMethod(obj, func, send_params, &reply_params);
+ WriteParam(reply, reply_params);
+ LogReplyParamsToMessage(reply_params, msg);
+ } else {
+ NOTREACHED() << "Error deserializing message " << msg->type();
+ reply->set_reply_error();
+ }
+ sender->Send(reply);
+ return ok;
+ }
+
+ template <class T, class P, class Method>
+ static bool DispatchDelayReply(const Message* msg,
+ T* obj,
+ P* parameter,
+ Method func) {
+ SendParam send_params;
+ bool ok = ReadSendParam(msg, &send_params);
+ Message* reply = SyncMessage::GenerateReply(msg);
+ if (ok) {
+ base::Tuple<Message&> t = base::MakeRefTuple(*reply);
+ ConnectMessageAndReply(msg, reply);
+ base::DispatchToMethod(obj, func, send_params, &t);
+ } else {
+ NOTREACHED() << "Error deserializing message " << msg->type();
+ reply->set_reply_error();
+ obj->Send(reply);
+ }
+ return ok;
+ }
+
+ private:
+ MessageT(Routing routing, const Ins&... ins, Outs*... outs);
+};
+
+} // namespace IPC
+
+#if defined(IPC_MESSAGE_IMPL)
+#include "ipc/ipc_message_templates_impl.h"
+#endif
+
+#endif // IPC_IPC_MESSAGE_TEMPLATES_H_

Powered by Google App Engine
This is Rietveld 408576698