1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275
  276
  277
  278
  279
  280
  281
  282
  283
  284
  285
  286
  287
  288
  289
  290
  291
  292
  293
  294
  295
  296
  297
  298
  299
  300
  301
  302
  303
  304
  305
  306
  307
  308
  309
  310
  311
  312
  313
  314
  315
  316
  317
  318
  319
  320
  321
  322
  323
  324
  325
  326
  327
  328
  329
  330
  331
  332
  333
  334
  335
  336
  337
  338
  339
  340
  341
  342
  343
  344
  345
  346
  347
  348
  349
  350
  351
  352
  353
  354
  355
  356
  357
  358
  359
  360
  361
  362
  363
  364
  365
  366
  367
  368
  369
  370
  371
  372
  373
  374
  375
  376
  377
  378
  379
  380
  381
  382
  383
  384
  385
  386
  387
  388
  389
  390
  391
  392
  393
  394
  395
  396
  397
  398
  399
  400
  401
  402
  403
  404
  405
  406
  407
  408
  409
  410
  411
  412
  413
  414
  415
  416
  417
  418
  419
  420
  421
  422
  423
  424
  425
  426
  427
  428
  429
  430
  431
  432
  433
  434
  435
  436
  437
  438
  439
  440
  441
  442
  443
  444
  445
  446
  447
  448
  449
  450
  451
  452
  453
  454
  455
  456
  457
  458
  459
  460
  461
  462
  463
  464
  465
  466
  467
  468
  469
  470
  471
  472
  473
  474
  475
  476
  477
  478
  479
  480
  481
  482
  483
  484
  485
  486
  487
  488
  489
  490
  491
  492
  493
  494
  495
  496
  497
  498
  499
  500
  501
  502
  503
  504
  505
  506
  507
  508
  509
  510
  511
  512
  513
  514
  515
  516
  517
  518
  519
  520
  521
  522
  523
  524
  525
  526
  527
  528
  529
  530
  531
  532
  533
  534
  535
  536
  537
  538
  539
  540
  541
  542
  543
  544
  545
  546
  547
  548
  549
  550
  551

