xref: /aosp_15_r20/external/pigweed/pw_rpc/public/pw_rpc/internal/config.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 // Configuration macros for the pw_rpc module.
16 #pragma once
17 
18 #include <cstddef>
19 #include <type_traits>
20 
21 #if defined(PW_RPC_CLIENT_STREAM_END_CALLBACK) && \
22     PW_RPC_CLIENT_STREAM_END_CALLBACK
23 #pragma message(                                                \
24     "Warning PW_RPC_CLIENT_STREAM_END_CALLBACK is deprecated! " \
25     "Use PW_RPC_COMPLETION_REQUEST_CALLBACK instead.")
26 #define PW_RPC_COMPLETION_REQUEST_CALLBACK 1
27 #endif
28 
29 #undef PW_RPC_CLIENT_STREAM_END_CALLBACK
30 
31 /// pw_rpc clients may request call completion by sending
32 /// `CLIENT_REQUEST_COMPLETION` packet. For client streaming or bi-direction
33 /// RPCs, this also indicates that the client is done sending requests. While
34 /// this can be useful in some circumstances, it is often not necessary.
35 ///
36 /// This option controls whether or not include a callback that is called when
37 /// the client stream requests for completion. The callback is included in all
38 /// ServerReader/Writer objects as a @cpp_type{pw::Function}, so may have a
39 /// significant cost.
40 ///
41 /// This is disabled by default.
42 #ifndef PW_RPC_COMPLETION_REQUEST_CALLBACK
43 #define PW_RPC_COMPLETION_REQUEST_CALLBACK 0
44 #endif  // PW_RPC_COMPLETION_REQUEST_CALLBACK
45 
46 /// pw_rpc Method's can include their MethodType as a runtime accessible
47 /// variable.
48 ///
49 /// This isn't needed for most applications so is disabled by default.
50 #ifndef PW_RPC_METHOD_STORES_TYPE
51 #define PW_RPC_METHOD_STORES_TYPE 0
52 #endif  // PW_RPC_METHOD_STORES_TYPE
53 
54 /// The Nanopb-based pw_rpc implementation allocates memory to use for Nanopb
55 /// structs for the request and response protobufs. The template function that
56 /// allocates these structs rounds struct sizes up to this value so that
57 /// different structs can be allocated with the same function. Structs with
58 /// sizes larger than this value cause an extra function to be created, which
59 /// slightly increases code size.
60 ///
61 /// Ideally, this value will be set to the size of the largest Nanopb struct
62 /// used as an RPC request or response. The buffer can be stack or globally
63 /// allocated (see @c_macro{PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE}).
64 ///
65 /// This defaults to 64 bytes.
66 #ifndef PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE
67 #define PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE 64
68 #endif  // PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE
69 
70 /// Enable global synchronization for RPC calls. If this is set, a backend must
71 /// be configured for pw_sync:mutex.
72 ///
73 /// This is enabled by default.
74 #ifndef PW_RPC_USE_GLOBAL_MUTEX
75 #define PW_RPC_USE_GLOBAL_MUTEX 1
76 #endif  // PW_RPC_USE_GLOBAL_MUTEX
77 
78 /// pw_rpc must yield the current thread when waiting for a callback to complete
79 /// in a different thread. PW_RPC_YIELD_MODE determines how to yield. There are
80 /// three supported settings:
81 ///
82 ///   - @c_macro{PW_RPC_YIELD_MODE_BUSY_LOOP} - Do nothing. Release and
83 ///     reacquire the RPC lock in a busy loop. @c_macro{PW_RPC_USE_GLOBAL_MUTEX}
84 ///     must be 0.
85 ///   - @c_macro{PW_RPC_YIELD_MODE_SLEEP} - Yield with 1-tick calls to
86 ///     @cpp_func{pw::this_thread::sleep_for()}. A backend must be configured
87 ///     for pw_thread:sleep.
88 ///   - @c_macro{PW_RPC_YIELD_MODE_YIELD} - Yield with
89 ///     @cpp_func{pw::this_thread::yield()}. A backend must be configured for
90 ///     pw_thread:yield. IMPORTANT: On some platforms,
91 ///     @cpp_func{pw::this_thread::yield()} does not yield to lower priority
92 ///     tasks and should not be used here.
93 ///
94 /// Note: The dependencies of pw_rpc depend on the value of PW_RPC_YIELD_MODE.
95 /// When building pw_rpc with Bazel, you should NOT set this module config value
96 /// directly. Instead, tell the build system which value you wish to select by
97 /// adding one of the following constraint_values to the target platform:
98 ///
99 ///   - `@pigweed//pw_rpc:yield_mode_busy_loop`
100 ///   - `@pigweed//pw_rpc:yield_mode_busy_sleep` (the default)
101 ///   - `@pigweed//pw_rpc:yield_mode_busy_yield`
102 #ifndef PW_RPC_YIELD_MODE
103 #if PW_RPC_USE_GLOBAL_MUTEX == 0
104 #define PW_RPC_YIELD_MODE PW_RPC_YIELD_MODE_BUSY_LOOP
105 #else
106 #define PW_RPC_YIELD_MODE PW_RPC_YIELD_MODE_SLEEP
107 #endif  // PW_RPC_USE_GLOBAL_MUTEX == 0
108 #endif  // PW_RPC_YIELD_MODE
109 
110 /// @def PW_RPC_YIELD_MODE_BUSY_LOOP
111 /// @def PW_RPC_YIELD_MODE_SLEEP
112 /// @def PW_RPC_YIELD_MODE_YIELD
113 ///
114 /// Supported configuration values for @c_macro{PW_RPC_YIELD_MODE}.
115 // LINT.IfChange
116 #define PW_RPC_YIELD_MODE_BUSY_LOOP 100
117 #define PW_RPC_YIELD_MODE_SLEEP 101
118 #define PW_RPC_YIELD_MODE_YIELD 102
119 // LINT.ThenChange(//pw_rpc/BUILD.bazel)
120 
121 /// If `PW_RPC_YIELD_MODE == PW_RPC_YIELD_MODE_SLEEP`,
122 /// `PW_RPC_YIELD_SLEEP_DURATION` sets how long to sleep during each iteration
123 /// of the yield loop. The value must be a constant expression that converts to
124 /// a @cpp_type{pw::chrono::SystemClock::duration}.
125 #ifndef PW_RPC_YIELD_SLEEP_DURATION
126 
127 // When building for a desktop operating system, use a 1ms sleep by default.
128 // 1-tick duration sleeps can result in spurious timeouts.
129 #if defined(_WIN32) || defined(__APPLE__) || \
130     defined(__linux__) && !defined(__ZEPHYR__)
131 #define PW_RPC_YIELD_SLEEP_DURATION std::chrono::milliseconds(1)
132 #else
133 #define PW_RPC_YIELD_SLEEP_DURATION pw::chrono::SystemClock::duration(1)
134 #endif  // defined(_WIN32) || defined(__APPLE__) || defined(__linux__)
135         // && !defined(__ZEPHYR__)
136 
137 #endif  // PW_RPC_YIELD_SLEEP_DURATION
138 
139 // PW_RPC_YIELD_SLEEP_DURATION is not needed for non-sleep yield modes.
140 #if PW_RPC_YIELD_MODE != PW_RPC_YIELD_MODE_SLEEP
141 #undef PW_RPC_YIELD_SLEEP_DURATION
142 #endif  // PW_RPC_YIELD_MODE != PW_RPC_YIELD_MODE_SLEEP
143 
144 /// pw_rpc call objects wait for their callbacks to complete before they are
145 /// moved or destoyed. Deadlocks occur if a callback:
146 ///
147 ///   - attempts to destroy its call object,
148 ///   - attempts to move its call object while the call is still active, or
149 ///   - never returns.
150 ///
151 /// If `PW_RPC_CALLBACK_TIMEOUT_TICKS` is greater than 0, then `PW_CRASH` is
152 /// invoked if a thread waits for an RPC callback to complete for more than the
153 /// specified tick count.
154 ///
155 /// A "tick" in this context is one iteration of a loop that yields releases the
156 /// RPC lock and yields the thread according to @c_macro{PW_RPC_YIELD_MODE}. By
157 /// default, the thread yields with a 1-tick call to
158 /// @cpp_func{pw::this_thread::sleep_for()}.
159 #ifndef PW_RPC_CALLBACK_TIMEOUT_TICKS
160 #define PW_RPC_CALLBACK_TIMEOUT_TICKS 10000
161 #endif  // PW_RPC_CALLBACK_TIMEOUT_TICKS
162 
163 /// Whether pw_rpc should use dynamic memory allocation internally. If enabled,
164 /// pw_rpc dynamically allocates channels and its encoding buffer. RPC users may
165 /// use dynamic allocation independently of this option (e.g. to allocate pw_rpc
166 /// call objects).
167 ///
168 /// The semantics for allocating and initializing channels change depending on
169 /// this option. If dynamic allocation is disabled, pw_rpc endpoints (servers or
170 /// clients) use an externally-allocated, fixed-size array of channels.  That
171 /// array must include unassigned channels or existing channels must be closed
172 /// to add new channels.
173 ///
174 /// If dynamic allocation is enabled, an span of channels may be passed to the
175 /// endpoint at construction, but these channels are only used to initialize its
176 /// internal channels container. External channel objects are NOT used by the
177 /// endpoint and cannot be updated if dynamic allocation is enabled. No
178 /// unassigned channels should be passed to the endpoint; they will be ignored.
179 /// Any number of channels may be added to the endpoint, without closing
180 /// existing channels, but adding channels will use more memory.
181 #ifndef PW_RPC_DYNAMIC_ALLOCATION
182 #define PW_RPC_DYNAMIC_ALLOCATION 0
183 #endif  // PW_RPC_DYNAMIC_ALLOCATION
184 
185 #if defined(PW_RPC_DYNAMIC_CONTAINER) || \
186     defined(PW_RPC_DYNAMIC_CONTAINER_INCLUDE)
187 static_assert(
188     PW_RPC_DYNAMIC_ALLOCATION == 1,
189     "PW_RPC_DYNAMIC_ALLOCATION is disabled, so PW_RPC_DYNAMIC_CONTAINER and "
190     "PW_RPC_DYNAMIC_CONTAINER_INCLUDE have no effect and should not be set.");
191 #endif  // PW_RPC_DYNAMIC_CONTAINER || PW_RPC_DYNAMIC_CONTAINER_INCLUDE
192 
193 /// If @c_macro{PW_RPC_DYNAMIC_ALLOCATION} is enabled, this macro must expand to
194 /// a container capable of storing objects of the provided type. This container
195 /// will be used internally by pw_rpc to allocate the channels list and encoding
196 /// buffer. Defaults to `std::vector<type>`, but may be set to any type that
197 /// supports the following `std::vector` operations:
198 ///
199 ///   - Default construction
200 ///   - `emplace_back()`
201 ///   - `pop_back()`
202 ///   - `back()`
203 ///   - `resize()`
204 ///   - `clear()`
205 ///   - Range-based for loop iteration (`begin()`, `end()`)
206 ///
207 #ifndef PW_RPC_DYNAMIC_CONTAINER
208 #define PW_RPC_DYNAMIC_CONTAINER(type) std::vector<type>
209 #endif  // PW_RPC_DYNAMIC_CONTAINER
210 
211 /// If @c_macro{PW_RPC_DYNAMIC_ALLOCATION} is enabled, this header file is
212 /// included in files that use @c_macro{PW_RPC_DYNAMIC_CONTAINER}. Defaults to
213 /// `<vector>`, but may be set in conjunction with
214 /// @c_macro{PW_RPC_DYNAMIC_CONTAINER} to use a different container type for
215 /// dynamic allocations in pw_rpc.
216 #ifndef PW_RPC_DYNAMIC_CONTAINER_INCLUDE
217 #define PW_RPC_DYNAMIC_CONTAINER_INCLUDE <vector>
218 #endif  // PW_RPC_DYNAMIC_CONTAINER_INCLUDE
219 
220 /// If @c_macro{PW_RPC_DYNAMIC_ALLOCATION} is enabled, this macro must expand to
221 /// a statement that creates a `std::unique_ptr`-like smart pointer.
222 /// @param type The type of the object to construct (e.g. with `new`)
223 /// @param ... Arguments to pass to the constructor, if any
224 #ifndef PW_RPC_MAKE_UNIQUE_PTR
225 #define PW_RPC_MAKE_UNIQUE_PTR(type, ...) \
226   std::unique_ptr<type>(new type(__VA_ARGS__))
227 #endif  // PW_RPC_DYNAMIC_CONTAINER
228 
229 /// If @c_macro{PW_RPC_DYNAMIC_ALLOCATION} is enabled, this header file is
230 /// included in files that use @c_macro{PW_RPC_MAKE_UNIQUE_PTR}. Defaults to
231 /// `<memory>` for `std::make_unique`.
232 #ifndef PW_RPC_MAKE_UNIQUE_PTR_INCLUDE
233 #define PW_RPC_MAKE_UNIQUE_PTR_INCLUDE <memory>
234 #endif  // PW_RPC_MAKE_UNIQUE_PTR_INCLUDE
235 
236 /// Size of the global RPC packet encoding buffer in bytes. If dynamic
237 /// allocation is enabled, this value is only used for test helpers that
238 /// allocate RPC encoding buffers.
239 #ifndef PW_RPC_ENCODING_BUFFER_SIZE_BYTES
240 #define PW_RPC_ENCODING_BUFFER_SIZE_BYTES 512
241 #endif  // PW_RPC_ENCODING_BUFFER_SIZE_BYTES
242 
243 /// The log level to use for this module. Logs below this level are omitted.
244 #ifndef PW_RPC_CONFIG_LOG_LEVEL
245 #define PW_RPC_CONFIG_LOG_LEVEL PW_LOG_LEVEL_INFO
246 #endif  // PW_RPC_CONFIG_LOG_LEVEL
247 
248 /// The log module name to use for this module.
249 #ifndef PW_RPC_CONFIG_LOG_MODULE_NAME
250 #define PW_RPC_CONFIG_LOG_MODULE_NAME "PW_RPC"
251 #endif  // PW_RPC_CONFIG_LOG_MODULE_NAME
252 
253 namespace pw::rpc::cfg {
254 
255 template <typename...>
256 constexpr std::bool_constant<PW_RPC_COMPLETION_REQUEST_CALLBACK>
257     kClientStreamEndCallbackEnabled;
258 
259 template <typename...>
260 constexpr std::bool_constant<PW_RPC_METHOD_STORES_TYPE> kMethodStoresType;
261 
262 template <typename...>
263 constexpr std::bool_constant<PW_RPC_DYNAMIC_ALLOCATION>
264     kDynamicAllocationEnabled;
265 
266 inline constexpr size_t kNanopbStructMinBufferSize =
267     PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE;
268 
269 inline constexpr size_t kEncodingBufferSizeBytes =
270     PW_RPC_ENCODING_BUFFER_SIZE_BYTES;
271 
272 #undef PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE
273 #undef PW_RPC_ENCODING_BUFFER_SIZE_BYTES
274 
275 }  // namespace pw::rpc::cfg
276 
277 /// This option determines whether to allocate the Nanopb structs on the stack
278 /// or in a global variable. Globally allocated structs are NOT thread safe, but
279 /// work fine when the RPC server's ProcessPacket function is only called from
280 /// one thread.
281 #ifndef PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE
282 #define PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE 1
283 #endif  // PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE
284 
285 /// @private Internal macro for declaring the Nanopb struct; do not use.
286 #if PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE
287 #define _PW_RPC_NANOPB_STRUCT_STORAGE_CLASS
288 #else
289 #define _PW_RPC_NANOPB_STRUCT_STORAGE_CLASS static
290 #endif  // PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE
291 
292 #undef PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE
293