LCOV - code coverage report
Current view: top level - src/ipc/libmultiprocess/include/mp - proxy.h (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 93.8 % 16 15
Test Date: 2025-08-25 05:11:47 Functions: 44.4 % 18 8
Branches: 20.7 % 58 12

             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_H
       6                 :             : #define MP_PROXY_H
       7                 :             : 
       8                 :             : #include <mp/util.h>
       9                 :             : 
      10                 :             : #include <cassert>
      11                 :             : #include <functional>
      12                 :             : #include <list>
      13                 :             : #include <memory>
      14                 :             : #include <stddef.h>
      15                 :             : #include <tuple>
      16                 :             : #include <type_traits>
      17                 :             : #include <utility>
      18                 :             : #include <variant> // IWYU pragma: keep
      19                 :             : 
      20                 :             : namespace mp {
      21                 :             : class Connection;
      22                 :             : class EventLoop;
      23                 :             : //! Mapping from capnp interface type to proxy client implementation (specializations are generated by
      24                 :             : //! proxy-codegen.cpp).
      25                 :             : template <typename Interface> struct ProxyClient; // IWYU pragma: export
      26                 :             : //! Mapping from capnp interface type to proxy server implementation (specializations are generated by
      27                 :             : //! proxy-codegen.cpp).
      28                 :             : template <typename Interface> struct ProxyServer; // IWYU pragma: export
      29                 :             : //! Mapping from capnp method params type to method traits (specializations are generated by proxy-codegen.cpp).
      30                 :             : template <typename Params> struct ProxyMethod; // IWYU pragma: export
      31                 :             : //! Mapping from capnp struct type to struct traits (specializations are generated by proxy-codegen.cpp).
      32                 :             : template <typename Struct> struct ProxyStruct; // IWYU pragma: export
      33                 :             : //! Mapping from local c++ type to capnp type and traits (specializations are generated by proxy-codegen.cpp).
      34                 :             : template <typename Type> struct ProxyType; // IWYU pragma: export
      35                 :             : 
      36                 :             : using CleanupList = std::list<std::function<void()>>;
      37                 :             : using CleanupIt = typename CleanupList::iterator;
      38                 :             : 
      39                 :          56 : inline void CleanupRun(CleanupList& fns) {
      40         [ +  + ]:          99 :     while (!fns.empty()) {
      41                 :          43 :         auto fn = std::move(fns.front());
      42                 :          43 :         fns.pop_front();
      43         [ +  - ]:          43 :         fn();
      44                 :          43 :     }
      45                 :          56 : }
      46                 :             : 
      47                 :             : //! Event loop smart pointer automatically managing m_num_clients.
      48                 :             : //! If a lock pointer argument is passed, the specified lock will be used,
      49                 :             : //! otherwise EventLoop::m_mutex will be locked when needed.
      50                 :             : class EventLoopRef
      51                 :             : {
      52                 :             : public:
      53                 :             :     explicit EventLoopRef(EventLoop& loop, Lock* lock = nullptr);
      54                 :             :     EventLoopRef(EventLoopRef&& other) noexcept : m_loop(other.m_loop) { other.m_loop = nullptr; }
      55                 :             :     EventLoopRef(const EventLoopRef&) = delete;
      56                 :             :     EventLoopRef& operator=(const EventLoopRef&) = delete;
      57                 :             :     EventLoopRef& operator=(EventLoopRef&&) = delete;
      58         [ +  - ]:         109 :     ~EventLoopRef() { reset(); }
      59         [ -  + ]:          70 :     EventLoop& operator*() const { assert(m_loop); return *m_loop; }
      60         [ -  + ]:         455 :     EventLoop* operator->() const { assert(m_loop); return m_loop; }
      61                 :             :     void reset(bool relock=false);
      62                 :             : 
      63                 :             :     EventLoop* m_loop{nullptr};
      64                 :             :     Lock* m_lock{nullptr};
      65                 :             : };
      66                 :             : 
      67                 :             : //! Context data associated with proxy client and server classes.
      68                 :             : struct ProxyContext
      69                 :             : {
      70                 :             :     Connection* connection;
      71                 :             :     EventLoopRef loop;
      72                 :             :     CleanupList cleanup_fns;
      73                 :             : 
      74                 :             :     ProxyContext(Connection* connection);
      75                 :             : };
      76                 :             : 
      77                 :             : //! Base class for generated ProxyClient classes that implement a C++ interface
      78                 :             : //! and forward calls to a capnp interface.
      79                 :             : template <typename Interface_, typename Impl_>
      80                 :             : class ProxyClientBase : public Impl_
      81                 :             : {
      82                 :             : public:
      83                 :             :     using Interface = Interface_;
      84                 :             :     using Impl = Impl_;
      85                 :             :     using Sub = ProxyClient<Interface>;
      86                 :             :     using Super = ProxyClientBase<Interface, Impl>;
      87                 :             : 
      88                 :             :     //! Construct libmultiprocess client object wrapping Cap'n Proto client
      89                 :             :     //! object with a reference to the associated mp::Connection object.
      90                 :             :     //!
      91                 :             :     //! The destroy_connection option determines whether destroying this client
      92                 :             :     //! object closes the connection. It is set to true for the
      93                 :             :     //! ProxyClient<InitInterface> object returned by ConnectStream, to let IPC
      94                 :             :     //! clients close the connection by freeing the object. It is false for
      95                 :             :     //! other client objects so they can be destroyed without affecting the
      96                 :             :     //! connection.
      97                 :             :     ProxyClientBase(typename Interface::Client client, Connection* connection, bool destroy_connection);
      98                 :             :     ~ProxyClientBase() noexcept;
      99                 :             : 
     100                 :             :     // construct/destroy methods called during client construction/destruction
     101                 :             :     // that can optionally be defined in capnp interfaces to invoke code on the
     102                 :             :     // server when proxy client objects are created and destroyed.
     103                 :             :     //
     104                 :             :     // The construct() method is not generally very useful, but can be used to
     105                 :             :     // run custom code on the server automatically when a ProxyClient client is
     106                 :             :     // constructed. The only current use is adding a construct method to Init
     107                 :             :     // interfaces that is called automatically on construction, so client and
     108                 :             :     // server exchange ThreadMap references and set Connection::m_thread_map
     109                 :             :     // values as soon as the Init client is created.
     110                 :             :     //
     111                 :             :     //     construct @0 (threadMap: Proxy.ThreadMap) -> (threadMap: Proxy.ThreadMap);
     112                 :             :     //
     113                 :             :     // But construct() is not necessary for this, thread maps could be passed
     114                 :             :     // through a normal method that is just called explicitly rather than
     115                 :             :     // implicitly.
     116                 :             :     //
     117                 :             :     // The destroy() method is more generally useful than construct(), because
     118                 :             :     // it ensures that the server object will be destroyed synchronously before
     119                 :             :     // the client destructor returns, instead of asynchronously at some
     120                 :             :     // unpredictable time after the client object is already destroyed and
     121                 :             :     // client code has moved on. If the destroy method accepts a Context
     122                 :             :     // parameter like:
     123                 :             :     //
     124                 :             :     //     destroy @0 (context: Proxy.Context) -> ();
     125                 :             :     //
     126                 :             :     // then it will also ensure that the destructor runs on the same thread the
     127                 :             :     // client used to make other RPC calls, instead of running on the server
     128                 :             :     // EventLoop thread and possibly blocking it.
     129                 :          37 :     static void construct(Super&) {}
     130                 :             :     static void destroy(Super&) {}
     131                 :             : 
     132                 :             :     typename Interface::Client m_client;
     133                 :             :     ProxyContext m_context;
     134                 :             : };
     135                 :             : 
     136                 :             : //! Customizable (through template specialization) base class used in generated ProxyClient implementations from
     137                 :             : //! proxy-codegen.cpp.
     138                 :             : template <typename Interface, typename Impl>
     139                 :          13 : class ProxyClientCustom : public ProxyClientBase<Interface, Impl>
     140                 :             : {
     141 [ +  - ][ +  -  :          13 :     using ProxyClientBase<Interface, Impl>::ProxyClientBase;
          +  -  #  #  #  
          #  #  #  #  #  
           #  # ][ -  -  
          -  -  +  -  +  
                      - ]
           [ #  #  #  # ]
     142                 :             : };
     143                 :             : 
     144                 :             : //! Base class for generated ProxyServer classes that implement capnp server
     145                 :             : //! methods and forward calls to a wrapped c++ implementation class.
     146                 :             : template <typename Interface_, typename Impl_>
     147                 :             : struct ProxyServerBase : public virtual Interface_::Server
     148                 :             : {
     149                 :             : public:
     150                 :             :     using Interface = Interface_;
     151                 :             :     using Impl = Impl_;
     152                 :             : 
     153                 :             :     ProxyServerBase(std::shared_ptr<Impl> impl, Connection& connection);
     154                 :             :     virtual ~ProxyServerBase();
     155                 :             :     void invokeDestroy();
     156                 :             : 
     157                 :             :     /**
     158                 :             :      * Implementation pointer that may or may not be owned and deleted when this
     159                 :             :      * capnp server goes out of scope. It is owned for servers created to wrap
     160                 :             :      * unique_ptr<Impl> method arguments, but unowned for servers created to
     161                 :             :      * wrap Impl& method arguments.
     162                 :             :      *
     163                 :             :      * In the case of Impl& arguments, custom code is required on other side of
     164                 :             :      * the connection to delete the capnp client & server objects since native
     165                 :             :      * code on that side of the connection will just be taking a plain reference
     166                 :             :      * rather than a pointer, so won't be able to do its own cleanup. Right now
     167                 :             :      * this is implemented with addCloseHook callbacks to delete clients at
     168                 :             :      * appropriate times depending on semantics of the particular method being
     169                 :             :      * wrapped. */
     170                 :             :     std::shared_ptr<Impl> m_impl;
     171                 :             :     ProxyContext m_context;
     172                 :             : };
     173                 :             : 
     174                 :             : //! Customizable (through template specialization) base class which ProxyServer
     175                 :             : //! classes produced by generated code will inherit from. The default
     176                 :             : //! specialization of this class just inherits from ProxyServerBase, but custom
     177                 :             : //! specializations can be defined to control ProxyServer behavior.
     178                 :             : //!
     179                 :             : //! Specifically, it can be useful to specialize this class to add additional
     180                 :             : //! state to ProxyServer classes, for example to cache state between IPC calls.
     181                 :             : //! If this is done, however, care should be taken to ensure that the extra
     182                 :             : //! state can be destroyed without blocking, because ProxyServer destructors are
     183                 :             : //! called from the EventLoop thread, and if they block, it could deadlock the
     184                 :             : //! program. One way to do avoid blocking is to clean up the state by pushing
     185                 :             : //! cleanup callbacks to the m_context.cleanup_fns list, which run after the server
     186                 :             : //! m_impl object is destroyed on the same thread destroying it (which will
     187                 :             : //! either be an IPC worker thread if the ProxyServer is being explicitly
     188                 :             : //! destroyed by a client calling a destroy() method with a Context argument and
     189                 :             : //! Context.thread value set, or the temporary EventLoop::m_async_thread used to
     190                 :             : //! run destructors without blocking the event loop when no-longer used server
     191                 :             : //! objects are garbage collected by Cap'n Proto.) Alternately, if cleanup needs
     192                 :             : //! to run before m_impl is destroyed, the specialization can override
     193                 :             : //! invokeDestroy and destructor methods to do that.
     194                 :             : template <typename Interface, typename Impl>
     195                 :             : struct ProxyServerCustom : public ProxyServerBase<Interface, Impl>
     196                 :             : {
     197                 :             :     using ProxyServerBase<Interface, Impl>::ProxyServerBase;
     198                 :             : };
     199                 :             : 
     200                 :             : //! Function traits class used to get method parameter and result types, used in
     201                 :             : //! generated ProxyClient and ProxyServer classes produced by gen.cpp to get C++
     202                 :             : //! method type information. The generated code accesses these traits via
     203                 :             : //! intermediate ProxyClientMethodTraits and ProxyServerMethodTraits classes,
     204                 :             : //! which it is possible to specialize to change the way method arguments and
     205                 :             : //! return values are handled.
     206                 :             : //!
     207                 :             : //! Fields of the trait class are:
     208                 :             : //!
     209                 :             : //! Params   - TypeList of C++ ClassName::methodName parameter types
     210                 :             : //! Result   - Return type of ClassName::method
     211                 :             : //! Param<N> - helper to access individual parameter types by index number.
     212                 :             : //! Fwd<N>   - helper to forward arguments by index number.
     213                 :             : //! Fields   - helper alias that appends Result type to the Params typelist if
     214                 :             : //!            it not void.
     215                 :             : template <class Fn>
     216                 :             : struct FunctionTraits;
     217                 :             : 
     218                 :             : //! Specialization of above extracting result and params types assuming the
     219                 :             : //! template argument is a pointer-to-method type,
     220                 :             : //! decltype(&ClassName::methodName)
     221                 :             : template <class _Class, class _Result, class... _Params>
     222                 :             : struct FunctionTraits<_Result (_Class::*const)(_Params...)>
     223                 :             : {
     224                 :             :     using Params = TypeList<_Params...>;
     225                 :             :     using Result = _Result;
     226                 :             :     template <size_t N>
     227                 :             :     using Param = typename std::tuple_element<N, std::tuple<_Params...>>::type;
     228                 :             :     using Fields =
     229                 :             :         std::conditional_t<std::is_same_v<void, Result>, Params, TypeList<_Params..., _Result>>;
     230                 :             : 
     231                 :             :     //! Enable perfect forwarding for clientInvoke calls. If parameter is a
     232                 :             :     //! value type or rvalue reference type, pass it as an rvalue-reference to
     233                 :             :     //! MakeClientParam and BuildField calls so it can be moved from, and if it
     234                 :             :     //! is an lvalue reference, pass it an lvalue reference so it won't be moved
     235                 :             :     //! from. This method does the same thing as std::forward except it takes a
     236                 :             :     //! parameter number instead of a type as a template argument, so generated
     237                 :             :     //! code calling this can be less repetitive and verbose.
     238                 :             :     template <size_t N>
     239                 :             :     static decltype(auto) Fwd(Param<N>& arg) { return static_cast<Param<N>&&>(arg); }
     240                 :             : };
     241                 :             : 
     242                 :             : //! Traits class for a proxy method, providing the same
     243                 :             : //! Params/Result/Param/Fields described in the FunctionTraits class above, plus
     244                 :             : //! an additional invoke() method that calls the C++ method which is being
     245                 :             : //! proxied, forwarding any arguments.
     246                 :             : //!
     247                 :             : //! The template argument should be the InterfaceName::MethodNameParams class
     248                 :             : //! (generated by Cap'n Proto) associated with the method.
     249                 :             : //!
     250                 :             : //! Note: The class definition here is just the fallback definition used when
     251                 :             : //! the other specialization below doesn't match. The fallback is only used for
     252                 :             : //! capnp methods which do not have corresponding C++ methods, which in practice
     253                 :             : //! is just the two special construct() and destroy() methods described in \ref
     254                 :             : //! ProxyClientBase. These methods don't have any C++ parameters or return
     255                 :             : //! types, so the trait information below reflects that.
     256                 :             : template <typename MethodParams, typename Enable = void>
     257                 :             : struct ProxyMethodTraits
     258                 :             : {
     259                 :             :     using Params = TypeList<>;
     260                 :             :     using Result = void;
     261                 :             :     using Fields = Params;
     262                 :             : 
     263                 :             :     template <typename ServerContext>
     264                 :             :     static void invoke(ServerContext&)
     265                 :             :     {
     266                 :             :     }
     267                 :             : };
     268                 :             : 
     269                 :             : //! Specialization of above for proxy methods that have a
     270                 :             : //! ProxyMethod<InterfaceName::MethodNameParams>::impl pointer-to-method
     271                 :             : //! constant defined by generated code. This includes all functions defined in
     272                 :             : //! the capnp interface except any construct() or destroy() methods, that are
     273                 :             : //! assumed not to correspond to real member functions in the C++ class, and
     274                 :             : //! will use the fallback traits definition above. The generated code this
     275                 :             : //! specialization relies on looks like:
     276                 :             : //!
     277                 :             : //! struct ProxyMethod<InterfaceName::MethodNameParams>
     278                 :             : //! {
     279                 :             : //!     static constexpr auto impl = &ClassName::methodName;
     280                 :             : //! };
     281                 :             : template <typename MethodParams>
     282                 :             : struct ProxyMethodTraits<MethodParams, Require<decltype(ProxyMethod<MethodParams>::impl)>>
     283                 :             :     : public FunctionTraits<decltype(ProxyMethod<MethodParams>::impl)>
     284                 :             : {
     285                 :             :     template <typename ServerContext, typename... Args>
     286                 :          18 :     static decltype(auto) invoke(ServerContext& server_context, Args&&... args)
     287                 :             :     {
     288 [ +  - ][ #  #  :          18 :         return (server_context.proxy_server.m_impl.get()->*ProxyMethod<MethodParams>::impl)(std::forward<Args>(args)...);
          #  #  #  #  #  
             #  #  #  #  
                      # ]
           [ #  #  #  # ]
     289                 :             :     }
     290                 :             : };
     291                 :             : 
     292                 :             : //! Customizable (through template specialization) traits class used in generated ProxyClient implementations from
     293                 :             : //! proxy-codegen.cpp.
     294                 :             : template <typename MethodParams>
     295                 :             : struct ProxyClientMethodTraits : public ProxyMethodTraits<MethodParams>
     296                 :             : {
     297                 :             : };
     298                 :             : 
     299                 :             : //! Customizable (through template specialization) traits class used in generated ProxyServer implementations from
     300                 :             : //! proxy-codegen.cpp.
     301                 :             : template <typename MethodParams>
     302                 :             : struct ProxyServerMethodTraits : public ProxyMethodTraits<MethodParams>
     303                 :             : {
     304                 :             : };
     305                 :             : 
     306                 :             : static constexpr int FIELD_IN = 1;
     307                 :             : static constexpr int FIELD_OUT = 2;
     308                 :             : static constexpr int FIELD_OPTIONAL = 4;
     309                 :             : static constexpr int FIELD_REQUESTED = 8;
     310                 :             : static constexpr int FIELD_BOXED = 16;
     311                 :             : 
     312                 :             : //! Accessor type holding flags that determine how to access a message field.
     313                 :             : template <typename Field, int flags>
     314                 :             : struct Accessor : public Field
     315                 :             : {
     316                 :             :     static const bool in = flags & FIELD_IN;
     317                 :             :     static const bool out = flags & FIELD_OUT;
     318                 :             :     static const bool optional = flags & FIELD_OPTIONAL;
     319                 :             :     static const bool requested = flags & FIELD_REQUESTED;
     320                 :             :     static const bool boxed = flags & FIELD_BOXED;
     321                 :             : };
     322                 :             : 
     323                 :             : //! Wrapper around std::function for passing std::function objects between client and servers.
     324                 :             : template <typename Fn>
     325                 :             : class ProxyCallback;
     326                 :             : 
     327                 :             : //! Specialization of above to separate Result and Arg types.
     328                 :             : template <typename Result, typename... Args>
     329         [ #  # ]:           0 : class ProxyCallback<std::function<Result(Args...)>>
     330                 :             : {
     331                 :             : public:
     332                 :             :     virtual Result call(Args&&... args) = 0;
     333                 :             : };
     334                 :             : 
     335                 :             : } // namespace mp
     336                 :             : 
     337                 :             : #endif // MP_PROXY_H
        

Generated by: LCOV version 2.0-1