PR target/65871
[official-gcc.git] / libcc1 / rpc.hh
blob58758d3d39ece3697f49957fbde5ed1d7737b990
1 /* RPC call and callback templates
2 Copyright (C) 2014 Free Software Foundation, Inc.
4 This file is part of GCC.
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.
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.
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/>. */
20 #ifndef CC1_PLUGIN_RPC_HH
21 #define CC1_PLUGIN_RPC_HH
23 #include "status.hh"
24 #include "marshall.hh"
25 #include "connection.hh"
27 namespace cc1_plugin
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.
35 template<typename T>
36 class argument_wrapper
38 public:
40 argument_wrapper () { }
41 ~argument_wrapper () { }
43 operator T () const { return m_object; }
45 status unmarshall (connection *conn)
47 return ::cc1_plugin::unmarshall (conn, &m_object);
50 private:
52 T m_object;
54 // No copying or assignment allowed.
55 argument_wrapper (const argument_wrapper &);
56 argument_wrapper &operator= (const argument_wrapper &);
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 *>;
65 // Specialization for string types.
66 template<>
67 class argument_wrapper<const char *>
69 public:
70 argument_wrapper () : m_object (NULL) { }
71 ~argument_wrapper ()
73 delete[] m_object;
76 operator const char * () const
78 return m_object;
81 status unmarshall (connection *conn)
83 return ::cc1_plugin::unmarshall (conn, &m_object);
86 private:
88 char *m_object;
90 // No copying or assignment allowed.
91 argument_wrapper (const argument_wrapper &);
92 argument_wrapper &operator= (const argument_wrapper &);
95 // Specialization for gcc_type_array.
96 template<>
97 class argument_wrapper<const gcc_type_array *>
99 public:
100 argument_wrapper () : m_object (NULL) { }
101 ~argument_wrapper ()
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;
110 operator const gcc_type_array * () const
112 return m_object;
115 status unmarshall (connection *conn)
117 return ::cc1_plugin::unmarshall (conn, &m_object);
120 private:
122 gcc_type_array *m_object;
124 // No copying or assignment allowed.
125 argument_wrapper (const argument_wrapper &);
126 argument_wrapper &operator= (const argument_wrapper &);
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.)
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.
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.
146 template<typename R>
147 status
148 call (connection *conn, const char *method, R *result)
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;
163 template<typename R, R (*func) (connection *)>
164 status
165 callback (connection *conn)
167 R result;
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);
177 template<typename R, typename A>
178 status
179 call (connection *conn, const char *method, R *result, A arg)
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;
196 template<typename R, typename A, R (*func) (connection *, A)>
197 status
198 callback (connection *conn)
200 argument_wrapper<A> arg;
201 R result;
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);
213 template<typename R, typename A1, typename A2>
214 status
215 call (connection *conn, const char *method, R *result, A1 arg1, A2 arg2)
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;
234 template<typename R, typename A1, typename A2, R (*func) (connection *,
235 A1, A2)>
236 status
237 callback (connection *conn)
239 argument_wrapper<A1> arg1;
240 argument_wrapper<A2> arg2;
241 R result;
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);
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)
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;
279 template<typename R, typename A1, typename A2, typename A3,
280 R (*func) (connection *, A1, A2, A3)>
281 status
282 callback (connection *conn)
284 argument_wrapper<A1> arg1;
285 argument_wrapper<A2> arg2;
286 argument_wrapper<A3> arg3;
287 R result;
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);
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)
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;
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)
334 argument_wrapper<A1> arg1;
335 argument_wrapper<A2> arg2;
336 argument_wrapper<A3> arg3;
337 argument_wrapper<A4> arg4;
338 R result;
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);
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)
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;
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)
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;
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);
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)
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;
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)
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;
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);
486 #endif // CC1_PLUGIN_RPC_HH