Home | History | Annotate | Line # | Download | only in libcc1
      1  1.1  mrg /* RPC call and callback templates
      2  1.7  mrg    Copyright (C) 2014-2022 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.7  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.7  mrg     argument_wrapper (const argument_wrapper &) = delete;
     44  1.7  mrg     argument_wrapper &operator= (const argument_wrapper &) = delete;
     45  1.7  mrg 
     46  1.7  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.7  mrg   // Specialization for any kind of pointer.
     59  1.1  mrg   template<typename T>
     60  1.7  mrg   class argument_wrapper<T *>
     61  1.3  mrg   {
     62  1.3  mrg   public:
     63  1.7  mrg     argument_wrapper () = default;
     64  1.7  mrg     ~argument_wrapper () = default;
     65  1.3  mrg 
     66  1.7  mrg     argument_wrapper (const argument_wrapper &) = delete;
     67  1.7  mrg     argument_wrapper &operator= (const argument_wrapper &) = delete;
     68  1.3  mrg 
     69  1.7  mrg     typedef typename std::remove_const<T>::type type;
     70  1.3  mrg 
     71  1.7  mrg     const type *get () const
     72  1.3  mrg     {
     73  1.7  mrg       return m_object.get ();
     74  1.3  mrg     }
     75  1.3  mrg 
     76  1.3  mrg     status unmarshall (connection *conn)
     77  1.3  mrg     {
     78  1.7  mrg       type *ptr;
     79  1.7  mrg       if (!::cc1_plugin::unmarshall (conn, &ptr))
     80  1.7  mrg 	return FAIL;
     81  1.7  mrg       m_object.reset (ptr);
     82  1.7  mrg       return OK;
     83  1.3  mrg     }
     84  1.3  mrg 
     85  1.3  mrg   private:
     86  1.3  mrg 
     87  1.7  mrg     unique_ptr<type> m_object;
     88  1.3  mrg   };
     89  1.3  mrg 
     90  1.1  mrg   // There are two kinds of template functions here: "call" and
     91  1.7  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.7  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.7  mrg   template<typename R, typename... Arg>
    105  1.1  mrg   status
    106  1.7  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.7  mrg     if (!marshall (conn, (int) sizeof... (Arg)))
    113  1.1  mrg       return FAIL;
    114  1.7  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.7  mrg   // The base case -- just return OK.
    124  1.7  mrg   template<int I, typename... T>
    125  1.7  mrg   typename std::enable_if<I == sizeof... (T), status>::type
    126  1.7  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.7  mrg   // Unmarshall this argument, then unmarshall all subsequent args.
    132  1.7  mrg   template<int I, typename... T>
    133  1.7  mrg   typename std::enable_if<I < sizeof... (T), status>::type
    134  1.7  mrg   unmarshall (connection *conn, std::tuple<T...> &value)
    135  1.1  mrg   {
    136  1.7  mrg     if (!std::get<I> (value).unmarshall (conn))
    137  1.1  mrg       return FAIL;
    138  1.7  mrg     return unmarshall<I + 1, T...> (conn, value);
    139  1.1  mrg   }
    140  1.1  mrg 
    141  1.7  mrg   // Wrap a static function that is suitable for use as a callback.
    142  1.7  mrg   // This is a template function inside a template class to work
    143  1.7  mrg   // around limitations with multiple variadic packs.
    144  1.7  mrg   template<typename R, typename... Arg>
    145  1.7  mrg   class invoker
    146  1.1  mrg   {
    147  1.7  mrg     // Base case -- we can call the function.
    148  1.7  mrg     template<int I, R func (connection *, Arg...), typename... T>
    149  1.7  mrg     static typename std::enable_if<I == sizeof... (Arg), R>::type
    150  1.7  mrg     call (connection *conn, const std::tuple<argument_wrapper<Arg>...> &,
    151  1.7  mrg 	  T... args)
    152  1.7  mrg     {
    153  1.7  mrg       return func (conn, args...);
    154  1.7  mrg     }
    155  1.1  mrg 
    156  1.7  mrg     // Unpack one argument and continue the recursion.
    157  1.7  mrg     template<int I, R func (connection *, Arg...), typename... T>
    158  1.7  mrg     static typename std::enable_if<I < sizeof... (Arg), R>::type
    159  1.7  mrg     call (connection *conn, const std::tuple<argument_wrapper<Arg>...> &value,
    160  1.7  mrg 	  T... args)
    161  1.7  mrg     {
    162  1.7  mrg       return call<I + 1, func> (conn, value, args...,
    163  1.7  mrg 				std::get<I> (value).get ());
    164  1.7  mrg     }
    165  1.1  mrg 
    166  1.7  mrg   public:
    167  1.1  mrg 
    168  1.7  mrg     // A callback function that reads arguments from the connection,
    169  1.7  mrg     // calls the wrapped function, and then sends the result back on
    170  1.7  mrg     // the connection.
    171  1.7  mrg     template<R func (connection *, Arg...)>
    172  1.7  mrg     static status
    173  1.7  mrg     invoke (connection *conn)
    174  1.7  mrg     {
    175  1.7  mrg       if (!unmarshall_check (conn, sizeof... (Arg)))
    176  1.7  mrg 	return FAIL;
    177  1.7  mrg       std::tuple<argument_wrapper<Arg>...> wrapped;
    178  1.7  mrg       if (!unmarshall<0> (conn, wrapped))
    179  1.7  mrg 	return FAIL;
    180  1.1  mrg 
    181  1.7  mrg       R result = call<0, func> (conn, wrapped);
    182  1.1  mrg 
    183  1.7  mrg       if (!conn->send ('R'))
    184  1.7  mrg 	return FAIL;
    185  1.7  mrg       return marshall (conn, result);
    186  1.7  mrg     }
    187  1.7  mrg   };
    188  1.1  mrg };
    189  1.1  mrg 
    190  1.1  mrg #endif // CC1_PLUGIN_RPC_HH
    191