summaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authormdempsky <mdempsky@chromium.org>2016-02-08 21:41:47 -0800
committerCommit bot <commit-bot@chromium.org>2016-02-09 05:42:41 +0000
commit8a5190449d48e06efa581390426dfa3bb6750f4c (patch)
tree4d0eedc7f5de614a881cd0f2db73721c76398c28 /ipc
parent022b60ae0d50b45a8252cbdd7c244162e8013380 (diff)
downloadchromium_src-8a5190449d48e06efa581390426dfa3bb6750f4c.zip
chromium_src-8a5190449d48e06efa581390426dfa3bb6750f4c.tar.gz
chromium_src-8a5190449d48e06efa581390426dfa3bb6750f4c.tar.bz2
use variadic macros/templates in IPC message implementation
TBR=jam@chromium.org, mseaborn@chromium.org Review URL: https://codereview.chromium.org/1532053002 Cr-Commit-Position: refs/heads/master@{#374316}
Diffstat (limited to 'ipc')
-rw-r--r--ipc/BUILD.gn3
-rw-r--r--ipc/export_template.h163
-rw-r--r--ipc/ipc.gypi3
-rw-r--r--ipc/ipc_message_macros.h849
-rw-r--r--ipc/ipc_message_null_macros.h4
-rw-r--r--ipc/ipc_message_templates.h210
-rw-r--r--ipc/ipc_message_templates_impl.h110
-rw-r--r--ipc/ipc_message_utils.h107
-rw-r--r--ipc/ipc_message_utils_impl.h51
9 files changed, 695 insertions, 805 deletions
diff --git a/ipc/BUILD.gn b/ipc/BUILD.gn
index 8c7a351..2451d6f 100644
--- a/ipc/BUILD.gn
+++ b/ipc/BUILD.gn
@@ -26,6 +26,7 @@ component("ipc") {
"brokerable_attachment.h",
"brokerable_attachment_mac.cc",
"brokerable_attachment_win.cc",
+ "export_template.h",
"handle_attachment_win.cc",
"handle_attachment_win.h",
"handle_win.cc",
@@ -65,6 +66,8 @@ component("ipc") {
"ipc_message_generator.h",
"ipc_message_macros.h",
"ipc_message_start.h",
+ "ipc_message_templates.h",
+ "ipc_message_templates_impl.h",
"ipc_message_utils.cc",
"ipc_message_utils.h",
"ipc_platform_file.cc",
diff --git a/ipc/export_template.h b/ipc/export_template.h
new file mode 100644
index 0000000..e743e19
--- /dev/null
+++ b/ipc/export_template.h
@@ -0,0 +1,163 @@
+// 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_EXPORT_TEMPLATE_H_
+#define IPC_EXPORT_TEMPLATE_H_
+
+// Synopsis
+//
+// This header provides macros for using FOO_EXPORT macros with explicit
+// template instantiation declarations and definitions.
+// Generally, the FOO_EXPORT macros are used at declarations,
+// and GCC requires them to be used at explicit instantiation declarations,
+// but MSVC requires __declspec(dllexport) to be used at the explicit
+// instantiation definitions instead.
+
+// Usage
+//
+// In a header file, write:
+//
+// extern template class EXPORT_TEMPLATE_DECLARE(FOO_EXPORT) foo<bar>;
+//
+// In a source file, write:
+//
+// template class EXPORT_TEMPLATE_DEFINE(FOO_EXPORT) foo<bar>;
+
+// Implementation notes
+//
+// The implementation of this header uses some subtle macro semantics to
+// detect what the provided FOO_EXPORT value was defined as and then
+// to dispatch to appropriate macro definitions. Unfortunately,
+// MSVC's C preprocessor is rather non-compliant and requires special
+// care to make it work.
+//
+// Issue 1.
+//
+// #define F(x)
+// F()
+//
+// MSVC emits warning C4003 ("not enough actual parameters for macro
+// 'F'), even though it's a valid macro invocation. This affects the
+// macros below that take just an "export" parameter, because export
+// may be empty.
+//
+// As a workaround, we can add a dummy parameter and arguments:
+//
+// #define F(x,_)
+// F(,)
+//
+// Issue 2.
+//
+// #define F(x) G##x
+// #define Gj() ok
+// F(j())
+//
+// The correct replacement for "F(j())" is "ok", but MSVC replaces it
+// with "Gj()". As a workaround, we can pass the result to an
+// identity macro to force MSVC to look for replacements again. (This
+// is why EXPORT_TEMPLATE_STYLE_3 exists.)
+
+#define EXPORT_TEMPLATE_DECLARE(export) \
+ EXPORT_TEMPLATE_INVOKE(DECLARE, EXPORT_TEMPLATE_STYLE(export, ), export)
+#define EXPORT_TEMPLATE_DEFINE(export) \
+ EXPORT_TEMPLATE_INVOKE(DEFINE, EXPORT_TEMPLATE_STYLE(export, ), export)
+
+// INVOKE is an internal helper macro to perform parameter replacements
+// and token pasting to chain invoke another macro. E.g.,
+// EXPORT_TEMPLATE_INVOKE(DECLARE, DEFAULT, FOO_EXPORT)
+// will export to call
+// EXPORT_TEMPLATE_DECLARE_DEFAULT(FOO_EXPORT, )
+// (but with FOO_EXPORT expanded too).
+#define EXPORT_TEMPLATE_INVOKE(which, style, export) \
+ EXPORT_TEMPLATE_INVOKE_2(which, style, export)
+#define EXPORT_TEMPLATE_INVOKE_2(which, style, export) \
+ EXPORT_TEMPLATE_##which##_##style(export, )
+
+// Default style is to apply the FOO_EXPORT macro at declaration sites.
+#define EXPORT_TEMPLATE_DECLARE_DEFAULT(export, _) export
+#define EXPORT_TEMPLATE_DEFINE_DEFAULT(export, _)
+
+// The "MSVC hack" style is used when FOO_EXPORT is defined
+// as __declspec(dllexport), which MSVC requires to be used at
+// definition sites instead.
+#define EXPORT_TEMPLATE_DECLARE_MSVC_HACK(export, _)
+#define EXPORT_TEMPLATE_DEFINE_MSVC_HACK(export, _) export
+
+// EXPORT_TEMPLATE_STYLE is an internal helper macro that identifies which
+// export style needs to be used for the provided FOO_EXPORT macro definition.
+// "", "__attribute__(...)", and "__declspec(dllimport)" are mapped
+// to "DEFAULT"; while "__declspec(dllexport)" is mapped to "MSVC_HACK".
+//
+// It's implemented with token pasting to transform the __attribute__ and
+// __declspec annotations into macro invocations. E.g., if FOO_EXPORT is
+// defined as "__declspec(dllimport)", it undergoes the following sequence of
+// macro substitutions:
+// EXPORT_TEMPLATE_STYLE(FOO_EXPORT, )
+// EXPORT_TEMPLATE_STYLE_2(__declspec(dllimport), )
+// EXPORT_TEMPLATE_STYLE_3(EXPORT_TEMPLATE_STYLE_MATCH__declspec(dllimport))
+// EXPORT_TEMPLATE_STYLE_MATCH__declspec(dllimport)
+// EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_dllimport
+// DEFAULT
+#define EXPORT_TEMPLATE_STYLE(export, _) EXPORT_TEMPLATE_STYLE_2(export, )
+#define EXPORT_TEMPLATE_STYLE_2(export, _) \
+ EXPORT_TEMPLATE_STYLE_3( \
+ EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA##export)
+#define EXPORT_TEMPLATE_STYLE_3(style) style
+
+// Internal helper macros for EXPORT_TEMPLATE_STYLE.
+//
+// XXX: C++ reserves all identifiers containing "__" for the implementation,
+// but "__attribute__" and "__declspec" already contain "__" and the token-paste
+// operator can only add characters; not remove them. To minimize the risk of
+// conflict with implementations, we include "foj3FJo5StF0OvIzl7oMxA" (a random
+// 128-bit string, encoded in Base64) in the macro name.
+#define EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA DEFAULT
+#define EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA__attribute__(...) \
+ DEFAULT
+#define EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA__declspec(arg) \
+ EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_##arg
+
+// Internal helper macros for EXPORT_TEMPLATE_STYLE.
+#define EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_dllexport MSVC_HACK
+#define EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_dllimport DEFAULT
+
+// Sanity checks.
+//
+// EXPORT_TEMPLATE_TEST uses the same macro invocation pattern as
+// EXPORT_TEMPLATE_DECLARE and EXPORT_TEMPLATE_DEFINE do to check that they're
+// working correctly. When they're working correctly, the sequence of macro
+// replacements should go something like:
+//
+// EXPORT_TEMPLATE_TEST(DEFAULT, __declspec(dllimport));
+//
+// static_assert(EXPORT_TEMPLATE_INVOKE(TEST_DEFAULT,
+// EXPORT_TEMPLATE_STYLE(__declspec(dllimport), ),
+// __declspec(dllimport)), "__declspec(dllimport)");
+//
+// static_assert(EXPORT_TEMPLATE_INVOKE(TEST_DEFAULT,
+// DEFAULT, __declspec(dllimport)), "__declspec(dllimport)");
+//
+// static_assert(EXPORT_TEMPLATE_TEST_DEFAULT_DEFAULT(
+// __declspec(dllimport)), "__declspec(dllimport)");
+//
+// static_assert(true, "__declspec(dllimport)");
+//
+// When they're not working correctly, a syntax error should occur instead.
+#define EXPORT_TEMPLATE_TEST(want, export) \
+ static_assert(EXPORT_TEMPLATE_INVOKE( \
+ TEST_##want, EXPORT_TEMPLATE_STYLE(export, ), export), \
+ #export)
+#define EXPORT_TEMPLATE_TEST_DEFAULT_DEFAULT(...) true
+#define EXPORT_TEMPLATE_TEST_MSVC_HACK_MSVC_HACK(...) true
+
+EXPORT_TEMPLATE_TEST(DEFAULT, );
+EXPORT_TEMPLATE_TEST(DEFAULT, __attribute__((visibility("default"))));
+EXPORT_TEMPLATE_TEST(MSVC_HACK, __declspec(dllexport));
+EXPORT_TEMPLATE_TEST(DEFAULT, __declspec(dllimport));
+
+#undef EXPORT_TEMPLATE_TEST
+#undef EXPORT_TEMPLATE_TEST_DEFAULT_DEFAULT
+#undef EXPORT_TEMPLATE_TEST_MSVC_HACK_MSVC_HACK
+
+#endif // IPC_EXPORT_TEMPLATE_H_
diff --git a/ipc/ipc.gypi b/ipc/ipc.gypi
index dbd2099..6b7cf93 100644
--- a/ipc/ipc.gypi
+++ b/ipc/ipc.gypi
@@ -30,6 +30,7 @@
'brokerable_attachment.h',
'brokerable_attachment_mac.cc',
'brokerable_attachment_win.cc',
+ 'export_template.h',
'handle_attachment_win.cc',
'handle_attachment_win.h',
'handle_win.cc',
@@ -69,6 +70,8 @@
'ipc_message_generator.h',
'ipc_message_macros.h',
'ipc_message_start.h',
+ 'ipc_message_templates.h',
+ 'ipc_message_templates_impl.h',
'ipc_message_utils.cc',
'ipc_message_utils.h',
'ipc_param_traits.h',
diff --git a/ipc/ipc_message_macros.h b/ipc/ipc_message_macros.h
index 9e9b3e0..a573265 100644
--- a/ipc/ipc_message_macros.h
+++ b/ipc/ipc_message_macros.h
@@ -202,13 +202,12 @@
#include <stdint.h>
#include "base/profiler/scoped_profile.h"
+#include "base/tuple.h"
+#include "ipc/export_template.h"
+#include "ipc/ipc_message_templates.h"
#include "ipc/ipc_message_utils.h"
#include "ipc/param_traits_macros.h"
-#if defined(IPC_MESSAGE_IMPL)
-#include "ipc/ipc_message_utils_impl.h"
-#endif
-
// Convenience macro for defining structs without inheritance. Should not need
// to be subsequently redefined.
#define IPC_STRUCT_BEGIN(struct_name) \
@@ -227,566 +226,63 @@
#define IPC_STRUCT_MEMBER(type, name, ...) type name;
#define IPC_STRUCT_END() };
-// Message macros collect specific numbers of arguments and funnel them into
-// the common message generation macro. These should never be redefined.
-#define IPC_MESSAGE_CONTROL0(msg_class) \
- IPC_MESSAGE_DECL(EMPTY, CONTROL, msg_class, 0, 0, (), ())
-
-#define IPC_MESSAGE_CONTROL1(msg_class, type1) \
- IPC_MESSAGE_DECL(ASYNC, CONTROL, msg_class, 1, 0, (type1), ())
-
-#define IPC_MESSAGE_CONTROL2(msg_class, type1, type2) \
- IPC_MESSAGE_DECL(ASYNC, CONTROL, msg_class, 2, 0, (type1, type2), ())
-
-#define IPC_MESSAGE_CONTROL3(msg_class, type1, type2, type3) \
- IPC_MESSAGE_DECL(ASYNC, CONTROL, msg_class, 3, 0, (type1, type2, type3), ())
-
-#define IPC_MESSAGE_CONTROL4(msg_class, type1, type2, type3, type4) \
- IPC_MESSAGE_DECL(ASYNC, CONTROL, msg_class, 4, 0, (type1, type2, type3, type4), ())
-
-#define IPC_MESSAGE_CONTROL5(msg_class, type1, type2, type3, type4, type5) \
- IPC_MESSAGE_DECL(ASYNC, CONTROL, msg_class, 5, 0, (type1, type2, type3, type4, type5), ())
-
-#define IPC_MESSAGE_ROUTED0(msg_class) \
- IPC_MESSAGE_DECL(EMPTY, ROUTED, msg_class, 0, 0, (), ())
-
-#define IPC_MESSAGE_ROUTED1(msg_class, type1) \
- IPC_MESSAGE_DECL(ASYNC, ROUTED, msg_class, 1, 0, (type1), ())
-
-#define IPC_MESSAGE_ROUTED2(msg_class, type1, type2) \
- IPC_MESSAGE_DECL(ASYNC, ROUTED, msg_class, 2, 0, (type1, type2), ())
-
-#define IPC_MESSAGE_ROUTED3(msg_class, type1, type2, type3) \
- IPC_MESSAGE_DECL(ASYNC, ROUTED, msg_class, 3, 0, (type1, type2, type3), ())
-
-#define IPC_MESSAGE_ROUTED4(msg_class, type1, type2, type3, type4) \
- IPC_MESSAGE_DECL(ASYNC, ROUTED, msg_class, 4, 0, (type1, type2, type3, type4), ())
-
-#define IPC_MESSAGE_ROUTED5(msg_class, type1, type2, type3, type4, type5) \
- IPC_MESSAGE_DECL(ASYNC, ROUTED, msg_class, 5, 0, (type1, type2, type3, type4, type5), ())
-
-#define IPC_SYNC_MESSAGE_CONTROL0_0(msg_class) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 0, 0, (), ())
-
-#define IPC_SYNC_MESSAGE_CONTROL0_1(msg_class, type1_out) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 0, 1, (), (type1_out))
-
-#define IPC_SYNC_MESSAGE_CONTROL0_2(msg_class, type1_out, type2_out) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 0, 2, (), (type1_out, type2_out))
-
-#define IPC_SYNC_MESSAGE_CONTROL0_3(msg_class, type1_out, type2_out, type3_out) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 0, 3, (), (type1_out, type2_out, type3_out))
-
-#define IPC_SYNC_MESSAGE_CONTROL0_4(msg_class, type1_out, type2_out, type3_out, type4_out) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 0, 4, (), (type1_out, type2_out, type3_out, type4_out))
-
-#define IPC_SYNC_MESSAGE_CONTROL1_0(msg_class, type1_in) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 1, 0, (type1_in), ())
-
-#define IPC_SYNC_MESSAGE_CONTROL1_1(msg_class, type1_in, type1_out) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 1, 1, (type1_in), (type1_out))
-
-#define IPC_SYNC_MESSAGE_CONTROL1_2(msg_class, type1_in, type1_out, type2_out) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 1, 2, (type1_in), (type1_out, type2_out))
-
-#define IPC_SYNC_MESSAGE_CONTROL1_3(msg_class, type1_in, type1_out, type2_out, type3_out) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 1, 3, (type1_in), (type1_out, type2_out, type3_out))
-
-#define IPC_SYNC_MESSAGE_CONTROL1_4(msg_class, type1_in, type1_out, type2_out, type3_out, type4_out) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 1, 4, (type1_in), (type1_out, type2_out, type3_out, type4_out))
-
-#define IPC_SYNC_MESSAGE_CONTROL2_0(msg_class, type1_in, type2_in) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 2, 0, (type1_in, type2_in), ())
-
-#define IPC_SYNC_MESSAGE_CONTROL2_1(msg_class, type1_in, type2_in, type1_out) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 2, 1, (type1_in, type2_in), (type1_out))
-
-#define IPC_SYNC_MESSAGE_CONTROL2_2(msg_class, type1_in, type2_in, type1_out, type2_out) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 2, 2, (type1_in, type2_in), (type1_out, type2_out))
-
-#define IPC_SYNC_MESSAGE_CONTROL2_3(msg_class, type1_in, type2_in, type1_out, type2_out, type3_out) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 2, 3, (type1_in, type2_in), (type1_out, type2_out, type3_out))
-
-#define IPC_SYNC_MESSAGE_CONTROL2_4(msg_class, type1_in, type2_in, type1_out, type2_out, type3_out, type4_out) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 2, 4, (type1_in, type2_in), (type1_out, type2_out, type3_out, type4_out))
-
-#define IPC_SYNC_MESSAGE_CONTROL3_0(msg_class, type1_in, type2_in, type3_in) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 3, 0, (type1_in, type2_in, type3_in), ())
-
-#define IPC_SYNC_MESSAGE_CONTROL3_1(msg_class, type1_in, type2_in, type3_in, type1_out) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 3, 1, (type1_in, type2_in, type3_in), (type1_out))
+// Message macros collect arguments and funnel them into the common message
+// generation macro. These should never be redefined.
-#define IPC_SYNC_MESSAGE_CONTROL3_2(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 3, 2, (type1_in, type2_in, type3_in), (type1_out, type2_out))
+// Asynchronous messages have only in parameters and are declared like:
+// IPC_MESSAGE_CONTROL(FooMsg, int, float)
+#define IPC_MESSAGE_CONTROL(msg_class, ...) \
+ IPC_MESSAGE_DECL(msg_class, CONTROL, IPC_TUPLE(__VA_ARGS__), void)
+#define IPC_MESSAGE_ROUTED(msg_class, ...) \
+ IPC_MESSAGE_DECL(msg_class, ROUTED, IPC_TUPLE(__VA_ARGS__), void)
-#define IPC_SYNC_MESSAGE_CONTROL3_3(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out, type3_out) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 3, 3, (type1_in, type2_in, type3_in), (type1_out, type2_out, type3_out))
-
-#define IPC_SYNC_MESSAGE_CONTROL3_4(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out, type3_out, type4_out) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 3, 4, (type1_in, type2_in, type3_in), (type1_out, type2_out, type3_out, type4_out))
-
-#define IPC_SYNC_MESSAGE_CONTROL4_0(msg_class, type1_in, type2_in, type3_in, type4_in) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 4, 0, (type1_in, type2_in, type3_in, type4_in), ())
-
-#define IPC_SYNC_MESSAGE_CONTROL4_1(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 4, 1, (type1_in, type2_in, type3_in, type4_in), (type1_out))
-
-#define IPC_SYNC_MESSAGE_CONTROL4_2(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 4, 2, (type1_in, type2_in, type3_in, type4_in), (type1_out, type2_out))
-
-#define IPC_SYNC_MESSAGE_CONTROL4_3(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out, type3_out) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 4, 3, (type1_in, type2_in, type3_in, type4_in), (type1_out, type2_out, type3_out))
-
-#define IPC_SYNC_MESSAGE_CONTROL4_4(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out, type3_out, type4_out) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 4, 4, (type1_in, type2_in, type3_in, type4_in), (type1_out, type2_out, type3_out, type4_out))
-
-#define IPC_SYNC_MESSAGE_CONTROL5_0(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 5, 0, (type1_in, type2_in, type3_in, type4_in, type5_in), ())
-
-#define IPC_SYNC_MESSAGE_CONTROL5_1(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in, type1_out) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 5, 1, (type1_in, type2_in, type3_in, type4_in, type5_in), (type1_out))
-
-#define IPC_SYNC_MESSAGE_CONTROL5_2(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in, type1_out, type2_out) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 5, 2, (type1_in, type2_in, type3_in, type4_in, type5_in), (type1_out, type2_out))
-
-#define IPC_SYNC_MESSAGE_CONTROL5_3(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in, type1_out, type2_out, type3_out) \
- IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 5, 3, (type1_in, type2_in, type3_in, type4_in, type5_in), (type1_out, type2_out, type3_out))
-
-#define IPC_SYNC_MESSAGE_ROUTED0_0(msg_class) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 0, 0, (), ())
-
-#define IPC_SYNC_MESSAGE_ROUTED0_1(msg_class, type1_out) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 0, 1, (), (type1_out))
-
-#define IPC_SYNC_MESSAGE_ROUTED0_2(msg_class, type1_out, type2_out) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 0, 2, (), (type1_out, type2_out))
-
-#define IPC_SYNC_MESSAGE_ROUTED0_3(msg_class, type1_out, type2_out, type3_out) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 0, 3, (), (type1_out, type2_out, type3_out))
-
-#define IPC_SYNC_MESSAGE_ROUTED0_4(msg_class, type1_out, type2_out, type3_out, type4_out) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 0, 4, (), (type1_out, type2_out, type3_out, type4_out))
-
-#define IPC_SYNC_MESSAGE_ROUTED1_0(msg_class, type1_in) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 1, 0, (type1_in), ())
-
-#define IPC_SYNC_MESSAGE_ROUTED1_1(msg_class, type1_in, type1_out) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 1, 1, (type1_in), (type1_out))
-
-#define IPC_SYNC_MESSAGE_ROUTED1_2(msg_class, type1_in, type1_out, type2_out) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 1, 2, (type1_in), (type1_out, type2_out))
-
-#define IPC_SYNC_MESSAGE_ROUTED1_3(msg_class, type1_in, type1_out, type2_out, type3_out) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 1, 3, (type1_in), (type1_out, type2_out, type3_out))
-
-#define IPC_SYNC_MESSAGE_ROUTED1_4(msg_class, type1_in, type1_out, type2_out, type3_out, type4_out) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 1, 4, (type1_in), (type1_out, type2_out, type3_out, type4_out))
-
-#define IPC_SYNC_MESSAGE_ROUTED2_0(msg_class, type1_in, type2_in) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 2, 0, (type1_in, type2_in), ())
-
-#define IPC_SYNC_MESSAGE_ROUTED2_1(msg_class, type1_in, type2_in, type1_out) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 2, 1, (type1_in, type2_in), (type1_out))
-
-#define IPC_SYNC_MESSAGE_ROUTED2_2(msg_class, type1_in, type2_in, type1_out, type2_out) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 2, 2, (type1_in, type2_in), (type1_out, type2_out))
-
-#define IPC_SYNC_MESSAGE_ROUTED2_3(msg_class, type1_in, type2_in, type1_out, type2_out, type3_out) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 2, 3, (type1_in, type2_in), (type1_out, type2_out, type3_out))
-
-#define IPC_SYNC_MESSAGE_ROUTED2_4(msg_class, type1_in, type2_in, type1_out, type2_out, type3_out, type4_out) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 2, 4, (type1_in, type2_in), (type1_out, type2_out, type3_out, type4_out))
-
-#define IPC_SYNC_MESSAGE_ROUTED3_0(msg_class, type1_in, type2_in, type3_in) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 3, 0, (type1_in, type2_in, type3_in), ())
-
-#define IPC_SYNC_MESSAGE_ROUTED3_1(msg_class, type1_in, type2_in, type3_in, type1_out) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 3, 1, (type1_in, type2_in, type3_in), (type1_out))
-
-#define IPC_SYNC_MESSAGE_ROUTED3_2(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 3, 2, (type1_in, type2_in, type3_in), (type1_out, type2_out))
-
-#define IPC_SYNC_MESSAGE_ROUTED3_3(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out, type3_out) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 3, 3, (type1_in, type2_in, type3_in), (type1_out, type2_out, type3_out))
-
-#define IPC_SYNC_MESSAGE_ROUTED3_4(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out, type3_out, type4_out) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 3, 4, (type1_in, type2_in, type3_in), (type1_out, type2_out, type3_out, type4_out))
-
-#define IPC_SYNC_MESSAGE_ROUTED4_0(msg_class, type1_in, type2_in, type3_in, type4_in) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 4, 0, (type1_in, type2_in, type3_in, type4_in), ())
-
-#define IPC_SYNC_MESSAGE_ROUTED4_1(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 4, 1, (type1_in, type2_in, type3_in, type4_in), (type1_out))
-
-#define IPC_SYNC_MESSAGE_ROUTED4_2(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 4, 2, (type1_in, type2_in, type3_in, type4_in), (type1_out, type2_out))
-
-#define IPC_SYNC_MESSAGE_ROUTED4_3(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out, type3_out) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 4, 3, (type1_in, type2_in, type3_in, type4_in), (type1_out, type2_out, type3_out))
-
-#define IPC_SYNC_MESSAGE_ROUTED4_4(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out, type3_out, type4_out) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 4, 4, (type1_in, type2_in, type3_in, type4_in), (type1_out, type2_out, type3_out, type4_out))
-
-#define IPC_SYNC_MESSAGE_ROUTED5_0(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 5, 0, (type1_in, type2_in, type3_in, type4_in, type5_in), ())
-
-#define IPC_SYNC_MESSAGE_ROUTED5_1(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in, type1_out) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 5, 1, (type1_in, type2_in, type3_in, type4_in, type5_in), (type1_out))
-
-#define IPC_SYNC_MESSAGE_ROUTED5_2(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in, type1_out, type2_out) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 5, 2, (type1_in, type2_in, type3_in, type4_in, type5_in), (type1_out, type2_out))
-
-#define IPC_SYNC_MESSAGE_ROUTED5_3(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in, type1_out, type2_out, type3_out) \
- IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 5, 3, (type1_in, type2_in, type3_in, type4_in, type5_in), (type1_out, type2_out, type3_out))
-
-// The following macros define the common set of methods provided by ASYNC
-// message classes.
-// This macro is for all the async IPCs that don't pass an extra parameter using
-// IPC_BEGIN_MESSAGE_MAP_WITH_PARAM.
-#define IPC_ASYNC_MESSAGE_METHODS_GENERIC \
- template<class T, class S, class P, class Method> \
- static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter, \
- Method func) { \
- Schema::Param p; \
- if (Read(msg, &p)) { \
- base::DispatchToMethod(obj, func, p); \
- return true; \
- } \
- return false; \
- }
-
-// The following macros are for for async IPCs which have a dispatcher with an
-// extra parameter specified using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM.
-#define IPC_ASYNC_MESSAGE_METHODS_1 \
- IPC_ASYNC_MESSAGE_METHODS_GENERIC \
- template<class T, class S, class P, typename TA> \
- static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter, \
- void (T::*func)(P*, TA)) { \
- Schema::Param p; \
- if (Read(msg, &p)) { \
- (obj->*func)(parameter, base::get<0>(p)); \
- return true; \
- } \
- return false; \
- }
-#define IPC_ASYNC_MESSAGE_METHODS_2 \
- IPC_ASYNC_MESSAGE_METHODS_GENERIC \
- template<class T, class S, class P, typename TA, typename TB> \
- static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter, \
- void (T::*func)(P*, TA, TB)) { \
- Schema::Param p; \
- if (Read(msg, &p)) { \
- (obj->*func)(parameter, base::get<0>(p), base::get<1>(p)); \
- return true; \
- } \
- return false; \
- }
-#define IPC_ASYNC_MESSAGE_METHODS_3 \
- IPC_ASYNC_MESSAGE_METHODS_GENERIC \
- template<class T, class S, class P, typename TA, typename TB, typename TC> \
- static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter, \
- void (T::*func)(P*, TA, TB, TC)) { \
- Schema::Param p; \
- if (Read(msg, &p)) { \
- (obj->*func)(parameter, base::get<0>(p), base::get<1>(p), \
- base::get<2>(p)); \
- return true; \
- } \
- return false; \
- }
-#define IPC_ASYNC_MESSAGE_METHODS_4 \
- IPC_ASYNC_MESSAGE_METHODS_GENERIC \
- template<class T, class S, class P, typename TA, typename TB, typename TC, \
- typename TD> \
- static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter, \
- void (T::*func)(P*, TA, TB, TC, TD)) { \
- Schema::Param p; \
- if (Read(msg, &p)) { \
- (obj->*func)(parameter, base::get<0>(p), base::get<1>(p), \
- base::get<2>(p), base::get<3>(p)); \
- return true; \
- } \
- return false; \
- }
-#define IPC_ASYNC_MESSAGE_METHODS_5 \
- IPC_ASYNC_MESSAGE_METHODS_GENERIC \
- template<class T, class S, class P, typename TA, typename TB, typename TC, \
- typename TD, typename TE> \
- static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter, \
- void (T::*func)(P*, TA, TB, TC, TD, TE)) { \
- Schema::Param p; \
- if (Read(msg, &p)) { \
- (obj->*func)(parameter, base::get<0>(p), base::get<1>(p), \
- base::get<2>(p), base::get<3>(p), base::get<4>(p)); \
- return true; \
- } \
- return false; \
- }
-
-// The following macros define the common set of methods provided by SYNC
-// message classes.
-#define IPC_SYNC_MESSAGE_METHODS_GENERIC \
- template<class T, class S, class P, class Method> \
- static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter, \
- Method func) { \
- Schema::SendParam send_params; \
- bool ok = ReadSendParam(msg, &send_params); \
- return Schema::DispatchWithSendParams(ok, send_params, msg, obj, sender, \
- func); \
- } \
- template<class T, class P, class Method> \
- static bool DispatchDelayReply(const Message* msg, T* obj, P* parameter, \
- Method func) { \
- Schema::SendParam send_params; \
- bool ok = ReadSendParam(msg, &send_params); \
- return Schema::DispatchDelayReplyWithSendParams(ok, send_params, msg, \
- obj, func); \
- }
-#define IPC_SYNC_MESSAGE_METHODS_0 \
- IPC_SYNC_MESSAGE_METHODS_GENERIC
-#define IPC_SYNC_MESSAGE_METHODS_1 \
- IPC_SYNC_MESSAGE_METHODS_GENERIC \
- template<typename TA> \
- static void WriteReplyParams(Message* reply, TA a) { \
- Schema::WriteReplyParams(reply, a); \
- }
-#define IPC_SYNC_MESSAGE_METHODS_2 \
- IPC_SYNC_MESSAGE_METHODS_GENERIC \
- template<typename TA, typename TB> \
- static void WriteReplyParams(Message* reply, TA a, TB b) { \
- Schema::WriteReplyParams(reply, a, b); \
- }
-#define IPC_SYNC_MESSAGE_METHODS_3 \
- IPC_SYNC_MESSAGE_METHODS_GENERIC \
- template<typename TA, typename TB, typename TC> \
- static void WriteReplyParams(Message* reply, TA a, TB b, TC c) { \
- Schema::WriteReplyParams(reply, a, b, c); \
- }
-#define IPC_SYNC_MESSAGE_METHODS_4 \
- IPC_SYNC_MESSAGE_METHODS_GENERIC \
- template<typename TA, typename TB, typename TC, typename TD> \
- static void WriteReplyParams(Message* reply, TA a, TB b, TC c, TD d) { \
- Schema::WriteReplyParams(reply, a, b, c, d); \
- }
-#define IPC_SYNC_MESSAGE_METHODS_5 \
- IPC_SYNC_MESSAGE_METHODS_GENERIC \
- template<typename TA, typename TB, typename TC, typename TD, typename TE> \
- static void WriteReplyParams(Message* reply, TA a, TB b, TC c, TD d, TE e) { \
- Schema::WriteReplyParams(reply, a, b, c, d, e); \
- }
-
-// Common message macro which dispatches into one of the 6 (sync x kind)
-// routines. There is a way that these 6 cases can be lumped together,
-// but the macros get very complicated in that case.
-// Note: intended be redefined to generate other information.
-#define IPC_MESSAGE_DECL(sync, kind, msg_class, \
- in_cnt, out_cnt, in_list, out_list) \
- IPC_##sync##_##kind##_DECL(msg_class, in_cnt, out_cnt, in_list, out_list) \
- IPC_MESSAGE_EXTRA(sync, kind, msg_class, in_cnt, out_cnt, in_list, out_list)
-
-#define IPC_EMPTY_CONTROL_DECL(msg_class, in_cnt, out_cnt, in_list, out_list) \
- class IPC_MESSAGE_EXPORT msg_class : public IPC::Message { \
- public: \
- typedef IPC::Message Schema; \
- enum { ID = IPC_MESSAGE_ID() }; \
- msg_class() : IPC::Message(MSG_ROUTING_CONTROL, ID, PRIORITY_NORMAL) {} \
- static void Log(std::string* name, const Message* msg, std::string* l); \
- };
-
-#define IPC_EMPTY_ROUTED_DECL(msg_class, in_cnt, out_cnt, in_list, out_list) \
- class IPC_MESSAGE_EXPORT msg_class : public IPC::Message { \
- public: \
- typedef IPC::Message Schema; \
- enum { ID = IPC_MESSAGE_ID() }; \
- msg_class(int32_t routing_id) \
- : IPC::Message(routing_id, ID, PRIORITY_NORMAL) {} \
- static void Log(std::string* name, const Message* msg, std::string* l); \
- };
-
-#define IPC_ASYNC_CONTROL_DECL(msg_class, in_cnt, out_cnt, in_list, out_list) \
- class IPC_MESSAGE_EXPORT msg_class : public IPC::Message { \
- public: \
- typedef IPC::MessageSchema<IPC_TUPLE_IN_##in_cnt in_list> Schema; \
- typedef Schema::Param Param; \
- enum { ID = IPC_MESSAGE_ID() }; \
- msg_class(IPC_TYPE_IN_##in_cnt in_list); \
- ~msg_class() override; \
- static bool Read(const Message* msg, Schema::Param* p); \
- static void Log(std::string* name, const Message* msg, std::string* l); \
- IPC_ASYNC_MESSAGE_METHODS_##in_cnt \
- };
-
-#define IPC_ASYNC_ROUTED_DECL(msg_class, in_cnt, out_cnt, in_list, out_list) \
- class IPC_MESSAGE_EXPORT msg_class : public IPC::Message { \
- public: \
- typedef IPC::MessageSchema<IPC_TUPLE_IN_##in_cnt in_list> Schema; \
- typedef Schema::Param Param; \
- enum { ID = IPC_MESSAGE_ID() }; \
- msg_class(int32_t routing_id IPC_COMMA_##in_cnt \
- IPC_TYPE_IN_##in_cnt in_list); \
- ~msg_class() override; \
- static bool Read(const Message* msg, Schema::Param* p); \
- static void Log(std::string* name, const Message* msg, std::string* l); \
- IPC_ASYNC_MESSAGE_METHODS_##in_cnt \
- };
-
-#define IPC_SYNC_CONTROL_DECL(msg_class, in_cnt, out_cnt, in_list, out_list) \
- class IPC_MESSAGE_EXPORT msg_class : public IPC::SyncMessage { \
- public: \
- typedef IPC::SyncMessageSchema<IPC_TUPLE_IN_##in_cnt in_list, \
- IPC_TUPLE_OUT_##out_cnt out_list> Schema; \
- typedef Schema::ReplyParam ReplyParam; \
- typedef Schema::SendParam SendParam; \
- enum { ID = IPC_MESSAGE_ID() }; \
- msg_class(IPC_TYPE_IN_##in_cnt in_list \
- IPC_COMMA_AND_##in_cnt(IPC_COMMA_##out_cnt) \
- IPC_TYPE_OUT_##out_cnt out_list); \
- ~msg_class() override; \
- static bool ReadSendParam(const Message* msg, Schema::SendParam* p); \
- static bool ReadReplyParam( \
- const Message* msg, \
- base::TupleTypes<ReplyParam>::ValueTuple* p); \
- static void Log(std::string* name, const Message* msg, std::string* l); \
- IPC_SYNC_MESSAGE_METHODS_##out_cnt \
- };
-
-#define IPC_SYNC_ROUTED_DECL(msg_class, in_cnt, out_cnt, in_list, out_list) \
- class IPC_MESSAGE_EXPORT msg_class : public IPC::SyncMessage { \
- public: \
- typedef IPC::SyncMessageSchema<IPC_TUPLE_IN_##in_cnt in_list, \
- IPC_TUPLE_OUT_##out_cnt out_list> Schema; \
- typedef Schema::ReplyParam ReplyParam; \
- typedef Schema::SendParam SendParam; \
- enum { ID = IPC_MESSAGE_ID() }; \
- msg_class(int32_t routing_id \
- IPC_COMMA_OR_##in_cnt(IPC_COMMA_##out_cnt) \
- IPC_TYPE_IN_##in_cnt in_list \
- IPC_COMMA_AND_##in_cnt(IPC_COMMA_##out_cnt) \
- IPC_TYPE_OUT_##out_cnt out_list); \
- ~msg_class() override; \
- static bool ReadSendParam(const Message* msg, Schema::SendParam* p); \
- static bool ReadReplyParam( \
- const Message* msg, \
- base::TupleTypes<ReplyParam>::ValueTuple* p); \
- static void Log(std::string* name, const Message* msg, std::string* l); \
- IPC_SYNC_MESSAGE_METHODS_##out_cnt \
- };
+// Synchronous messages have both in and out parameters, so the lists need to
+// be parenthesized to disambiguate:
+// IPC_SYNC_MESSAGE_CONTROL(BarMsg, (int, int), (bool))
+//
+// Implementation detail: The parentheses supplied by the caller for
+// disambiguation are also used to trigger the IPC_TUPLE invocations below,
+// so "IPC_TUPLE in" and "IPC_TUPLE out" are intentional.
+#define IPC_SYNC_MESSAGE_CONTROL(msg_class, in, out) \
+ IPC_MESSAGE_DECL(msg_class, CONTROL, IPC_TUPLE in, IPC_TUPLE out)
+#define IPC_SYNC_MESSAGE_ROUTED(msg_class, in, out) \
+ IPC_MESSAGE_DECL(msg_class, ROUTED, IPC_TUPLE in, IPC_TUPLE out)
+
+#define IPC_TUPLE(...) base::Tuple<__VA_ARGS__>
+
+#define IPC_MESSAGE_DECL(msg_name, kind, in_tuple, out_tuple) \
+ struct IPC_MESSAGE_EXPORT msg_name##_Meta { \
+ using InTuple = in_tuple; \
+ using OutTuple = out_tuple; \
+ enum { ID = IPC_MESSAGE_ID() }; \
+ static const IPC::MessageKind kKind = IPC::MessageKind::kind; \
+ static const char kName[]; \
+ }; \
+ extern template class EXPORT_TEMPLATE_DECLARE(IPC_MESSAGE_EXPORT) \
+ IPC::MessageT<msg_name##_Meta>; \
+ using msg_name = IPC::MessageT<msg_name##_Meta>; \
+ IPC_MESSAGE_EXTRA(msg_name)
#if defined(IPC_MESSAGE_IMPL)
-// "Implementation" inclusion produces constructors, destructors, and
-// logging functions, except for the no-arg special cases, where the
-// implementation occurs in the declaration, and there is no special
-// logging function.
-#define IPC_MESSAGE_EXTRA(sync, kind, msg_class, \
- in_cnt, out_cnt, in_list, out_list) \
- IPC_##sync##_##kind##_IMPL(msg_class, in_cnt, out_cnt, in_list, out_list) \
- IPC_##sync##_MESSAGE_LOG(msg_class)
-
-#define IPC_EMPTY_CONTROL_IMPL(msg_class, in_cnt, out_cnt, in_list, out_list)
-#define IPC_EMPTY_ROUTED_IMPL(msg_class, in_cnt, out_cnt, in_list, out_list)
-
-#define IPC_ASYNC_CONTROL_IMPL(msg_class, in_cnt, out_cnt, in_list, out_list) \
- msg_class::msg_class(IPC_TYPE_IN_##in_cnt in_list) : \
- IPC::Message(MSG_ROUTING_CONTROL, ID, PRIORITY_NORMAL) { \
- Schema::Write(this, IPC_NAME_IN_##in_cnt in_list); \
- } \
- msg_class::~msg_class() {} \
- bool msg_class::Read(const Message* msg, Schema::Param* p) { \
- return Schema::Read(msg, p); \
- }
-
-#define IPC_ASYNC_ROUTED_IMPL(msg_class, in_cnt, out_cnt, in_list, out_list) \
- msg_class::msg_class(int32_t routing_id IPC_COMMA_##in_cnt \
- IPC_TYPE_IN_##in_cnt in_list) : \
- IPC::Message(routing_id, ID, PRIORITY_NORMAL) { \
- Schema::Write(this, IPC_NAME_IN_##in_cnt in_list); \
- } \
- msg_class::~msg_class() {} \
- bool msg_class::Read(const Message* msg, Schema::Param* p) { \
- return Schema::Read(msg, p); \
- }
-
-#define IPC_SYNC_CONTROL_IMPL(msg_class, in_cnt, out_cnt, in_list, out_list) \
- msg_class::msg_class(IPC_TYPE_IN_##in_cnt in_list \
- IPC_COMMA_AND_##in_cnt(IPC_COMMA_##out_cnt) \
- IPC_TYPE_OUT_##out_cnt out_list) : \
- IPC::SyncMessage(MSG_ROUTING_CONTROL, ID, PRIORITY_NORMAL, \
- new IPC::ParamDeserializer<Schema::ReplyParam>( \
- IPC_NAME_OUT_##out_cnt out_list)) { \
- Schema::Write(this, IPC_NAME_IN_##in_cnt in_list); \
- } \
- msg_class::~msg_class() {} \
- bool msg_class::ReadSendParam(const Message* msg, Schema::SendParam* p) { \
- return Schema::ReadSendParam(msg, p); \
- } \
- bool msg_class::ReadReplyParam( \
- const Message* msg, \
- base::TupleTypes<ReplyParam>::ValueTuple* p) { \
- return Schema::ReadReplyParam(msg, p); \
- }
-
-#define IPC_SYNC_ROUTED_IMPL(msg_class, in_cnt, out_cnt, in_list, out_list) \
- msg_class::msg_class(int32_t routing_id \
- IPC_COMMA_OR_##in_cnt(IPC_COMMA_##out_cnt) \
- IPC_TYPE_IN_##in_cnt in_list \
- IPC_COMMA_AND_##in_cnt(IPC_COMMA_##out_cnt) \
- IPC_TYPE_OUT_##out_cnt out_list) : \
- IPC::SyncMessage(routing_id, ID, PRIORITY_NORMAL, \
- new IPC::ParamDeserializer<Schema::ReplyParam>( \
- IPC_NAME_OUT_##out_cnt out_list)) { \
- Schema::Write(this, IPC_NAME_IN_##in_cnt in_list); \
- } \
- msg_class::~msg_class() {} \
- bool msg_class::ReadSendParam(const Message* msg, Schema::SendParam* p) { \
- return Schema::ReadSendParam(msg, p); \
- } \
- bool msg_class::ReadReplyParam( \
- const Message* msg, \
- base::TupleTypes<ReplyParam>::ValueTuple* p) { \
- return Schema::ReadReplyParam(msg, p); \
- }
-
-#define IPC_EMPTY_MESSAGE_LOG(msg_class) \
- void msg_class::Log(std::string* name, \
- const Message* msg, \
- std::string* l) { \
- if (name) \
- *name = #msg_class; \
- }
-
-#define IPC_ASYNC_MESSAGE_LOG(msg_class) \
- void msg_class::Log(std::string* name, \
- const Message* msg, \
- std::string* l) { \
- if (name) \
- *name = #msg_class; \
- if (!msg || !l) \
- return; \
- Schema::Param p; \
- if (Schema::Read(msg, &p)) \
- IPC::LogParam(p, l); \
- }
-
-#define IPC_SYNC_MESSAGE_LOG(msg_class) \
- void msg_class::Log(std::string* name, \
- const Message* msg, \
- std::string* l) { \
- if (name) \
- *name = #msg_class; \
- if (!msg || !l) \
- return; \
- if (msg->is_sync()) { \
- base::TupleTypes<Schema::SendParam>::ValueTuple p; \
- if (Schema::ReadSendParam(msg, &p)) \
- IPC::LogParam(p, l); \
- AddOutputParamsToLog(msg, l); \
- } else { \
- base::TupleTypes<Schema::ReplyParam>::ValueTuple p; \
- if (Schema::ReadReplyParam(msg, &p)) \
- IPC::LogParam(p, l); \
- } \
- }
+// "Implementation" inclusion provides the explicit template definition
+// for msg_name.
+#define IPC_MESSAGE_EXTRA(msg_name) \
+ const char msg_name##_Meta::kName[] = #msg_name; \
+ IPC_MESSAGE_DEFINE_KIND(msg_name) \
+ template class EXPORT_TEMPLATE_DEFINE(IPC_MESSAGE_EXPORT) \
+ IPC::MessageT<msg_name##_Meta>;
+
+// MSVC has an intentionally non-compliant "feature" that results in LNK2005
+// ("symbol already defined") errors if we provide an out-of-line definition
+// for kKind. Microsoft's official response is to test for _MSC_EXTENSIONS:
+// https://connect.microsoft.com/VisualStudio/feedback/details/786583/
+#if defined(_MSC_EXTENSIONS)
+#define IPC_MESSAGE_DEFINE_KIND(msg_name)
+#else
+#define IPC_MESSAGE_DEFINE_KIND(msg_name) \
+ const IPC::MessageKind msg_name##_Meta::kKind;
+#endif
#elif defined(IPC_MESSAGE_MACROS_LOG_ENABLED)
@@ -795,95 +291,22 @@
#endif
// "Log table" inclusion produces extra logging registration code.
-#define IPC_MESSAGE_EXTRA(sync, kind, msg_class, \
- in_cnt, out_cnt, in_list, out_list) \
- class LoggerRegisterHelper##msg_class { \
- public: \
- LoggerRegisterHelper##msg_class() { \
- const uint32_t msg_id = static_cast<uint32_t>(msg_class::ID); \
- IPC_LOG_TABLE_ADD_ENTRY(msg_id, msg_class::Log); \
- } \
- }; \
- LoggerRegisterHelper##msg_class g_LoggerRegisterHelper##msg_class;
+#define IPC_MESSAGE_EXTRA(msg_name) \
+ class LoggerRegisterHelper##msg_name { \
+ public: \
+ LoggerRegisterHelper##msg_name() { \
+ const uint32_t msg_id = static_cast<uint32_t>(msg_name::ID); \
+ IPC_LOG_TABLE_ADD_ENTRY(msg_id, msg_name::Log); \
+ } \
+ }; \
+ LoggerRegisterHelper##msg_name g_LoggerRegisterHelper##msg_name;
#else
// Normal inclusion produces nothing extra.
-#define IPC_MESSAGE_EXTRA(sync, kind, msg_class, \
- in_cnt, out_cnt, in_list, out_list)
-
-#endif // defined(IPC_MESSAGE_IMPL)
-
-// Handle variable sized argument lists. These are usually invoked by token
-// pasting against the argument counts.
-#define IPC_TYPE_IN_0()
-#define IPC_TYPE_IN_1(t1) const t1& arg1
-#define IPC_TYPE_IN_2(t1, t2) const t1& arg1, const t2& arg2
-#define IPC_TYPE_IN_3(t1, t2, t3) const t1& arg1, const t2& arg2, const t3& arg3
-#define IPC_TYPE_IN_4(t1, t2, t3, t4) const t1& arg1, const t2& arg2, const t3& arg3, const t4& arg4
-#define IPC_TYPE_IN_5(t1, t2, t3, t4, t5) const t1& arg1, const t2& arg2, const t3& arg3, const t4& arg4, const t5& arg5
-
-#define IPC_TYPE_OUT_0()
-#define IPC_TYPE_OUT_1(t1) t1* arg6
-#define IPC_TYPE_OUT_2(t1, t2) t1* arg6, t2* arg7
-#define IPC_TYPE_OUT_3(t1, t2, t3) t1* arg6, t2* arg7, t3* arg8
-#define IPC_TYPE_OUT_4(t1, t2, t3, t4) t1* arg6, t2* arg7, t3* arg8, \
- t4* arg9
-
-#define IPC_TUPLE_IN_0() base::Tuple<>
-#define IPC_TUPLE_IN_1(t1) base::Tuple<t1>
-#define IPC_TUPLE_IN_2(t1, t2) base::Tuple<t1, t2>
-#define IPC_TUPLE_IN_3(t1, t2, t3) base::Tuple<t1, t2, t3>
-#define IPC_TUPLE_IN_4(t1, t2, t3, t4) base::Tuple<t1, t2, t3, t4>
-#define IPC_TUPLE_IN_5(t1, t2, t3, t4, t5) base::Tuple<t1, t2, t3, t4, t5>
-
-#define IPC_TUPLE_OUT_0() base::Tuple<>
-#define IPC_TUPLE_OUT_1(t1) base::Tuple<t1&>
-#define IPC_TUPLE_OUT_2(t1, t2) base::Tuple<t1&, t2&>
-#define IPC_TUPLE_OUT_3(t1, t2, t3) base::Tuple<t1&, t2&, t3&>
-#define IPC_TUPLE_OUT_4(t1, t2, t3, t4) base::Tuple<t1&, t2&, t3&, t4&>
-
-#define IPC_NAME_IN_0() base::MakeTuple()
-#define IPC_NAME_IN_1(t1) base::MakeRefTuple(arg1)
-#define IPC_NAME_IN_2(t1, t2) base::MakeRefTuple(arg1, arg2)
-#define IPC_NAME_IN_3(t1, t2, t3) base::MakeRefTuple(arg1, arg2, arg3)
-#define IPC_NAME_IN_4(t1, t2, t3, t4) base::MakeRefTuple(arg1, arg2, \
- arg3, arg4)
-#define IPC_NAME_IN_5(t1, t2, t3, t4, t5) base::MakeRefTuple(arg1, arg2, \
- arg3, arg4, arg5)
-
-#define IPC_NAME_OUT_0() base::MakeTuple()
-#define IPC_NAME_OUT_1(t1) base::MakeRefTuple(*arg6)
-#define IPC_NAME_OUT_2(t1, t2) base::MakeRefTuple(*arg6, *arg7)
-#define IPC_NAME_OUT_3(t1, t2, t3) base::MakeRefTuple(*arg6, *arg7, \
- *arg8)
-#define IPC_NAME_OUT_4(t1, t2, t3, t4) base::MakeRefTuple(*arg6, *arg7, \
- *arg8, *arg9)
-
-// There are places where the syntax requires a comma if there are input args,
-// if there are input args and output args, or if there are input args or
-// output args. These macros allow generation of the comma as needed; invoke
-// by token pasting against the argument counts.
-#define IPC_COMMA_0
-#define IPC_COMMA_1 ,
-#define IPC_COMMA_2 ,
-#define IPC_COMMA_3 ,
-#define IPC_COMMA_4 ,
-#define IPC_COMMA_5 ,
-
-#define IPC_COMMA_AND_0(x)
-#define IPC_COMMA_AND_1(x) x
-#define IPC_COMMA_AND_2(x) x
-#define IPC_COMMA_AND_3(x) x
-#define IPC_COMMA_AND_4(x) x
-#define IPC_COMMA_AND_5(x) x
-
-#define IPC_COMMA_OR_0(x) x
-#define IPC_COMMA_OR_1(x) ,
-#define IPC_COMMA_OR_2(x) ,
-#define IPC_COMMA_OR_3(x) ,
-#define IPC_COMMA_OR_4(x) ,
-#define IPC_COMMA_OR_5(x) ,
+#define IPC_MESSAGE_EXTRA(msg_name)
+
+#endif // defined(IPC_MESSAGE_IMPL)
// Message IDs
// Note: we currently use __LINE__ to give unique IDs to messages within
@@ -982,6 +405,144 @@
#define IPC_MESSAGE_CLASS(message) \
IPC_MESSAGE_ID_CLASS(message.type())
+// Deprecated legacy macro names.
+// TODO(mdempsky): Replace uses with generic names.
+
+#define IPC_MESSAGE_CONTROL0(msg) IPC_MESSAGE_CONTROL(msg)
+#define IPC_MESSAGE_CONTROL1(msg, a) IPC_MESSAGE_CONTROL(msg, a)
+#define IPC_MESSAGE_CONTROL2(msg, a, b) IPC_MESSAGE_CONTROL(msg, a, b)
+#define IPC_MESSAGE_CONTROL3(msg, a, b, c) IPC_MESSAGE_CONTROL(msg, a, b, c)
+#define IPC_MESSAGE_CONTROL4(msg, a, b, c, d) \
+ IPC_MESSAGE_CONTROL(msg, a, b, c, d)
+#define IPC_MESSAGE_CONTROL5(msg, a, b, c, d, e) \
+ IPC_MESSAGE_CONTROL(msg, a, b, c, d, e)
+
+#define IPC_MESSAGE_ROUTED0(msg) IPC_MESSAGE_ROUTED(msg)
+#define IPC_MESSAGE_ROUTED1(msg, a) IPC_MESSAGE_ROUTED(msg, a)
+#define IPC_MESSAGE_ROUTED2(msg, a, b) IPC_MESSAGE_ROUTED(msg, a, b)
+#define IPC_MESSAGE_ROUTED3(msg, a, b, c) IPC_MESSAGE_ROUTED(msg, a, b, c)
+#define IPC_MESSAGE_ROUTED4(msg, a, b, c, d) IPC_MESSAGE_ROUTED(msg, a, b, c, d)
+#define IPC_MESSAGE_ROUTED5(msg, a, b, c, d, e) \
+ IPC_MESSAGE_ROUTED(msg, a, b, c, d, e)
+
+#define IPC_SYNC_MESSAGE_CONTROL0_0(msg) IPC_SYNC_MESSAGE_CONTROL(msg, (), ())
+#define IPC_SYNC_MESSAGE_CONTROL0_1(msg, a) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (), (a))
+#define IPC_SYNC_MESSAGE_CONTROL0_2(msg, a, b) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (), (a, b))
+#define IPC_SYNC_MESSAGE_CONTROL0_3(msg, a, b, c) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (), (a, b, c))
+#define IPC_SYNC_MESSAGE_CONTROL0_4(msg, a, b, c, d) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (), (a, b, c, d))
+#define IPC_SYNC_MESSAGE_CONTROL1_0(msg, a) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a), ())
+#define IPC_SYNC_MESSAGE_CONTROL1_1(msg, a, b) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a), (b))
+#define IPC_SYNC_MESSAGE_CONTROL1_2(msg, a, b, c) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a), (b, c))
+#define IPC_SYNC_MESSAGE_CONTROL1_3(msg, a, b, c, d) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a), (b, c, d))
+#define IPC_SYNC_MESSAGE_CONTROL1_4(msg, a, b, c, d, e) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a), (b, c, d, e))
+#define IPC_SYNC_MESSAGE_CONTROL2_0(msg, a, b) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a, b), ())
+#define IPC_SYNC_MESSAGE_CONTROL2_1(msg, a, b, c) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a, b), (c))
+#define IPC_SYNC_MESSAGE_CONTROL2_2(msg, a, b, c, d) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a, b), (c, d))
+#define IPC_SYNC_MESSAGE_CONTROL2_3(msg, a, b, c, d, e) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a, b), (c, d, e))
+#define IPC_SYNC_MESSAGE_CONTROL2_4(msg, a, b, c, d, e, f) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a, b), (c, d, e, f))
+#define IPC_SYNC_MESSAGE_CONTROL3_0(msg, a, b, c) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c), ())
+#define IPC_SYNC_MESSAGE_CONTROL3_1(msg, a, b, c, d) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c), (d))
+#define IPC_SYNC_MESSAGE_CONTROL3_2(msg, a, b, c, d, e) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c), (d, e))
+#define IPC_SYNC_MESSAGE_CONTROL3_3(msg, a, b, c, d, e, f) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c), (d, e, f))
+#define IPC_SYNC_MESSAGE_CONTROL3_4(msg, a, b, c, d, e, f, g) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c), (d, e, f, g))
+#define IPC_SYNC_MESSAGE_CONTROL4_0(msg, a, b, c, d) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d), ())
+#define IPC_SYNC_MESSAGE_CONTROL4_1(msg, a, b, c, d, e) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d), (e))
+#define IPC_SYNC_MESSAGE_CONTROL4_2(msg, a, b, c, d, e, f) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d), (e, f))
+#define IPC_SYNC_MESSAGE_CONTROL4_3(msg, a, b, c, d, e, f, g) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d), (e, f, g))
+#define IPC_SYNC_MESSAGE_CONTROL4_4(msg, a, b, c, d, e, f, g, h) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d), (e, f, g, h))
+#define IPC_SYNC_MESSAGE_CONTROL5_0(msg, a, b, c, d, e) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d, e), ())
+#define IPC_SYNC_MESSAGE_CONTROL5_1(msg, a, b, c, d, e, f) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d, e), (f))
+#define IPC_SYNC_MESSAGE_CONTROL5_2(msg, a, b, c, d, e, f, g) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d, e), (f, g))
+#define IPC_SYNC_MESSAGE_CONTROL5_3(msg, a, b, c, d, e, f, g, h) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d, e), (f, g, h))
+#define IPC_SYNC_MESSAGE_CONTROL5_4(msg, a, b, c, d, e, f, g, h, i) \
+ IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d, e), (f, g, h, i))
+
+#define IPC_SYNC_MESSAGE_ROUTED0_0(msg) IPC_SYNC_MESSAGE_ROUTED(msg, (), ())
+#define IPC_SYNC_MESSAGE_ROUTED0_1(msg, a) IPC_SYNC_MESSAGE_ROUTED(msg, (), (a))
+#define IPC_SYNC_MESSAGE_ROUTED0_2(msg, a, b) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (), (a, b))
+#define IPC_SYNC_MESSAGE_ROUTED0_3(msg, a, b, c) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (), (a, b, c))
+#define IPC_SYNC_MESSAGE_ROUTED0_4(msg, a, b, c, d) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (), (a, b, c, d))
+#define IPC_SYNC_MESSAGE_ROUTED1_0(msg, a) IPC_SYNC_MESSAGE_ROUTED(msg, (a), ())
+#define IPC_SYNC_MESSAGE_ROUTED1_1(msg, a, b) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a), (b))
+#define IPC_SYNC_MESSAGE_ROUTED1_2(msg, a, b, c) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a), (b, c))
+#define IPC_SYNC_MESSAGE_ROUTED1_3(msg, a, b, c, d) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a), (b, c, d))
+#define IPC_SYNC_MESSAGE_ROUTED1_4(msg, a, b, c, d, e) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a), (b, c, d, e))
+#define IPC_SYNC_MESSAGE_ROUTED2_0(msg, a, b) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a, b), ())
+#define IPC_SYNC_MESSAGE_ROUTED2_1(msg, a, b, c) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a, b), (c))
+#define IPC_SYNC_MESSAGE_ROUTED2_2(msg, a, b, c, d) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a, b), (c, d))
+#define IPC_SYNC_MESSAGE_ROUTED2_3(msg, a, b, c, d, e) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a, b), (c, d, e))
+#define IPC_SYNC_MESSAGE_ROUTED2_4(msg, a, b, c, d, e, f) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a, b), (c, d, e, f))
+#define IPC_SYNC_MESSAGE_ROUTED3_0(msg, a, b, c) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c), ())
+#define IPC_SYNC_MESSAGE_ROUTED3_1(msg, a, b, c, d) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c), (d))
+#define IPC_SYNC_MESSAGE_ROUTED3_2(msg, a, b, c, d, e) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c), (d, e))
+#define IPC_SYNC_MESSAGE_ROUTED3_3(msg, a, b, c, d, e, f) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c), (d, e, f))
+#define IPC_SYNC_MESSAGE_ROUTED3_4(msg, a, b, c, d, e, f, g) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c), (d, e, f, g))
+#define IPC_SYNC_MESSAGE_ROUTED4_0(msg, a, b, c, d) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d), ())
+#define IPC_SYNC_MESSAGE_ROUTED4_1(msg, a, b, c, d, e) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d), (e))
+#define IPC_SYNC_MESSAGE_ROUTED4_2(msg, a, b, c, d, e, f) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d), (e, f))
+#define IPC_SYNC_MESSAGE_ROUTED4_3(msg, a, b, c, d, e, f, g) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d), (e, f, g))
+#define IPC_SYNC_MESSAGE_ROUTED4_4(msg, a, b, c, d, e, f, g, h) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d), (e, f, g, h))
+#define IPC_SYNC_MESSAGE_ROUTED5_0(msg, a, b, c, d, e) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d, e), ())
+#define IPC_SYNC_MESSAGE_ROUTED5_1(msg, a, b, c, d, e, f) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d, e), (f))
+#define IPC_SYNC_MESSAGE_ROUTED5_2(msg, a, b, c, d, e, f, g) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d, e), (f, g))
+#define IPC_SYNC_MESSAGE_ROUTED5_3(msg, a, b, c, d, e, f, g, h) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d, e), (f, g, h))
+#define IPC_SYNC_MESSAGE_ROUTED5_4(msg, a, b, c, d, e, f, g, h, i) \
+ IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d, e), (f, g, h, i))
+
#endif // IPC_IPC_MESSAGE_MACROS_H_
// Clean up IPC_MESSAGE_START in this unguarded section so that the
diff --git a/ipc/ipc_message_null_macros.h b/ipc/ipc_message_null_macros.h
index 5a1ff4f..6eab784 100644
--- a/ipc/ipc_message_null_macros.h
+++ b/ipc/ipc_message_null_macros.h
@@ -24,6 +24,4 @@
#define IPC_STRUCT_TRAITS_PARENT(type)
#define IPC_STRUCT_TRAITS_END()
#define IPC_ENUM_TRAITS_VALIDATE(enum_name, validation_expression)
-#define IPC_MESSAGE_DECL(sync, kind, msg_class, \
- in_cnt, out_cnt, in_list, out_list)
-
+#define IPC_MESSAGE_DECL(...)
diff --git a/ipc/ipc_message_templates.h b/ipc/ipc_message_templates.h
new file mode 100644
index 0000000..17dfc1b
--- /dev/null
+++ b/ipc/ipc_message_templates.h
@@ -0,0 +1,210 @@
+// 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 {
+ explicit Routing(int32_t id) : id(id) {}
+ 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.
+#define IPC_MESSAGET_SFINAE(x)
+#else
+#define IPC_MESSAGET_SFINAE(x) \
+ template <bool X = (x), typename std::enable_if<X, bool>::type = false>
+#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. Uses of MyMessage::Schema::Param can be replaced
+ // with just MyMessage::Param.
+ using Schema = MessageT;
+
+ IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL)
+ MessageT(const Ins&... ins) : MessageT(Routing(MSG_ROUTING_CONTROL), ins...) {
+ 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. Uses of MyMessage::Schema::{Send,Reply}Param can
+ // be replaced with just MyMessage::{Send,Reply}Param.
+ 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_
diff --git a/ipc/ipc_message_templates_impl.h b/ipc/ipc_message_templates_impl.h
new file mode 100644
index 0000000..bfcdad0
--- /dev/null
+++ b/ipc/ipc_message_templates_impl.h
@@ -0,0 +1,110 @@
+// 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_IMPL_H_
+#define IPC_IPC_MESSAGE_TEMPLATES_IMPL_H_
+
+namespace IPC {
+
+template <typename... Ts>
+class ParamDeserializer : public MessageReplyDeserializer {
+ public:
+ explicit ParamDeserializer(const base::Tuple<Ts&...>& out) : out_(out) {}
+
+ bool SerializeOutputParameters(const IPC::Message& msg,
+ base::PickleIterator iter) override {
+ return ReadParam(&msg, &iter, &out_);
+ }
+
+ base::Tuple<Ts&...> out_;
+};
+
+template <typename Meta, typename... Ins>
+MessageT<Meta, base::Tuple<Ins...>, void>::MessageT(Routing routing,
+ const Ins&... ins)
+ : Message(routing.id, ID, PRIORITY_NORMAL) {
+ WriteParam(this, base::MakeRefTuple(ins...));
+}
+
+template <typename Meta, typename... Ins>
+bool MessageT<Meta, base::Tuple<Ins...>, void>::Read(const Message* msg,
+ Param* p) {
+ base::PickleIterator iter(*msg);
+ return ReadParam(msg, &iter, p);
+}
+
+template <typename Meta, typename... Ins>
+void MessageT<Meta, base::Tuple<Ins...>, void>::Log(std::string* name,
+ const Message* msg,
+ std::string* l) {
+ if (name)
+ *name = Meta::kName;
+ if (!msg || !l)
+ return;
+ Param p;
+ if (Read(msg, &p))
+ LogParam(p, l);
+}
+
+template <typename Meta, typename... Ins, typename... Outs>
+MessageT<Meta, base::Tuple<Ins...>, base::Tuple<Outs...>>::MessageT(
+ Routing routing,
+ const Ins&... ins,
+ Outs*... outs)
+ : SyncMessage(
+ routing.id,
+ ID,
+ PRIORITY_NORMAL,
+ new ParamDeserializer<Outs...>(base::MakeRefTuple(*outs...))) {
+ WriteParam(this, base::MakeRefTuple(ins...));
+}
+
+template <typename Meta, typename... Ins, typename... Outs>
+bool MessageT<Meta, base::Tuple<Ins...>, base::Tuple<Outs...>>::ReadSendParam(
+ const Message* msg,
+ SendParam* p) {
+ base::PickleIterator iter = SyncMessage::GetDataIterator(msg);
+ return ReadParam(msg, &iter, p);
+}
+
+template <typename Meta, typename... Ins, typename... Outs>
+bool MessageT<Meta, base::Tuple<Ins...>, base::Tuple<Outs...>>::ReadReplyParam(
+ const Message* msg,
+ ReplyParam* p) {
+ base::PickleIterator iter = SyncMessage::GetDataIterator(msg);
+ return ReadParam(msg, &iter, p);
+}
+
+template <typename Meta, typename... Ins, typename... Outs>
+void MessageT<Meta,
+ base::Tuple<Ins...>,
+ base::Tuple<Outs...>>::WriteReplyParams(Message* reply,
+ const Outs&... outs) {
+ WriteParam(reply, base::MakeRefTuple(outs...));
+}
+
+template <typename Meta, typename... Ins, typename... Outs>
+void MessageT<Meta, base::Tuple<Ins...>, base::Tuple<Outs...>>::Log(
+ std::string* name,
+ const Message* msg,
+ std::string* l) {
+ if (name)
+ *name = Meta::kName;
+ if (!msg || !l)
+ return;
+ if (msg->is_sync()) {
+ SendParam p;
+ if (ReadSendParam(msg, &p))
+ LogParam(p, l);
+ AddOutputParamsToLog(msg, l);
+ } else {
+ ReplyParam p;
+ if (ReadReplyParam(msg, &p))
+ LogParam(p, l);
+ }
+}
+
+} // namespace IPC
+
+#endif // IPC_IPC_MESSAGE_TEMPLATES_IMPL_H_
diff --git a/ipc/ipc_message_utils.h b/ipc/ipc_message_utils.h
index d8b6607..9ae39c2 100644
--- a/ipc/ipc_message_utils.h
+++ b/ipc/ipc_message_utils.h
@@ -31,29 +31,6 @@
#include "ipc/ipc_param_traits.h"
#include "ipc/ipc_sync_message.h"
-#if defined(COMPILER_GCC)
-// GCC "helpfully" tries to inline template methods in release mode. Except we
-// want the majority of the template junk being expanded once in the
-// implementation file (and only provide the definitions in
-// ipc_message_utils_impl.h in those files) and exported, instead of expanded
-// at every call site. Special note: GCC happily accepts the attribute before
-// the method declaration, but only acts on it if it is after.
-#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100) >= 40500
-// Starting in gcc 4.5, the noinline no longer implies the concept covered by
-// the introduced noclone attribute, which will create specialized versions of
-// functions/methods when certain types are constant.
-// www.gnu.org/software/gcc/gcc-4.5/changes.html
-#define IPC_MSG_NOINLINE __attribute__((noinline, noclone));
-#else
-#define IPC_MSG_NOINLINE __attribute__((noinline));
-#endif
-#elif defined(COMPILER_MSVC)
-// MSVC++ doesn't do this.
-#define IPC_MSG_NOINLINE
-#else
-#error "Please add the noinline property for your new compiler here."
-#endif
-
namespace base {
class DictionaryValue;
class FilePath;
@@ -1051,17 +1028,6 @@ struct IPC_EXPORT ParamTraits<MSG> {
//-----------------------------------------------------------------------------
// Generic message subclasses
-// Used for asynchronous messages.
-template <class ParamType>
-class MessageSchema {
- public:
- typedef ParamType Param;
- typedef typename base::TupleTypes<ParamType>::ParamTuple RefParam;
-
- static void Write(Message* msg, const RefParam& p) IPC_MSG_NOINLINE;
- static bool Read(const Message* msg, Param* p) IPC_MSG_NOINLINE;
-};
-
// defined in ipc_logging.cc
IPC_EXPORT void GenerateLogData(const std::string& channel,
const Message& message,
@@ -1108,79 +1074,6 @@ inline void LogReplyParamsToMessage(const ReplyParamType& reply_params,
inline void ConnectMessageAndReply(const Message* msg, Message* reply) {}
#endif
-// This class assumes that its template argument is a RefTuple (a Tuple with
-// reference elements). This would go into ipc_message_utils_impl.h, but it is
-// also used by chrome_frame.
-template <class RefTuple>
-class ParamDeserializer : public MessageReplyDeserializer {
- public:
- explicit ParamDeserializer(const RefTuple& out) : out_(out) { }
-
- bool SerializeOutputParameters(const IPC::Message& msg,
- base::PickleIterator iter) override {
- return ReadParam(&msg, &iter, &out_);
- }
-
- RefTuple out_;
-};
-
-// Used for synchronous messages.
-template <class SendParamType, class ReplyParamType>
-class SyncMessageSchema {
- public:
- typedef SendParamType SendParam;
- typedef typename base::TupleTypes<SendParam>::ParamTuple RefSendParam;
- typedef ReplyParamType ReplyParam;
-
- static void Write(Message* msg, const RefSendParam& send) IPC_MSG_NOINLINE;
- static bool ReadSendParam(const Message* msg, SendParam* p) IPC_MSG_NOINLINE;
- static bool ReadReplyParam(
- const Message* msg,
- typename base::TupleTypes<ReplyParam>::ValueTuple* p) IPC_MSG_NOINLINE;
-
- template<class T, class S, class Method>
- static bool DispatchWithSendParams(bool ok, const SendParam& send_params,
- const Message* msg, T* obj, S* sender,
- Method func) {
- Message* reply = SyncMessage::GenerateReply(msg);
- if (ok) {
- typename base::TupleTypes<ReplyParam>::ValueTuple 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 Method>
- static bool DispatchDelayReplyWithSendParams(bool ok,
- const SendParam& send_params,
- const Message* msg, T* obj,
- Method func) {
- 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;
- }
-
- template <typename... Ts>
- static void WriteReplyParams(Message* reply, Ts... args) {
- ReplyParam p(args...);
- WriteParam(reply, p);
- }
-};
-
} // namespace IPC
#endif // IPC_IPC_MESSAGE_UTILS_H_
diff --git a/ipc/ipc_message_utils_impl.h b/ipc/ipc_message_utils_impl.h
deleted file mode 100644
index 485dca5..0000000
--- a/ipc/ipc_message_utils_impl.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (c) 2012 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.
-//
-// This file contains templates forward declared (but not defined) in
-// ipc_message_utils.h so that they are only instantiated in certain files,
-// notably a few IPC unit tests.
-
-#ifndef IPC_IPC_MESSAGE_UTILS_IMPL_H_
-#define IPC_IPC_MESSAGE_UTILS_IMPL_H_
-
-namespace IPC {
-
-template <class ParamType>
-void MessageSchema<ParamType>::Write(Message* msg, const RefParam& p) {
- WriteParam(msg, p);
-}
-
-template <class ParamType>
-bool MessageSchema<ParamType>::Read(const Message* msg, Param* p) {
- base::PickleIterator iter(*msg);
- if (ReadParam(msg, &iter, p))
- return true;
- NOTREACHED() << "Error deserializing message " << msg->type();
- return false;
-}
-
-template <class SendParamType, class ReplyParamType>
-void SyncMessageSchema<SendParamType, ReplyParamType>::Write(
- Message* msg,
- const RefSendParam& send) {
- WriteParam(msg, send);
-}
-
-template <class SendParamType, class ReplyParamType>
-bool SyncMessageSchema<SendParamType, ReplyParamType>::ReadSendParam(
- const Message* msg, SendParam* p) {
- base::PickleIterator iter = SyncMessage::GetDataIterator(msg);
- return ReadParam(msg, &iter, p);
-}
-
-template <class SendParamType, class ReplyParamType>
-bool SyncMessageSchema<SendParamType, ReplyParamType>::ReadReplyParam(
- const Message* msg, typename base::TupleTypes<ReplyParam>::ValueTuple* p) {
- base::PickleIterator iter = SyncMessage::GetDataIterator(msg);
- return ReadParam(msg, &iter, p);
-}
-
-} // namespace IPC
-
-#endif // IPC_IPC_MESSAGE_UTILS_IMPL_H_