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