MOS Source Code
Loading...
Searching...
No Matches
macro_magic.h
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#pragma once
4
5#include <mos/mos_global.h>
6
58// ============ COMMON ============
59// generate enum values for function IDs
60#define RPC_DEFINE_ENUMS(name, NAME, X_MACRO) \
61 MOS_WARNING_PUSH \
62 MOS_WARNING_DISABLE("-Wgnu-zero-variadic-macro-arguments") \
63 typedef enum \
64 { \
65 X_MACRO(X_GENERATE_ENUM, X_GENERATE_ENUM, NAME##_) \
66 } name##_rpc_functions; \
67 MOS_WARNING_POP
68
69#define X_GENERATE_ENUM(prefix, id, name, NAME, ...) prefix##NAME = id,
70
71// ============ CLIENT SIDE ============
72#define X_GENERATE_FUNCTION_STUB_IMPL_ARGS(prefix, id, name, NAME, spec, ...) \
73 should_inline rpc_result_code_t prefix##name(rpc_server_stub_t *server_stub FOR_EACH(RPC_GENERATE_PROTOTYPE, __VA_ARGS__)) \
74 { \
75 if (unlikely(spec == NULL)) \
76 return RPC_RESULT_INVALID_ARGUMENT; \
77 return rpc_simple_call(server_stub, id, NULL, spec FOR_EACH(RPC_EXTRACT_NAME, __VA_ARGS__)); \
78 }
79
80#define X_GENERATE_FUNCTION_STUB_IMPL_PB(prefix, id, name, NAME, reqtype, resptype) \
81 should_inline rpc_result_code_t prefix##name(rpc_server_stub_t *server_stub, const reqtype *request, resptype *response) \
82 { \
83 return rpc_do_pb_call(server_stub, id, reqtype##_fields, request, resptype##_fields, response); \
84 }
85
86// generate the simplecall implementation
87#define RPC_DECLARE_CLIENT(prefix, X_MACRO) \
88 MOS_WARNING_PUSH \
89 MOS_WARNING_DISABLE("-Wgnu-zero-variadic-macro-arguments") \
90 X_MACRO(X_GENERATE_FUNCTION_STUB_IMPL_ARGS, X_GENERATE_FUNCTION_STUB_IMPL_PB, prefix##_) \
91 MOS_WARNING_POP
92
93// generate a stub class for C++ clients
94#define X_GENERATE_FUNCTION_STUB_IMPL_CLASS_ARGS(prefix, id, name, NAME, spec, ...) \
95 rpc_result_code_t prefix##name(FOR_EACH(RPC_GENERATE_PROTOTYPE, __VA_ARGS__)) \
96 { \
97 if (unlikely(spec == NULL)) \
98 return RPC_RESULT_INVALID_ARGUMENT; \
99 return rpc_simple_call(this->server_stub, id, NULL, spec FOR_EACH(RPC_EXTRACT_NAME, __VA_ARGS__)); \
100 }
101
102#define X_GENERATE_FUNCTION_STUB_IMPL_CLASS_PB(prefix, id, name, NAME, reqtype, resptype) \
103 rpc_result_code_t prefix##name(const reqtype *request, resptype *response) \
104 { \
105 return rpc_do_pb_call(this->server_stub, id, reqtype##_fields, request, resptype##_fields, response); \
106 }
107
108#define RPC_CLIENT_DEFINE_STUB_CLASS(_class_name, X_MACRO) \
109 class _class_name \
110 { \
111 public: \
112 explicit _class_name(const std::string &servername) : server_stub(rpc_client_create(servername.c_str())) {}; \
113 X_MACRO(X_GENERATE_FUNCTION_STUB_IMPL_CLASS_ARGS, X_GENERATE_FUNCTION_STUB_IMPL_CLASS_PB, ); \
114 ~_class_name() \
115 { \
116 rpc_client_destroy(server_stub); \
117 } \
118 rpc_server_stub_t *get() const \
119 { \
120 return server_stub; \
121 } \
122 \
123 private: \
124 rpc_server_stub_t *server_stub; \
125 };
126
127#define FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
128
129#define EXPAND(x) x
130#define FOR_EACH_0(what, ...)
131#define FOR_EACH_1(what, x, ...) what(x) EXPAND(FOR_EACH_0(what, __VA_ARGS__))
132#define FOR_EACH_2(what, x, ...) what(x) EXPAND(FOR_EACH_1(what, __VA_ARGS__))
133#define FOR_EACH_3(what, x, ...) what(x) EXPAND(FOR_EACH_2(what, __VA_ARGS__))
134#define FOR_EACH_4(what, x, ...) what(x) EXPAND(FOR_EACH_3(what, __VA_ARGS__))
135#define FOR_EACH_5(what, x, ...) what(x) EXPAND(FOR_EACH_4(what, __VA_ARGS__))
136#define FOR_EACH_6(what, x, ...) what(x) EXPAND(FOR_EACH_5(what, __VA_ARGS__))
137#define FOR_EACH_7(what, x, ...) what(x) EXPAND(FOR_EACH_6(what, __VA_ARGS__))
138#define FOR_EACH_8(what, x, ...) what(x) EXPAND(FOR_EACH_7(what, __VA_ARGS__))
139#define FOR_EACH_9(what, x, ...) what(x) EXPAND(FOR_EACH_8(what, __VA_ARGS__))
140#define FOR_EACH_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0
141#define FOR_EACH_NARG_(...) EXPAND(FOR_EACH_ARG_N(__VA_ARGS__))
142#define FOR_EACH_NARG(...) FOR_EACH_NARG_(__VA_ARGS__, FOR_EACH_RSEQ_N())
143#define FOR_EACH_(N, what, ...) EXPAND(MOS_CONCAT(FOR_EACH_, N)(what, __VA_ARGS__))
144#define FOR_EACH(what, ...) __VA_OPT__(FOR_EACH_(FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__))
145
146#define X_EXTRACT_NAME_ARG(type, name) , name
147#define RPC_EXTRACT_NAME(y) X_EXTRACT_NAME_##y
148
149#define _RPC_ARGTYPE_UINT8 u8
150#define _RPC_ARGTYPE_UINT16 u16
151#define _RPC_ARGTYPE_UINT32 u32
152#define _RPC_ARGTYPE_UINT64 u64
153#define _RPC_ARGTYPE_INT8 s8
154#define _RPC_ARGTYPE_INT16 s16
155#define _RPC_ARGTYPE_INT32 s32
156#define _RPC_ARGTYPE_INT64 s64
157#define _RPC_ARGTYPE_STRING const char *
158#define _RPC_ARGTYPE_BUFFER const void *
159
160#define _RPC_GETARG_UINT8 u8
161#define _RPC_GETARG_UINT16 u16
162#define _RPC_GETARG_UINT32 u32
163#define _RPC_GETARG_UINT64 u64
164#define _RPC_GETARG_INT8 s8
165#define _RPC_GETARG_INT16 s16
166#define _RPC_GETARG_INT32 s32
167#define _RPC_GETARG_INT64 s64
168#define _RPC_GETARG_STRING string
169#define _RPC_GETARG_BUFFER buffer
170
171#define X_GENERATE_PROTOTYPE_ARG(type, name) , __maybe_unused _RPC_ARGTYPE_##type name
172#define RPC_GENERATE_PROTOTYPE(y) X_GENERATE_PROTOTYPE_##y
173
174// ============ SERVER SIDE ============
175#define X_RPC_DO_GET_ARG(type, name) _RPC_ARGTYPE_##type name = MOS_CONCAT(rpc_arg_next_, EXPAND(_RPC_GETARG_##type))(context);
176#define X_RPC_GET_ARG(arg) X_RPC_DO_GET_##arg
177
178#define X_GENERATE_FUNCTION_FORWARDS_ARGS(prefix, _id, _func, _FUNC, _spec, ...) \
179 static rpc_result_code_t prefix##_func(rpc_context_t *context __VA_OPT__(FOR_EACH(RPC_GENERATE_PROTOTYPE, __VA_ARGS__))); \
180 static rpc_result_code_t prefix##_func##_wrapper(rpc_context_t *context) \
181 { \
182 __VA_OPT__(FOR_EACH(X_RPC_GET_ARG, __VA_ARGS__)) \
183 return prefix##_func(context FOR_EACH(RPC_EXTRACT_NAME, __VA_ARGS__)); \
184 }
185
186#define X_GENERATE_FUNCTION_FORWARDS_PB(prefix, _id, _func, _FUNC, reqtype, resptype) \
187 static rpc_result_code_t prefix##_func(rpc_context_t *context, reqtype *req, resptype *resp); \
188 static rpc_result_code_t prefix##_func##_pb_wrapper(rpc_context_t *context) \
189 { \
190 reqtype req = { 0 }; \
191 if (!rpc_arg_pb(context, reqtype##_fields, &req, 0)) \
192 return RPC_RESULT_SERVER_INTERNAL_ERROR; \
193 resptype resp = resptype##_init_zero; \
194 const rpc_result_code_t result = prefix##_func(context, &req, &resp); \
195 pb_release(reqtype##_fields, &req); \
196 rpc_write_result_pb(context, resptype##_fields, &resp); \
197 pb_release(resptype##_fields, &resp); \
198 return result; \
199 }
200
201// clang-format off
202#define X_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, N, ...) N
203#define X_NARGS(...) X_NARGS_IMPL(_ __VA_OPT__(, ) __VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, _err)
204// clang-format on
205
206#define X_GENERATE_FUNCTION_INFO_ARGS_X(X) X_GENERATE_FUNCTION_INFO_ARGS_X_##X
207#define X_GENERATE_FUNCTION_INFO_ARGS_X_ARG(TYPE, _) RPC_ARGTYPE_##TYPE,
208#define X_GENERATE_FUNCTION_INFO_ARGS_X_PB(TYPE, _) /* unreachable */
209
210#define X_DO_MAKE_FUNCINFO(_fid, _func, _nargs, _argtypes) { .function_id = _fid, .func = _func, .args_count = _nargs, .args_type = _argtypes },
211
212#define X_DO_GENERATE_FUNCTION_INFO_ARGS(_fid, _func, _nargs, ...) X_DO_MAKE_FUNCINFO(_fid, _func, _nargs, { FOR_EACH(X_GENERATE_FUNCTION_INFO_ARGS_X, __VA_ARGS__) })
213#define X_DO_GENERATE_FUNCTION_INFO_PB(_fid, _func) X_DO_MAKE_FUNCINFO(_fid, _func, 1, { RPC_ARGTYPE_BUFFER })
214
215#define X_GENERATE_FUNCTION_INFO_ARGS(prefix, fid, func, _1, _2, ...) X_DO_GENERATE_FUNCTION_INFO_ARGS(fid, prefix##func##_wrapper, X_NARGS(__VA_ARGS__), __VA_ARGS__)
216#define X_GENERATE_FUNCTION_INFO_PB(prefix, fid, func, _1, _2, ...) X_DO_GENERATE_FUNCTION_INFO_PB(fid, prefix##func##_pb_wrapper)
217
218// Generate the function prototypes and the function info array
219#define RPC_DECLARE_SERVER(prefix, X_MACRO) \
220 MOS_WARNING_PUSH \
221 MOS_WARNING_DISABLE("-Wgnu-zero-variadic-macro-arguments") \
222 X_MACRO(X_GENERATE_FUNCTION_FORWARDS_ARGS, X_GENERATE_FUNCTION_FORWARDS_PB, prefix##_) \
223 static const rpc_function_info_t prefix##_functions[] = { X_MACRO(X_GENERATE_FUNCTION_INFO_ARGS, X_GENERATE_FUNCTION_INFO_PB, prefix##_) }; \
224 MOS_WARNING_POP
225
226// ============ cpp class wrapper ============
227#define X_GENERATE_NULL_FUNC_INFO_ARGS(unused, fid, func, _1, _2, ...) X_DO_GENERATE_FUNCTION_INFO_ARGS(fid, nullptr, X_NARGS(__VA_ARGS__), __VA_ARGS__)
228#define X_GENERATE_NULL_FUNC_INFO_PB(unused, fid, func, _1, _2, ...) X_DO_GENERATE_FUNCTION_INFO_PB(fid, nullptr)
229
230#define X_GENERATE_SWITCH_CASE_CLASS_ARGS(unused, id, name, NAME, spec, ...) \
231 case id: \
232 { \
233 __VA_OPT__(FOR_EACH(X_RPC_GET_ARG, __VA_ARGS__)) \
234 return this->name(context FOR_EACH(RPC_EXTRACT_NAME, __VA_ARGS__)); \
235 }
236
237#define X_GENERATE_SWITCH_CASE_CLASS_PB(unused, id, name, NAME, reqtype, resptype) \
238 case id: \
239 { \
240 reqtype req; \
241 if (!rpc_arg_pb(context, reqtype##_fields, &req, 0)) \
242 return RPC_RESULT_SERVER_INTERNAL_ERROR; \
243 resptype resp = resptype##_init_zero; \
244 const rpc_result_code_t result = this->name(context, &req, &resp); \
245 pb_release(reqtype##_fields, &req); \
246 rpc_write_result_pb(context, resptype##_fields, &resp); \
247 pb_release(resptype##_fields, &resp); \
248 return result; \
249 }
250
251#define __X_GENERATE_FUNCTION_FORWARDS_ARGS_CPP_CLASS(_prefix, _id, func, _FUNC, _spec, ...) \
252 virtual rpc_result_code_t func(__maybe_unused rpc_context_t *ctx __VA_OPT__(FOR_EACH(RPC_GENERATE_PROTOTYPE, __VA_ARGS__))) \
253 { \
254 return rpc_result_code_t::RPC_RESULT_NOT_IMPLEMENTED; \
255 };
256
257#define __X_GENERATE_FUNCTION_FORWARDS_PB_CPP_CLASS(_prefix, _id, func, _FUNC, reqtype, resptype) \
258 virtual rpc_result_code_t func(rpc_context_t *, reqtype *, resptype *) \
259 { \
260 return rpc_result_code_t::RPC_RESULT_NOT_IMPLEMENTED; \
261 }
262
263#define __RPC_DEFINE_SERVER_CPP_CLASS_WRAPPER(X_MACRO) \
264 X_MACRO(__X_GENERATE_FUNCTION_FORWARDS_ARGS_CPP_CLASS, __X_GENERATE_FUNCTION_FORWARDS_PB_CPP_CLASS, ) \
265 virtual rpc_result_code_t dispatcher(rpc_context_t *context, u32 funcid) override final \
266 { \
267 switch (funcid) \
268 { \
269 X_MACRO(X_GENERATE_SWITCH_CASE_CLASS_ARGS, X_GENERATE_SWITCH_CASE_CLASS_PB, ) \
270 default: __builtin_unreachable(); \
271 } \
272 }
273
274#define RPC_DECL_SERVER_INTERFACE_CLASS(classname, X_MACRO) \
275 class classname : public RPCServer \
276 { \
277 constexpr const static rpc_function_info_t rpc_functions[] = { X_MACRO(X_GENERATE_NULL_FUNC_INFO_ARGS, X_GENERATE_NULL_FUNC_INFO_PB, _) }; \
278 \
279 public: \
280 explicit classname(const std::string &rpcname) : RPCServer(rpcname, rpc_functions, MOS_ARRAY_SIZE(rpc_functions)) {}; \
281 virtual ~classname() {}; \
282 __RPC_DEFINE_SERVER_CPP_CLASS_WRAPPER(X_MACRO) \
283 }
284
285// ============ CPP TYPE NAMESPACE ============
286#define __RPC_DO_DECL_CPP_TYPE_NAMESPACE_ALIAS_IMPL(subns, _id, action, ...) \
287 namespace action \
288 { \
289 using request = mosrpc##_##subns##_##action##_request; \
290 using response = mosrpc##_##subns##_##action##_response; \
291 }
292
293#ifdef __cplusplus
294#define RPC_DECL_CPP_TYPE_NAMESPACE(subns, X_MACRO) \
295 namespace mosrpc::subns \
296 { \
297 X_MACRO(__NO_OP, __RPC_DO_DECL_CPP_TYPE_NAMESPACE_ALIAS_IMPL, subns) \
298 }
299#else
300#define RPC_DECL_CPP_TYPE_NAMESPACE(subns, X_MACRO)
301#endif