diff options
author | mdempsky <mdempsky@chromium.org> | 2016-02-08 21:41:47 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-02-09 05:42:41 +0000 |
commit | 8a5190449d48e06efa581390426dfa3bb6750f4c (patch) | |
tree | 4d0eedc7f5de614a881cd0f2db73721c76398c28 /ipc | |
parent | 022b60ae0d50b45a8252cbdd7c244162e8013380 (diff) | |
download | chromium_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.gn | 3 | ||||
-rw-r--r-- | ipc/export_template.h | 163 | ||||
-rw-r--r-- | ipc/ipc.gypi | 3 | ||||
-rw-r--r-- | ipc/ipc_message_macros.h | 849 | ||||
-rw-r--r-- | ipc/ipc_message_null_macros.h | 4 | ||||
-rw-r--r-- | ipc/ipc_message_templates.h | 210 | ||||
-rw-r--r-- | ipc/ipc_message_templates_impl.h | 110 | ||||
-rw-r--r-- | ipc/ipc_message_utils.h | 107 | ||||
-rw-r--r-- | ipc/ipc_message_utils_impl.h | 51 |
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_ |