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 /// In client and bidirectional RPCs, pw_rpc clients may signal that they have 22 /// finished sending requests with a `CLIENT_STREAM_END` packet. While this can 23 /// be useful in some circumstances, it is often not necessary. 24 /// 25 /// This option controls whether or not include a callback that is called when 26 /// the client stream ends. The callback is included in all ServerReader/Writer 27 /// objects as a @cpp_type{pw::Function}, so may have a significant cost. 28 /// 29 /// This is disabled by default. 30 #ifndef PW_RPC_CLIENT_STREAM_END_CALLBACK 31 #define PW_RPC_CLIENT_STREAM_END_CALLBACK 0 32 #endif // PW_RPC_CLIENT_STREAM_END_CALLBACK 33 34 /// The Nanopb-based pw_rpc implementation allocates memory to use for Nanopb 35 /// structs for the request and response protobufs. The template function that 36 /// allocates these structs rounds struct sizes up to this value so that 37 /// different structs can be allocated with the same function. Structs with 38 /// sizes larger than this value cause an extra function to be created, which 39 /// slightly increases code size. 40 /// 41 /// Ideally, this value will be set to the size of the largest Nanopb struct 42 /// used as an RPC request or response. The buffer can be stack or globally 43 /// allocated (see @c_macro{PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE}). 44 /// 45 /// This defaults to 64 bytes. 46 #ifndef PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE 47 #define PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE 64 48 #endif // PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE 49 50 /// Enable global synchronization for RPC calls. If this is set, a backend must 51 /// be configured for pw_sync:mutex. 52 /// 53 /// This is enabled by default. 54 #ifndef PW_RPC_USE_GLOBAL_MUTEX 55 #define PW_RPC_USE_GLOBAL_MUTEX 1 56 #endif // PW_RPC_USE_GLOBAL_MUTEX 57 58 /// pw_rpc must yield the current thread when waiting for a callback to complete 59 /// in a different thread. PW_RPC_YIELD_MODE determines how to yield. There are 60 /// three supported settings: 61 /// 62 /// - @c_macro{PW_RPC_YIELD_MODE_BUSY_LOOP} - Do nothing. Release and 63 /// reacquire the RPC lock in a busy loop. @c_macro{PW_RPC_USE_GLOBAL_MUTEX} 64 /// must be 0. 65 /// - @c_macro{PW_RPC_YIELD_MODE_SLEEP} - Yield with 1-tick calls to 66 /// @cpp_func{pw::this_thread::sleep_for()}. A backend must be configured 67 /// for pw_thread:sleep. 68 /// - @c_macro{PW_RPC_YIELD_MODE_YIELD} - Yield with 69 /// @cpp_func{pw::this_thread::yield()}. A backend must be configured for 70 /// pw_thread:yield. IMPORTANT: On some platforms, 71 /// @cpp_func{pw::this_thread::yield()} does not yield to lower priority 72 /// tasks and should not be used here. 73 /// 74 #ifndef PW_RPC_YIELD_MODE 75 #if PW_RPC_USE_GLOBAL_MUTEX == 0 76 #define PW_RPC_YIELD_MODE PW_RPC_YIELD_MODE_BUSY_LOOP 77 #else 78 #define PW_RPC_YIELD_MODE PW_RPC_YIELD_MODE_SLEEP 79 #endif // PW_RPC_USE_GLOBAL_MUTEX == 0 80 #endif // PW_RPC_YIELD_MODE 81 82 /// @def PW_RPC_YIELD_MODE_BUSY_LOOP 83 /// @def PW_RPC_YIELD_MODE_SLEEP 84 /// @def PW_RPC_YIELD_MODE_YIELD 85 /// 86 /// Supported configuration values for @c_macro{PW_RPC_YIELD_MODE}. 87 #define PW_RPC_YIELD_MODE_BUSY_LOOP 100 88 #define PW_RPC_YIELD_MODE_SLEEP 101 89 #define PW_RPC_YIELD_MODE_YIELD 102 90 91 /// If `PW_RPC_YIELD_MODE == PW_RPC_YIELD_MODE_SLEEP`, 92 /// `PW_RPC_YIELD_SLEEP_DURATION` sets how long to sleep during each iteration 93 /// of the yield loop. The value must be a constant expression that converts to 94 /// a @cpp_type{pw::chrono::SystemClock::duration}. 95 #ifndef PW_RPC_YIELD_SLEEP_DURATION 96 97 // When building for a desktop operating system, use a 1ms sleep by default. 98 // 1-tick duration sleeps can result in spurious timeouts. 99 #if defined(_WIN32) || defined(__APPLE__) || defined(__linux__) 100 #define PW_RPC_YIELD_SLEEP_DURATION std::chrono::milliseconds(1) 101 #else 102 #define PW_RPC_YIELD_SLEEP_DURATION pw::chrono::SystemClock::duration(1) 103 #endif // defined(_WIN32) || defined(__APPLE__) || defined(__linux__) 104 105 #endif // PW_RPC_YIELD_SLEEP_DURATION 106 107 // PW_RPC_YIELD_SLEEP_DURATION is not needed for non-sleep yield modes. 108 #if PW_RPC_YIELD_MODE != PW_RPC_YIELD_MODE_SLEEP 109 #undef PW_RPC_YIELD_SLEEP_DURATION 110 #endif // PW_RPC_YIELD_MODE != PW_RPC_YIELD_MODE_SLEEP 111 112 /// pw_rpc call objects wait for their callbacks to complete before they are 113 /// moved or destoyed. Deadlocks occur if a callback: 114 /// 115 /// - attempts to destroy its call object, 116 /// - attempts to move its call object while the call is still active, or 117 /// - never returns. 118 /// 119 /// If `PW_RPC_CALLBACK_TIMEOUT_TICKS` is greater than 0, then `PW_CRASH` is 120 /// invoked if a thread waits for an RPC callback to complete for more than the 121 /// specified tick count. 122 /// 123 /// A "tick" in this context is one iteration of a loop that yields releases the 124 /// RPC lock and yields the thread according to @c_macro{PW_RPC_YIELD_MODE}. By 125 /// default, the thread yields with a 1-tick call to 126 /// @cpp_func{pw::this_thread::sleep_for()}. 127 #ifndef PW_RPC_CALLBACK_TIMEOUT_TICKS 128 #define PW_RPC_CALLBACK_TIMEOUT_TICKS 10000 129 #endif // PW_RPC_CALLBACK_TIMEOUT_TICKS 130 131 /// Whether pw_rpc should use dynamic memory allocation internally. If enabled, 132 /// pw_rpc dynamically allocates channels and its encoding buffer. RPC users may 133 /// use dynamic allocation independently of this option (e.g. to allocate pw_rpc 134 /// call objects). 135 /// 136 /// The semantics for allocating and initializing channels change depending on 137 /// this option. If dynamic allocation is disabled, pw_rpc endpoints (servers or 138 /// clients) use an externally-allocated, fixed-size array of channels. That 139 /// array must include unassigned channels or existing channels must be closed 140 /// to add new channels. 141 /// 142 /// If dynamic allocation is enabled, an span of channels may be passed to the 143 /// endpoint at construction, but these channels are only used to initialize its 144 /// internal channels container. External channel objects are NOT used by the 145 /// endpoint and cannot be updated if dynamic allocation is enabled. No 146 /// unassigned channels should be passed to the endpoint; they will be ignored. 147 /// Any number of channels may be added to the endpoint, without closing 148 /// existing channels, but adding channels will use more memory. 149 #ifndef PW_RPC_DYNAMIC_ALLOCATION 150 #define PW_RPC_DYNAMIC_ALLOCATION 0 151 #endif // PW_RPC_DYNAMIC_ALLOCATION 152 153 #if defined(PW_RPC_DYNAMIC_CONTAINER) || \ 154 defined(PW_RPC_DYNAMIC_CONTAINER_INCLUDE) 155 static_assert( 156 PW_RPC_DYNAMIC_ALLOCATION == 1, 157 "PW_RPC_DYNAMIC_ALLOCATION is disabled, so PW_RPC_DYNAMIC_CONTAINER and " 158 "PW_RPC_DYNAMIC_CONTAINER_INCLUDE have no effect and should not be set."); 159 #endif // PW_RPC_DYNAMIC_CONTAINER || PW_RPC_DYNAMIC_CONTAINER_INCLUDE 160 161 /// If @c_macro{PW_RPC_DYNAMIC_ALLOCATION} is enabled, this macro must expand to 162 /// a container capable of storing objects of the provided type. This container 163 /// will be used internally by pw_rpc to allocate the channels list and encoding 164 /// buffer. Defaults to `std::vector<type>`, but may be set to any type that 165 /// supports the following `std::vector` operations: 166 /// 167 /// - Default construction 168 /// - `emplace_back()` 169 /// - `pop_back()` 170 /// - `back()` 171 /// - `resize()` 172 /// - `clear()` 173 /// - Range-based for loop iteration (`begin()`, `end()`) 174 /// 175 #ifndef PW_RPC_DYNAMIC_CONTAINER 176 #define PW_RPC_DYNAMIC_CONTAINER(type) std::vector<type> 177 #endif // PW_RPC_DYNAMIC_CONTAINER 178 179 /// If @c_macro{PW_RPC_DYNAMIC_ALLOCATION} is enabled, this header file is 180 /// included in files that use @c_macro{PW_RPC_DYNAMIC_CONTAINER}. Defaults to 181 /// `<vector>`, but may be set in conjunction with 182 /// @c_macro{PW_RPC_DYNAMIC_CONTAINER} to use a different container type for 183 /// dynamic allocations in pw_rpc. 184 #ifndef PW_RPC_DYNAMIC_CONTAINER_INCLUDE 185 #define PW_RPC_DYNAMIC_CONTAINER_INCLUDE <vector> 186 #endif // PW_RPC_DYNAMIC_CONTAINER_INCLUDE 187 188 /// Size of the global RPC packet encoding buffer in bytes. If dynamic 189 /// allocation is enabled, this value is only used for test helpers that 190 /// allocate RPC encoding buffers. 191 #ifndef PW_RPC_ENCODING_BUFFER_SIZE_BYTES 192 #define PW_RPC_ENCODING_BUFFER_SIZE_BYTES 512 193 #endif // PW_RPC_ENCODING_BUFFER_SIZE_BYTES 194 195 /// The log level to use for this module. Logs below this level are omitted. 196 #ifndef PW_RPC_CONFIG_LOG_LEVEL 197 #define PW_RPC_CONFIG_LOG_LEVEL PW_LOG_LEVEL_INFO 198 #endif // PW_RPC_CONFIG_LOG_LEVEL 199 200 /// The log module name to use for this module. 201 #ifndef PW_RPC_CONFIG_LOG_MODULE_NAME 202 #define PW_RPC_CONFIG_LOG_MODULE_NAME "PW_RPC" 203 #endif // PW_RPC_CONFIG_LOG_MODULE_NAME 204 205 namespace pw::rpc::cfg { 206 207 template <typename...> 208 constexpr std::bool_constant<PW_RPC_CLIENT_STREAM_END_CALLBACK> 209 kClientStreamEndCallbackEnabled; 210 211 template <typename...> 212 constexpr std::bool_constant<PW_RPC_DYNAMIC_ALLOCATION> 213 kDynamicAllocationEnabled; 214 215 inline constexpr size_t kNanopbStructMinBufferSize = 216 PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE; 217 218 inline constexpr size_t kEncodingBufferSizeBytes = 219 PW_RPC_ENCODING_BUFFER_SIZE_BYTES; 220 221 #undef PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE 222 #undef PW_RPC_ENCODING_BUFFER_SIZE_BYTES 223 224 } // namespace pw::rpc::cfg 225 226 /// This option determines whether to allocate the Nanopb structs on the stack 227 /// or in a global variable. Globally allocated structs are NOT thread safe, but 228 /// work fine when the RPC server's ProcessPacket function is only called from 229 /// one thread. 230 #ifndef PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE 231 #define PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE 1 232 #endif // PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE 233 234 /// @private Internal macro for declaring the Nanopb struct; do not use. 235 #if PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE 236 #define _PW_RPC_NANOPB_STRUCT_STORAGE_CLASS 237 #else 238 #define _PW_RPC_NANOPB_STRUCT_STORAGE_CLASS static 239 #endif // PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE 240 241 #undef PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE 242