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
|
// 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/task/common/task_annotator.h"
#include "ipc/ipc_message_templates.h"
#include "ipc/ipc_message_utils.h"
#include "ipc/param_traits_macros.h"
#include "ipc/tracing_helpers.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 = \
ipc::GetLegacyIpcTraceId(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
|