Home | History | Annotate | Line # | Download | only in libcc1
rpc.hh revision 1.1.1.3
      1 /* RPC call and callback templates
      2    Copyright (C) 2014-2018 Free Software Foundation, Inc.
      3 
      4 This file is part of GCC.
      5 
      6 GCC is free software; you can redistribute it and/or modify it under
      7 the terms of the GNU General Public License as published by the Free
      8 Software Foundation; either version 3, or (at your option) any later
      9 version.
     10 
     11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
     12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14 for more details.
     15 
     16 You should have received a copy of the GNU General Public License
     17 along with GCC; see the file COPYING3.  If not see
     18 <http://www.gnu.org/licenses/>.  */
     19 
     20 #ifndef CC1_PLUGIN_RPC_HH
     21 #define CC1_PLUGIN_RPC_HH
     22 
     23 #include "status.hh"
     24 #include "connection.hh"
     25 
     26 namespace cc1_plugin
     27 {
     28   // The plugin API may contain some "const" method parameters.
     29   // However, when unmarshalling we cannot unmarshall into a const
     30   // object; and furthermore we want to be able to deallocate pointers
     31   // when finished with them.  This wrapper class lets us properly
     32   // remove the "const" and handle deallocation from pointer types.
     33 
     34   template<typename T>
     35   class argument_wrapper
     36   {
     37   public:
     38 
     39     argument_wrapper () { }
     40     ~argument_wrapper () { }
     41 
     42     operator T () const { return m_object; }
     43 
     44     status unmarshall (connection *conn)
     45     {
     46       return ::cc1_plugin::unmarshall (conn, &m_object);
     47     }
     48 
     49   private:
     50 
     51     T m_object;
     52 
     53     // No copying or assignment allowed.
     54     argument_wrapper (const argument_wrapper &);
     55     argument_wrapper &operator= (const argument_wrapper &);
     56   };
     57 
     58   // Specialization for any kind of pointer.  This is declared but not
     59   // defined to avoid bugs if a new pointer type is introduced into
     60   // the API.  Instead you will just get a compilation error.
     61   template<typename T>
     62   class argument_wrapper<const T *>;
     63 
     64   // Specialization for string types.
     65   template<>
     66   class argument_wrapper<const char *>
     67   {
     68   public:
     69     argument_wrapper () : m_object (NULL) { }
     70     ~argument_wrapper ()
     71     {
     72       delete[] m_object;
     73     }
     74 
     75     operator const char * () const
     76     {
     77       return m_object;
     78     }
     79 
     80     status unmarshall (connection *conn)
     81     {
     82       return ::cc1_plugin::unmarshall (conn, &m_object);
     83     }
     84 
     85   private:
     86 
     87     char *m_object;
     88 
     89     // No copying or assignment allowed.
     90     argument_wrapper (const argument_wrapper &);
     91     argument_wrapper &operator= (const argument_wrapper &);
     92   };
     93 
     94   // Specialization for gcc_type_array.
     95   template<>
     96   class argument_wrapper<const gcc_type_array *>
     97   {
     98   public:
     99     argument_wrapper () : m_object (NULL) { }
    100     ~argument_wrapper ()
    101     {
    102       // It would be nicer if gcc_type_array could have a destructor.
    103       // But, it is in code shared with gdb and cannot.
    104       if (m_object != NULL)
    105 	delete[] m_object->elements;
    106       delete m_object;
    107     }
    108 
    109     operator const gcc_type_array * () const
    110     {
    111       return m_object;
    112     }
    113 
    114     status unmarshall (connection *conn)
    115     {
    116       return ::cc1_plugin::unmarshall (conn, &m_object);
    117     }
    118 
    119   private:
    120 
    121     gcc_type_array *m_object;
    122 
    123     // No copying or assignment allowed.
    124     argument_wrapper (const argument_wrapper &);
    125     argument_wrapper &operator= (const argument_wrapper &);
    126   };
    127 
    128 #ifdef GCC_CP_INTERFACE_H
    129   // Specialization for gcc_vbase_array.
    130   template<>
    131   class argument_wrapper<const gcc_vbase_array *>
    132   {
    133   public:
    134     argument_wrapper () : m_object (NULL) { }
    135     ~argument_wrapper ()
    136     {
    137       // It would be nicer if gcc_type_array could have a destructor.
    138       // But, it is in code shared with gdb and cannot.
    139       if (m_object != NULL)
    140 	{
    141 	  delete[] m_object->flags;
    142 	  delete[] m_object->elements;
    143 	}
    144       delete m_object;
    145     }
    146 
    147     operator const gcc_vbase_array * () const
    148     {
    149       return m_object;
    150     }
    151 
    152     status unmarshall (connection *conn)
    153     {
    154       return ::cc1_plugin::unmarshall (conn, &m_object);
    155     }
    156 
    157   private:
    158 
    159     gcc_vbase_array *m_object;
    160 
    161     // No copying or assignment allowed.
    162     argument_wrapper (const argument_wrapper &);
    163     argument_wrapper &operator= (const argument_wrapper &);
    164   };
    165 
    166   // Specialization for gcc_cp_template_args.
    167   template<>
    168   class argument_wrapper<const gcc_cp_template_args *>
    169   {
    170   public:
    171     argument_wrapper () : m_object (NULL) { }
    172     ~argument_wrapper ()
    173     {
    174       // It would be nicer if gcc_type_array could have a destructor.
    175       // But, it is in code shared with gdb and cannot.
    176       if (m_object != NULL)
    177 	{
    178 	  delete[] m_object->elements;
    179 	  delete[] m_object->kinds;
    180 	}
    181       delete m_object;
    182     }
    183 
    184     operator const gcc_cp_template_args * () const
    185     {
    186       return m_object;
    187     }
    188 
    189     status unmarshall (connection *conn)
    190     {
    191       return ::cc1_plugin::unmarshall (conn, &m_object);
    192     }
    193 
    194   private:
    195 
    196     gcc_cp_template_args *m_object;
    197 
    198     // No copying or assignment allowed.
    199     argument_wrapper (const argument_wrapper &);
    200     argument_wrapper &operator= (const argument_wrapper &);
    201   };
    202 
    203   // Specialization for gcc_cp_function_args.
    204   template<>
    205   class argument_wrapper<const gcc_cp_function_args *>
    206   {
    207   public:
    208     argument_wrapper () : m_object (NULL) { }
    209     ~argument_wrapper ()
    210     {
    211       // It would be nicer if gcc_type_array could have a destructor.
    212       // But, it is in code shared with gdb and cannot.
    213       if (m_object != NULL)
    214 	{
    215 	  delete[] m_object->elements;
    216 	}
    217       delete m_object;
    218     }
    219 
    220     operator const gcc_cp_function_args * () const
    221     {
    222       return m_object;
    223     }
    224 
    225     status unmarshall (connection *conn)
    226     {
    227       return ::cc1_plugin::unmarshall (conn, &m_object);
    228     }
    229 
    230   private:
    231 
    232     gcc_cp_function_args *m_object;
    233 
    234     // No copying or assignment allowed.
    235     argument_wrapper (const argument_wrapper &);
    236     argument_wrapper &operator= (const argument_wrapper &);
    237   };
    238 #endif /* GCC_CP_INTERFACE_H */
    239 
    240   // There are two kinds of template functions here: "call" and
    241   // "callback".  They are each repeated multiple times to handle
    242   // different numbers of arguments.  (This would be improved with
    243   // C++11, though applying a call is still tricky until C++14 can be
    244   // used.)
    245 
    246   // The "call" template is used for making a remote procedure call.
    247   // It starts a query ('Q') packet, marshalls its arguments, waits
    248   // for a result, and finally reads and returns the result via an
    249   // "out" parameter.
    250 
    251   // The "callback" template is used when receiving a remote procedure
    252   // call.  This template function is suitable for use with the
    253   // "callbacks" and "connection" classes.  It decodes incoming
    254   // arguments, passes them to the wrapped function, and finally
    255   // marshalls a reply packet.
    256 
    257   template<typename R>
    258   status
    259   call (connection *conn, const char *method, R *result)
    260   {
    261     if (!conn->send ('Q'))
    262       return FAIL;
    263     if (!marshall (conn, method))
    264       return FAIL;
    265     if (!marshall (conn, 0))
    266       return FAIL;
    267     if (!conn->wait_for_result ())
    268       return FAIL;
    269     if (!unmarshall (conn, result))
    270       return FAIL;
    271     return OK;
    272   }
    273 
    274   template<typename R, R (*func) (connection *)>
    275   status
    276   callback (connection *conn)
    277   {
    278     R result;
    279 
    280     if (!unmarshall_check (conn, 0))
    281       return FAIL;
    282     result = func (conn);
    283     if (!conn->send ('R'))
    284       return FAIL;
    285     return marshall (conn, result);
    286   }
    287 
    288   template<typename R, typename A>
    289   status
    290   call (connection *conn, const char *method, R *result, A arg)
    291   {
    292     if (!conn->send ('Q'))
    293       return FAIL;
    294     if (!marshall (conn, method))
    295       return FAIL;
    296     if (!marshall (conn, 1))
    297       return FAIL;
    298     if (!marshall (conn, arg))
    299       return FAIL;
    300     if (!conn->wait_for_result ())
    301       return FAIL;
    302     if (!unmarshall (conn, result))
    303       return FAIL;
    304     return OK;
    305   }
    306 
    307   template<typename R, typename A, R (*func) (connection *, A)>
    308   status
    309   callback (connection *conn)
    310   {
    311     argument_wrapper<A> arg;
    312     R result;
    313 
    314     if (!unmarshall_check (conn, 1))
    315       return FAIL;
    316     if (!arg.unmarshall (conn))
    317       return FAIL;
    318     result = func (conn, arg);
    319     if (!conn->send ('R'))
    320       return FAIL;
    321     return marshall (conn, result);
    322   }
    323 
    324   template<typename R, typename A1, typename A2>
    325   status
    326   call (connection *conn, const char *method, R *result, A1 arg1, A2 arg2)
    327   {
    328     if (!conn->send ('Q'))
    329       return FAIL;
    330     if (!marshall (conn, method))
    331       return FAIL;
    332     if (!marshall (conn, 2))
    333       return FAIL;
    334     if (!marshall (conn, arg1))
    335       return FAIL;
    336     if (!marshall (conn, arg2))
    337       return FAIL;
    338     if (!conn->wait_for_result ())
    339       return FAIL;
    340     if (!unmarshall (conn, result))
    341       return FAIL;
    342     return OK;
    343   }
    344 
    345   template<typename R, typename A1, typename A2, R (*func) (connection *,
    346 							    A1, A2)>
    347   status
    348   callback (connection *conn)
    349   {
    350     argument_wrapper<A1> arg1;
    351     argument_wrapper<A2> arg2;
    352     R result;
    353 
    354     if (!unmarshall_check (conn, 2))
    355       return FAIL;
    356     if (!arg1.unmarshall (conn))
    357       return FAIL;
    358     if (!arg2.unmarshall (conn))
    359       return FAIL;
    360     result = func (conn, arg1, arg2);
    361     if (!conn->send ('R'))
    362       return FAIL;
    363     return marshall (conn, result);
    364   }
    365 
    366   template<typename R, typename A1, typename A2, typename A3>
    367   status
    368   call (connection *conn, const char *method, R *result, A1 arg1, A2 arg2,
    369 	A3 arg3)
    370   {
    371     if (!conn->send ('Q'))
    372       return FAIL;
    373     if (!marshall (conn, method))
    374       return FAIL;
    375     if (!marshall (conn, 3))
    376       return FAIL;
    377     if (!marshall (conn, arg1))
    378       return FAIL;
    379     if (!marshall (conn, arg2))
    380       return FAIL;
    381     if (!marshall (conn, arg3))
    382       return FAIL;
    383     if (!conn->wait_for_result ())
    384       return FAIL;
    385     if (!unmarshall (conn, result))
    386       return FAIL;
    387     return OK;
    388   }
    389 
    390   template<typename R, typename A1, typename A2, typename A3,
    391 	   R (*func) (connection *, A1, A2, A3)>
    392   status
    393   callback (connection *conn)
    394   {
    395     argument_wrapper<A1> arg1;
    396     argument_wrapper<A2> arg2;
    397     argument_wrapper<A3> arg3;
    398     R result;
    399 
    400     if (!unmarshall_check (conn, 3))
    401       return FAIL;
    402     if (!arg1.unmarshall (conn))
    403       return FAIL;
    404     if (!arg2.unmarshall (conn))
    405       return FAIL;
    406     if (!arg3.unmarshall (conn))
    407       return FAIL;
    408     result = func (conn, arg1, arg2, arg3);
    409     if (!conn->send ('R'))
    410       return FAIL;
    411     return marshall (conn, result);
    412   }
    413 
    414   template<typename R, typename A1, typename A2, typename A3, typename A4>
    415   status
    416   call (connection *conn, const char *method, R *result, A1 arg1, A2 arg2,
    417 	A3 arg3, A4 arg4)
    418   {
    419     if (!conn->send ('Q'))
    420       return FAIL;
    421     if (!marshall (conn, method))
    422       return FAIL;
    423     if (!marshall (conn, 4))
    424       return FAIL;
    425     if (!marshall (conn, arg1))
    426       return FAIL;
    427     if (!marshall (conn, arg2))
    428       return FAIL;
    429     if (!marshall (conn, arg3))
    430       return FAIL;
    431     if (!marshall (conn, arg4))
    432       return FAIL;
    433     if (!conn->wait_for_result ())
    434       return FAIL;
    435     if (!unmarshall (conn, result))
    436       return FAIL;
    437     return OK;
    438   }
    439 
    440   template<typename R, typename A1, typename A2, typename A3, typename A4,
    441 	   R (*func) (connection *, A1, A2, A3, A4)>
    442   status
    443   callback (connection *conn)
    444   {
    445     argument_wrapper<A1> arg1;
    446     argument_wrapper<A2> arg2;
    447     argument_wrapper<A3> arg3;
    448     argument_wrapper<A4> arg4;
    449     R result;
    450 
    451     if (!unmarshall_check (conn, 4))
    452       return FAIL;
    453     if (!arg1.unmarshall (conn))
    454       return FAIL;
    455     if (!arg2.unmarshall (conn))
    456       return FAIL;
    457     if (!arg3.unmarshall (conn))
    458       return FAIL;
    459     if (!arg4.unmarshall (conn))
    460       return FAIL;
    461     result = func (conn, arg1, arg2, arg3, arg4);
    462     if (!conn->send ('R'))
    463       return FAIL;
    464     return marshall (conn, result);
    465   }
    466 
    467   template<typename R, typename A1, typename A2, typename A3, typename A4,
    468 	   typename A5>
    469   status
    470   call (connection *conn, const char *method, R *result, A1 arg1, A2 arg2,
    471 	A3 arg3, A4 arg4, A5 arg5)
    472   {
    473     if (!conn->send ('Q'))
    474       return FAIL;
    475     if (!marshall (conn, method))
    476       return FAIL;
    477     if (!marshall (conn, 5))
    478       return FAIL;
    479     if (!marshall (conn, arg1))
    480       return FAIL;
    481     if (!marshall (conn, arg2))
    482       return FAIL;
    483     if (!marshall (conn, arg3))
    484       return FAIL;
    485     if (!marshall (conn, arg4))
    486       return FAIL;
    487     if (!marshall (conn, arg5))
    488       return FAIL;
    489     if (!conn->wait_for_result ())
    490       return FAIL;
    491     if (!unmarshall (conn, result))
    492       return FAIL;
    493     return OK;
    494   }
    495 
    496   template<typename R, typename A1, typename A2, typename A3, typename A4,
    497 	   typename A5, R (*func) (connection *, A1, A2, A3, A4, A5)>
    498   status
    499   callback (connection *conn)
    500   {
    501     argument_wrapper<A1> arg1;
    502     argument_wrapper<A2> arg2;
    503     argument_wrapper<A3> arg3;
    504     argument_wrapper<A4> arg4;
    505     argument_wrapper<A5> arg5;
    506     R result;
    507 
    508     if (!unmarshall_check (conn, 5))
    509       return FAIL;
    510     if (!arg1.unmarshall (conn))
    511       return FAIL;
    512     if (!arg2.unmarshall (conn))
    513       return FAIL;
    514     if (!arg3.unmarshall (conn))
    515       return FAIL;
    516     if (!arg4.unmarshall (conn))
    517       return FAIL;
    518     if (!arg5.unmarshall (conn))
    519       return FAIL;
    520     result = func (conn, arg1, arg2, arg3, arg4, arg5);
    521     if (!conn->send ('R'))
    522       return FAIL;
    523     return marshall (conn, result);
    524   }
    525 
    526   template<typename R, typename A1, typename A2, typename A3, typename A4,
    527 	   typename A5, typename A6, typename A7>
    528   status
    529   call (connection *conn, const char *method, R *result, A1 arg1, A2 arg2,
    530 	A3 arg3, A4 arg4, A5 arg5, A6 arg6, A7 arg7)
    531   {
    532     if (!conn->send ('Q'))
    533       return FAIL;
    534     if (!marshall (conn, method))
    535       return FAIL;
    536     if (!marshall (conn, 7))
    537       return FAIL;
    538     if (!marshall (conn, arg1))
    539       return FAIL;
    540     if (!marshall (conn, arg2))
    541       return FAIL;
    542     if (!marshall (conn, arg3))
    543       return FAIL;
    544     if (!marshall (conn, arg4))
    545       return FAIL;
    546     if (!marshall (conn, arg5))
    547       return FAIL;
    548     if (!marshall (conn, arg6))
    549       return FAIL;
    550     if (!marshall (conn, arg7))
    551       return FAIL;
    552     if (!conn->wait_for_result ())
    553       return FAIL;
    554     if (!unmarshall (conn, result))
    555       return FAIL;
    556     return OK;
    557   }
    558 
    559   template<typename R, typename A1, typename A2, typename A3, typename A4,
    560 	   typename A5, typename A6, typename A7,
    561 	   R (*func) (connection *, A1, A2, A3, A4, A5, A6, A7)>
    562   status
    563   callback (connection *conn)
    564   {
    565     argument_wrapper<A1> arg1;
    566     argument_wrapper<A2> arg2;
    567     argument_wrapper<A3> arg3;
    568     argument_wrapper<A4> arg4;
    569     argument_wrapper<A5> arg5;
    570     argument_wrapper<A6> arg6;
    571     argument_wrapper<A7> arg7;
    572     R result;
    573 
    574     if (!unmarshall_check (conn, 7))
    575       return FAIL;
    576     if (!arg1.unmarshall (conn))
    577       return FAIL;
    578     if (!arg2.unmarshall (conn))
    579       return FAIL;
    580     if (!arg3.unmarshall (conn))
    581       return FAIL;
    582     if (!arg4.unmarshall (conn))
    583       return FAIL;
    584     if (!arg5.unmarshall (conn))
    585       return FAIL;
    586     if (!arg6.unmarshall (conn))
    587       return FAIL;
    588     if (!arg7.unmarshall (conn))
    589       return FAIL;
    590     result = func (conn, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
    591     if (!conn->send ('R'))
    592       return FAIL;
    593     return marshall (conn, result);
    594   }
    595 };
    596 
    597 #endif // CC1_PLUGIN_RPC_HH
    598