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