]>
Commit | Line | Data |
---|---|---|
ddc8de03 | 1 | /* RPC call and callback templates |
99dee823 | 2 | Copyright (C) 2014-2021 Free Software Foundation, Inc. |
ddc8de03 PM |
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" | |
ddc8de03 | 24 | #include "connection.hh" |
0f237df2 | 25 | #include "deleter.hh" |
ddc8de03 PM |
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 | ||
c10a3b13 TT |
43 | argument_wrapper (const argument_wrapper &) = delete; |
44 | argument_wrapper &operator= (const argument_wrapper &) = delete; | |
45 | ||
ddc8de03 PM |
46 | operator T () const { return m_object; } |
47 | ||
48 | status unmarshall (connection *conn) | |
49 | { | |
50 | return ::cc1_plugin::unmarshall (conn, &m_object); | |
51 | } | |
52 | ||
53 | private: | |
54 | ||
55 | T m_object; | |
ddc8de03 PM |
56 | }; |
57 | ||
0d5a0b9a TT |
58 | // Specialization for any kind of pointer. |
59 | template<typename T> | |
60 | class argument_wrapper<T *> | |
8db29d88 AO |
61 | { |
62 | public: | |
0d5a0b9a TT |
63 | argument_wrapper () = default; |
64 | ~argument_wrapper () = default; | |
8db29d88 | 65 | |
c10a3b13 TT |
66 | argument_wrapper (const argument_wrapper &) = delete; |
67 | argument_wrapper &operator= (const argument_wrapper &) = delete; | |
68 | ||
0d5a0b9a TT |
69 | typedef typename std::remove_const<T>::type type; |
70 | ||
71 | operator const type * () const | |
8db29d88 | 72 | { |
0d5a0b9a | 73 | return m_object.get (); |
8db29d88 AO |
74 | } |
75 | ||
76 | status unmarshall (connection *conn) | |
77 | { | |
0d5a0b9a TT |
78 | type *ptr; |
79 | if (!::cc1_plugin::unmarshall (conn, &ptr)) | |
80 | return FAIL; | |
81 | m_object.reset (ptr); | |
82 | return OK; | |
8db29d88 AO |
83 | } |
84 | ||
85 | private: | |
86 | ||
0f237df2 | 87 | unique_ptr<type> m_object; |
8db29d88 | 88 | }; |
8db29d88 | 89 | |
ddc8de03 | 90 | // There are two kinds of template functions here: "call" and |
dc6be7c0 TT |
91 | // "callback". "call" is implemented with variadic templates, but |
92 | // "callback" is repeated multiple times to handle different numbers | |
93 | // of arguments. (This could be improved with C++17 and | |
94 | // std::apply.) | |
ddc8de03 PM |
95 | |
96 | // The "call" template is used for making a remote procedure call. | |
97 | // It starts a query ('Q') packet, marshalls its arguments, waits | |
98 | // for a result, and finally reads and returns the result via an | |
99 | // "out" parameter. | |
100 | ||
101 | // The "callback" template is used when receiving a remote procedure | |
102 | // call. This template function is suitable for use with the | |
103 | // "callbacks" and "connection" classes. It decodes incoming | |
104 | // arguments, passes them to the wrapped function, and finally | |
105 | // marshalls a reply packet. | |
106 | ||
dc6be7c0 | 107 | template<typename R, typename... Arg> |
ddc8de03 | 108 | status |
dc6be7c0 | 109 | call (connection *conn, const char *method, R *result, Arg... args) |
ddc8de03 PM |
110 | { |
111 | if (!conn->send ('Q')) | |
112 | return FAIL; | |
113 | if (!marshall (conn, method)) | |
114 | return FAIL; | |
dc6be7c0 TT |
115 | if (!marshall (conn, (int) sizeof... (Arg))) |
116 | return FAIL; | |
117 | if (!marshall (conn, args...)) | |
ddc8de03 PM |
118 | return FAIL; |
119 | if (!conn->wait_for_result ()) | |
120 | return FAIL; | |
121 | if (!unmarshall (conn, result)) | |
122 | return FAIL; | |
123 | return OK; | |
124 | } | |
125 | ||
126 | template<typename R, R (*func) (connection *)> | |
127 | status | |
128 | callback (connection *conn) | |
129 | { | |
130 | R result; | |
131 | ||
132 | if (!unmarshall_check (conn, 0)) | |
133 | return FAIL; | |
134 | result = func (conn); | |
135 | if (!conn->send ('R')) | |
136 | return FAIL; | |
137 | return marshall (conn, result); | |
138 | } | |
139 | ||
ddc8de03 PM |
140 | template<typename R, typename A, R (*func) (connection *, A)> |
141 | status | |
142 | callback (connection *conn) | |
143 | { | |
144 | argument_wrapper<A> arg; | |
145 | R result; | |
146 | ||
147 | if (!unmarshall_check (conn, 1)) | |
148 | return FAIL; | |
149 | if (!arg.unmarshall (conn)) | |
150 | return FAIL; | |
151 | result = func (conn, arg); | |
152 | if (!conn->send ('R')) | |
153 | return FAIL; | |
154 | return marshall (conn, result); | |
155 | } | |
156 | ||
ddc8de03 PM |
157 | template<typename R, typename A1, typename A2, R (*func) (connection *, |
158 | A1, A2)> | |
159 | status | |
160 | callback (connection *conn) | |
161 | { | |
162 | argument_wrapper<A1> arg1; | |
163 | argument_wrapper<A2> arg2; | |
164 | R result; | |
165 | ||
166 | if (!unmarshall_check (conn, 2)) | |
167 | return FAIL; | |
168 | if (!arg1.unmarshall (conn)) | |
169 | return FAIL; | |
170 | if (!arg2.unmarshall (conn)) | |
171 | return FAIL; | |
172 | result = func (conn, arg1, arg2); | |
173 | if (!conn->send ('R')) | |
174 | return FAIL; | |
175 | return marshall (conn, result); | |
176 | } | |
177 | ||
ddc8de03 PM |
178 | template<typename R, typename A1, typename A2, typename A3, |
179 | R (*func) (connection *, A1, A2, A3)> | |
180 | status | |
181 | callback (connection *conn) | |
182 | { | |
183 | argument_wrapper<A1> arg1; | |
184 | argument_wrapper<A2> arg2; | |
185 | argument_wrapper<A3> arg3; | |
186 | R result; | |
187 | ||
188 | if (!unmarshall_check (conn, 3)) | |
189 | return FAIL; | |
190 | if (!arg1.unmarshall (conn)) | |
191 | return FAIL; | |
192 | if (!arg2.unmarshall (conn)) | |
193 | return FAIL; | |
194 | if (!arg3.unmarshall (conn)) | |
195 | return FAIL; | |
196 | result = func (conn, arg1, arg2, arg3); | |
197 | if (!conn->send ('R')) | |
198 | return FAIL; | |
199 | return marshall (conn, result); | |
200 | } | |
201 | ||
ddc8de03 PM |
202 | template<typename R, typename A1, typename A2, typename A3, typename A4, |
203 | R (*func) (connection *, A1, A2, A3, A4)> | |
204 | status | |
205 | callback (connection *conn) | |
206 | { | |
207 | argument_wrapper<A1> arg1; | |
208 | argument_wrapper<A2> arg2; | |
209 | argument_wrapper<A3> arg3; | |
210 | argument_wrapper<A4> arg4; | |
211 | R result; | |
212 | ||
213 | if (!unmarshall_check (conn, 4)) | |
214 | return FAIL; | |
215 | if (!arg1.unmarshall (conn)) | |
216 | return FAIL; | |
217 | if (!arg2.unmarshall (conn)) | |
218 | return FAIL; | |
219 | if (!arg3.unmarshall (conn)) | |
220 | return FAIL; | |
221 | if (!arg4.unmarshall (conn)) | |
222 | return FAIL; | |
223 | result = func (conn, arg1, arg2, arg3, arg4); | |
224 | if (!conn->send ('R')) | |
225 | return FAIL; | |
226 | return marshall (conn, result); | |
227 | } | |
228 | ||
ddc8de03 PM |
229 | template<typename R, typename A1, typename A2, typename A3, typename A4, |
230 | typename A5, R (*func) (connection *, A1, A2, A3, A4, A5)> | |
231 | status | |
232 | callback (connection *conn) | |
233 | { | |
234 | argument_wrapper<A1> arg1; | |
235 | argument_wrapper<A2> arg2; | |
236 | argument_wrapper<A3> arg3; | |
237 | argument_wrapper<A4> arg4; | |
238 | argument_wrapper<A5> arg5; | |
239 | R result; | |
240 | ||
241 | if (!unmarshall_check (conn, 5)) | |
242 | return FAIL; | |
243 | if (!arg1.unmarshall (conn)) | |
244 | return FAIL; | |
245 | if (!arg2.unmarshall (conn)) | |
246 | return FAIL; | |
247 | if (!arg3.unmarshall (conn)) | |
248 | return FAIL; | |
249 | if (!arg4.unmarshall (conn)) | |
250 | return FAIL; | |
251 | if (!arg5.unmarshall (conn)) | |
252 | return FAIL; | |
253 | result = func (conn, arg1, arg2, arg3, arg4, arg5); | |
254 | if (!conn->send ('R')) | |
255 | return FAIL; | |
256 | return marshall (conn, result); | |
257 | } | |
258 | ||
ddc8de03 PM |
259 | template<typename R, typename A1, typename A2, typename A3, typename A4, |
260 | typename A5, typename A6, typename A7, | |
261 | R (*func) (connection *, A1, A2, A3, A4, A5, A6, A7)> | |
262 | status | |
263 | callback (connection *conn) | |
264 | { | |
265 | argument_wrapper<A1> arg1; | |
266 | argument_wrapper<A2> arg2; | |
267 | argument_wrapper<A3> arg3; | |
268 | argument_wrapper<A4> arg4; | |
269 | argument_wrapper<A5> arg5; | |
270 | argument_wrapper<A6> arg6; | |
271 | argument_wrapper<A7> arg7; | |
272 | R result; | |
273 | ||
274 | if (!unmarshall_check (conn, 7)) | |
275 | return FAIL; | |
276 | if (!arg1.unmarshall (conn)) | |
277 | return FAIL; | |
278 | if (!arg2.unmarshall (conn)) | |
279 | return FAIL; | |
280 | if (!arg3.unmarshall (conn)) | |
281 | return FAIL; | |
282 | if (!arg4.unmarshall (conn)) | |
283 | return FAIL; | |
284 | if (!arg5.unmarshall (conn)) | |
285 | return FAIL; | |
286 | if (!arg6.unmarshall (conn)) | |
287 | return FAIL; | |
288 | if (!arg7.unmarshall (conn)) | |
289 | return FAIL; | |
290 | result = func (conn, arg1, arg2, arg3, arg4, arg5, arg6, arg7); | |
291 | if (!conn->send ('R')) | |
292 | return FAIL; | |
293 | return marshall (conn, result); | |
294 | } | |
295 | }; | |
296 | ||
297 | #endif // CC1_PLUGIN_RPC_HH |