ipc / ipc_message_macros.h [blame]

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Defining IPC Messages
//
// Your IPC messages will be defined by macros inside of an XXX_messages.h
// header file.  Most of the time, the system can automatically generate all
// of messaging mechanism from these definitions, but sometimes some manual
// coding is required.  In these cases, you will also have an XXX_messages.cc
// implementation file as well.
//
// The senders of your messages will include your XXX_messages.h file to
// get the full set of definitions they need to send your messages.
//
// Each XXX_messages.h file must be registered with the IPC system.  This
// requires adding two things:
//   - An XXXMsgStart value to the IPCMessageStart enum in ipc_message_start.h
//   - An inclusion of XXX_messages.h file in a message generator .h file
//
// The XXXMsgStart value is an enumeration that ensures uniqueness for
// each different message file.  Later, you will use this inside your
// XXX_messages.h file before invoking message declaration macros:
//     #define IPC_MESSAGE_START XXXMsgStart
//       ( ... your macro invocations go here ... )
//
// Message Generator Files
//
// A message generator .h header file pulls in all other message-declaring
// headers for a given component.  It is included by a message generator
// .cc file, which is where all the generated code will wind up.  Typically,
// you will use an existing generator (e.g. common_message_generator.cc
// in /chrome/common), but there are circumstances where you may add a
// new one.
//
// In the rare circumstances where you can't re-use an existing file,
// your YYY_message_generator.cc file for a component YYY would contain
// the following code:
//     // Get basic type definitions.
//     #define IPC_MESSAGE_IMPL
//     #include "path/to/YYY_message_generator.h"
//     // Generate constructors.
//     #include "ipc/struct_constructor_macros.h"
//     #include "path/to/YYY_message_generator.h"
//     // Generate param traits write methods.
//     #include "ipc/param_traits_write_macros.h"
//     namespace IPC {
//     #include "path/to/YYY_message_generator.h"
//     }  // namespace IPC
//     // Generate param traits read methods.
//     #include "ipc/param_traits_read_macros.h"
//     namespace IPC {
//     #include "path/to/YYY_message_generator.h"
//     }  // namespace IPC
//     // Generate param traits log methods.
//     #include "ipc/param_traits_log_macros.h"
//     namespace IPC {
//     #include "path/to/YYY_message_generator.h"
//     }  // namespace IPC
//
// In cases where manual generation is required, in your XXX_messages.cc
// file, put the following after all the includes for param types:
//     #define IPC_MESSAGE_IMPL
//     #include "XXX_messages.h"
//        (... implementation of traits not auto-generated ...)
//
// Multiple Inclusion
//
// The XXX_messages.h file will be multiply-included by the
// YYY_message_generator.cc file, so your XXX_messages file can't be
// guarded in the usual manner.  Ideally, there will be no need for any
// inclusion guard, since the XXX_messages.h file should consist solely
// of inclusions of other headers (which are self-guarding) and IPC
// macros (which are multiply evaluating).
//
// Note that #pragma once cannot be used here; doing so would mark the whole
// file as being singly-included.  Since your XXX_messages.h file is only
// partially-guarded, care must be taken to ensure that it is only included
// by other .cc files (and the YYY_message_generator.h file).  Including an
// XXX_messages.h file in some other .h file may result in duplicate
// declarations and a compilation failure.
//
// Type Declarations
//
// It is generally a bad idea to have type definitions in a XXX_messages.h
// file; most likely the typedef will then be used in the message, as opposed
// to the struct itself.  Later, an IPC message dispatcher will need to call
// a function taking that type, and that function is declared in some other
// header.  Thus, in order to get the type definition, the other header
// would have to include the XXX_messages.h file, violating the rule above
// about not including XXX_messages.h file in other .h files.
//
// One approach here is to move these type definitions to another (guarded)
// .h file and include this second .h in your XXX_messages.h file.  This
// is still less than ideal, because the dispatched function would have to
// redeclare the typedef or include this second header.  This may be
// reasonable in a few cases.
//
// Failing all of the above, then you will want to bracket the smallest
// possible section of your XXX_messages.h file containing these types
// with an include guard macro.  Be aware that providing an incomplete
// class type declaration to avoid pulling in a long chain of headers is
// acceptable when your XXX_messages.h header is being included by the
// message sending caller's code, but not when the YYY_message_generator.c
// is building the messages. In addition, due to the multiple inclusion
// restriction, these type ought to be guarded.  Follow a convention like:
//      #ifndef SOME_GUARD_MACRO
//      #define SOME_GUARD_MACRO
//      class some_class;        // One incomplete class declaration
//      class_some_other_class;  // Another incomplete class declaration
//      #endif  // SOME_GUARD_MACRO
//      #ifdef IPC_MESSAGE_IMPL
//      #include "path/to/some_class.h"        // Full class declaration
//      #include "path/to/some_other_class.h"  // Full class declaration
//      #endif  // IPC_MESSAGE_IMPL
//        (.. IPC macros using some_class and some_other_class ...)
//
// Macro Invocations
//
// You will use IPC message macro invocations for three things:
//   - New struct definitions for IPC
//   - Registering existing struct and enum definitions with IPC
//   - Defining the messages themselves
//
// New structs are defined with IPC_STRUCT_BEGIN(), IPC_STRUCT_MEMBER(),
// IPC_STRUCT_END() family of macros.  These cause the XXX_messages.h
// to proclaim equivalent struct declarations for use by callers, as well
// as later registering the type with the message generation.  Note that
// IPC_STRUCT_MEMBER() is only permitted inside matching calls to
// IPC_STRUCT_BEGIN() / IPC_STRUCT_END(). There is also an
// IPC_STRUCT_BEGIN_WITH_PARENT(), which behaves like IPC_STRUCT_BEGIN(),
// but also accommodates structs that inherit from other structs.
//
// Externally-defined structs are registered with IPC_STRUCT_TRAITS_BEGIN(),
// IPC_STRUCT_TRAITS_MEMBER(), and IPC_STRUCT_TRAITS_END() macros. These
// cause registration of the types with message generation only.
// There's also IPC_STRUCT_TRAITS_PARENT, which is used to register a parent
// class (whose own traits are already defined). Note that
// IPC_STRUCT_TRAITS_MEMBER() and IPC_STRUCT_TRAITS_PARENT are only permitted
// inside matching calls to IPC_STRUCT_TRAITS_BEGIN() /
// IPC_STRUCT_TRAITS_END().
//
// Enum types are registered with a single IPC_ENUM_TRAITS_VALIDATE() macro.
// There is no need to enumerate each value to the IPC mechanism. Instead,
// pass an expression in terms of the parameter |value| to provide
// range-checking.  For convenience, the IPC_ENUM_TRAITS() is provided which
// performs no checking, passing everything including out-of-range values.
// Its use is discouraged. The IPC_ENUM_TRAITS_MAX_VALUE() macro can be used
// for the typical case where the enum must be in the range 0..maxvalue
// inclusive. The IPC_ENUM_TRAITS_MIN_MAX_VALUE() macro can be used for the
// less typical case where the enum must be in the range minvalue..maxvalue
// inclusive.
//
// Do not place semicolons following these IPC_ macro invocations.  There
// is no reason to expect that their expansion corresponds one-to-one with
// C++ statements.
//
// Once the types have been declared / registered, message definitions follow.
// "Sync" messages are just synchronous calls, the Send() call doesn't return
// until a reply comes back.  To declare a sync message, use the IPC_SYNC_
// macros.  The numbers at the end show how many input/output parameters there
// are (i.e. 1_2 is 1 in, 2 out).  Input parameters are first, followed by
// output parameters.  The caller uses Send([route id, ], in1, &out1, &out2).
// The receiver's handler function will be
//     void OnSyncMessageName(const type1& in1, type2* out1, type3* out2)
//
// A caller can also send a synchronous message, while the receiver can respond
// at a later time.  This is transparent from the sender's side.  The receiver
// needs to use a different handler that takes in a IPC::Message* as the output
// type, stash the message, and when it has the data it can Send the message.
//
// Use the IPC_MESSAGE_HANDLER_DELAY_REPLY macro instead of IPC_MESSAGE_HANDLER
//     IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_SyncMessageName,
//                                     OnSyncMessageName)
// Unlike IPC_MESSAGE_HANDLER which works with IPC_BEGIN_MESSAGE_MAP as well as
// IPC_BEGIN_MESSAGE_MAP_WITH_PARAM, one needs to use
// IPC_MESSAGE_HANDLER_WITH_PARAM_DELAY_REPLY to properly handle the param.
//
// The handler function will look like:
//     void OnSyncMessageName(const type1& in1, IPC::Message* reply_msg);
//
// Receiver stashes the IPC::Message* pointer, and when it's ready, it does:
//     ViewHostMsg_SyncMessageName::WriteReplyParams(reply_msg, out1, out2);
//     Send(reply_msg);

