Home | History | Annotate | Line # | Download | only in libcc1
rpc.hh revision 1.1
      1 /* RPC call and callback templates
      2    Copyright (C) 2014 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 "marshall.hh"
     25 #include "connection.hh"
     26 
     27 namespace cc1_plugin
     28 {
     29   // The plugin API may contain some "const" method parameters.
     30   // However, when unmarshalling we cannot unmarshall into a const
     31   // object; and furthermore we want to be able to deallocate pointers
     32   // when finished with them.  This wrapper class lets us properly
     33   // remove the "const" and handle deallocation from pointer types.
     34 
     35   template<typename T>
     36   class argument_wrapper
     37   {
     38   public:
     39 
     40     argument_wrapper () { }
     41     ~argument_wrapper () { }
     42 
     43     operator T () const { return m_object; }
     44 
     45     status unmarshall (connection *conn)
     46     {
     47       return ::cc1_plugin::unmarshall (conn, &m_object);
     48     }
     49 
     50   private:
     51 
     52     T m_object;
     53 
     54     // No copying or assignment allowed.
     55     argument_wrapper (const argument_wrapper &);
     56     argument_wrapper &operator= (const argument_wrapper &);
     57   };
     58 
     59   // Specialization for any kind of pointer.  This is declared but not
     60   // defined to avoid bugs if a new pointer type is introduced into
     61   // the API.  Instead you will just get a compilation error.
     62   template<typename T>
     63   class argument_wrapper<const T *>;
     64 
     65   // Specialization for string types.
     66   template<>
     67   class argument_wrapper<const char *>
     68   {
     69   public:
     70     argument_wrapper () : m_object (NULL) { }
     71     ~argument_wrapper ()
     72     {
     73       delete[] m_object;
     74     }
     75 
     76     operator const char * () const
     77     {
     78       return m_object;
     79     }
     80 
     81     status unmarshall (connection *conn)
     82     {
     83       return ::cc1_plugin::unmarshall (conn, &m_object);
     84     }
     85 
     86   private:
     87 
     88     char *m_object;
     89 
     90     // No copying or assignment allowed.
     91     argument_wrapper (const argument_wrapper &);
     92     argument_wrapper &operator= (const argument_wrapper &);
     93   };
     94 
     95   // Specialization for gcc_type_array.
     96   template<>
     97   class argument_wrapper<const gcc_type_array *>
     98   {
     99   public:
    100     argument_wrapper () : m_object (NULL) { }
    101     ~argument_wrapper ()
    102     {
    103       // It would be nicer if gcc_type_array could have a destructor.
    104       // But, it is in code shared with gdb and cannot.
    105       if (m_object != NULL)
    106 	delete[] m_object->elements;
    107       delete m_object;
    108     }
    109 
    110     operator const gcc_type_array * () const
    111     {
    112       return m_object;
    113     }
    114 
    115     status unmarshall (connection *conn)
    116     {
    117       return ::cc1_plugin::unmarshall (conn, &m_object);
    118     }
    119 
    120   private:
    121 
    122     gcc_type_array *m_object;
    123 
    124     // No copying or assignment allowed.
    125     argument_wrapper (const argument_wrapper &);
    126     argument_wrapper &operator= (const argument_wrapper &);
    127   };
    128 
    129   // There are two kinds of template functions here: "call" and
    130   // "callback".  They are each repeated multiple times to handle
    131   // different numbers of arguments.  (This would be improved with
    132   // C++11, though applying a call is still tricky until C++14 can be
    133   // used.)
    134 
    135   // The "call" template is used for making a remote procedure call.
    136   // It starts a query ('Q') packet, marshalls its arguments, waits
    137   // for a result, and finally reads and returns the result via an
    138   // "out" parameter.
    139 
    140   // The "callback" template is used when receiving a remote procedure
    141   // call.  This template function is suitable for use with the
    142   // "callbacks" and "connection" classes.  It decodes incoming
    143   // arguments, passes them to the wrapped function, and finally
    144   // marshalls a reply packet.
    145 
    146   template<typename R>
    147   status
    148   call (connection *conn, const char *method, R *result)
    149   {
    150     if (!conn->send ('Q'))
    151       return FAIL;
    152     if (!marshall (conn, method))
    153       return FAIL;
    154     if (!marshall (conn, 0))
    155       return FAIL;
    156     if (!conn->wait_for_result ())
    157       return FAIL;
    158     if (!unmarshall (conn, result))
    159       return FAIL;
    160     return OK;
    161   }
    162 
    163   template<typename R, R (*func) (connection *)>
    164   status
    165   callback (connection *conn)
    166   {
    167     R result;
    168 
    169     if (!unmarshall_check (conn, 0))
    170       return FAIL;
    171     result = func (conn);
    172     if (!conn->send ('R'))
    173       return FAIL;
    174     return marshall (conn, result);
    175   }
    176 
    177   template<typename R, typename A>
    178   status
    179   call (connection *conn, const char *method, R *result, A arg)
    180   {
    181     if (!conn->send ('Q'))
    182       return FAIL;
    183     if (!marshall (conn, method))
    184       return FAIL;
    185     if (!marshall (conn, 1))
    186       return FAIL;
    187     if (!marshall (conn, arg))
    188       return FAIL;
    189     if (!conn->wait_for_result ())
    190       return FAIL;
    191     if (!unmarshall (conn, result))
    192       return FAIL;
    193     return OK;
    194   }
    195 
    196   template<typename R, typename A, R (*func) (connection *, A)>
    197   status
    198   callback (connection *conn)
    199   {
    200     argument_wrapper<A> arg;
    201     R result;
    202 
    203     if (!unmarshall_check (conn, 1))
    204       return FAIL;
    205     if (!arg.unmarshall (conn))
    206       return FAIL;
    207     result = func (conn, arg);
    208     if (!conn->send ('R'))
    209       return FAIL;
    210     return marshall (conn, result);
    211   }
    212 
    213   template<typename R, typename A1, typename A2>
    214   status
    215   call (connection *conn, const char *method, R *result, A1 arg1, A2 arg2)
    216   {
    217     if (!conn->send ('Q'))
    218       return FAIL;
    219     if (!marshall (conn, method))
    220       return FAIL;
    221     if (!marshall (conn, 2))
    222       return FAIL;
    223     if (!marshall (conn, arg1))
    224       return FAIL;
    225     if (!marshall (conn, arg2))
    226       return FAIL;
    227     if (!conn->wait_for_result ())
    228       return FAIL;
    229     if (!unmarshall (conn, result))
    230       return FAIL;
    231     return OK;
    232   }
    233 
    234   template<typename R, typename A1, typename A2, R (*func) (connection *,
    235 							    A1, A2)>
    236   status
    237   callback (connection *conn)
    238   {
    239     argument_wrapper<A1> arg1;
    240     argument_wrapper<A2> arg2;
    241     R result;
    242 
    243     if (!unmarshall_check (conn, 2))
    244       return FAIL;
    245     if (!arg1.unmarshall (conn))
    246       return FAIL;
    247     if (!arg2.unmarshall (conn))
    248       return FAIL;
    249     result = func (conn, arg1, arg2);
    250     if (!conn->send ('R'))
    251       return FAIL;
    252     return marshall (conn, result);
    253   }
    254 
    255   template<typename R, typename A1, typename A2, typename A3>
    256   status
    257   call (connection *conn, const char *method, R *result, A1 arg1, A2 arg2,
    258 	A3 arg3)
    259   {
    260     if (!conn->send ('Q'))
    261       return FAIL;
    262     if (!marshall (conn, method))
    263       return FAIL;
    264     if (!marshall (conn, 3))
    265       return FAIL;
    266     if (!marshall (conn, arg1))
    267       return FAIL;
    268     if (!marshall (conn, arg2))
    269       return FAIL;
    270     if (!marshall (conn, arg3))
    271       return FAIL;
    272     if (!conn->wait_for_result ())
    273       return FAIL;
    274     if (!unmarshall (conn, result))
    275       return FAIL;
    276     return OK;
    277   }
    278 
    279   template<typename R, typename A1, typename A2, typename A3,
    280 	   R (*func) (connection *, A1, A2, A3)>
    281   status
    282   callback (connection *conn)
    283   {
    284     argument_wrapper<A1> arg1;
    285     argument_wrapper<A2> arg2;
    286     argument_wrapper<A3> arg3;
    287     R result;
    288 
    289     if (!unmarshall_check (conn, 3))
    290       return FAIL;
    291     if (!arg1.unmarshall (conn))
    292       return FAIL;
    293     if (!arg2.unmarshall (conn))
    294       return FAIL;
    295     if (!arg3.unmarshall (conn))
    296       return FAIL;
    297     result = func (conn, arg1, arg2, arg3);
    298     if (!conn->send ('R'))
    299       return FAIL;
    300     return marshall (conn, result);
    301   }
    302 
    303   template<typename R, typename A1, typename A2, typename A3, typename A4>
    304   status
    305   call (connection *conn, const char *method, R *result, A1 arg1, A2 arg2,
    306 	A3 arg3, A4 arg4)
    307   {
    308     if (!conn->send ('Q'))
    309       return FAIL;
    310     if (!marshall (conn, method))
    311       return FAIL;
    312     if (!marshall (conn, 4))
    313       return FAIL;
    314     if (!marshall (conn, arg1))
    315       return FAIL;
    316     if (!marshall (conn, arg2))
    317       return FAIL;
    318     if (!marshall (conn, arg3))
    319       return FAIL;
    320     if (!marshall (conn, arg4))
    321       return FAIL;
    322     if (!conn->wait_for_result ())
    323       return FAIL;
    324     if (!unmarshall (conn, result))
    325       return FAIL;
    326     return OK;
    327   }
    328 
    329   template<typename R, typename A1, typename A2, typename A3, typename A4,
    330 	   R (*func) (connection *, A1, A2, A3, A4)>
    331   status
    332   callback (connection *conn)
    333   {
    334     argument_wrapper<A1> arg1;
    335     argument_wrapper<A2> arg2;
    336     argument_wrapper<A3> arg3;
    337     argument_wrapper<A4> arg4;
    338     R result;
    339 
    340     if (!unmarshall_check (conn, 4))
    341       return FAIL;
    342     if (!arg1.unmarshall (conn))
    343       return FAIL;
    344     if (!arg2.unmarshall (conn))
    345       return FAIL;
    346     if (!arg3.unmarshall (conn))
    347       return FAIL;
    348     if (!arg4.unmarshall (conn))
    349       return FAIL;
    350     result = func (conn, arg1, arg2, arg3, arg4);
    351     if (!conn->send ('R'))
    352       return FAIL;
    353     return marshall (conn, result);
    354   }
    355 
    356   template<typename R, typename A1, typename A2, typename A3, typename A4,
    357 	   typename A5>
    358   status
    359   call (connection *conn, const char *method, R *result, A1 arg1, A2 arg2,
    360 	A3 arg3, A4 arg4, A5 arg5)
    361   {
    362     if (!conn->send ('Q'))
    363       return FAIL;
    364     if (!marshall (conn, method))
    365       return FAIL;
    366     if (!marshall (conn, 5))
    367       return FAIL;
    368     if (!marshall (conn, arg1))
    369       return FAIL;
    370     if (!marshall (conn, arg2))
    371       return FAIL;
    372     if (!marshall (conn, arg3))
    373       return FAIL;
    374     if (!marshall (conn, arg4))
    375       return FAIL;
    376     if (!marshall (conn, arg5))
    377       return FAIL;
    378     if (!conn->wait_for_result ())
    379       return FAIL;
    380     if (!unmarshall (conn, result))
    381       return FAIL;
    382     return OK;
    383   }
    384 
    385   template<typename R, typename A1, typename A2, typename A3, typename A4,
    386 	   typename A5, R (*func) (connection *, A1, A2, A3, A4, A5)>
    387   status
    388   callback (connection *conn)
    389   {
    390     argument_wrapper<A1> arg1;
    391     argument_wrapper<A2> arg2;
    392     argument_wrapper<A3> arg3;
    393     argument_wrapper<A4> arg4;
    394     argument_wrapper<A5> arg5;
    395     R result;
    396 
    397     if (!unmarshall_check (conn, 5))
    398       return FAIL;
    399     if (!arg1.unmarshall (conn))
    400       return FAIL;
    401     if (!arg2.unmarshall (conn))
    402       return FAIL;
    403     if (!arg3.unmarshall (conn))
    404       return FAIL;
    405     if (!arg4.unmarshall (conn))
    406       return FAIL;
    407     if (!arg5.unmarshall (conn))
    408       return FAIL;
    409     result = func (conn, arg1, arg2, arg3, arg4, arg5);
    410     if (!conn->send ('R'))
    411       return FAIL;
    412     return marshall (conn, result);
    413   }
    414 
    415   template<typename R, typename A1, typename A2, typename A3, typename A4,
    416 	   typename A5, typename A6, typename A7>
    417   status
    418   call (connection *conn, const char *method, R *result, A1 arg1, A2 arg2,
    419 	A3 arg3, A4 arg4, A5 arg5, A6 arg6, A7 arg7)
    420   {
    421     if (!conn->send ('Q'))
    422       return FAIL;
    423     if (!marshall (conn, method))
    424       return FAIL;
    425     if (!marshall (conn, 7))
    426       return FAIL;
    427     if (!marshall (conn, arg1))
    428       return FAIL;
    429     if (!marshall (conn, arg2))
    430       return FAIL;
    431     if (!marshall (conn, arg3))
    432       return FAIL;
    433     if (!marshall (conn, arg4))
    434       return FAIL;
    435     if (!marshall (conn, arg5))
    436       return FAIL;
    437     if (!marshall (conn, arg6))
    438       return FAIL;
    439     if (!marshall (conn, arg7))
    440       return FAIL;
    441     if (!conn->wait_for_result ())
    442       return FAIL;
    443     if (!unmarshall (conn, result))
    444       return FAIL;
    445     return OK;
    446   }
    447 
    448   template<typename R, typename A1, typename A2, typename A3, typename A4,
    449 	   typename A5, typename A6, typename A7,
    450 	   R (*func) (connection *, A1, A2, A3, A4, A5, A6, A7)>
    451   status
    452   callback (connection *conn)
    453   {
    454     argument_wrapper<A1> arg1;
    455     argument_wrapper<A2> arg2;
    456     argument_wrapper<A3> arg3;
    457     argument_wrapper<A4> arg4;
    458     argument_wrapper<A5> arg5;
    459     argument_wrapper<A6> arg6;
    460     argument_wrapper<A7> arg7;
    461     R result;
    462 
    463     if (!unmarshall_check (conn, 7))
    464       return FAIL;
    465     if (!arg1.unmarshall (conn))
    466       return FAIL;
    467     if (!arg2.unmarshall (conn))
    468       return FAIL;
    469     if (!arg3.unmarshall (conn))
    470       return FAIL;
    471     if (!arg4.unmarshall (conn))
    472       return FAIL;
    473     if (!arg5.unmarshall (conn))
    474       return FAIL;
    475     if (!arg6.unmarshall (conn))
    476       return FAIL;
    477     if (!arg7.unmarshall (conn))
    478       return FAIL;
    479     result = func (conn, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
    480     if (!conn->send ('R'))
    481       return FAIL;
    482     return marshall (conn, result);
    483   }
    484 };
    485 
    486 #endif // CC1_PLUGIN_RPC_HH
    487