1/* RPC call and callback templates
2   Copyright (C) 2014 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 3, or (at your option) any later
9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
17along 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
27namespace 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