123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- // Copyright 2015 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #ifndef IPC_IPC_MESSAGE_TEMPLATES_H_
- #define IPC_IPC_MESSAGE_TEMPLATES_H_
- #include <stdint.h>
- #include <tuple>
- #include <type_traits>
- #include <utility>
- #include "base/check.h"
- #include "base/notreached.h"
- #include "base/trace_event/trace_event.h"
- #include "base/tuple.h"
- #include "build/build_config.h"
- #include "ipc/ipc_message.h"
- #include "ipc/ipc_message_utils.h"
- #include "ipc/ipc_sync_message.h"
- namespace IPC {
- template <typename Tuple, size_t... Ns>
- auto TupleForwardImpl(Tuple&& tuple, std::index_sequence<Ns...>) -> decltype(
- std::forward_as_tuple(std::get<Ns>(std::forward<Tuple>(tuple))...)) {
- return std::forward_as_tuple(std::get<Ns>(std::forward<Tuple>(tuple))...);
- }
- // Transforms std::tuple contents to the forwarding form.
- // Example:
- // std::tuple<int, int&, const int&, int&&>&&
- // -> std::tuple<int&&, int&, const int&, int&&>.
- // const std::tuple<int, const int&, int&&>&
- // -> std::tuple<const int&, int&, const int&, int&>.
- //
- // TupleForward(std::make_tuple(a, b, c)) is equivalent to
- // std::forward_as_tuple(a, b, c).
- template <typename Tuple>
- auto TupleForward(Tuple&& tuple) -> decltype(TupleForwardImpl(
- std::forward<Tuple>(tuple),
- std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>())) {
- return TupleForwardImpl(
- std::forward<Tuple>(tuple),
- std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>());
- }
- // This function is for all the async IPCs that don't pass an extra parameter
- // using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM.
- template <typename ObjT, typename Method, typename P, typename Tuple>
- void DispatchToMethod(ObjT* obj, Method method, P*, Tuple&& tuple) {
- base::DispatchToMethod(obj, method, std::forward<Tuple>(tuple));
- }
- template <typename ObjT,
- typename Method,
- typename P,
- typename Tuple,
- size_t... Ns>
- void DispatchToMethodImpl(ObjT* obj,
- Method method,
- P* parameter,
- Tuple&& tuple,
- std::index_sequence<Ns...>) {
- (obj->*method)(parameter, std::get<Ns>(std::forward<Tuple>(tuple))...);
- }
- // The following function is for async IPCs which have a dispatcher with an
- // extra parameter specified using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM.
- template <typename ObjT, typename P, typename... Args, typename Tuple>
- std::enable_if_t<sizeof...(Args) == std::tuple_size<std::decay_t<Tuple>>::value>
- DispatchToMethod(ObjT* obj,
- void (ObjT::*method)(P*, Args...),
- P* parameter,
- Tuple&& tuple) {
- constexpr size_t size = std::tuple_size<std::decay_t<Tuple>>::value;
- DispatchToMethodImpl(obj, method, parameter, std::forward<Tuple>(tuple),
- std::make_index_sequence<size>());
- }
- enum class MessageKind {
- CONTROL,
- ROUTED,
- };
- // Routing is a helper struct so MessageT's private common constructor has a
- // different type signature than the public "int32_t routing_id" one.
- struct Routing {
- explicit Routing(int32_t id) : id(id) {}
- int32_t id;
- };
- // We want to restrict MessageT's constructors so that a routing_id is always
- // provided for ROUTED messages and never provided for CONTROL messages, so
- // use the SFINAE technique from N4387's "Implementation Hint" section.
- #define IPC_MESSAGET_SFINAE(x) \
- template <bool X = (x), typename std::enable_if<X, bool>::type = false>
- // MessageT is the common template used for all user-defined message types.
- // It's intended to be used via the macros defined in ipc_message_macros.h.
- template <typename Meta,
- typename InTuple = typename Meta::InTuple,
- typename OutTuple = typename Meta::OutTuple>
- class MessageT;
- // Asynchronous message partial specialization.
- template <typename Meta, typename... Ins>
- class MessageT<Meta, std::tuple<Ins...>, void> : public Message {
- public:
- using Param = std::tuple<Ins...>;
- enum { ID = Meta::ID };
- // TODO(mdempsky): Remove. Uses of MyMessage::Schema::Param can be replaced
- // with just MyMessage::Param.
- using Schema = MessageT;
- IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL)
- MessageT(const Ins&... ins) : MessageT(Routing(MSG_ROUTING_CONTROL), ins...) {
- DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName;
- }
- IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED)
- MessageT(int32_t routing_id, const Ins&... ins)
- : MessageT(Routing(routing_id), ins...) {
- DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName;
- }
- static bool Read(const Message* msg, Param* p);
- static void Log(std::string* name, const Message* msg, std::string* l);
- template <class T, class S, class P, class Method>
- static bool Dispatch(const Message* msg,
- T* obj,
- S* sender,
- P* parameter,
- Method func) {
- TRACE_EVENT0("ipc", Meta::kName);
- Param p;
- if (Read(msg, &p)) {
- DispatchToMethod(obj, func, parameter, std::move(p));
- return true;
- }
- return false;
- }
- private:
- MessageT(Routing routing, const Ins&... ins);
- };
- // Synchronous message partial specialization.
- template <typename Meta, typename... Ins, typename... Outs>
- class MessageT<Meta, std::tuple<Ins...>, std::tuple<Outs...>>
- : public SyncMessage {
- public:
- using SendParam = std::tuple<Ins...>;
- using ReplyParam = std::tuple<Outs...>;
- enum { ID = Meta::ID };
- // TODO(mdempsky): Remove. Uses of MyMessage::Schema::{Send,Reply}Param can
- // be replaced with just MyMessage::{Send,Reply}Param.
- using Schema = MessageT;
- IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL)
- MessageT(const Ins&... ins, Outs*... outs)
- : MessageT(Routing(MSG_ROUTING_CONTROL), ins..., outs...) {
- DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName;
- }
- IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED)
- MessageT(int32_t routing_id, const Ins&... ins, Outs*... outs)
- : MessageT(Routing(routing_id), ins..., outs...) {
- DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName;
- }
- static bool ReadSendParam(const Message* msg, SendParam* p);
- static bool ReadReplyParam(const Message* msg, ReplyParam* p);
- static void WriteReplyParams(Message* reply, const Outs&... outs);
- static void Log(std::string* name, const Message* msg, std::string* l);
- template <class T, class S, class P, class Method>
- static bool Dispatch(const Message* msg,
- T* obj,
- S* sender,
- P* /* parameter */,
- Method func) {
- TRACE_EVENT0("ipc", Meta::kName);
- SendParam send_params;
- bool ok = ReadSendParam(msg, &send_params);
- Message* reply = SyncMessage::GenerateReply(msg);
- if (!ok) {
- NOTREACHED() << "Error deserializing message " << msg->type();
- reply->set_reply_error();
- sender->Send(reply);
- return false;
- }
- ReplyParam reply_params;
- base::DispatchToMethod(obj, func, std::move(send_params), &reply_params);
- WriteParam(reply, reply_params);
- LogReplyParamsToMessage(reply_params, msg);
- sender->Send(reply);
- return true;
- }
- template <class T, class P, class Method>
- static bool DispatchDelayReply(const Message* msg,
- T* obj,
- P* /* parameter */,
- Method func) {
- TRACE_EVENT0("ipc", Meta::kName);
- SendParam send_params;
- bool ok = ReadSendParam(msg, &send_params);
- Message* reply = SyncMessage::GenerateReply(msg);
- if (!ok) {
- NOTREACHED() << "Error deserializing message " << msg->type();
- reply->set_reply_error();
- obj->Send(reply);
- return false;
- }
- std::tuple<Message&> t = std::tie(*reply);
- ConnectMessageAndReply(msg, reply);
- base::DispatchToMethod(obj, func, std::move(send_params), &t);
- return true;
- }
- template <class T, class P, class Method>
- static bool DispatchWithParamDelayReply(const Message* msg,
- T* obj,
- P* parameter,
- Method func) {
- TRACE_EVENT0("ipc", Meta::kName);
- SendParam send_params;
- bool ok = ReadSendParam(msg, &send_params);
- Message* reply = SyncMessage::GenerateReply(msg);
- if (!ok) {
- NOTREACHED() << "Error deserializing message " << msg->type();
- reply->set_reply_error();
- obj->Send(reply);
- return false;
- }
- std::tuple<Message&> t = std::tie(*reply);
- ConnectMessageAndReply(msg, reply);
- std::tuple<P*> parameter_tuple(parameter);
- base::DispatchToMethod(
- obj, func,
- std::tuple_cat(std::move(parameter_tuple), TupleForward(send_params)),
- &t);
- return true;
- }
- private:
- MessageT(Routing routing, const Ins&... ins, Outs*... outs);
- };
- } // namespace IPC
- #if defined(IPC_MESSAGE_IMPL)
- #include "ipc/ipc_message_templates_impl.h"
- #endif
- #endif // IPC_IPC_MESSAGE_TEMPLATES_H_
|