Home | History | Annotate | Line # | Download | only in libcc1
      1      1.1  mrg /* RPC call and callback templates
      2  1.1.1.9  mrg    Copyright (C) 2014-2024 Free Software Foundation, Inc.
      3      1.1  mrg 
      4      1.1  mrg This file is part of GCC.
      5      1.1  mrg 
      6      1.1  mrg GCC is free software; you can redistribute it and/or modify it under
      7      1.1  mrg the terms of the GNU General Public License as published by the Free
      8      1.1  mrg Software Foundation; either version 3, or (at your option) any later
      9      1.1  mrg version.
     10      1.1  mrg 
     11      1.1  mrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
     12      1.1  mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13      1.1  mrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14      1.1  mrg for more details.
     15      1.1  mrg 
     16      1.1  mrg You should have received a copy of the GNU General Public License
     17      1.1  mrg along with GCC; see the file COPYING3.  If not see
     18      1.1  mrg <http://www.gnu.org/licenses/>.  */
     19      1.1  mrg 
     20      1.1  mrg #ifndef CC1_PLUGIN_RPC_HH
     21      1.1  mrg #define CC1_PLUGIN_RPC_HH
     22      1.1  mrg 
     23      1.1  mrg #include "status.hh"
     24      1.1  mrg #include "connection.hh"
     25  1.1.1.8  mrg #include "deleter.hh"
     26      1.1  mrg 
     27      1.1  mrg namespace cc1_plugin
     28      1.1  mrg {
     29      1.1  mrg   // The plugin API may contain some "const" method parameters.
     30      1.1  mrg   // However, when unmarshalling we cannot unmarshall into a const
     31      1.1  mrg   // object; and furthermore we want to be able to deallocate pointers
     32      1.1  mrg   // when finished with them.  This wrapper class lets us properly
     33      1.1  mrg   // remove the "const" and handle deallocation from pointer types.
     34      1.1  mrg 
     35      1.1  mrg   template<typename T>
     36      1.1  mrg   class argument_wrapper
     37      1.1  mrg   {
     38      1.1  mrg   public:
     39      1.1  mrg 
     40      1.1  mrg     argument_wrapper () { }
     41      1.1  mrg     ~argument_wrapper () { }
     42      1.1  mrg 
     43  1.1.1.8  mrg     argument_wrapper (const argument_wrapper &) = delete;
     44  1.1.1.8  mrg     argument_wrapper &operator= (const argument_wrapper &) = delete;
     45  1.1.1.8  mrg 
     46  1.1.1.8  mrg     T get () const { return m_object; }
     47      1.1  mrg 
     48      1.1  mrg     status unmarshall (connection *conn)
     49      1.1  mrg     {
     50      1.1  mrg       return ::cc1_plugin::unmarshall (conn, &m_object);
     51      1.1  mrg     }
     52      1.1  mrg 
     53      1.1  mrg   private:
     54      1.1  mrg 
     55      1.1  mrg     T m_object;
     56      1.1  mrg   };
     57      1.1  mrg 
     58  1.1.1.8  mrg   // Specialization for any kind of pointer.
     59      1.1  mrg   template<typename T>
     60  1.1.1.8  mrg   class argument_wrapper<T *>
     61  1.1.1.2  mrg   {
     62  1.1.1.2  mrg   public:
     63  1.1.1.8  mrg     argument_wrapper () = default;
     64  1.1.1.8  mrg     ~argument_wrapper () = default;
     65  1.1.1.2  mrg 
     66  1.1.1.8  mrg     argument_wrapper (const argument_wrapper &) = delete;
     67  1.1.1.8  mrg     argument_wrapper &operator= (const argument_wrapper &) = delete;
     68  1.1.1.2  mrg 
     69  1.1.1.8  mrg     typedef typename std::remove_const<T>::type type;
     70  1.1.1.2  mrg 
     71  1.1.1.8  mrg     const type *get () const
     72  1.1.1.2  mrg     {
     73  1.1.1.8  mrg       return m_object.get ();
     74  1.1.1.2  mrg     }
     75  1.1.1.2  mrg 
     76  1.1.1.2  mrg     status unmarshall (connection *conn)
     77  1.1.1.2  mrg     {
     78  1.1.1.8  mrg       type *ptr;
     79  1.1.1.8  mrg       if (!::cc1_plugin::unmarshall (conn, &ptr))
     80  1.1.1.8  mrg 	return FAIL;
     81  1.1.1.8  mrg       m_object.reset (ptr);
     82  1.1.1.8  mrg       return OK;
     83  1.1.1.2  mrg     }
     84  1.1.1.2  mrg 
     85  1.1.1.2  mrg   private:
     86  1.1.1.2  mrg 
     87  1.1.1.8  mrg     unique_ptr<type> m_object;
     88  1.1.1.2  mrg   };
     89  1.1.1.2  mrg 
     90      1.1  mrg   // There are two kinds of template functions here: "call" and
     91  1.1.1.8  mrg   // "invoker".
     92      1.1  mrg 
     93      1.1  mrg   // The "call" template is used for making a remote procedure call.
     94      1.1  mrg   // It starts a query ('Q') packet, marshalls its arguments, waits
     95      1.1  mrg   // for a result, and finally reads and returns the result via an
     96      1.1  mrg   // "out" parameter.
     97      1.1  mrg 
     98  1.1.1.8  mrg   // The "invoker" template is used when receiving a remote procedure
     99      1.1  mrg   // call.  This template function is suitable for use with the
    100      1.1  mrg   // "callbacks" and "connection" classes.  It decodes incoming
    101      1.1  mrg   // arguments, passes them to the wrapped function, and finally
    102      1.1  mrg   // marshalls a reply packet.
    103      1.1  mrg 
    104  1.1.1.8  mrg   template<typename R, typename... Arg>
    105      1.1  mrg   status
    106  1.1.1.8  mrg   call (connection *conn, const char *method, R *result, Arg... args)
    107      1.1  mrg   {
    108      1.1  mrg     if (!conn->send ('Q'))
    109      1.1  mrg       return FAIL;
    110      1.1  mrg     if (!marshall (conn, method))
    111      1.1  mrg       return FAIL;
    112  1.1.1.8  mrg     if (!marshall (conn, (int) sizeof... (Arg)))
    113      1.1  mrg       return FAIL;
    114  1.1.1.8  mrg     if (!marshall (conn, args...))
    115      1.1  mrg       return FAIL;
    116      1.1  mrg     if (!conn->wait_for_result ())
    117      1.1  mrg       return FAIL;
    118      1.1  mrg     if (!unmarshall (conn, result))
    119      1.1  mrg       return FAIL;
    120      1.1  mrg     return OK;
    121      1.1  mrg   }
    122      1.1  mrg 
    123  1.1.1.8  mrg   // The base case -- just return OK.
    124  1.1.1.8  mrg   template<int I, typename... T>
    125  1.1.1.8  mrg   typename std::enable_if<I == sizeof... (T), status>::type
    126  1.1.1.8  mrg   unmarshall (connection *, std::tuple<T...> &)
    127      1.1  mrg   {
    128      1.1  mrg     return OK;
    129      1.1  mrg   }
    130      1.1  mrg 
    131  1.1.1.8  mrg   // Unmarshall this argument, then unmarshall all subsequent args.
    132  1.1.1.8  mrg   template<int I, typename... T>
    133  1.1.1.8  mrg   typename std::enable_if<I < sizeof... (T), status>::type
    134  1.1.1.8  mrg   unmarshall (connection *conn, std::tuple<T...> &value)
    135      1.1  mrg   {
    136  1.1.1.8  mrg     if (!std::get<I> (value).unmarshall (conn))
    137      1.1  mrg       return FAIL;
    138  1.1.1.8  mrg     return unmarshall<I + 1, T...> (conn, value);
    139      1.1  mrg   }
    140      1.1  mrg 
    141  1.1.1.8  mrg   // Wrap a static function that is suitable for use as a callback.
    142  1.1.1.8  mrg   // This is a template function inside a template class to work
    143  1.1.1.8  mrg   // around limitations with multiple variadic packs.
    144  1.1.1.8  mrg   template<typename R, typename... Arg>
    145  1.1.1.8  mrg   class invoker
    146      1.1  mrg   {
    147  1.1.1.8  mrg     // Base case -- we can call the function.
    148  1.1.1.8  mrg     template<int I, R func (connection *, Arg...), typename... T>
    149  1.1.1.8  mrg     static typename std::enable_if<I == sizeof... (Arg), R>::type
    150  1.1.1.8  mrg     call (connection *conn, const std::tuple<argument_wrapper<Arg>...> &,
    151  1.1.1.8  mrg 	  T... args)
    152  1.1.1.8  mrg     {
    153  1.1.1.8  mrg       return func (conn, args...);
    154  1.1.1.8  mrg     }
    155      1.1  mrg 
    156  1.1.1.8  mrg     // Unpack one argument and continue the recursion.
    157  1.1.1.8  mrg     template<int I, R func (connection *, Arg...), typename... T>
    158  1.1.1.8  mrg     static typename std::enable_if<I < sizeof... (Arg), R>::type
    159  1.1.1.8  mrg     call (connection *conn, const std::tuple<argument_wrapper<Arg>...> &value,
    160  1.1.1.8  mrg 	  T... args)
    161  1.1.1.8  mrg     {
    162  1.1.1.8  mrg       return call<I + 1, func> (conn, value, args...,
    163  1.1.1.8  mrg 				std::get<I> (value).get ());
    164  1.1.1.8  mrg     }
    165      1.1  mrg 
    166  1.1.1.8  mrg   public:
    167      1.1  mrg 
    168  1.1.1.8  mrg     // A callback function that reads arguments from the connection,
    169  1.1.1.8  mrg     // calls the wrapped function, and then sends the result back on
    170  1.1.1.8  mrg     // the connection.
    171  1.1.1.8  mrg     template<R func (connection *, Arg...)>
    172  1.1.1.8  mrg     static status
    173  1.1.1.8  mrg     invoke (connection *conn)
    174  1.1.1.8  mrg     {
    175  1.1.1.8  mrg       if (!unmarshall_check (conn, sizeof... (Arg)))
    176  1.1.1.8  mrg 	return FAIL;
    177  1.1.1.8  mrg       std::tuple<argument_wrapper<Arg>...> wrapped;
    178  1.1.1.8  mrg       if (!unmarshall<0> (conn, wrapped))
    179  1.1.1.8  mrg 	return FAIL;
    180      1.1  mrg 
    181  1.1.1.8  mrg       R result = call<0, func> (conn, wrapped);
    182      1.1  mrg 
    183  1.1.1.8  mrg       if (!conn->send ('R'))
    184  1.1.1.8  mrg 	return FAIL;
    185  1.1.1.8  mrg       return marshall (conn, result);
    186  1.1.1.8  mrg     }
    187  1.1.1.8  mrg   };
    188      1.1  mrg };
    189      1.1  mrg 
    190      1.1  mrg #endif // CC1_PLUGIN_RPC_HH
    191