111
|
1 /* RPC call and callback templates
|
145
|
2 Copyright (C) 2014-2020 Free Software Foundation, Inc.
|
111
|
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
|