MAINTAINERS: Add myself to write after approval and DCO
[official-gcc.git] / libcc1 / rpc.hh
blob51302568d527f5755d11824385fdbfed2f3e476f
1 /* RPC call and callback templates
2 Copyright (C) 2014-2023 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 "connection.hh"
25 #include "deleter.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 argument_wrapper (const argument_wrapper &) = delete;
44 argument_wrapper &operator= (const argument_wrapper &) = delete;
46 T get () const { return m_object; }
48 status unmarshall (connection *conn)
50 return ::cc1_plugin::unmarshall (conn, &m_object);
53 private:
55 T m_object;
58 // Specialization for any kind of pointer.
59 template<typename T>
60 class argument_wrapper<T *>
62 public:
63 argument_wrapper () = default;
64 ~argument_wrapper () = default;
66 argument_wrapper (const argument_wrapper &) = delete;
67 argument_wrapper &operator= (const argument_wrapper &) = delete;
69 typedef typename std::remove_const<T>::type type;
71 const type *get () const
73 return m_object.get ();
76 status unmarshall (connection *conn)
78 type *ptr;
79 if (!::cc1_plugin::unmarshall (conn, &ptr))
80 return FAIL;
81 m_object.reset (ptr);
82 return OK;
85 private:
87 unique_ptr<type> m_object;
90 // There are two kinds of template functions here: "call" and
91 // "invoker".
93 // The "call" template is used for making a remote procedure call.
94 // It starts a query ('Q') packet, marshalls its arguments, waits
95 // for a result, and finally reads and returns the result via an
96 // "out" parameter.
98 // The "invoker" template is used when receiving a remote procedure
99 // call. This template function is suitable for use with the
100 // "callbacks" and "connection" classes. It decodes incoming
101 // arguments, passes them to the wrapped function, and finally
102 // marshalls a reply packet.
104 template<typename R, typename... Arg>
105 status
106 call (connection *conn, const char *method, R *result, Arg... args)
108 if (!conn->send ('Q'))
109 return FAIL;
110 if (!marshall (conn, method))
111 return FAIL;
112 if (!marshall (conn, (int) sizeof... (Arg)))
113 return FAIL;
114 if (!marshall (conn, args...))
115 return FAIL;
116 if (!conn->wait_for_result ())
117 return FAIL;
118 if (!unmarshall (conn, result))
119 return FAIL;
120 return OK;
123 // The base case -- just return OK.
124 template<int I, typename... T>
125 typename std::enable_if<I == sizeof... (T), status>::type
126 unmarshall (connection *, std::tuple<T...> &)
128 return OK;
131 // Unmarshall this argument, then unmarshall all subsequent args.
132 template<int I, typename... T>
133 typename std::enable_if<I < sizeof... (T), status>::type
134 unmarshall (connection *conn, std::tuple<T...> &value)
136 if (!std::get<I> (value).unmarshall (conn))
137 return FAIL;
138 return unmarshall<I + 1, T...> (conn, value);
141 // Wrap a static function that is suitable for use as a callback.
142 // This is a template function inside a template class to work
143 // around limitations with multiple variadic packs.
144 template<typename R, typename... Arg>
145 class invoker
147 // Base case -- we can call the function.
148 template<int I, R func (connection *, Arg...), typename... T>
149 static typename std::enable_if<I == sizeof... (Arg), R>::type
150 call (connection *conn, const std::tuple<argument_wrapper<Arg>...> &,
151 T... args)
153 return func (conn, args...);
156 // Unpack one argument and continue the recursion.
157 template<int I, R func (connection *, Arg...), typename... T>
158 static typename std::enable_if<I < sizeof... (Arg), R>::type
159 call (connection *conn, const std::tuple<argument_wrapper<Arg>...> &value,
160 T... args)
162 return call<I + 1, func> (conn, value, args...,
163 std::get<I> (value).get ());
166 public:
168 // A callback function that reads arguments from the connection,
169 // calls the wrapped function, and then sends the result back on
170 // the connection.
171 template<R func (connection *, Arg...)>
172 static status
173 invoke (connection *conn)
175 if (!unmarshall_check (conn, sizeof... (Arg)))
176 return FAIL;
177 std::tuple<argument_wrapper<Arg>...> wrapped;
178 if (!unmarshall<0> (conn, wrapped))
179 return FAIL;
181 R result = call<0, func> (conn, wrapped);
183 if (!conn->send ('R'))
184 return FAIL;
185 return marshall (conn, result);
190 #endif // CC1_PLUGIN_RPC_HH