Construct DefaultReactor lazily since not always needed

pull/21774/head
Vijay Pai 5 years ago
parent 380b70d3a6
commit 1f0cdd5aad
  1. 19
      include/grpcpp/impl/codegen/server_context_impl.h
  2. 7
      include/grpcpp/test/default_reactor_test_peer.h
  3. 3
      src/cpp/server/server_context.cc

@ -20,8 +20,10 @@
#define GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_IMPL_H
#include <atomic>
#include <cassert>
#include <map>
#include <memory>
#include <type_traits>
#include <vector>
#include <grpc/impl/codegen/port_platform.h>
@ -301,8 +303,18 @@ class ServerContextBase {
///
/// WARNING: This is experimental API and could be changed or removed.
::grpc_impl::ServerUnaryReactor* DefaultReactor() {
auto reactor = &default_reactor_;
Reactor* reactor = reinterpret_cast<Reactor*>(&default_reactor_);
if (test_unary_ != nullptr) {
return reactor;
}
new (reactor) Reactor;
#ifndef NDEBUG
bool old = false;
assert(default_reactor_used_.compare_exchange_strong(
old, true, std::memory_order_relaxed));
#else
default_reactor_used_.store(true, std::memory_order_relaxed);
#endif
return reactor;
}
@ -445,7 +457,7 @@ class ServerContextBase {
public:
TestServerCallbackUnary(ServerContextBase* ctx,
std::function<void(::grpc::Status)> func)
: reactor_(&ctx->default_reactor_), func_(std::move(func)) {
: reactor_(ctx->DefaultReactor()), func_(std::move(func)) {
this->BindReactor(reactor_);
}
void Finish(::grpc::Status s) override {
@ -472,7 +484,8 @@ class ServerContextBase {
const std::function<void(::grpc::Status s)> func_;
};
Reactor default_reactor_;
typename std::aligned_storage<sizeof(Reactor), alignof(Reactor)>::type
default_reactor_;
std::atomic_bool default_reactor_used_{false};
std::unique_ptr<TestServerCallbackUnary> test_unary_;
};

@ -29,7 +29,9 @@ namespace testing {
/// DefaultReactor. It is intended for allow unit-testing of a callback API
/// service via direct invocation of the service methods rather than through
/// RPCs. It is only applicable for unary RPC methods that use the
/// DefaultReactor rather than any user-defined reactor.
/// DefaultReactor rather than any user-defined reactor. If it is used, it must
/// be created before the RPC is invoked so that it can bind the reactor into a
/// test mode rather than letting it follow the normal paths.
class DefaultReactorTestPeer {
public:
explicit DefaultReactorTestPeer(experimental::CallbackServerContext* ctx)
@ -40,7 +42,8 @@ class DefaultReactorTestPeer {
ctx->SetupTestDefaultReactor(std::move(finish_func));
}
::grpc::experimental::ServerUnaryReactor* reactor() const {
return &ctx_->default_reactor_;
return reinterpret_cast<experimental::ServerUnaryReactor*>(
&ctx_->default_reactor_);
}
bool test_status_set() const { return ctx_->test_status_set(); }
Status test_status() const { return ctx_->test_status(); }

@ -272,8 +272,7 @@ void ServerContextBase::Clear() {
grpc_call_unref(call);
}
if (default_reactor_used_.load(std::memory_order_relaxed)) {
default_reactor_.~Reactor();
new (&default_reactor_) Reactor;
reinterpret_cast<Reactor*>(&default_reactor_)->~Reactor();
default_reactor_used_.store(false, std::memory_order_relaxed);
}
test_unary_.reset();

Loading…
Cancel
Save