mdempsky | fba51c1 | 2016-02-09 14:41:47 +0900 | [diff] [blame] | 1 | // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef IPC_IPC_MESSAGE_TEMPLATES_H_ |
| 6 | #define IPC_IPC_MESSAGE_TEMPLATES_H_ |
| 7 | |
| 8 | #include <stdint.h> |
| 9 | |
tzik | a088e35 | 2016-03-08 14:47:44 +0900 | [diff] [blame] | 10 | #include <tuple> |
mdempsky | fba51c1 | 2016-02-09 14:41:47 +0900 | [diff] [blame] | 11 | #include <type_traits> |
| 12 | |
| 13 | #include "base/logging.h" |
ssid | 49c4822 | 2016-03-29 04:56:49 +0900 | [diff] [blame^] | 14 | #include "base/trace_event/trace_event.h" |
mdempsky | fba51c1 | 2016-02-09 14:41:47 +0900 | [diff] [blame] | 15 | #include "base/tuple.h" |
| 16 | #include "build/build_config.h" |
| 17 | #include "ipc/ipc_message.h" |
| 18 | #include "ipc/ipc_message_utils.h" |
| 19 | |
| 20 | namespace IPC { |
| 21 | |
| 22 | // This function is for all the async IPCs that don't pass an extra parameter |
| 23 | // using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM. |
| 24 | template <typename ObjT, typename Method, typename P, typename Tuple> |
| 25 | void DispatchToMethod(ObjT* obj, Method method, P*, const Tuple& tuple) { |
| 26 | base::DispatchToMethod(obj, method, tuple); |
| 27 | } |
| 28 | |
| 29 | template <typename ObjT, |
| 30 | typename Method, |
| 31 | typename P, |
| 32 | typename Tuple, |
| 33 | size_t... Ns> |
| 34 | void DispatchToMethodImpl(ObjT* obj, |
| 35 | Method method, |
| 36 | P* parameter, |
| 37 | const Tuple& tuple, |
| 38 | base::IndexSequence<Ns...>) { |
| 39 | // TODO(mdempsky): Apply UnwrapTraits like base::DispatchToMethod? |
tzik | a088e35 | 2016-03-08 14:47:44 +0900 | [diff] [blame] | 40 | (obj->*method)(parameter, std::get<Ns>(tuple)...); |
mdempsky | fba51c1 | 2016-02-09 14:41:47 +0900 | [diff] [blame] | 41 | } |
| 42 | |
| 43 | // The following function is for async IPCs which have a dispatcher with an |
| 44 | // extra parameter specified using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM. |
| 45 | template <typename ObjT, typename P, typename... Args, typename... Ts> |
| 46 | typename std::enable_if<sizeof...(Args) == sizeof...(Ts)>::type |
| 47 | DispatchToMethod(ObjT* obj, |
| 48 | void (ObjT::*method)(P*, Args...), |
| 49 | P* parameter, |
tzik | a088e35 | 2016-03-08 14:47:44 +0900 | [diff] [blame] | 50 | const std::tuple<Ts...>& tuple) { |
mdempsky | fba51c1 | 2016-02-09 14:41:47 +0900 | [diff] [blame] | 51 | DispatchToMethodImpl(obj, method, parameter, tuple, |
| 52 | base::MakeIndexSequence<sizeof...(Ts)>()); |
| 53 | } |
| 54 | |
| 55 | enum class MessageKind { |
| 56 | CONTROL, |
| 57 | ROUTED, |
| 58 | }; |
| 59 | |
| 60 | // Routing is a helper struct so MessageT's private common constructor has a |
| 61 | // different type signature than the public "int32_t routing_id" one. |
| 62 | struct Routing { |
| 63 | explicit Routing(int32_t id) : id(id) {} |
| 64 | int32_t id; |
| 65 | }; |
| 66 | |
| 67 | // We want to restrict MessageT's constructors so that a routing_id is always |
| 68 | // provided for ROUTED messages and never provided for CONTROL messages, so |
| 69 | // use the SFINAE technique from N4387's "Implementation Hint" section. |
| 70 | #if defined(COMPILER_MSVC) |
| 71 | // MSVC 2013 doesn't support default arguments for template member functions |
| 72 | // of templated classes, so there we have to rely on the DCHECKs instead. |
| 73 | // TODO(mdempsky): Reevaluate once MSVC 2015. |
| 74 | #define IPC_MESSAGET_SFINAE(x) |
| 75 | #else |
| 76 | #define IPC_MESSAGET_SFINAE(x) \ |
| 77 | template <bool X = (x), typename std::enable_if<X, bool>::type = false> |
| 78 | #endif |
| 79 | |
| 80 | // MessageT is the common template used for all user-defined message types. |
| 81 | // It's intended to be used via the macros defined in ipc_message_macros.h. |
| 82 | template <typename Meta, |
| 83 | typename InTuple = typename Meta::InTuple, |
| 84 | typename OutTuple = typename Meta::OutTuple> |
| 85 | class MessageT; |
| 86 | |
| 87 | // Asynchronous message partial specialization. |
| 88 | template <typename Meta, typename... Ins> |
tzik | a088e35 | 2016-03-08 14:47:44 +0900 | [diff] [blame] | 89 | class MessageT<Meta, std::tuple<Ins...>, void> : public Message { |
mdempsky | fba51c1 | 2016-02-09 14:41:47 +0900 | [diff] [blame] | 90 | public: |
tzik | a088e35 | 2016-03-08 14:47:44 +0900 | [diff] [blame] | 91 | using Param = std::tuple<Ins...>; |
mdempsky | fba51c1 | 2016-02-09 14:41:47 +0900 | [diff] [blame] | 92 | enum { ID = Meta::ID }; |
| 93 | |
| 94 | // TODO(mdempsky): Remove. Uses of MyMessage::Schema::Param can be replaced |
| 95 | // with just MyMessage::Param. |
| 96 | using Schema = MessageT; |
| 97 | |
| 98 | IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL) |
| 99 | MessageT(const Ins&... ins) : MessageT(Routing(MSG_ROUTING_CONTROL), ins...) { |
| 100 | DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName; |
| 101 | } |
| 102 | |
| 103 | IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED) |
| 104 | MessageT(int32_t routing_id, const Ins&... ins) |
| 105 | : MessageT(Routing(routing_id), ins...) { |
| 106 | DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName; |
| 107 | } |
| 108 | |
| 109 | static bool Read(const Message* msg, Param* p); |
| 110 | static void Log(std::string* name, const Message* msg, std::string* l); |
| 111 | |
| 112 | template <class T, class S, class P, class Method> |
| 113 | static bool Dispatch(const Message* msg, |
| 114 | T* obj, |
| 115 | S* sender, |
| 116 | P* parameter, |
| 117 | Method func) { |
ssid | 49c4822 | 2016-03-29 04:56:49 +0900 | [diff] [blame^] | 118 | TRACE_EVENT0("ipc", Meta::kName); |
mdempsky | fba51c1 | 2016-02-09 14:41:47 +0900 | [diff] [blame] | 119 | Param p; |
| 120 | if (Read(msg, &p)) { |
| 121 | DispatchToMethod(obj, func, parameter, p); |
| 122 | return true; |
| 123 | } |
| 124 | return false; |
| 125 | } |
| 126 | |
| 127 | private: |
| 128 | MessageT(Routing routing, const Ins&... ins); |
| 129 | }; |
| 130 | |
| 131 | // Synchronous message partial specialization. |
| 132 | template <typename Meta, typename... Ins, typename... Outs> |
tzik | a088e35 | 2016-03-08 14:47:44 +0900 | [diff] [blame] | 133 | class MessageT<Meta, std::tuple<Ins...>, std::tuple<Outs...>> |
mdempsky | fba51c1 | 2016-02-09 14:41:47 +0900 | [diff] [blame] | 134 | : public SyncMessage { |
| 135 | public: |
tzik | a088e35 | 2016-03-08 14:47:44 +0900 | [diff] [blame] | 136 | using SendParam = std::tuple<Ins...>; |
| 137 | using ReplyParam = std::tuple<Outs...>; |
mdempsky | fba51c1 | 2016-02-09 14:41:47 +0900 | [diff] [blame] | 138 | enum { ID = Meta::ID }; |
| 139 | |
| 140 | // TODO(mdempsky): Remove. Uses of MyMessage::Schema::{Send,Reply}Param can |
| 141 | // be replaced with just MyMessage::{Send,Reply}Param. |
| 142 | using Schema = MessageT; |
| 143 | |
| 144 | IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL) |
| 145 | MessageT(const Ins&... ins, Outs*... outs) |
| 146 | : MessageT(Routing(MSG_ROUTING_CONTROL), ins..., outs...) { |
| 147 | DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName; |
| 148 | } |
| 149 | |
| 150 | IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED) |
| 151 | MessageT(int32_t routing_id, const Ins&... ins, Outs*... outs) |
| 152 | : MessageT(Routing(routing_id), ins..., outs...) { |
| 153 | DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName; |
| 154 | } |
| 155 | |
| 156 | static bool ReadSendParam(const Message* msg, SendParam* p); |
| 157 | static bool ReadReplyParam(const Message* msg, ReplyParam* p); |
| 158 | static void WriteReplyParams(Message* reply, const Outs&... outs); |
| 159 | static void Log(std::string* name, const Message* msg, std::string* l); |
| 160 | |
| 161 | template <class T, class S, class P, class Method> |
| 162 | static bool Dispatch(const Message* msg, |
| 163 | T* obj, |
| 164 | S* sender, |
| 165 | P* parameter, |
| 166 | Method func) { |
ssid | 49c4822 | 2016-03-29 04:56:49 +0900 | [diff] [blame^] | 167 | TRACE_EVENT0("ipc", Meta::kName); |
mdempsky | fba51c1 | 2016-02-09 14:41:47 +0900 | [diff] [blame] | 168 | SendParam send_params; |
| 169 | bool ok = ReadSendParam(msg, &send_params); |
| 170 | Message* reply = SyncMessage::GenerateReply(msg); |
| 171 | if (ok) { |
| 172 | ReplyParam reply_params; |
| 173 | base::DispatchToMethod(obj, func, send_params, &reply_params); |
| 174 | WriteParam(reply, reply_params); |
| 175 | LogReplyParamsToMessage(reply_params, msg); |
| 176 | } else { |
| 177 | NOTREACHED() << "Error deserializing message " << msg->type(); |
| 178 | reply->set_reply_error(); |
| 179 | } |
| 180 | sender->Send(reply); |
| 181 | return ok; |
| 182 | } |
| 183 | |
| 184 | template <class T, class P, class Method> |
| 185 | static bool DispatchDelayReply(const Message* msg, |
| 186 | T* obj, |
| 187 | P* parameter, |
| 188 | Method func) { |
ssid | 49c4822 | 2016-03-29 04:56:49 +0900 | [diff] [blame^] | 189 | TRACE_EVENT0("ipc", Meta::kName); |
mdempsky | fba51c1 | 2016-02-09 14:41:47 +0900 | [diff] [blame] | 190 | SendParam send_params; |
| 191 | bool ok = ReadSendParam(msg, &send_params); |
| 192 | Message* reply = SyncMessage::GenerateReply(msg); |
| 193 | if (ok) { |
tzik | a088e35 | 2016-03-08 14:47:44 +0900 | [diff] [blame] | 194 | std::tuple<Message&> t = std::tie(*reply); |
mdempsky | fba51c1 | 2016-02-09 14:41:47 +0900 | [diff] [blame] | 195 | ConnectMessageAndReply(msg, reply); |
| 196 | base::DispatchToMethod(obj, func, send_params, &t); |
| 197 | } else { |
| 198 | NOTREACHED() << "Error deserializing message " << msg->type(); |
| 199 | reply->set_reply_error(); |
| 200 | obj->Send(reply); |
| 201 | } |
| 202 | return ok; |
| 203 | } |
| 204 | |
| 205 | private: |
| 206 | MessageT(Routing routing, const Ins&... ins, Outs*... outs); |
| 207 | }; |
| 208 | |
| 209 | } // namespace IPC |
| 210 | |
| 211 | #if defined(IPC_MESSAGE_IMPL) |
| 212 | #include "ipc/ipc_message_templates_impl.h" |
| 213 | #endif |
| 214 | |
| 215 | #endif // IPC_IPC_MESSAGE_TEMPLATES_H_ |