// Files that want to export their ipc messages should do
//   #undef IPC_MESSAGE_EXPORT
//   #define IPC_MESSAGE_EXPORT VISIBILITY_MACRO
// after including this header, but before using any of the macros below.
// (This needs to be before the include guard.)
#undef IPC_MESSAGE_EXPORT
#define IPC_MESSAGE_EXPORT

#ifndef IPC_IPC_MESSAGE_MACROS_H_
#define IPC_IPC_MESSAGE_MACROS_H_

#include <stdint.h>

#include <tuple>

#include "base/export_template.h"
#include "base/hash/md5_constexpr.h"
#include "base/notreached.h"
#include "base/task/common/task_annotator.h"
#include "ipc/ipc_message_templates.h"
#include "ipc/ipc_message_utils.h"
#include "ipc/param_traits_macros.h"

// Convenience macro for defining structs without inheritance. Should not need
// to be subsequently redefined.
#define IPC_STRUCT_BEGIN(struct_name) \
  IPC_STRUCT_BEGIN_WITH_PARENT(struct_name, IPC::NoParams)

// Macros for defining structs. Will be subsequently redefined.
#define IPC_STRUCT_BEGIN_WITH_PARENT(struct_name, parent) \
  struct struct_name; \
  IPC_STRUCT_TRAITS_BEGIN(struct_name) \
  IPC_STRUCT_TRAITS_END() \
  struct IPC_MESSAGE_EXPORT struct_name : parent { \
    struct_name();
// Optional variadic parameters specify the default value for this struct
// member. They are passed through to the constructor for |type|.
#define IPC_STRUCT_MEMBER(type, name, ...) type name;
#define IPC_STRUCT_END() };

// Message macros collect arguments and funnel them into the common message
// generation macro.  These should never be redefined.

// 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)

// 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(...) IPC::CheckedTuple<__VA_ARGS__>::Tuple

#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 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>;

#define IPC_MESSAGE_DEFINE_KIND(msg_name) \
  const IPC::MessageKind msg_name##_Meta::kKind;

#elif defined(IPC_MESSAGE_MACROS_LOG_ENABLED)

#ifndef IPC_LOG_TABLE_ADD_ENTRY
#error You need to define IPC_LOG_TABLE_ADD_ENTRY(msg_id, logger)
#endif

// "Log table" inclusion produces extra logging registration code.
#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(msg_name)

#endif  // defined(IPC_MESSAGE_IMPL)

// Message IDs
// Note: we currently use __LINE__ to give unique IDs to messages within
// a file.  They're globally unique since each file defines its own
// IPC_MESSAGE_START.
#define IPC_MESSAGE_ID() ((IPC_MESSAGE_START << 16) + __LINE__)
#define IPC_MESSAGE_ID_CLASS(id) ((id) >> 16)
#define IPC_MESSAGE_ID_LINE(id) ((id) & 0xffff)

// Message crackers and handlers. Usage:
//
//   bool MyClass::OnMessageReceived(const IPC::Message& msg) {
//     bool handled = true;
//     IPC_BEGIN_MESSAGE_MAP(MyClass, msg)
//       IPC_MESSAGE_HANDLER(MsgClassOne, OnMsgClassOne)
//       ...more handlers here ...
//       IPC_MESSAGE_HANDLER(MsgClassTen, OnMsgClassTen)
//       IPC_MESSAGE_UNHANDLED(handled = false)
//     IPC_END_MESSAGE_MAP()
//     return handled;
//   }

#define IPC_TASK_ANNOTATOR_STRINGIFY(s) #s

// A macro to be used from within the IPC_MESSAGE_FORWARD macros, for providing
// the IPC message context to the TaskAnnotator. This allows posted tasks to be
// associated with the incoming IPC message that caused them to be posted.
#define IPC_TASK_ANNOTATOR_CONTEXT(msg_class)                            \
  static constexpr uint32_t kMessageHash =                               \
      base::MD5Hash32Constexpr(IPC_TASK_ANNOTATOR_STRINGIFY(msg_class)); \
  base::TaskAnnotator::ScopedSetIpcHash scoped_ipc_hash(kMessageHash);

#define IPC_BEGIN_MESSAGE_MAP(class_name, msg)                   \
  {                                                              \
    using _IpcMessageHandlerClass [[maybe_unused]] = class_name; \
    [[maybe_unused]] void* param__ = nullptr;                    \
    const IPC::Message& ipc_message__ = msg;                     \
    switch (ipc_message__.type()) {

#define IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(class_name, msg, param) \
  {                                                              \
    using _IpcMessageHandlerClass [[maybe_unused]] = class_name; \
    decltype(param) param__ = param;                             \
    const IPC::Message& ipc_message__ = msg;                     \
    switch (ipc_message__.type()) {

#define IPC_MESSAGE_FORWARD(msg_class, obj, member_func)         \
  case msg_class::ID: {                                          \
    IPC_TASK_ANNOTATOR_CONTEXT(msg_class)                        \
    if (!msg_class::Dispatch(&ipc_message__, obj, this, param__, \
                             &member_func))                      \
      ipc_message__.set_dispatch_error();                        \
  } break;

#define IPC_MESSAGE_HANDLER(msg_class, member_func) \
  IPC_MESSAGE_FORWARD(msg_class, this, _IpcMessageHandlerClass::member_func)

#define IPC_MESSAGE_FORWARD_DELAY_REPLY(msg_class, obj, member_func) \
  case msg_class::ID: {                                              \
    IPC_TASK_ANNOTATOR_CONTEXT(msg_class)                            \
    if (!msg_class::DispatchDelayReply(&ipc_message__, obj, param__, \
                                       &member_func))                \
      ipc_message__.set_dispatch_error();                            \
  } break;

#define IPC_MESSAGE_HANDLER_DELAY_REPLY(msg_class, member_func)                \
    IPC_MESSAGE_FORWARD_DELAY_REPLY(msg_class, this,                           \
                                    _IpcMessageHandlerClass::member_func)

#define IPC_MESSAGE_FORWARD_WITH_PARAM_DELAY_REPLY(msg_class, obj,         \
                                                   member_func)            \
  case msg_class::ID: {                                                    \
    IPC_TASK_ANNOTATOR_CONTEXT(msg_class)                                  \
    if (!msg_class::DispatchWithParamDelayReply(&ipc_message__, obj,       \
                                                param__, &member_func))    \
      ipc_message__.set_dispatch_error();                                  \
  } break;

#define IPC_MESSAGE_HANDLER_WITH_PARAM_DELAY_REPLY(msg_class, member_func)     \
    IPC_MESSAGE_FORWARD_WITH_PARAM_DELAY_REPLY(                                \
        msg_class, this, _IpcMessageHandlerClass::member_func)

#define IPC_MESSAGE_HANDLER_GENERIC(msg_class, code) \
  case msg_class::ID: {                              \
    IPC_TASK_ANNOTATOR_CONTEXT(msg_class) { code; }  \
  } break;

#define IPC_REPLY_HANDLER(func)                                                \
    case IPC_REPLY_ID: {                                                       \
        func(ipc_message__);                                                   \
      }                                                                        \
      break;


#define IPC_MESSAGE_UNHANDLED(code)                                            \
    default: {                                                                 \
        code;                                                                  \
      }                                                                        \
      break;

#define IPC_END_MESSAGE_MAP() \
  } \
}

// This corresponds to an enum value from IPCMessageStart.
#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_ROUTED3_5(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_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
// XXX_messages.h files need not do so themselves.  This makes the
// XXX_messages.h files easier to write.
#undef IPC_MESSAGE_START