rpc.hh revision 1.1.1.9 1 1.1 mrg /* RPC call and callback templates
2 1.1.1.9 mrg Copyright (C) 2014-2024 Free Software Foundation, Inc.
3 1.1 mrg
4 1.1 mrg This file is part of GCC.
5 1.1 mrg
6 1.1 mrg GCC is free software; you can redistribute it and/or modify it under
7 1.1 mrg the terms of the GNU General Public License as published by the Free
8 1.1 mrg Software Foundation; either version 3, or (at your option) any later
9 1.1 mrg version.
10 1.1 mrg
11 1.1 mrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 1.1 mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 1.1 mrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 1.1 mrg for more details.
15 1.1 mrg
16 1.1 mrg You should have received a copy of the GNU General Public License
17 1.1 mrg along with GCC; see the file COPYING3. If not see
18 1.1 mrg <http://www.gnu.org/licenses/>. */
19 1.1 mrg
20 1.1 mrg #ifndef CC1_PLUGIN_RPC_HH
21 1.1 mrg #define CC1_PLUGIN_RPC_HH
22 1.1 mrg
23 1.1 mrg #include "status.hh"
24 1.1 mrg #include "connection.hh"
25 1.1.1.8 mrg #include "deleter.hh"
26 1.1 mrg
27 1.1 mrg namespace cc1_plugin
28 1.1 mrg {
29 1.1 mrg // The plugin API may contain some "const" method parameters.
30 1.1 mrg // However, when unmarshalling we cannot unmarshall into a const
31 1.1 mrg // object; and furthermore we want to be able to deallocate pointers
32 1.1 mrg // when finished with them. This wrapper class lets us properly
33 1.1 mrg // remove the "const" and handle deallocation from pointer types.
34 1.1 mrg
35 1.1 mrg template<typename T>
36 1.1 mrg class argument_wrapper
37 1.1 mrg {
38 1.1 mrg public:
39 1.1 mrg
40 1.1 mrg argument_wrapper () { }
41 1.1 mrg ~argument_wrapper () { }
42 1.1 mrg
43 1.1.1.8 mrg argument_wrapper (const argument_wrapper &) = delete;
44 1.1.1.8 mrg argument_wrapper &operator= (const argument_wrapper &) = delete;
45 1.1.1.8 mrg
46 1.1.1.8 mrg T get () const { return m_object; }
47 1.1 mrg
48 1.1 mrg status unmarshall (connection *conn)
49 1.1 mrg {
50 1.1 mrg return ::cc1_plugin::unmarshall (conn, &m_object);
51 1.1 mrg }
52 1.1 mrg
53 1.1 mrg private:
54 1.1 mrg
55 1.1 mrg T m_object;
56 1.1 mrg };
57 1.1 mrg
58 1.1.1.8 mrg // Specialization for any kind of pointer.
59 1.1 mrg template<typename T>
60 1.1.1.8 mrg class argument_wrapper<T *>
61 1.1.1.2 mrg {
62 1.1.1.2 mrg public:
63 1.1.1.8 mrg argument_wrapper () = default;
64 1.1.1.8 mrg ~argument_wrapper () = default;
65 1.1.1.2 mrg
66 1.1.1.8 mrg argument_wrapper (const argument_wrapper &) = delete;
67 1.1.1.8 mrg argument_wrapper &operator= (const argument_wrapper &) = delete;
68 1.1.1.2 mrg
69 1.1.1.8 mrg typedef typename std::remove_const<T>::type type;
70 1.1.1.2 mrg
71 1.1.1.8 mrg const type *get () const
72 1.1.1.2 mrg {
73 1.1.1.8 mrg return m_object.get ();
74 1.1.1.2 mrg }
75 1.1.1.2 mrg
76 1.1.1.2 mrg status unmarshall (connection *conn)
77 1.1.1.2 mrg {
78 1.1.1.8 mrg type *ptr;
79 1.1.1.8 mrg if (!::cc1_plugin::unmarshall (conn, &ptr))
80 1.1.1.8 mrg return FAIL;
81 1.1.1.8 mrg m_object.reset (ptr);
82 1.1.1.8 mrg return OK;
83 1.1.1.2 mrg }
84 1.1.1.2 mrg
85 1.1.1.2 mrg private:
86 1.1.1.2 mrg
87 1.1.1.8 mrg unique_ptr<type> m_object;
88 1.1.1.2 mrg };
89 1.1.1.2 mrg
90 1.1 mrg // There are two kinds of template functions here: "call" and
91 1.1.1.8 mrg // "invoker".
92 1.1 mrg
93 1.1 mrg // The "call" template is used for making a remote procedure call.
94 1.1 mrg // It starts a query ('Q') packet, marshalls its arguments, waits
95 1.1 mrg // for a result, and finally reads and returns the result via an
96 1.1 mrg // "out" parameter.
97 1.1 mrg
98 1.1.1.8 mrg // The "invoker" template is used when receiving a remote procedure
99 1.1 mrg // call. This template function is suitable for use with the
100 1.1 mrg // "callbacks" and "connection" classes. It decodes incoming
101 1.1 mrg // arguments, passes them to the wrapped function, and finally
102 1.1 mrg // marshalls a reply packet.
103 1.1 mrg
104 1.1.1.8 mrg template<typename R, typename... Arg>
105 1.1 mrg status
106 1.1.1.8 mrg call (connection *conn, const char *method, R *result, Arg... args)
107 1.1 mrg {
108 1.1 mrg if (!conn->send ('Q'))
109 1.1 mrg return FAIL;
110 1.1 mrg if (!marshall (conn, method))
111 1.1 mrg return FAIL;
112 1.1.1.8 mrg if (!marshall (conn, (int) sizeof... (Arg)))
113 1.1 mrg return FAIL;
114 1.1.1.8 mrg if (!marshall (conn, args...))
115 1.1 mrg return FAIL;
116 1.1 mrg if (!conn->wait_for_result ())
117 1.1 mrg return FAIL;
118 1.1 mrg if (!unmarshall (conn, result))
119 1.1 mrg return FAIL;
120 1.1 mrg return OK;
121 1.1 mrg }
122 1.1 mrg
123 1.1.1.8 mrg // The base case -- just return OK.
124 1.1.1.8 mrg template<int I, typename... T>
125 1.1.1.8 mrg typename std::enable_if<I == sizeof... (T), status>::type
126 1.1.1.8 mrg unmarshall (connection *, std::tuple<T...> &)
127 1.1 mrg {
128 1.1 mrg return OK;
129 1.1 mrg }
130 1.1 mrg
131 1.1.1.8 mrg // Unmarshall this argument, then unmarshall all subsequent args.
132 1.1.1.8 mrg template<int I, typename... T>
133 1.1.1.8 mrg typename std::enable_if<I < sizeof... (T), status>::type
134 1.1.1.8 mrg unmarshall (connection *conn, std::tuple<T...> &value)
135 1.1 mrg {
136 1.1.1.8 mrg if (!std::get<I> (value).unmarshall (conn))
137 1.1 mrg return FAIL;
138 1.1.1.8 mrg return unmarshall<I + 1, T...> (conn, value);
139 1.1 mrg }
140 1.1 mrg
141 1.1.1.8 mrg // Wrap a static function that is suitable for use as a callback.
142 1.1.1.8 mrg // This is a template function inside a template class to work
143 1.1.1.8 mrg // around limitations with multiple variadic packs.
144 1.1.1.8 mrg template<typename R, typename... Arg>
145 1.1.1.8 mrg class invoker
146 1.1 mrg {
147 1.1.1.8 mrg // Base case -- we can call the function.
148 1.1.1.8 mrg template<int I, R func (connection *, Arg...), typename... T>
149 1.1.1.8 mrg static typename std::enable_if<I == sizeof... (Arg), R>::type
150 1.1.1.8 mrg call (connection *conn, const std::tuple<argument_wrapper<Arg>...> &,
151 1.1.1.8 mrg T... args)
152 1.1.1.8 mrg {
153 1.1.1.8 mrg return func (conn, args...);
154 1.1.1.8 mrg }
155 1.1 mrg
156 1.1.1.8 mrg // Unpack one argument and continue the recursion.
157 1.1.1.8 mrg template<int I, R func (connection *, Arg...), typename... T>
158 1.1.1.8 mrg static typename std::enable_if<I < sizeof... (Arg), R>::type
159 1.1.1.8 mrg call (connection *conn, const std::tuple<argument_wrapper<Arg>...> &value,
160 1.1.1.8 mrg T... args)
161 1.1.1.8 mrg {
162 1.1.1.8 mrg return call<I + 1, func> (conn, value, args...,
163 1.1.1.8 mrg std::get<I> (value).get ());
164 1.1.1.8 mrg }
165 1.1 mrg
166 1.1.1.8 mrg public:
167 1.1 mrg
168 1.1.1.8 mrg // A callback function that reads arguments from the connection,
169 1.1.1.8 mrg // calls the wrapped function, and then sends the result back on
170 1.1.1.8 mrg // the connection.
171 1.1.1.8 mrg template<R func (connection *, Arg...)>
172 1.1.1.8 mrg static status
173 1.1.1.8 mrg invoke (connection *conn)
174 1.1.1.8 mrg {
175 1.1.1.8 mrg if (!unmarshall_check (conn, sizeof... (Arg)))
176 1.1.1.8 mrg return FAIL;
177 1.1.1.8 mrg std::tuple<argument_wrapper<Arg>...> wrapped;
178 1.1.1.8 mrg if (!unmarshall<0> (conn, wrapped))
179 1.1.1.8 mrg return FAIL;
180 1.1 mrg
181 1.1.1.8 mrg R result = call<0, func> (conn, wrapped);
182 1.1 mrg
183 1.1.1.8 mrg if (!conn->send ('R'))
184 1.1.1.8 mrg return FAIL;
185 1.1.1.8 mrg return marshall (conn, result);
186 1.1.1.8 mrg }
187 1.1.1.8 mrg };
188 1.1 mrg };
189 1.1 mrg
190 1.1 mrg #endif // CC1_PLUGIN_RPC_HH
191