1 // Copyright 2012 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Defining IPC Messages 6 // 7 // Your IPC messages will be defined by macros inside of an XXX_messages.h 8 // header file. Most of the time, the system can automatically generate all 9 // of messaging mechanism from these definitions, but sometimes some manual 10 // coding is required. In these cases, you will also have an XXX_messages.cc 11 // implementation file as well. 12 // 13 // The senders of your messages will include your XXX_messages.h file to 14 // get the full set of definitions they need to send your messages. 15 // 16 // Each XXX_messages.h file must be registered with the IPC system. This 17 // requires adding two things: 18 // - An XXXMsgStart value to the IPCMessageStart enum in ipc_message_start.h 19 // - An inclusion of XXX_messages.h file in a message generator .h file 20 // 21 // The XXXMsgStart value is an enumeration that ensures uniqueness for 22 // each different message file. Later, you will use this inside your 23 // XXX_messages.h file before invoking message declaration macros: 24 // #define IPC_MESSAGE_START XXXMsgStart 25 // ( ... your macro invocations go here ... ) 26 // 27 // Message Generator Files 28 // 29 // A message generator .h header file pulls in all other message-declaring 30 // headers for a given component. It is included by a message generator 31 // .cc file, which is where all the generated code will wind up. Typically, 32 // you will use an existing generator (e.g. common_message_generator.cc 33 // in /chrome/common), but there are circumstances where you may add a 34 // new one. 35 // 36 // In the rare circumstances where you can't re-use an existing file, 37 // your YYY_message_generator.cc file for a component YYY would contain 38 // the following code: 39 // // Get basic type definitions. 40 // #define IPC_MESSAGE_IMPL 41 // #include "path/to/YYY_message_generator.h" 42 // // Generate constructors. 43 // #include "ipc/struct_constructor_macros.h" 44 // #include "path/to/YYY_message_generator.h" 45 // // Generate param traits write methods. 46 // #include "ipc/param_traits_write_macros.h" 47 // namespace IPC { 48 // #include "path/to/YYY_message_generator.h" 49 // } // namespace IPC 50 // // Generate param traits read methods. 51 // #include "ipc/param_traits_read_macros.h" 52 // namespace IPC { 53 // #include "path/to/YYY_message_generator.h" 54 // } // namespace IPC 55 // // Generate param traits log methods. 56 // #include "ipc/param_traits_log_macros.h" 57 // namespace IPC { 58 // #include "path/to/YYY_message_generator.h" 59 // } // namespace IPC 60 // 61 // In cases where manual generation is required, in your XXX_messages.cc 62 // file, put the following after all the includes for param types: 63 // #define IPC_MESSAGE_IMPL 64 // #include "XXX_messages.h" 65 // (... implementation of traits not auto-generated ...) 66 // 67 // Multiple Inclusion 68 // 69 // The XXX_messages.h file will be multiply-included by the 70 // YYY_message_generator.cc file, so your XXX_messages file can't be 71 // guarded in the usual manner. Ideally, there will be no need for any 72 // inclusion guard, since the XXX_messages.h file should consist solely 73 // of inclusions of other headers (which are self-guarding) and IPC 74 // macros (which are multiply evaluating). 75 // 76 // Note that #pragma once cannot be used here; doing so would mark the whole 77 // file as being singly-included. Since your XXX_messages.h file is only 78 // partially-guarded, care must be taken to ensure that it is only included 79 // by other .cc files (and the YYY_message_generator.h file). Including an 80 // XXX_messages.h file in some other .h file may result in duplicate 81 // declarations and a compilation failure. 82 // 83 // Type Declarations 84 // 85 // It is generally a bad idea to have type definitions in a XXX_messages.h 86 // file; most likely the typedef will then be used in the message, as opposed 87 // to the struct itself. Later, an IPC message dispatcher will need to call 88 // a function taking that type, and that function is declared in some other 89 // header. Thus, in order to get the type definition, the other header 90 // would have to include the XXX_messages.h file, violating the rule above 91 // about not including XXX_messages.h file in other .h files. 92 // 93 // One approach here is to move these type definitions to another (guarded) 94 // .h file and include this second .h in your XXX_messages.h file. This 95 // is still less than ideal, because the dispatched function would have to 96 // redeclare the typedef or include this second header. This may be 97 // reasonable in a few cases. 98 // 99 // Failing all of the above, then you will want to bracket the smallest 100 // possible section of your XXX_messages.h file containing these types 101 // with an include guard macro. Be aware that providing an incomplete 102 // class type declaration to avoid pulling in a long chain of headers is 103 // acceptable when your XXX_messages.h header is being included by the 104 // message sending caller's code, but not when the YYY_message_generator.c 105 // is building the messages. In addition, due to the multiple inclusion 106 // restriction, these type ought to be guarded. Follow a convention like: 107 // #ifndef SOME_GUARD_MACRO 108 // #define SOME_GUARD_MACRO 109 // class some_class; // One incomplete class declaration 110 // class_some_other_class; // Another incomplete class declaration 111 // #endif // SOME_GUARD_MACRO 112 // #ifdef IPC_MESSAGE_IMPL 113 // #include "path/to/some_class.h" // Full class declaration 114 // #include "path/to/some_other_class.h" // Full class declaration 115 // #endif // IPC_MESSAGE_IMPL 116 // (.. IPC macros using some_class and some_other_class ...) 117 // 118 // Macro Invocations 119 // 120 // You will use IPC message macro invocations for three things: 121 // - New struct definitions for IPC 122 // - Registering existing struct and enum definitions with IPC 123 // - Defining the messages themselves 124 // 125 // New structs are defined with IPC_STRUCT_BEGIN(), IPC_STRUCT_MEMBER(), 126 // IPC_STRUCT_END() family of macros. These cause the XXX_messages.h 127 // to proclaim equivalent struct declarations for use by callers, as well 128 // as later registering the type with the message generation. Note that 129 // IPC_STRUCT_MEMBER() is only permitted inside matching calls to 130 // IPC_STRUCT_BEGIN() / IPC_STRUCT_END(). There is also an 131 // IPC_STRUCT_BEGIN_WITH_PARENT(), which behaves like IPC_STRUCT_BEGIN(), 132 // but also accommodates structs that inherit from other structs. 133 // 134 // Externally-defined structs are registered with IPC_STRUCT_TRAITS_BEGIN(), 135 // IPC_STRUCT_TRAITS_MEMBER(), and IPC_STRUCT_TRAITS_END() macros. These 136 // cause registration of the types with message generation only. 137 // There's also IPC_STRUCT_TRAITS_PARENT, which is used to register a parent 138 // class (whose own traits are already defined). Note that 139 // IPC_STRUCT_TRAITS_MEMBER() and IPC_STRUCT_TRAITS_PARENT are only permitted 140 // inside matching calls to IPC_STRUCT_TRAITS_BEGIN() / 141 // IPC_STRUCT_TRAITS_END(). 142 // 143 // Enum types are registered with a single IPC_ENUM_TRAITS_VALIDATE() macro. 144 // There is no need to enumerate each value to the IPC mechanism. Instead, 145 // pass an expression in terms of the parameter |value| to provide 146 // range-checking. For convenience, the IPC_ENUM_TRAITS() is provided which 147 // performs no checking, passing everything including out-of-range values. 148 // Its use is discouraged. The IPC_ENUM_TRAITS_MAX_VALUE() macro can be used 149 // for the typical case where the enum must be in the range 0..maxvalue 150 // inclusive. The IPC_ENUM_TRAITS_MIN_MAX_VALUE() macro can be used for the 151 // less typical case where the enum must be in the range minvalue..maxvalue 152 // inclusive. 153 // 154 // Do not place semicolons following these IPC_ macro invocations. There 155 // is no reason to expect that their expansion corresponds one-to-one with 156 // C++ statements. 157 // 158 // Once the types have been declared / registered, message definitions follow. 159 // "Sync" messages are just synchronous calls, the Send() call doesn't return 160 // until a reply comes back. To declare a sync message, use the IPC_SYNC_ 161 // macros. The numbers at the end show how many input/output parameters there 162 // are (i.e. 1_2 is 1 in, 2 out). Input parameters are first, followed by 163 // output parameters. The caller uses Send([route id, ], in1, &out1, &out2). 164 // The receiver's handler function will be 165 // void OnSyncMessageName(const type1& in1, type2* out1, type3* out2) 166 // 167 // A caller can also send a synchronous message, while the receiver can respond 168 // at a later time. This is transparent from the sender's side. The receiver 169 // needs to use a different handler that takes in a IPC::Message* as the output 170 // type, stash the message, and when it has the data it can Send the message. 171 // 172 // Use the IPC_MESSAGE_HANDLER_DELAY_REPLY macro instead of IPC_MESSAGE_HANDLER 173 // IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_SyncMessageName, 174 // OnSyncMessageName) 175 // Unlike IPC_MESSAGE_HANDLER which works with IPC_BEGIN_MESSAGE_MAP as well as 176 // IPC_BEGIN_MESSAGE_MAP_WITH_PARAM, one needs to use 177 // IPC_MESSAGE_HANDLER_WITH_PARAM_DELAY_REPLY to properly handle the param. 178 // 179 // The handler function will look like: 180 // void OnSyncMessageName(const type1& in1, IPC::Message* reply_msg); 181 // 182 // Receiver stashes the IPC::Message* pointer, and when it's ready, it does: 183 // ViewHostMsg_SyncMessageName::WriteReplyParams(reply_msg, out1, out2); 184 // Send(reply_msg); 185 186 // Files that want to export their ipc messages should do 187 // #undef IPC_MESSAGE_EXPORT 188 // #define IPC_MESSAGE_EXPORT VISIBILITY_MACRO 189 // after including this header, but before using any of the macros below. 190 // (This needs to be before the include guard.) 191 #undef IPC_MESSAGE_EXPORT 192 #define IPC_MESSAGE_EXPORT 193 194 #ifndef IPC_IPC_MESSAGE_MACROS_H_ 195 #define IPC_IPC_MESSAGE_MACROS_H_ 196 197 #include <stdint.h> 198 199 #include <tuple> 200 201 #include "base/export_template.h" 202 #include "base/hash/md5_constexpr.h" 203 #include "base/notreached.h" 204 #include "base/task/common/task_annotator.h" 205 #include "ipc/ipc_message_templates.h" 206 #include "ipc/ipc_message_utils.h" 207 #include "ipc/param_traits_macros.h" 208 209 // Convenience macro for defining structs without inheritance. Should not need 210 // to be subsequently redefined. 211 #define IPC_STRUCT_BEGIN(struct_name) \ 212 IPC_STRUCT_BEGIN_WITH_PARENT(struct_name, IPC::NoParams) 213 214 // Macros for defining structs. Will be subsequently redefined. 215 #define IPC_STRUCT_BEGIN_WITH_PARENT(struct_name, parent) \ 216 struct struct_name; \ 217 IPC_STRUCT_TRAITS_BEGIN(struct_name) \ 218 IPC_STRUCT_TRAITS_END() \ 219 struct IPC_MESSAGE_EXPORT struct_name : parent { \ 220 struct_name(); 221 // Optional variadic parameters specify the default value for this struct 222 // member. They are passed through to the constructor for |type|. 223 #define IPC_STRUCT_MEMBER(type, name, ...) type name; 224 #define IPC_STRUCT_END() }; 225 226 // Message macros collect arguments and funnel them into the common message 227 // generation macro. These should never be redefined. 228 229 // Asynchronous messages have only in parameters and are declared like: 230 // IPC_MESSAGE_CONTROL(FooMsg, int, float) 231 #define IPC_MESSAGE_CONTROL(msg_class, ...) \ 232 IPC_MESSAGE_DECL(msg_class, CONTROL, IPC_TUPLE(__VA_ARGS__), void) 233 #define IPC_MESSAGE_ROUTED(msg_class, ...) \ 234 IPC_MESSAGE_DECL(msg_class, ROUTED, IPC_TUPLE(__VA_ARGS__), void) 235 236 // Synchronous messages have both in and out parameters, so the lists need to 237 // be parenthesized to disambiguate: 238 // IPC_SYNC_MESSAGE_CONTROL(BarMsg, (int, int), (bool)) 239 // 240 // Implementation detail: The parentheses supplied by the caller for 241 // disambiguation are also used to trigger the IPC_TUPLE invocations below, 242 // so "IPC_TUPLE in" and "IPC_TUPLE out" are intentional. 243 #define IPC_SYNC_MESSAGE_CONTROL(msg_class, in, out) \ 244 IPC_MESSAGE_DECL(msg_class, CONTROL, IPC_TUPLE in, IPC_TUPLE out) 245 #define IPC_SYNC_MESSAGE_ROUTED(msg_class, in, out) \ 246 IPC_MESSAGE_DECL(msg_class, ROUTED, IPC_TUPLE in, IPC_TUPLE out) 247 248 #define IPC_TUPLE(...) IPC::CheckedTuple<__VA_ARGS__>::Tuple 249 250 #define IPC_MESSAGE_DECL(msg_name, kind, in_tuple, out_tuple) \ 251 struct IPC_MESSAGE_EXPORT msg_name##_Meta { \ 252 using InTuple = in_tuple; \ 253 using OutTuple = out_tuple; \ 254 enum { ID = IPC_MESSAGE_ID() }; \ 255 static const IPC::MessageKind kKind = IPC::MessageKind::kind; \ 256 static const char kName[]; \ 257 }; \ 258 extern template class EXPORT_TEMPLATE_DECLARE(IPC_MESSAGE_EXPORT) \ 259 IPC::MessageT<msg_name##_Meta>; \ 260 using msg_name = IPC::MessageT<msg_name##_Meta>; \ 261 IPC_MESSAGE_EXTRA(msg_name) 262 263 #if defined(IPC_MESSAGE_IMPL) 264 265 // "Implementation" inclusion provides the explicit template definition 266 // for msg_name. 267 #define IPC_MESSAGE_EXTRA(msg_name) \ 268 const char msg_name##_Meta::kName[] = #msg_name; \ 269 IPC_MESSAGE_DEFINE_KIND(msg_name) \ 270 template class EXPORT_TEMPLATE_DEFINE(IPC_MESSAGE_EXPORT) \ 271 IPC::MessageT<msg_name##_Meta>; 272 273 #define IPC_MESSAGE_DEFINE_KIND(msg_name) \ 274 const IPC::MessageKind msg_name##_Meta::kKind; 275 276 #elif defined(IPC_MESSAGE_MACROS_LOG_ENABLED) 277 278 #ifndef IPC_LOG_TABLE_ADD_ENTRY 279 #error You need to define IPC_LOG_TABLE_ADD_ENTRY(msg_id, logger) 280 #endif 281 282 // "Log table" inclusion produces extra logging registration code. 283 #define IPC_MESSAGE_EXTRA(msg_name) \ 284 class LoggerRegisterHelper##msg_name { \ 285 public: \ 286 LoggerRegisterHelper##msg_name() { \ 287 const uint32_t msg_id = static_cast<uint32_t>(msg_name::ID); \ 288 IPC_LOG_TABLE_ADD_ENTRY(msg_id, msg_name::Log); \ 289 } \ 290 }; \ 291 LoggerRegisterHelper##msg_name g_LoggerRegisterHelper##msg_name; 292 293 #else 294 295 // Normal inclusion produces nothing extra. 296 #define IPC_MESSAGE_EXTRA(msg_name) 297 298 #endif // defined(IPC_MESSAGE_IMPL) 299 300 // Message IDs 301 // Note: we currently use __LINE__ to give unique IDs to messages within 302 // a file. They're globally unique since each file defines its own 303 // IPC_MESSAGE_START. 304 #define IPC_MESSAGE_ID() ((IPC_MESSAGE_START << 16) + __LINE__) 305 #define IPC_MESSAGE_ID_CLASS(id) ((id) >> 16) 306 #define IPC_MESSAGE_ID_LINE(id) ((id) & 0xffff) 307 308 // Message crackers and handlers. Usage: 309 // 310 // bool MyClass::OnMessageReceived(const IPC::Message& msg) { 311 // bool handled = true; 312 // IPC_BEGIN_MESSAGE_MAP(MyClass, msg) 313 // IPC_MESSAGE_HANDLER(MsgClassOne, OnMsgClassOne) 314 // ...more handlers here ... 315 // IPC_MESSAGE_HANDLER(MsgClassTen, OnMsgClassTen) 316 // IPC_MESSAGE_UNHANDLED(handled = false) 317 // IPC_END_MESSAGE_MAP() 318 // return handled; 319 // } 320 321 #define IPC_TASK_ANNOTATOR_STRINGIFY(s) #s 322 323 // A macro to be used from within the IPC_MESSAGE_FORWARD macros, for providing 324 // the IPC message context to the TaskAnnotator. This allows posted tasks to be 325 // associated with the incoming IPC message that caused them to be posted. 326 #define IPC_TASK_ANNOTATOR_CONTEXT(msg_class) \ 327 static constexpr uint32_t kMessageHash = \ 328 base::MD5Hash32Constexpr(IPC_TASK_ANNOTATOR_STRINGIFY(msg_class)); \ 329 base::TaskAnnotator::ScopedSetIpcHash scoped_ipc_hash(kMessageHash); 330 331 #define IPC_BEGIN_MESSAGE_MAP(class_name, msg) \ 332 { \ 333 using _IpcMessageHandlerClass [[maybe_unused]] = class_name; \ 334 [[maybe_unused]] void* param__ = nullptr; \ 335 const IPC::Message& ipc_message__ = msg; \ 336 switch (ipc_message__.type()) { 337 338 #define IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(class_name, msg, param) \ 339 { \ 340 using _IpcMessageHandlerClass [[maybe_unused]] = class_name; \ 341 decltype(param) param__ = param; \ 342 const IPC::Message& ipc_message__ = msg; \ 343 switch (ipc_message__.type()) { 344 345 #define IPC_MESSAGE_FORWARD(msg_class, obj, member_func) \ 346 case msg_class::ID: { \ 347 IPC_TASK_ANNOTATOR_CONTEXT(msg_class) \ 348 if (!msg_class::Dispatch(&ipc_message__, obj, this, param__, \ 349 &member_func)) \ 350 ipc_message__.set_dispatch_error(); \ 351 } break; 352 353 #define IPC_MESSAGE_HANDLER(msg_class, member_func) \ 354 IPC_MESSAGE_FORWARD(msg_class, this, _IpcMessageHandlerClass::member_func) 355 356 #define IPC_MESSAGE_FORWARD_DELAY_REPLY(msg_class, obj, member_func) \ 357 case msg_class::ID: { \ 358 IPC_TASK_ANNOTATOR_CONTEXT(msg_class) \ 359 if (!msg_class::DispatchDelayReply(&ipc_message__, obj, param__, \ 360 &member_func)) \ 361 ipc_message__.set_dispatch_error(); \ 362 } break; 363 364 #define IPC_MESSAGE_HANDLER_DELAY_REPLY(msg_class, member_func) \ 365 IPC_MESSAGE_FORWARD_DELAY_REPLY(msg_class, this, \ 366 _IpcMessageHandlerClass::member_func) 367 368 #define IPC_MESSAGE_FORWARD_WITH_PARAM_DELAY_REPLY(msg_class, obj, \ 369 member_func) \ 370 case msg_class::ID: { \ 371 IPC_TASK_ANNOTATOR_CONTEXT(msg_class) \ 372 if (!msg_class::DispatchWithParamDelayReply(&ipc_message__, obj, \ 373 param__, &member_func)) \ 374 ipc_message__.set_dispatch_error(); \ 375 } break; 376 377 #define IPC_MESSAGE_HANDLER_WITH_PARAM_DELAY_REPLY(msg_class, member_func) \ 378 IPC_MESSAGE_FORWARD_WITH_PARAM_DELAY_REPLY( \ 379 msg_class, this, _IpcMessageHandlerClass::member_func) 380 381 #define IPC_MESSAGE_HANDLER_GENERIC(msg_class, code) \ 382 case msg_class::ID: { \ 383 IPC_TASK_ANNOTATOR_CONTEXT(msg_class) { code; } \ 384 } break; 385 386 #define IPC_REPLY_HANDLER(func) \ 387 case IPC_REPLY_ID: { \ 388 func(ipc_message__); \ 389 } \ 390 break; 391 392 393 #define IPC_MESSAGE_UNHANDLED(code) \ 394 default: { \ 395 code; \ 396 } \ 397 break; 398 399 #define IPC_MESSAGE_UNHANDLED_ERROR() \ 400 IPC_MESSAGE_UNHANDLED(NOTREACHED() << \ 401 "Invalid message with type = " << \ 402 ipc_message__.type()) 403 404 #define IPC_END_MESSAGE_MAP() \ 405 } \ 406 } 407 408 // This corresponds to an enum value from IPCMessageStart. 409 #define IPC_MESSAGE_CLASS(message) IPC_MESSAGE_ID_CLASS((message).type()) 410 411 // Deprecated legacy macro names. 412 // TODO(mdempsky): Replace uses with generic names. 413 414 #define IPC_MESSAGE_CONTROL0(msg) IPC_MESSAGE_CONTROL(msg) 415 #define IPC_MESSAGE_CONTROL1(msg, a) IPC_MESSAGE_CONTROL(msg, a) 416 #define IPC_MESSAGE_CONTROL2(msg, a, b) IPC_MESSAGE_CONTROL(msg, a, b) 417 #define IPC_MESSAGE_CONTROL3(msg, a, b, c) IPC_MESSAGE_CONTROL(msg, a, b, c) 418 #define IPC_MESSAGE_CONTROL4(msg, a, b, c, d) \ 419 IPC_MESSAGE_CONTROL(msg, a, b, c, d) 420 #define IPC_MESSAGE_CONTROL5(msg, a, b, c, d, e) \ 421 IPC_MESSAGE_CONTROL(msg, a, b, c, d, e) 422 423 #define IPC_MESSAGE_ROUTED0(msg) IPC_MESSAGE_ROUTED(msg) 424 #define IPC_MESSAGE_ROUTED1(msg, a) IPC_MESSAGE_ROUTED(msg, a) 425 #define IPC_MESSAGE_ROUTED2(msg, a, b) IPC_MESSAGE_ROUTED(msg, a, b) 426 #define IPC_MESSAGE_ROUTED3(msg, a, b, c) IPC_MESSAGE_ROUTED(msg, a, b, c) 427 #define IPC_MESSAGE_ROUTED4(msg, a, b, c, d) IPC_MESSAGE_ROUTED(msg, a, b, c, d) 428 #define IPC_MESSAGE_ROUTED5(msg, a, b, c, d, e) \ 429 IPC_MESSAGE_ROUTED(msg, a, b, c, d, e) 430 431 #define IPC_SYNC_MESSAGE_CONTROL0_0(msg) IPC_SYNC_MESSAGE_CONTROL(msg, (), ()) 432 #define IPC_SYNC_MESSAGE_CONTROL0_1(msg, a) \ 433 IPC_SYNC_MESSAGE_CONTROL(msg, (), (a)) 434 #define IPC_SYNC_MESSAGE_CONTROL0_2(msg, a, b) \ 435 IPC_SYNC_MESSAGE_CONTROL(msg, (), (a, b)) 436 #define IPC_SYNC_MESSAGE_CONTROL0_3(msg, a, b, c) \ 437 IPC_SYNC_MESSAGE_CONTROL(msg, (), (a, b, c)) 438 #define IPC_SYNC_MESSAGE_CONTROL0_4(msg, a, b, c, d) \ 439 IPC_SYNC_MESSAGE_CONTROL(msg, (), (a, b, c, d)) 440 #define IPC_SYNC_MESSAGE_CONTROL1_0(msg, a) \ 441 IPC_SYNC_MESSAGE_CONTROL(msg, (a), ()) 442 #define IPC_SYNC_MESSAGE_CONTROL1_1(msg, a, b) \ 443 IPC_SYNC_MESSAGE_CONTROL(msg, (a), (b)) 444 #define IPC_SYNC_MESSAGE_CONTROL1_2(msg, a, b, c) \ 445 IPC_SYNC_MESSAGE_CONTROL(msg, (a), (b, c)) 446 #define IPC_SYNC_MESSAGE_CONTROL1_3(msg, a, b, c, d) \ 447 IPC_SYNC_MESSAGE_CONTROL(msg, (a), (b, c, d)) 448 #define IPC_SYNC_MESSAGE_CONTROL1_4(msg, a, b, c, d, e) \ 449 IPC_SYNC_MESSAGE_CONTROL(msg, (a), (b, c, d, e)) 450 #define IPC_SYNC_MESSAGE_CONTROL2_0(msg, a, b) \ 451 IPC_SYNC_MESSAGE_CONTROL(msg, (a, b), ()) 452 #define IPC_SYNC_MESSAGE_CONTROL2_1(msg, a, b, c) \ 453 IPC_SYNC_MESSAGE_CONTROL(msg, (a, b), (c)) 454 #define IPC_SYNC_MESSAGE_CONTROL2_2(msg, a, b, c, d) \ 455 IPC_SYNC_MESSAGE_CONTROL(msg, (a, b), (c, d)) 456 #define IPC_SYNC_MESSAGE_CONTROL2_3(msg, a, b, c, d, e) \ 457 IPC_SYNC_MESSAGE_CONTROL(msg, (a, b), (c, d, e)) 458 #define IPC_SYNC_MESSAGE_CONTROL2_4(msg, a, b, c, d, e, f) \ 459 IPC_SYNC_MESSAGE_CONTROL(msg, (a, b), (c, d, e, f)) 460 #define IPC_SYNC_MESSAGE_CONTROL3_0(msg, a, b, c) \ 461 IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c), ()) 462 #define IPC_SYNC_MESSAGE_CONTROL3_1(msg, a, b, c, d) \ 463 IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c), (d)) 464 #define IPC_SYNC_MESSAGE_CONTROL3_2(msg, a, b, c, d, e) \ 465 IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c), (d, e)) 466 #define IPC_SYNC_MESSAGE_CONTROL3_3(msg, a, b, c, d, e, f) \ 467 IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c), (d, e, f)) 468 #define IPC_SYNC_MESSAGE_CONTROL3_4(msg, a, b, c, d, e, f, g) \ 469 IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c), (d, e, f, g)) 470 #define IPC_SYNC_MESSAGE_CONTROL4_0(msg, a, b, c, d) \ 471 IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d), ()) 472 #define IPC_SYNC_MESSAGE_CONTROL4_1(msg, a, b, c, d, e) \ 473 IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d), (e)) 474 #define IPC_SYNC_MESSAGE_CONTROL4_2(msg, a, b, c, d, e, f) \ 475 IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d), (e, f)) 476 #define IPC_SYNC_MESSAGE_CONTROL4_3(msg, a, b, c, d, e, f, g) \ 477 IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d), (e, f, g)) 478 #define IPC_SYNC_MESSAGE_CONTROL4_4(msg, a, b, c, d, e, f, g, h) \ 479 IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d), (e, f, g, h)) 480 #define IPC_SYNC_MESSAGE_CONTROL5_0(msg, a, b, c, d, e) \ 481 IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d, e), ()) 482 #define IPC_SYNC_MESSAGE_CONTROL5_1(msg, a, b, c, d, e, f) \ 483 IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d, e), (f)) 484 #define IPC_SYNC_MESSAGE_CONTROL5_2(msg, a, b, c, d, e, f, g) \ 485 IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d, e), (f, g)) 486 #define IPC_SYNC_MESSAGE_CONTROL5_3(msg, a, b, c, d, e, f, g, h) \ 487 IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d, e), (f, g, h)) 488 #define IPC_SYNC_MESSAGE_CONTROL5_4(msg, a, b, c, d, e, f, g, h, i) \ 489 IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d, e), (f, g, h, i)) 490 491 #define IPC_SYNC_MESSAGE_ROUTED0_0(msg) IPC_SYNC_MESSAGE_ROUTED(msg, (), ()) 492 #define IPC_SYNC_MESSAGE_ROUTED0_1(msg, a) IPC_SYNC_MESSAGE_ROUTED(msg, (), (a)) 493 #define IPC_SYNC_MESSAGE_ROUTED0_2(msg, a, b) \ 494 IPC_SYNC_MESSAGE_ROUTED(msg, (), (a, b)) 495 #define IPC_SYNC_MESSAGE_ROUTED0_3(msg, a, b, c) \ 496 IPC_SYNC_MESSAGE_ROUTED(msg, (), (a, b, c)) 497 #define IPC_SYNC_MESSAGE_ROUTED0_4(msg, a, b, c, d) \ 498 IPC_SYNC_MESSAGE_ROUTED(msg, (), (a, b, c, d)) 499 #define IPC_SYNC_MESSAGE_ROUTED1_0(msg, a) IPC_SYNC_MESSAGE_ROUTED(msg, (a), ()) 500 #define IPC_SYNC_MESSAGE_ROUTED1_1(msg, a, b) \ 501 IPC_SYNC_MESSAGE_ROUTED(msg, (a), (b)) 502 #define IPC_SYNC_MESSAGE_ROUTED1_2(msg, a, b, c) \ 503 IPC_SYNC_MESSAGE_ROUTED(msg, (a), (b, c)) 504 #define IPC_SYNC_MESSAGE_ROUTED1_3(msg, a, b, c, d) \ 505 IPC_SYNC_MESSAGE_ROUTED(msg, (a), (b, c, d)) 506 #define IPC_SYNC_MESSAGE_ROUTED1_4(msg, a, b, c, d, e) \ 507 IPC_SYNC_MESSAGE_ROUTED(msg, (a), (b, c, d, e)) 508 #define IPC_SYNC_MESSAGE_ROUTED2_0(msg, a, b) \ 509 IPC_SYNC_MESSAGE_ROUTED(msg, (a, b), ()) 510 #define IPC_SYNC_MESSAGE_ROUTED2_1(msg, a, b, c) \ 511 IPC_SYNC_MESSAGE_ROUTED(msg, (a, b), (c)) 512 #define IPC_SYNC_MESSAGE_ROUTED2_2(msg, a, b, c, d) \ 513 IPC_SYNC_MESSAGE_ROUTED(msg, (a, b), (c, d)) 514 #define IPC_SYNC_MESSAGE_ROUTED2_3(msg, a, b, c, d, e) \ 515 IPC_SYNC_MESSAGE_ROUTED(msg, (a, b), (c, d, e)) 516 #define IPC_SYNC_MESSAGE_ROUTED2_4(msg, a, b, c, d, e, f) \ 517 IPC_SYNC_MESSAGE_ROUTED(msg, (a, b), (c, d, e, f)) 518 #define IPC_SYNC_MESSAGE_ROUTED3_0(msg, a, b, c) \ 519 IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c), ()) 520 #define IPC_SYNC_MESSAGE_ROUTED3_1(msg, a, b, c, d) \ 521 IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c), (d)) 522 #define IPC_SYNC_MESSAGE_ROUTED3_2(msg, a, b, c, d, e) \ 523 IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c), (d, e)) 524 #define IPC_SYNC_MESSAGE_ROUTED3_3(msg, a, b, c, d, e, f) \ 525 IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c), (d, e, f)) 526 #define IPC_SYNC_MESSAGE_ROUTED3_4(msg, a, b, c, d, e, f, g) \ 527 IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c), (d, e, f, g)) 528 #define IPC_SYNC_MESSAGE_ROUTED3_5(msg, a, b, c, d, e, f, g, h) \ 529 IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c), (d, e, f, g, h)) 530 #define IPC_SYNC_MESSAGE_ROUTED4_0(msg, a, b, c, d) \ 531 IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d), ()) 532 #define IPC_SYNC_MESSAGE_ROUTED4_1(msg, a, b, c, d, e) \ 533 IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d), (e)) 534 #define IPC_SYNC_MESSAGE_ROUTED4_2(msg, a, b, c, d, e, f) \ 535 IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d), (e, f)) 536 #define IPC_SYNC_MESSAGE_ROUTED4_3(msg, a, b, c, d, e, f, g) \ 537 IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d), (e, f, g)) 538 #define IPC_SYNC_MESSAGE_ROUTED4_4(msg, a, b, c, d, e, f, g, h) \ 539 IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d), (e, f, g, h)) 540 #define IPC_SYNC_MESSAGE_ROUTED5_0(msg, a, b, c, d, e) \ 541 IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d, e), ()) 542 #define IPC_SYNC_MESSAGE_ROUTED5_1(msg, a, b, c, d, e, f) \ 543 IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d, e), (f)) 544 #define IPC_SYNC_MESSAGE_ROUTED5_2(msg, a, b, c, d, e, f, g) \ 545 IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d, e), (f, g)) 546 #define IPC_SYNC_MESSAGE_ROUTED5_3(msg, a, b, c, d, e, f, g, h) \ 547 IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d, e), (f, g, h)) 548 #define IPC_SYNC_MESSAGE_ROUTED5_4(msg, a, b, c, d, e, f, g, h, i) \ 549 IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d, e), (f, g, h, i)) 550 551 #endif // IPC_IPC_MESSAGE_MACROS_H_ 552 553 // Clean up IPC_MESSAGE_START in this unguarded section so that the 554 // XXX_messages.h files need not do so themselves. This makes the 555 // XXX_messages.h files easier to write. 556 #undef IPC_MESSAGE_START 557