LCOV - code coverage report
Current view: top level - src/ipc/libmultiprocess/include/mp - proxy-types.h (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 71.9 % 231 166
Test Date: 2025-08-25 05:11:47 Functions: 19.8 % 1404 278
Branches: 6.5 % 7674 501

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) The Bitcoin Core developers
       2                 :             : // Distributed under the MIT software license, see the accompanying
       3                 :             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4                 :             : 
       5                 :             : #ifndef MP_PROXY_TYPES_H
       6                 :             : #define MP_PROXY_TYPES_H
       7                 :             : 
       8                 :             : #include <mp/proxy-io.h>
       9                 :             : 
      10                 :             : #include <exception>
      11                 :             : #include <optional>
      12                 :             : #include <set>
      13                 :             : #include <typeindex>
      14                 :             : #include <vector>
      15                 :             : 
      16                 :             : namespace mp {
      17                 :             : 
      18                 :             : template <typename Value>
      19                 :             : class ValueField
      20                 :             : {
      21                 :             : public:
      22                 :           0 :     ValueField(Value& value) : m_value(value) {}
      23                 :           0 :     ValueField(Value&& value) : m_value(value) {}
      24                 :             :     Value& m_value;
      25                 :             : 
      26                 :           0 :     Value& get() { return m_value; }
      27                 :             :     Value& init() { return m_value; }
      28                 :             :     bool has() { return true; }
      29                 :             : };
      30                 :             : 
      31                 :             : template <typename Accessor, typename Struct>
      32                 :             : struct StructField
      33                 :             : {
      34                 :             :     template <typename S>
      35                 :         185 :     StructField(S& struct_) : m_struct(struct_)
      36                 :             :     {
      37                 :             :     }
      38                 :             :     Struct& m_struct;
      39                 :             : 
      40   [ +  -  -  +  :          45 :     decltype(auto) get() const { return Accessor::get(this->m_struct); }
             +  -  -  + ]
           [ +  -  #  #  
             #  #  #  # ]
           [ #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ -  -  
             +  -  +  - ]
           [ #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
           [ #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
      41                 :             : 
      42                 :          12 :     bool has() const {
      43                 :             :       if constexpr (Accessor::optional) {
      44   [ #  #  #  #  :           0 :         return Accessor::getHas(m_struct);
                   #  # ]
      45                 :             :       } else if constexpr (Accessor::boxed) {
      46   [ -  +  -  +  :          12 :         return Accessor::has(m_struct);
           +  - ][ #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
           [ #  #  #  #  
             #  #  #  # ]
           [ -  -  +  -  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ #  #  
          #  #  #  #  #  
                      # ]
      47                 :             :       } else {
      48                 :             :         return true;
      49                 :             :       }
      50                 :             :     }
      51                 :             : 
      52                 :             :     bool want() const {
      53                 :             :       if constexpr (Accessor::requested) {
      54                 :             :         return Accessor::getWant(m_struct);
      55                 :             :       } else {
      56                 :             :         return true;
      57                 :             :       }
      58                 :             :     }
      59                 :             : 
      60                 :          21 :     template <typename... Args> decltype(auto) set(Args &&...args) const {
      61   [ #  #  #  # ]:          21 :       return Accessor::set(this->m_struct, std::forward<Args>(args)...);
           [ +  -  #  #  
          #  #  #  #  #  
             #  #  #  #  
           # ][ -  -  +  
           -  +  - ][ #  
             #  #  #  #  
                      # ]
      62                 :             :     }
      63                 :             : 
      64                 :          40 :     template <typename... Args> decltype(auto) init(Args &&...args) const {
      65   [ +  -  -  +  :          40 :       return Accessor::init(this->m_struct, std::forward<Args>(args)...);
          +  -  -  +  +  
           -  -  + ][ -  
             +  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ #  # ]
           [ #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
      66                 :             :     }
      67                 :             : 
      68                 :           0 :     void setHas() const {
      69                 :             :       if constexpr (Accessor::optional) {
      70                 :           0 :         Accessor::setHas(m_struct);
      71                 :             :       }
      72                 :             :     }
      73                 :             : 
      74                 :             :     void setWant() const {
      75                 :             :       if constexpr (Accessor::requested) {
      76                 :             :         Accessor::setWant(m_struct);
      77                 :             :       }
      78                 :             :     }
      79                 :             : };
      80                 :             : 
      81                 :             : 
      82                 :             : 
      83                 :             : // Destination parameter type that can be passed to ReadField function as an
      84                 :             : // alternative to ReadDestUpdate. It allows the ReadField implementation to call
      85                 :             : // the provided emplace_fn function with constructor arguments, so it only needs
      86                 :             : // to determine the arguments, and can let the emplace function decide how to
      87                 :             : // actually construct the read destination object. For example, if a std::string
      88                 :             : // is being read, the ReadField call will call the custom emplace_fn with char*
      89                 :             : // and size_t arguments, and the emplace function can decide whether to call the
      90                 :             : // constructor via the operator or make_shared or emplace or just return a
      91                 :             : // temporary string that is moved from.
      92                 :             : template <typename LocalType, typename EmplaceFn>
      93                 :             : struct ReadDestEmplace
      94                 :             : {
      95                 :           8 :     ReadDestEmplace(TypeList<LocalType>, EmplaceFn emplace_fn) : m_emplace_fn(std::move(emplace_fn)) {}
      96                 :             : 
      97                 :             :     //! Simple case. If ReadField implementation calls this construct() method
      98                 :             :     //! with constructor arguments, just pass them on to the emplace function.
      99                 :             :     template <typename... Args>
     100                 :          15 :     decltype(auto) construct(Args&&... args)
     101                 :             :     {
     102         [ #  # ]:          14 :         return m_emplace_fn(std::forward<Args>(args)...);
     103                 :             :     }
     104                 :             : 
     105                 :             :     //! More complicated case. If ReadField implementation works by calling this
     106                 :             :     //! update() method, adapt it call construct() instead. This requires
     107                 :             :     //! LocalType to have a default constructor to create new object that can be
     108                 :             :     //! passed to update()
     109                 :             :     template <typename UpdateFn>
     110         [ #  # ]:           3 :     decltype(auto) update(UpdateFn&& update_fn)
     111                 :             :     {
     112                 :             :         if constexpr (std::is_const_v<std::remove_reference_t<std::invoke_result_t<EmplaceFn>>>) {
     113                 :             :             // If destination type is const, default construct temporary
     114                 :             :             // to pass to update, then call move constructor via construct() to
     115                 :             :             // move from that temporary.
     116                 :           0 :             std::remove_cv_t<LocalType> temp;
     117         [ #  # ]:           0 :             update_fn(temp);
     118                 :             :             return construct(std::move(temp));
     119                 :           0 :         } else {
     120                 :             :             // Default construct object and pass it to update_fn.
     121                 :           3 :             decltype(auto) temp = construct();
     122                 :           3 :             update_fn(temp);
     123                 :           1 :             return temp;
     124                 :             :         }
     125                 :             :     }
     126                 :             :     EmplaceFn m_emplace_fn;
     127                 :             : };
     128                 :             : 
     129                 :             : //! Helper function to create a ReadDestEmplace object that constructs a
     130                 :             : //! temporary, ReadField can return.
     131                 :             : template <typename LocalType>
     132                 :             : auto ReadDestTemp()
     133                 :             : {
     134                 :           0 :     return ReadDestEmplace{TypeList<LocalType>(), [](auto&&... args) -> decltype(auto) {
     135                 :           0 :         return LocalType{std::forward<decltype(args)>(args)...};
     136                 :             :     }};
     137                 :             : }
     138                 :             : 
     139                 :             : //! Destination parameter type that can be passed to ReadField function as an
     140                 :             : //! alternative to ReadDestEmplace. Instead of requiring an emplace callback to
     141                 :             : //! construct a new value, it just takes a reference to an existing value and
     142                 :             : //! assigns a new value to it.
     143                 :             : template <typename Value>
     144                 :             : struct ReadDestUpdate
     145                 :             : {
     146                 :          31 :     ReadDestUpdate(Value& value) : m_value(value) {}
     147                 :             : 
     148                 :             :     //! Simple case. If ReadField works by calling update() just forward arguments to update_fn.
     149                 :             :     template <typename UpdateFn>
     150                 :           3 :     Value& update(UpdateFn&& update_fn)
     151                 :             :     {
     152                 :           3 :         update_fn(m_value);
     153                 :           3 :         return m_value;
     154                 :             :     }
     155                 :             : 
     156                 :             :     //! More complicated case. If ReadField works by calling construct(), need
     157                 :             :     //! to reconstruct m_value in place.
     158                 :             :     template <typename... Args>
     159                 :          15 :     Value& construct(Args&&... args)
     160                 :             :     {
     161                 :          15 :         m_value.~Value();
     162                 :          15 :         new (&m_value) Value(std::forward<Args>(args)...);
     163                 :          15 :         return m_value;
     164                 :             :     }
     165                 :             : 
     166                 :             :     Value& m_value;
     167                 :             : };
     168                 :             : 
     169                 :             : template <typename... LocalTypes, typename... Args>
     170                 :          45 : decltype(auto) ReadField(TypeList<LocalTypes...>, Args&&... args)
     171                 :             : {
     172                 :          45 :     return CustomReadField(TypeList<RemoveCvRef<LocalTypes>...>(), Priority<2>(), std::forward<Args>(args)...);
     173                 :             : }
     174                 :             : 
     175                 :             : template <typename LocalType, typename Input>
     176                 :           0 : void ThrowField(TypeList<LocalType>, InvokeContext& invoke_context, Input&& input)
     177                 :             : {
     178                 :           0 :     ReadField(
     179                 :           0 :         TypeList<LocalType>(), invoke_context, input, ReadDestEmplace(TypeList<LocalType>(),
     180                 :           0 :             [](auto&& ...args) -> const LocalType& { throw LocalType{std::forward<decltype(args)>(args)...}; }));
     181                 :             : }
     182                 :             : 
     183                 :             : //! Special case for generic std::exception. It's an abstract type so it can't
     184                 :             : //! be created directly. Rethrow as std::runtime_error so callers expecting it
     185                 :             : //! will still catch it.
     186                 :             : template <typename Input>
     187                 :             : void ThrowField(TypeList<std::exception>, InvokeContext& invoke_context, Input&& input)
     188                 :             : {
     189                 :             :     auto data = input.get();
     190                 :             :     throw std::runtime_error(std::string(CharCast(data.begin()), data.size()));
     191                 :             : }
     192                 :             : 
     193                 :             : template <typename... Values>
     194                 :          93 : bool CustomHasValue(InvokeContext& invoke_context, const Values&... value)
     195                 :             : {
     196                 :          93 :     return true;
     197                 :             : }
     198                 :             : 
     199                 :             : template <typename... LocalTypes, typename Context, typename... Values, typename Output>
     200                 :          93 : void BuildField(TypeList<LocalTypes...>, Context& context, Output&& output, Values&&... values)
     201                 :             : {
     202         [ +  - ]:          93 :     if (CustomHasValue(context, values...)) {
     203                 :          93 :         CustomBuildField(TypeList<LocalTypes...>(), Priority<3>(), context, std::forward<Values>(values)...,
     204                 :             :             std::forward<Output>(output));
     205                 :             :     }
     206                 :          93 : }
     207                 :             : 
     208                 :             : // Adapter to let BuildField overloads methods work set & init list elements as
     209                 :             : // if they were fields of a struct. If BuildField is changed to use some kind of
     210                 :             : // accessor class instead of calling method pointers, then then maybe this could
     211                 :             : // go away or be simplified, because would no longer be a need to return
     212                 :             : // ListOutput method pointers emulating capnp struct method pointers..
     213                 :             : template <typename ListType>
     214                 :             : struct ListOutput;
     215                 :             : 
     216                 :             : template <typename T, ::capnp::Kind kind>
     217                 :             : struct ListOutput<::capnp::List<T, kind>>
     218                 :             : {
     219                 :             :     using Builder = typename ::capnp::List<T, kind>::Builder;
     220                 :             : 
     221                 :           0 :     ListOutput(Builder& builder, size_t index) : m_builder(builder), m_index(index) {}
     222                 :             :     Builder& m_builder;
     223                 :             :     size_t m_index;
     224                 :             : 
     225                 :             :     // clang-format off
     226                 :             :     decltype(auto) get() const { return this->m_builder[this->m_index]; }
     227                 :           0 :     decltype(auto) init() const { return this->m_builder[this->m_index]; }
     228                 :           0 :     template<typename B = Builder, typename Arg> decltype(auto) set(Arg&& arg) const { return static_cast<B&>(this->m_builder).set(m_index, std::forward<Arg>(arg)); }
     229         [ #  # ]:           0 :     template<typename B = Builder, typename Arg> decltype(auto) init(Arg&& arg) const { return static_cast<B&>(this->m_builder).init(m_index, std::forward<Arg>(arg)); }
     230                 :             :     // clang-format on
     231                 :             : };
     232                 :             : 
     233                 :             : template <typename LocalType, typename Value, typename Output>
     234                 :           3 : void CustomBuildField(TypeList<LocalType>, Priority<0>, InvokeContext& invoke_context, Value&& value, Output&& output)
     235                 :             : {
     236                 :           3 :     output.set(BuildPrimitive(invoke_context, std::forward<Value>(value), TypeList<decltype(output.get())>()));
     237                 :           3 : }
     238                 :             : 
     239                 :             : //! PassField override for callable interface reference arguments.
     240                 :             : template <typename Accessor, typename LocalType, typename ServerContext, typename Fn, typename... Args>
     241                 :           0 : auto PassField(Priority<1>, TypeList<LocalType&>, ServerContext& server_context, Fn&& fn, Args&&... args)
     242                 :             :     -> Require<typename decltype(Accessor::get(server_context.call_context.getParams()))::Calls>
     243                 :             : {
     244                 :             :     // Just create a temporary ProxyClient if argument is a reference to an
     245                 :             :     // interface client. If argument needs to have a longer lifetime and not be
     246                 :             :     // destroyed after this call, a CustomPassField overload can be implemented
     247                 :             :     // to bypass this code, and a custom ProxyServerMethodTraits overload can be
     248                 :             :     // implemented in order to read the capability pointer out of params and
     249                 :             :     // construct a ProxyClient with a longer lifetime.
     250                 :           0 :     const auto& params = server_context.call_context.getParams();
     251                 :           0 :     const auto& input = Make<StructField, Accessor>(params);
     252                 :             :     using Interface = typename Decay<decltype(input.get())>::Calls;
     253         [ #  # ]:           0 :     auto param = std::make_unique<ProxyClient<Interface>>(input.get(), server_context.proxy_server.m_context.connection, false);
     254         [ #  # ]:           0 :     fn.invoke(server_context, std::forward<Args>(args)..., *param);
     255                 :           0 : }
     256                 :             : 
     257                 :             : template <typename... Args>
     258                 :          37 : void MaybeBuildField(std::true_type, Args&&... args)
     259                 :             : {
     260                 :          37 :     BuildField(std::forward<Args>(args)...);
     261                 :          37 : }
     262                 :             : template <typename... Args>
     263                 :             : void MaybeBuildField(std::false_type, Args&&...)
     264                 :             : {
     265                 :             : }
     266                 :             : template <typename... Args>
     267                 :          37 : void MaybeReadField(std::true_type, Args&&... args)
     268                 :             : {
     269                 :          37 :     ReadField(std::forward<Args>(args)...);
     270                 :          37 : }
     271                 :             : template <typename... Args>
     272                 :             : void MaybeReadField(std::false_type, Args&&...)
     273                 :             : {
     274                 :             : }
     275                 :             : 
     276                 :             : template <typename LocalType, typename Value, typename Output>
     277                 :             : void MaybeSetWant(TypeList<LocalType*>, Priority<1>, const Value& value, Output&& output)
     278                 :             : {
     279                 :             :     if (value) {
     280                 :             :         output.setWant();
     281                 :             :     }
     282                 :             : }
     283                 :             : 
     284                 :             : template <typename LocalTypes, typename... Args>
     285                 :             : void MaybeSetWant(LocalTypes, Priority<0>, const Args&...)
     286                 :             : {
     287                 :             : }
     288                 :             : 
     289                 :             : //! Default PassField implementation calling MaybeReadField/MaybeBuildField.
     290                 :             : template <typename Accessor, typename LocalType, typename ServerContext, typename Fn, typename... Args>
     291                 :          13 : void PassField(Priority<0>, TypeList<LocalType>, ServerContext& server_context, Fn&& fn, Args&&... args)
     292                 :             : {
     293                 :          13 :     InvokeContext& invoke_context = server_context;
     294                 :             :     using ArgType = RemoveCvRef<LocalType>;
     295                 :          13 :     std::optional<ArgType> param;
     296         [ +  - ]:          13 :     const auto& params = server_context.call_context.getParams();
     297         [ -  + ]:          13 :     MaybeReadField(std::integral_constant<bool, Accessor::in>(), TypeList<ArgType>(), invoke_context,
     298         [ +  - ]:          20 :         Make<StructField, Accessor>(params), ReadDestEmplace(TypeList<ArgType>(), [&](auto&&... args) -> auto& {
     299   [ -  +  -  + ]:          13 :             param.emplace(std::forward<decltype(args)>(args)...);
           [ #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     300         [ #  # ]:           9 :             return *param;
     301                 :             :         }));
     302                 :             :     if constexpr (Accessor::in) {
     303         [ -  + ]:          13 :         assert(param);
     304                 :             :     } else {
     305         [ #  # ]:           0 :         if (!param) param.emplace();
     306                 :             :     }
     307         [ +  - ]:          14 :     fn.invoke(server_context, std::forward<Args>(args)..., static_cast<LocalType&&>(*param));
     308   [ +  -  -  + ]:          13 :     auto&& results = server_context.call_context.getResults();
           [ #  #  #  #  
                   #  # ]
     309                 :          13 :     MaybeBuildField(std::integral_constant<bool, Accessor::out>(), TypeList<LocalType>(), invoke_context,
     310         [ #  # ]:          13 :         Make<StructField, Accessor>(results), *param);
     311                 :          13 : }
     312                 :             : 
     313                 :             : //! Default PassField implementation for count(0) arguments, calling ReadField/BuildField
     314                 :             : template <typename Accessor, typename ServerContext, typename Fn, typename... Args>
     315                 :           6 : void PassField(Priority<0>, TypeList<>, ServerContext& server_context, const Fn& fn, Args&&... args)
     316                 :             : {
     317                 :           6 :     const auto& params = server_context.call_context.getParams();
     318                 :           6 :     const auto& input = Make<StructField, Accessor>(params);
     319                 :           6 :     ReadField(TypeList<>(), server_context, input);
     320                 :             :     fn.invoke(server_context, std::forward<Args>(args)...);
     321   [ +  -  -  + ]:           6 :     auto&& results = server_context.call_context.getResults();
     322                 :           6 :     BuildField(TypeList<>(), server_context, Make<StructField, Accessor>(results));
     323                 :           6 : }
     324                 :             : 
     325                 :             : template <typename Derived, size_t N = 0>
     326                 :             : struct IterateFieldsHelper
     327                 :             : {
     328                 :             :     template <typename Arg1, typename Arg2, typename ParamList, typename NextFn, typename... NextFnArgs>
     329                 :          99 :     void handleChain(Arg1& arg1, Arg2& arg2, ParamList, NextFn&& next_fn, NextFnArgs&&... next_fn_args)
     330                 :             :     {
     331                 :             :         using S = Split<N, ParamList>;
     332                 :          85 :         handleChain(arg1, arg2, typename S::First());
     333   [ +  -  +  -  :          57 :         next_fn.handleChain(arg1, arg2, typename S::Second(),
          +  -  +  -  +  
           - ][ +  -  +  
          -  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
           [ #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     334                 :             :             std::forward<NextFnArgs>(next_fn_args)...);
     335                 :          73 :     }
     336                 :             : 
     337                 :             :     template <typename Arg1, typename Arg2, typename ParamList>
     338                 :          92 :     void handleChain(Arg1& arg1, Arg2& arg2, ParamList)
     339                 :             :     {
     340                 :          25 :         static_cast<Derived*>(this)->handleField(arg1, arg2, ParamList());
     341                 :             :     }
     342                 :             : private:
     343                 :             :     IterateFieldsHelper() = default;
     344                 :             :     friend Derived;
     345                 :             : };
     346                 :             : 
     347                 :             : struct IterateFields : IterateFieldsHelper<IterateFields, 0>
     348                 :             : {
     349                 :             :     template <typename Arg1, typename Arg2, typename ParamList>
     350                 :             :     void handleField(Arg1&&, Arg2&&, ParamList)
     351                 :             :     {
     352                 :             :     }
     353                 :             : };
     354                 :             : 
     355                 :             : template <typename Exception, typename Accessor>
     356                 :             : struct ClientException
     357                 :             : {
     358                 :             :     struct BuildParams : IterateFieldsHelper<BuildParams, 0>
     359                 :             :     {
     360                 :             :         template <typename Params, typename ParamList>
     361                 :             :         void handleField(InvokeContext& invoke_context, Params& params, ParamList)
     362                 :             :         {
     363                 :             :         }
     364                 :             : 
     365                 :           0 :         BuildParams(ClientException* client_exception) : m_client_exception(client_exception) {}
     366                 :             :         ClientException* m_client_exception;
     367                 :             :     };
     368                 :             : 
     369                 :             :     struct ReadResults : IterateFieldsHelper<ReadResults, 0>
     370                 :             :     {
     371                 :             :         template <typename Results, typename ParamList>
     372                 :           0 :         void handleField(InvokeContext& invoke_context, Results& results, ParamList)
     373                 :             :         {
     374                 :           0 :             StructField<Accessor, Results> input(results);
     375         [ #  # ]:           0 :             if (input.has()) {
     376                 :           0 :                 ThrowField(TypeList<Exception>(), invoke_context, input);
     377                 :             :             }
     378                 :           0 :         }
     379                 :             : 
     380                 :           0 :         ReadResults(ClientException* client_exception) : m_client_exception(client_exception) {}
     381                 :             :         ClientException* m_client_exception;
     382                 :             :     };
     383                 :             : };
     384                 :             : 
     385                 :             : template <typename Accessor, typename... Types>
     386                 :             : struct ClientParam
     387                 :             : {
     388                 :          31 :     ClientParam(Types&&... values) : m_values{std::forward<Types>(values)...} {}
     389                 :             : 
     390                 :             :     struct BuildParams : IterateFieldsHelper<BuildParams, sizeof...(Types)>
     391                 :             :     {
     392                 :             :         template <typename Params, typename ParamList>
     393                 :          55 :         void handleField(ClientInvokeContext& invoke_context, Params& params, ParamList)
     394                 :             :         {
     395                 :         129 :             auto const fun = [&]<typename... Values>(Values&&... values) {
     396                 :             :                 MaybeSetWant(
     397                 :          37 :                     ParamList(), Priority<1>(), values..., Make<StructField, Accessor>(params));
     398                 :          37 :                 MaybeBuildField(std::integral_constant<bool, Accessor::in>(), ParamList(), invoke_context,
     399                 :          37 :                     Make<StructField, Accessor>(params), std::forward<Values>(values)...);
     400                 :             :             };
     401                 :             : 
     402                 :             :             // Note: The m_values tuple just consists of lvalue and rvalue
     403                 :             :             // references, so calling std::move doesn't change the tuple, it
     404                 :             :             // just causes std::apply to call the std::get overload that returns
     405                 :             :             // && instead of &, so rvalue references are preserved and not
     406                 :             :             // turned into lvalue references. This allows the BuildField call to
     407                 :             :             // move from the argument if it is an rvalue reference or was passed
     408                 :             :             // by value.
     409   [ +  -  +  -  :          30 :             std::apply(fun, std::move(m_client_param->m_values));
          +  -  +  -  +  
           - ][ +  -  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  #  # ][ #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
           # ][ -  -  +  
                -  +  - ]
     410                 :             :         }
     411                 :             : 
     412                 :          30 :         BuildParams(ClientParam* client_param) : m_client_param(client_param) {}
     413                 :             :         ClientParam* m_client_param;
     414                 :             :     };
     415                 :             : 
     416                 :             :     struct ReadResults : IterateFieldsHelper<ReadResults, sizeof...(Types)>
     417                 :             :     {
     418                 :             :         template <typename Results, typename... Params>
     419                 :          37 :         void handleField(ClientInvokeContext& invoke_context, Results& results, TypeList<Params...>)
     420                 :             :         {
     421                 :          85 :             auto const fun = [&]<typename... Values>(Values&&... values) {
     422                 :          24 :                 MaybeReadField(std::integral_constant<bool, Accessor::out>(), TypeList<Decay<Params>...>(), invoke_context,
     423                 :          55 :                     Make<StructField, Accessor>(results), ReadDestUpdate(values)...);
     424                 :             :             };
     425                 :             : 
     426   [ +  -  #  # ]:          37 :             std::apply(fun, m_client_param->m_values);
                 [ #  # ]
     427                 :             :         }
     428                 :             : 
     429                 :          30 :         ReadResults(ClientParam* client_param) : m_client_param(client_param) {}
     430                 :             :         ClientParam* m_client_param;
     431                 :             :     };
     432                 :             : 
     433                 :             :     std::tuple<Types&&...> m_values;
     434                 :             : };
     435                 :             : 
     436                 :             : template <typename Accessor, typename... Types>
     437                 :          31 : ClientParam<Accessor, Types...> MakeClientParam(Types&&... values)
     438                 :             : {
     439                 :          31 :     return {std::forward<Types>(values)...};
     440                 :             : }
     441                 :             : 
     442                 :             : struct ServerCall
     443                 :             : {
     444                 :             :     // FIXME: maybe call call_context.releaseParams()
     445                 :             :     template <typename ServerContext, typename... Args>
     446         [ #  # ]:          18 :     decltype(auto) invoke(ServerContext& server_context, TypeList<>, Args&&... args) const
     447                 :             :     {
     448                 :           2 :         return ProxyServerMethodTraits<typename decltype(server_context.call_context.getParams())::Reads>::invoke(
     449                 :             :             server_context,
     450                 :          16 :             std::forward<Args>(args)...);
     451                 :             :     }
     452                 :             : };
     453                 :             : 
     454                 :             : struct ServerDestroy
     455                 :             : {
     456                 :             :     template <typename ServerContext, typename... Args>
     457                 :           6 :     void invoke(ServerContext& server_context, TypeList<>, Args&&... args) const
     458                 :             :     {
     459   [ +  -  #  #  :           6 :         server_context.proxy_server.invokeDestroy(std::forward<Args>(args)...);
           #  # ][ #  # ]
     460                 :           6 :     }
     461                 :             : };
     462                 :             : 
     463                 :             : template <typename Accessor, typename Parent>
     464                 :             : struct ServerRet : Parent
     465                 :             : {
     466                 :             :     ServerRet(Parent parent) : Parent(parent) {}
     467                 :             : 
     468                 :             :     template <typename ServerContext, typename... Args>
     469         [ +  - ]:          18 :     void invoke(ServerContext& server_context, TypeList<>, Args&&... args) const
     470                 :             :     {
     471                 :          27 :         auto&& result = Parent::invoke(server_context, TypeList<>(), std::forward<Args>(args)...);
     472   [ +  -  -  + ]:          18 :         auto&& results = server_context.call_context.getResults();
     473                 :          18 :         InvokeContext& invoke_context = server_context;
     474         [ +  - ]:          18 :         BuildField(TypeList<decltype(result)>(), invoke_context, Make<StructField, Accessor>(results),
     475                 :             :             std::forward<decltype(result)>(result));
     476                 :          18 :     }
     477                 :             : };
     478                 :             : 
     479                 :             : template <typename Exception, typename Accessor, typename Parent>
     480                 :             : struct ServerExcept : Parent
     481                 :             : {
     482                 :             :     ServerExcept(Parent parent) : Parent(parent) {}
     483                 :             : 
     484                 :             :     template <typename ServerContext, typename... Args>
     485                 :           0 :     void invoke(ServerContext& server_context, TypeList<>, Args&&... args) const
     486                 :             :     {
     487                 :             :         try {
     488                 :             :             return Parent::invoke(server_context, TypeList<>(), std::forward<Args>(args)...);
     489         [ -  - ]:           0 :         } catch (const Exception& exception) {
     490   [ -  -  -  - ]:           0 :             auto&& results = server_context.call_context.getResults();
     491         [ -  - ]:           0 :             BuildField(TypeList<Exception>(), server_context, Make<StructField, Accessor>(results), exception);
     492                 :             :         }
     493                 :             :     }
     494                 :             : };
     495                 :             : 
     496                 :             : //! Helper for CustomPassField below. Call Accessor::get method if it has one,
     497                 :             : //! otherwise return capnp::Void.
     498                 :             : template <typename Accessor, typename Message>
     499                 :           0 : decltype(auto) MaybeGet(Message&& message, decltype(Accessor::get(message))* enable = nullptr)
     500                 :             : {
     501                 :           0 :     return Accessor::get(message);
     502                 :             : }
     503                 :             : 
     504                 :             : template <typename Accessor>
     505                 :             : ::capnp::Void MaybeGet(...)
     506                 :             : {
     507                 :             :     return {};
     508                 :             : }
     509                 :             : 
     510                 :             : template <class Accessor>
     511                 :             : void CustomPassField();
     512                 :             : 
     513                 :             : //! PassField override calling CustomPassField function, if it exists.
     514                 :             : //! Defining a CustomPassField or CustomPassMessage overload is useful for
     515                 :             : //! input/output parameters. If an overload is not defined these parameters will
     516                 :             : //! just be deserialized on the server side with ReadField into a temporary
     517                 :             : //! variable, then the server method will be called passing the temporary
     518                 :             : //! variable as a parameter, then the temporary variable will be serialized and
     519                 :             : //! sent back to the client with BuildField. But if a PassField or PassMessage
     520                 :             : //! overload is defined, the overload is called with a callback to invoke and
     521                 :             : //! pass parameters to the server side function, and run arbitrary code before
     522                 :             : //! and after invoking the function.
     523                 :             : template <typename Accessor, typename... Args>
     524                 :           0 : auto PassField(Priority<2>, Args&&... args) -> decltype(CustomPassField<Accessor>(std::forward<Args>(args)...))
     525                 :             : {
     526                 :           0 :     return CustomPassField<Accessor>(std::forward<Args>(args)...);
     527                 :             : };
     528                 :             : 
     529                 :             : template <int argc, typename Accessor, typename Parent>
     530                 :             : struct ServerField : Parent
     531                 :             : {
     532                 :             :     ServerField(Parent parent) : Parent(parent) {}
     533                 :             : 
     534                 :             :     const Parent& parent() const { return *this; }
     535                 :             : 
     536                 :             :     template <typename ServerContext, typename ArgTypes, typename... Args>
     537                 :          37 :     decltype(auto) invoke(ServerContext& server_context, ArgTypes, Args&&... args) const
     538                 :             :     {
     539   [ +  -  #  #  :          13 :         return PassField<Accessor>(Priority<2>(),
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
           [ #  #  #  #  
          #  #  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
                   #  # ]
     540                 :             :             typename Split<argc, ArgTypes>::First(),
     541                 :             :             server_context,
     542                 :             :             this->parent(),
     543                 :             :             typename Split<argc, ArgTypes>::Second(),
     544                 :          12 :             std::forward<Args>(args)...);
     545                 :             :     }
     546                 :             : };
     547                 :             : 
     548                 :             : template <int argc, typename Accessor, typename Parent>
     549                 :             : ServerField<argc, Accessor, Parent> MakeServerField(Parent parent)
     550                 :             : {
     551                 :             :     return {parent};
     552                 :             : }
     553                 :             : 
     554                 :             : template <typename Request>
     555                 :             : struct CapRequestTraits;
     556                 :             : 
     557                 :             : template <typename _Params, typename _Results>
     558                 :             : struct CapRequestTraits<::capnp::Request<_Params, _Results>>
     559                 :             : {
     560                 :             :     using Params = _Params;
     561                 :             :     using Results = _Results;
     562                 :             : };
     563                 :             : 
     564                 :             : //! Entry point called by all generated ProxyClient destructors. This only logs
     565                 :             : //! the object destruction. The actual cleanup happens in the ProxyClient base
     566                 :             : //! destructor.
     567                 :             : template <typename Client>
     568                 :          13 : void clientDestroy(Client& client)
     569                 :             : {
     570         [ +  - ]:          13 :     if (client.m_context.connection) {
     571   [ +  -  +  - ]:          26 :         client.m_context.loop->log() << "IPC client destroy " << typeid(client).name();
           [ #  #  #  #  
                   #  # ]
     572                 :             :     } else {
     573         [ #  # ]:           0 :         KJ_LOG(INFO, "IPC interrupted client destroy", typeid(client).name());
     574                 :             :     }
     575                 :          13 : }
     576                 :             : 
     577                 :             : template <typename Server>
     578                 :          13 : void serverDestroy(Server& server)
     579                 :             : {
     580   [ +  -  -  +  :          26 :     server.m_context.loop->log() << "IPC server destroy " << typeid(server).name();
                   +  - ]
     581                 :          13 : }
     582                 :             : 
     583                 :             : //! Entry point called by generated client code that looks like:
     584                 :             : //!
     585                 :             : //! ProxyClient<ClassName>::M0::Result ProxyClient<ClassName>::methodName(M0::Param<0> arg0, M0::Param<1> arg1) {
     586                 :             : //!     typename M0::Result result;
     587                 :             : //!     clientInvoke(*this, &InterfaceName::Client::methodNameRequest, MakeClientParam<...>(M0::Fwd<0>(arg0)), MakeClientParam<...>(M0::Fwd<1>(arg1)), MakeClientParam<...>(result));
     588                 :             : //!     return result;
     589                 :             : //! }
     590                 :             : //!
     591                 :             : //! Ellipses above are where generated Accessor<> type declarations are inserted.
     592                 :             : template <typename ProxyClient, typename GetRequest, typename... FieldObjs>
     593                 :          30 : void clientInvoke(ProxyClient& proxy_client, const GetRequest& get_request, FieldObjs&&... fields)
     594                 :             : {
     595         [ +  + ]:          30 :     if (!g_thread_context.waiter) {
     596         [ -  + ]:           1 :         assert(g_thread_context.thread_name.empty());
     597         [ +  - ]:           1 :         g_thread_context.thread_name = ThreadName(proxy_client.m_context.loop->m_exe_name);
     598                 :             :         // If next assert triggers, it means clientInvoke is being called from
     599                 :             :         // the capnp event loop thread. This can happen when a ProxyServer
     600                 :             :         // method implementation that runs synchronously on the event loop
     601                 :             :         // thread tries to make a blocking callback to the client. Any server
     602                 :             :         // method that makes a blocking callback or blocks in general needs to
     603                 :             :         // run asynchronously off the event loop thread. This is easy to fix by
     604                 :             :         // just adding a 'context :Proxy.Context' argument to the capnp method
     605                 :             :         // declaration so the server method runs in a dedicated thread.
     606         [ -  + ]:           1 :         assert(!g_thread_context.loop_thread);
     607         [ +  - ]:           1 :         g_thread_context.waiter = std::make_unique<Waiter>();
     608         [ +  - ]:           2 :         proxy_client.m_context.loop->logPlain()
     609         [ +  - ]:           1 :             << "{" << g_thread_context.thread_name
     610   [ +  -  +  -  :           1 :             << "} IPC client first request from current thread, constructing waiter";
                   +  - ]
     611                 :             :     }
     612                 :          30 :     ThreadContext& thread_context{g_thread_context};
     613                 :          30 :     std::optional<ClientInvokeContext> invoke_context; // Must outlive waiter->wait() call below
     614                 :          30 :     std::exception_ptr exception;
     615                 :          30 :     std::string kj_exception;
     616                 :          30 :     bool done = false;
     617                 :          30 :     const char* disconnected = nullptr;
     618         [ +  - ]:          60 :     proxy_client.m_context.loop->sync([&]() {
     619   [ -  +  -  +  :          30 :         if (!proxy_client.m_context.connection) {
          -  +  -  +  -  
           +  -  + ][ -  
          +  -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ -  -  -  
           +  -  + ][ #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     620                 :           0 :             const std::unique_lock<std::mutex> lock(thread_context.waiter->m_mutex);
     621                 :           0 :             done = true;
     622                 :           0 :             disconnected = "IPC client method called after disconnect.";
     623                 :           0 :             thread_context.waiter->m_cv.notify_all();
     624   [ #  #  #  #  :           0 :             return;
          #  #  #  #  #  
           #  #  # ][ #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ #  #  #  
           #  #  # ][ #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     625                 :           0 :         }
     626                 :             : 
     627   [ +  -  +  -  :          30 :         auto request = (proxy_client.m_client.*get_request)(nullptr);
          +  -  +  -  +  
           -  +  - ][ +  
          -  +  -  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ -  -  +  
           -  +  - ][ #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     628                 :             :         using Request = CapRequestTraits<decltype(request)>;
     629                 :             :         using FieldList = typename ProxyClientMethodTraits<typename Request::Params>::Fields;
     630   [ -  +  -  +  :          30 :         invoke_context.emplace(*proxy_client.m_context.connection, thread_context);
          -  +  -  +  -  
           +  -  + ][ -  
          +  -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ -  -  -  
           +  -  + ][ #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     631   [ +  -  +  -  :          30 :         IterateFields().handleChain(*invoke_context, request, FieldList(), typename FieldObjs::BuildParams{&fields}...);
          +  -  +  -  +  
           - ][ +  -  +  
          -  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  #  # ][ #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  #  # ][ -  
             -  +  -  +  
           - ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     632   [ +  -  +  -  :          60 :         proxy_client.m_context.loop->logPlain()
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
             -  +  -  +  
           - ][ +  -  +  
          -  +  -  +  -  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
           # ][ -  -  -  
          -  +  -  +  -  
             +  -  +  - ]
           [ #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     633                 :          30 :             << "{" << thread_context.thread_name << "} IPC client send "
     634   [ +  -  +  -  :         180 :             << TypeName<typename Request::Params>() << " " << LogEscape(request.toString());
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
           [ +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
           [ #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
           +  - ][ #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     635                 :             : 
     636   [ +  -  +  -  :          90 :         proxy_client.m_context.loop->m_task_set->add(request.send().then(
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
           +  - ][ +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
           [ #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  #  # ][ -  
          -  -  -  -  -  
          +  -  +  -  +  
          -  +  -  +  -  
           +  - ][ #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     637                 :          90 :             [&](::capnp::Response<typename Request::Results>&& response) {
     638   [ +  -  +  -  :          30 :                 proxy_client.m_context.loop->logPlain()
          +  -  +  -  +  
           -  +  - ][ +  
          -  +  -  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ -  -  +  
           -  +  - ][ #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     639                 :          30 :                     << "{" << thread_context.thread_name << "} IPC client recv "
     640   [ +  -  +  -  :         180 :                     << TypeName<typename Request::Results>() << " " << LogEscape(response.toString());
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
           +  - ][ +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
           [ #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  #  # ][ -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
           +  - ][ #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     641                 :             :                 try {
     642   [ +  -  +  -  :          30 :                     IterateFields().handleChain(
          +  -  +  -  +  
           - ][ +  -  #  
          #  #  #  #  #  
             #  #  #  # ]
           [ #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
           # ][ -  -  +  
           -  +  - ][ #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     643                 :             :                         *invoke_context, response, FieldList(), typename FieldObjs::ReadResults{&fields}...);
     644                 :           0 :                 } catch (...) {
     645   [ -  -  -  -  :           0 :                     exception = std::current_exception();
          -  -  -  -  -  
           - ][ -  -  -  
          -  -  -  -  -  
             -  -  -  - ]
           [ -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
             -  -  -  -  
           - ][ -  -  -  
           -  -  - ][ -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
                -  -  - ]
     646                 :             :                 }
     647                 :          30 :                 const std::unique_lock<std::mutex> lock(thread_context.waiter->m_mutex);
     648                 :          30 :                 done = true;
     649   [ +  -  +  -  :          30 :                 thread_context.waiter->m_cv.notify_all();
          +  -  +  -  +  
           -  +  - ][ +  
          -  +  -  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ -  -  +  
           -  +  - ][ #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     650                 :          30 :             },
     651   [ +  -  +  -  :          30 :             [&](const ::kj::Exception& e) {
          +  -  +  -  +  
           -  +  - ][ +  
          -  +  -  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ -  -  +  
           -  +  - ][ #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     652   [ #  #  #  #  :           0 :                 if (e.getType() == ::kj::Exception::Type::DISCONNECTED) {
          #  #  #  #  #  
           #  #  # ][ #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ #  #  #  
           #  #  # ][ #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     653                 :           0 :                     disconnected = "IPC client method call interrupted by disconnect.";
     654                 :             :                 } else {
     655   [ #  #  #  #  :           0 :                     kj_exception = kj::str("kj::Exception: ", e).cStr();
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
           [ #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     656   [ #  #  #  #  :           0 :                     proxy_client.m_context.loop->logPlain()
          #  #  #  #  #  
           #  #  # ][ #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ #  #  #  
           #  #  # ][ #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     657   [ #  #  #  #  :           0 :                         << "{" << thread_context.thread_name << "} IPC client exception " << kj_exception;
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
           [ #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  #  # ][ #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     658                 :             :                 }
     659                 :           0 :                 const std::unique_lock<std::mutex> lock(thread_context.waiter->m_mutex);
     660                 :           0 :                 done = true;
     661   [ #  #  #  #  :           0 :                 thread_context.waiter->m_cv.notify_all();
          #  #  #  #  #  
           #  #  # ][ #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ #  #  #  
           #  #  # ][ #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     662                 :           0 :             }));
     663                 :          30 :     });
     664                 :             : 
     665         [ +  - ]:          30 :     std::unique_lock<std::mutex> lock(thread_context.waiter->m_mutex);
     666         [ +  - ]:          90 :     thread_context.waiter->wait(lock, [&done]() { return done; });
     667         [ -  + ]:          30 :     if (exception) std::rethrow_exception(exception);
     668   [ -  +  -  -  :          30 :     if (!kj_exception.empty()) proxy_client.m_context.loop->raise() << kj_exception;
             -  -  -  - ]
     669   [ -  +  -  -  :          30 :     if (disconnected) proxy_client.m_context.loop->raise() << disconnected;
             -  -  -  - ]
     670         [ -  + ]:          30 : }
     671                 :             : 
     672                 :             : //! Invoke callable `fn()` that may return void. If it does return void, replace
     673                 :             : //! return value with value of `ret()`. This is useful for avoiding code
     674                 :             : //! duplication and branching in generic code that forwards calls to functions.
     675                 :             : template <typename Fn, typename Ret>
     676                 :          30 : auto ReplaceVoid(Fn&& fn, Ret&& ret)
     677                 :             : {
     678                 :             :     if constexpr (std::is_same_v<decltype(fn()), void>) {
     679                 :          12 :         fn();
     680                 :          12 :         return ret();
     681                 :             :     } else {
     682                 :          18 :         return fn();
     683                 :             :     }
     684                 :             : }
     685                 :             : 
     686                 :             : extern std::atomic<int> server_reqs;
     687                 :             : 
     688                 :             : //! Entry point called by generated server code that looks like:
     689                 :             : //!
     690                 :             : //! kj::Promise<void> ProxyServer<InterfaceName>::methodName(CallContext call_context) {
     691                 :             : //!     return serverInvoke(*this, call_context, MakeServerField<0, ...>(MakeServerField<1, ...>(Make<ServerRet, ...>(ServerCall()))));
     692                 :             : //! }
     693                 :             : //!
     694                 :             : //! Ellipses above are where generated Accessor<> type declarations are inserted.
     695                 :             : template <typename Server, typename CallContext, typename Fn>
     696                 :          30 : kj::Promise<void> serverInvoke(Server& server, CallContext& call_context, Fn fn)
     697                 :             : {
     698                 :          30 :     auto params = call_context.getParams();
     699                 :             :     using Params = decltype(params);
     700                 :             :     using Results = typename decltype(call_context.getResults())::Builds;
     701                 :             : 
     702                 :          30 :     int req = ++server_reqs;
     703                 :          30 :     server.m_context.loop->log() << "IPC server recv request  #" << req << " "
     704   [ +  -  +  -  :         210 :                                      << TypeName<typename Params::Reads>() << " " << LogEscape(params.toString());
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
     705                 :             : 
     706                 :             :     try {
     707                 :             :         using ServerContext = ServerInvokeContext<Server, CallContext>;
     708                 :             :         using ArgList = typename ProxyClientMethodTraits<typename Params::Reads>::Params;
     709         [ +  - ]:          30 :         ServerContext server_context{server, call_context, req};
     710                 :             :         // ReplaceVoid is used to support fn.invoke implementations that
     711                 :             :         // execute asynchronously and return promises, as well as
     712                 :             :         // implementations that execute synchronously and return void. The
     713                 :             :         // invoke function will be synchronous by default, but asynchronous if
     714                 :             :         // an mp.Context argument is passed, and the mp.Context PassField
     715                 :             :         // overload returns a promise executing the request in a worker thread
     716                 :             :         // and waiting for it to complete.
     717                 :          30 :         return ReplaceVoid([&]() { return fn.invoke(server_context, ArgList()); },
     718         [ +  - ]:          42 :             [&]() { return kj::Promise<CallContext>(kj::mv(call_context)); })
     719                 :          60 :             .then([&server, req](CallContext call_context) {
     720   [ +  -  +  -  :          60 :                 server.m_context.loop->log() << "IPC server send response #" << req << " " << TypeName<Results>()
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
             -  +  -  +  
           - ][ +  -  +  
          -  +  -  +  -  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
           # ][ -  -  -  
          -  +  -  +  -  
          +  -  +  -  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     721   [ +  -  +  -  :         210 :                                                  << " " << LogEscape(call_context.getResults().toString());
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  -  + ]
           [ +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
           [ #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
           [ #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     722   [ +  -  -  + ]:          30 :             });
     723   [ -  -  -  - ]:           0 :     } catch (const std::exception& e) {
     724   [ -  -  -  -  :           0 :         server.m_context.loop->log() << "IPC server unhandled exception: " << e.what();
                   -  - ]
     725                 :           0 :         throw;
     726                 :           0 :     } catch (...) {
     727   [ -  -  -  -  :           0 :         server.m_context.loop->log() << "IPC server unhandled exception";
                   -  - ]
     728                 :           0 :         throw;
     729                 :             :     }
     730                 :             : }
     731                 :             : 
     732                 :             : //! Map to convert client interface pointers to ProxyContext struct references
     733                 :             : //! at runtime using typeids.
     734                 :             : struct ProxyTypeRegister {
     735                 :             :     template<typename Interface>
     736                 :         705 :     ProxyTypeRegister(TypeList<Interface>) {
     737                 :        1410 :         types().emplace(typeid(Interface), [](void* iface) -> ProxyContext& { return static_cast<typename mp::ProxyType<Interface>::Client&>(*static_cast<Interface*>(iface)).m_context; });
     738                 :         705 :     }
     739                 :             :     using Types = std::map<std::type_index, ProxyContext&(*)(void*)>;
     740   [ +  +  +  - ]:         705 :     static Types& types() { static Types types; return types; }
     741                 :             : };
     742                 :             : 
     743                 :             : } // namespace mp
     744                 :             : 
     745                 :             : #endif // MP_PROXY_TYPES_H
        

Generated by: LCOV version 2.0-1