pw_rpc: Add config header; Nanopb struct options
- Add a configuration header for pw_rpc.
- Expose options for configuring how to allocate the buffers for Nanopb
request/response structs and how large to make them by default.
Change-Id: I741fdf852468d6e4200e5338a9dd939751ba19e4
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/26141
Pigweed-Auto-Submit: Wyatt Hepler <hepler@google.com>
Reviewed-by: Keir Mierle <keir@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed.google.com.iam.gserviceaccount.com>
diff --git a/pw_rpc/BUILD b/pw_rpc/BUILD
index cdd1084..244ce00 100644
--- a/pw_rpc/BUILD
+++ b/pw_rpc/BUILD
@@ -68,6 +68,7 @@
"channel.cc",
"packet.cc",
"public/pw_rpc/internal/channel.h",
+ "public/pw_rpc/internal/config.h",
"public/pw_rpc/internal/method_type.h",
"public/pw_rpc/internal/packet.h",
],
diff --git a/pw_rpc/BUILD.gn b/pw_rpc/BUILD.gn
index 4b6d0ea..939f074 100644
--- a/pw_rpc/BUILD.gn
+++ b/pw_rpc/BUILD.gn
@@ -15,19 +15,35 @@
import("//build_overrides/pigweed.gni")
import("$dir_pw_bloat/bloat.gni")
+import("$dir_pw_build/module_config.gni")
import("$dir_pw_build/target_types.gni")
import("$dir_pw_docgen/docs.gni")
import("$dir_pw_protobuf_compiler/proto.gni")
import("$dir_pw_third_party/nanopb/nanopb.gni")
import("$dir_pw_unit_test/test.gni")
-config("default_config") {
+declare_args() {
+ # The build target that overrides the default configuration options for this
+ # module. This should point to a source set that provides defines through a
+ # public config (which may -include a file or add defines directly).
+ pw_rpc_CONFIG = pw_build_DEFAULT_MODULE_CONFIG
+}
+
+config("public_include_path") {
include_dirs = [ "public" ]
visibility = [ ":*" ]
}
+pw_source_set("config") {
+ sources = [ "public/pw_rpc/internal/config.h" ]
+ public_configs = [ ":public_include_path" ]
+ public_deps = [ pw_rpc_CONFIG ]
+ visibility = [ "./*" ]
+ friend = [ "./*" ]
+}
+
pw_source_set("server") {
- public_configs = [ ":default_config" ]
+ public_configs = [ ":public_include_path" ]
public_deps = [ ":common" ]
deps = [ dir_pw_log ]
public = [
@@ -51,7 +67,7 @@
}
pw_source_set("client") {
- public_configs = [ ":default_config" ]
+ public_configs = [ ":public_include_path" ]
public_deps = [ ":common" ]
deps = [ dir_pw_log ]
public = [
@@ -66,7 +82,7 @@
# Classes shared by the server and client.
pw_source_set("common") {
- public_configs = [ ":default_config" ]
+ public_configs = [ ":public_include_path" ]
public_deps = [
":protos.pwpb",
"$dir_pw_containers:intrusive_list",
diff --git a/pw_rpc/nanopb/BUILD.gn b/pw_rpc/nanopb/BUILD.gn
index baf2805..97b97a1 100644
--- a/pw_rpc/nanopb/BUILD.gn
+++ b/pw_rpc/nanopb/BUILD.gn
@@ -30,6 +30,7 @@
sources = [ "nanopb_method.cc" ]
public_deps = [
":common",
+ "..:config",
"..:server",
]
deps = [ dir_pw_log ]
diff --git a/pw_rpc/nanopb/public/pw_rpc/internal/nanopb_method.h b/pw_rpc/nanopb/public/pw_rpc/internal/nanopb_method.h
index 33cbaf7..2a20600 100644
--- a/pw_rpc/nanopb/public/pw_rpc/internal/nanopb_method.h
+++ b/pw_rpc/nanopb/public/pw_rpc/internal/nanopb_method.h
@@ -20,6 +20,7 @@
#include <type_traits>
#include "pw_rpc/internal/base_server_writer.h"
+#include "pw_rpc/internal/config.h"
#include "pw_rpc/internal/method.h"
#include "pw_rpc/internal/method_type.h"
#include "pw_rpc/internal/nanopb_common.h"
@@ -222,7 +223,7 @@
// avoid generating unnecessary copies of the invoker functions.
template <typename T>
static constexpr size_t AllocateSpaceFor() {
- return std::max(sizeof(T), size_t(64));
+ return std::max(sizeof(T), cfg::kNanopbStructMinBufferSize);
}
constexpr NanopbMethod(uint32_t id,
@@ -250,8 +251,10 @@
static void UnaryInvoker(const Method& method,
ServerCall& call,
const Packet& request) {
+ _PW_RPC_NANOPB_STRUCT_STORAGE_CLASS
std::aligned_storage_t<request_size, alignof(std::max_align_t)>
request_struct{};
+ _PW_RPC_NANOPB_STRUCT_STORAGE_CLASS
std::aligned_storage_t<response_size, alignof(std::max_align_t)>
response_struct{};
@@ -266,6 +269,7 @@
static void ServerStreamingInvoker(const Method& method,
ServerCall& call,
const Packet& request) {
+ _PW_RPC_NANOPB_STRUCT_STORAGE_CLASS
std::aligned_storage_t<request_size, alignof(std::max_align_t)>
request_struct{};
diff --git a/pw_rpc/public/pw_rpc/internal/config.h b/pw_rpc/public/pw_rpc/internal/config.h
new file mode 100644
index 0000000..aa9d9ee
--- /dev/null
+++ b/pw_rpc/public/pw_rpc/internal/config.h
@@ -0,0 +1,57 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+// Configuration macros for the pw_rpc module.
+#pragma once
+
+#include <cstddef>
+
+// The Nanopb-based pw_rpc implementation allocates memory to use for Nanopb
+// structs for the request and response protobufs. The template function that
+// allocates these structs rounds struct sizes up to this value so that
+// different structs can be allocated with the same function. Structs with sizes
+// larger than this value cause an extra function to be created, which slightly
+// increases code size.
+//
+// Ideally, this value will be set to the size of the largest Nanopb struct used
+// as an RPC request or response. The buffer can be stack or globally allocated
+// (see PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE).
+#ifndef PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE
+#define PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE 64
+#endif // PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE
+
+namespace pw::rpc::cfg {
+
+inline constexpr size_t kNanopbStructMinBufferSize =
+ PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE;
+
+} // namespace pw::rpc::cfg
+
+#undef PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE
+
+// This option determines whether to allocate the Nanopb structs on the stack or
+// in a global variable. Globally allocated structs are NOT thread safe, but
+// work fine when the RPC server's ProcessPacket function is only called from
+// one thread.
+#ifndef PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE
+#define PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE 1
+#endif // PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE
+
+#if PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE
+#define _PW_RPC_NANOPB_STRUCT_STORAGE_CLASS
+#else
+#define _PW_RPC_NANOPB_STRUCT_STORAGE_CLASS static
+#endif // PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE
+
+#undef PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE