| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802 | /* * * Copyright 2019 gRPC 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 * *     http://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. */#ifndef GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_HANDLERS_H#define GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_HANDLERS_H#include <grpcpp/impl/codegen/message_allocator.h>#include <grpcpp/impl/codegen/rpc_service_method.h>#include <grpcpp/impl/codegen/server_callback_impl.h>#include <grpcpp/impl/codegen/server_context_impl.h>#include <grpcpp/impl/codegen/status.h>namespace grpc_impl {namespace internal {template <class RequestType, class ResponseType>class CallbackUnaryHandler : public ::grpc::internal::MethodHandler { public:  explicit CallbackUnaryHandler(      std::function<ServerUnaryReactor*(::grpc_impl::CallbackServerContext*,                                        const RequestType*, ResponseType*)>          get_reactor)      : get_reactor_(std::move(get_reactor)) {}  void SetMessageAllocator(      ::grpc::experimental::MessageAllocator<RequestType, ResponseType>*          allocator) {    allocator_ = allocator;  }  void RunHandler(const HandlerParameter& param) final {    // Arena allocate a controller structure (that includes request/response)    ::grpc::g_core_codegen_interface->grpc_call_ref(param.call->call());    auto* allocator_state = static_cast<        ::grpc::experimental::MessageHolder<RequestType, ResponseType>*>(        param.internal_data);    auto* call = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(        param.call->call(), sizeof(ServerCallbackUnaryImpl)))        ServerCallbackUnaryImpl(            static_cast<::grpc_impl::CallbackServerContext*>(                param.server_context),            param.call, allocator_state, std::move(param.call_requester));    param.server_context->BeginCompletionOp(        param.call, [call](bool) { call->MaybeDone(); }, call);    ServerUnaryReactor* reactor = nullptr;    if (param.status.ok()) {      reactor = ::grpc::internal::CatchingReactorGetter<ServerUnaryReactor>(          get_reactor_,          static_cast<::grpc_impl::CallbackServerContext*>(              param.server_context),          call->request(), call->response());    }    if (reactor == nullptr) {      // if deserialization or reactor creator failed, we need to fail the call      reactor = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(          param.call->call(), sizeof(UnimplementedUnaryReactor)))          UnimplementedUnaryReactor(              ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""));    }    /// Invoke SetupReactor as the last part of the handler    call->SetupReactor(reactor);  }  void* Deserialize(grpc_call* call, grpc_byte_buffer* req,                    ::grpc::Status* status, void** handler_data) final {    ::grpc::ByteBuffer buf;    buf.set_buffer(req);    RequestType* request = nullptr;    ::grpc::experimental::MessageHolder<RequestType, ResponseType>*        allocator_state = nullptr;    if (allocator_ != nullptr) {      allocator_state = allocator_->AllocateMessages();    } else {      allocator_state =          new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(              call, sizeof(DefaultMessageHolder<RequestType, ResponseType>)))              DefaultMessageHolder<RequestType, ResponseType>();    }    *handler_data = allocator_state;    request = allocator_state->request();    *status =        ::grpc::SerializationTraits<RequestType>::Deserialize(&buf, request);    buf.Release();    if (status->ok()) {      return request;    }    // Clean up on deserialization failure.    allocator_state->Release();    return nullptr;  } private:  std::function<ServerUnaryReactor*(::grpc_impl::CallbackServerContext*,                                    const RequestType*, ResponseType*)>      get_reactor_;  ::grpc::experimental::MessageAllocator<RequestType, ResponseType>*      allocator_ = nullptr;  class ServerCallbackUnaryImpl : public ServerCallbackUnary {   public:    void Finish(::grpc::Status s) override {      finish_tag_.Set(          call_.call(), [this](bool) { MaybeDone(); }, &finish_ops_,          reactor_.load(std::memory_order_relaxed)->InternalInlineable());      finish_ops_.set_core_cq_tag(&finish_tag_);      if (!ctx_->sent_initial_metadata_) {        finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_,                                        ctx_->initial_metadata_flags());        if (ctx_->compression_level_set()) {          finish_ops_.set_compression_level(ctx_->compression_level());        }        ctx_->sent_initial_metadata_ = true;      }      // The response is dropped if the status is not OK.      if (s.ok()) {        finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_,                                     finish_ops_.SendMessagePtr(response()));      } else {        finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s);      }      finish_ops_.set_core_cq_tag(&finish_tag_);      call_.PerformOps(&finish_ops_);    }    void SendInitialMetadata() override {      GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);      this->Ref();      meta_tag_.Set(call_.call(),                    [this](bool ok) {                      reactor_.load(std::memory_order_relaxed)                          ->OnSendInitialMetadataDone(ok);                      MaybeDone();                    },                    &meta_ops_, false);      meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,                                    ctx_->initial_metadata_flags());      if (ctx_->compression_level_set()) {        meta_ops_.set_compression_level(ctx_->compression_level());      }      ctx_->sent_initial_metadata_ = true;      meta_ops_.set_core_cq_tag(&meta_tag_);      call_.PerformOps(&meta_ops_);    }   private:    friend class CallbackUnaryHandler<RequestType, ResponseType>;    ServerCallbackUnaryImpl(        ::grpc_impl::CallbackServerContext* ctx, ::grpc::internal::Call* call,        ::grpc::experimental::MessageHolder<RequestType, ResponseType>*            allocator_state,        std::function<void()> call_requester)        : ctx_(ctx),          call_(*call),          allocator_state_(allocator_state),          call_requester_(std::move(call_requester)) {      ctx_->set_message_allocator_state(allocator_state);    }    /// SetupReactor binds the reactor (which also releases any queued    /// operations), maybe calls OnCancel if possible/needed, and maybe marks    /// the completion of the RPC. This should be the last component of the    /// handler.    void SetupReactor(ServerUnaryReactor* reactor) {      reactor_.store(reactor, std::memory_order_relaxed);      this->BindReactor(reactor);      this->MaybeCallOnCancel(reactor);      this->MaybeDone();    }    const RequestType* request() { return allocator_state_->request(); }    ResponseType* response() { return allocator_state_->response(); }    void MaybeDone() override {      if (GPR_UNLIKELY(this->Unref() == 1)) {        reactor_.load(std::memory_order_relaxed)->OnDone();        grpc_call* call = call_.call();        auto call_requester = std::move(call_requester_);        allocator_state_->Release();        this->~ServerCallbackUnaryImpl();  // explicitly call destructor        ::grpc::g_core_codegen_interface->grpc_call_unref(call);        call_requester();      }    }    ServerReactor* reactor() override {      return reactor_.load(std::memory_order_relaxed);    }    ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>        meta_ops_;    ::grpc::internal::CallbackWithSuccessTag meta_tag_;    ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,                                ::grpc::internal::CallOpSendMessage,                                ::grpc::internal::CallOpServerSendStatus>        finish_ops_;    ::grpc::internal::CallbackWithSuccessTag finish_tag_;    ::grpc_impl::CallbackServerContext* const ctx_;    ::grpc::internal::Call call_;    ::grpc::experimental::MessageHolder<RequestType, ResponseType>* const        allocator_state_;    std::function<void()> call_requester_;    // reactor_ can always be loaded/stored with relaxed memory ordering because    // its value is only set once, independently of other data in the object,    // and the loads that use it will always actually come provably later even    // though they are from different threads since they are triggered by    // actions initiated only by the setting up of the reactor_ variable. In    // a sense, it's a delayed "const": it gets its value from the SetupReactor    // method (not the constructor, so it's not a true const), but it doesn't    // change after that and it only gets used by actions caused, directly or    // indirectly, by that setup. This comment also applies to the reactor_    // variables of the other streaming objects in this file.    std::atomic<ServerUnaryReactor*> reactor_;    // callbacks_outstanding_ follows a refcount pattern    std::atomic<intptr_t> callbacks_outstanding_{        3};  // reserve for start, Finish, and CompletionOp  };};template <class RequestType, class ResponseType>class CallbackClientStreamingHandler : public ::grpc::internal::MethodHandler { public:  explicit CallbackClientStreamingHandler(      std::function<ServerReadReactor<RequestType>*(          ::grpc_impl::CallbackServerContext*, ResponseType*)>          get_reactor)      : get_reactor_(std::move(get_reactor)) {}  void RunHandler(const HandlerParameter& param) final {    // Arena allocate a reader structure (that includes response)    ::grpc::g_core_codegen_interface->grpc_call_ref(param.call->call());    auto* reader = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(        param.call->call(), sizeof(ServerCallbackReaderImpl)))        ServerCallbackReaderImpl(            static_cast<::grpc_impl::CallbackServerContext*>(                param.server_context),            param.call, std::move(param.call_requester));    param.server_context->BeginCompletionOp(        param.call, [reader](bool) { reader->MaybeDone(); }, reader);    ServerReadReactor<RequestType>* reactor = nullptr;    if (param.status.ok()) {      reactor = ::grpc::internal::CatchingReactorGetter<          ServerReadReactor<RequestType>>(          get_reactor_,          static_cast<::grpc_impl::CallbackServerContext*>(              param.server_context),          reader->response());    }    if (reactor == nullptr) {      // if deserialization or reactor creator failed, we need to fail the call      reactor = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(          param.call->call(), sizeof(UnimplementedReadReactor<RequestType>)))          UnimplementedReadReactor<RequestType>(              ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""));    }    reader->SetupReactor(reactor);  } private:  std::function<ServerReadReactor<RequestType>*(      ::grpc_impl::CallbackServerContext*, ResponseType*)>      get_reactor_;  class ServerCallbackReaderImpl : public ServerCallbackReader<RequestType> {   public:    void Finish(::grpc::Status s) override {      finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, &finish_ops_,                      false);      if (!ctx_->sent_initial_metadata_) {        finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_,                                        ctx_->initial_metadata_flags());        if (ctx_->compression_level_set()) {          finish_ops_.set_compression_level(ctx_->compression_level());        }        ctx_->sent_initial_metadata_ = true;      }      // The response is dropped if the status is not OK.      if (s.ok()) {        finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_,                                     finish_ops_.SendMessagePtr(&resp_));      } else {        finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s);      }      finish_ops_.set_core_cq_tag(&finish_tag_);      call_.PerformOps(&finish_ops_);    }    void SendInitialMetadata() override {      GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);      this->Ref();      meta_tag_.Set(call_.call(),                    [this](bool ok) {                      reactor_.load(std::memory_order_relaxed)                          ->OnSendInitialMetadataDone(ok);                      MaybeDone();                    },                    &meta_ops_, false);      meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,                                    ctx_->initial_metadata_flags());      if (ctx_->compression_level_set()) {        meta_ops_.set_compression_level(ctx_->compression_level());      }      ctx_->sent_initial_metadata_ = true;      meta_ops_.set_core_cq_tag(&meta_tag_);      call_.PerformOps(&meta_ops_);    }    void Read(RequestType* req) override {      this->Ref();      read_ops_.RecvMessage(req);      call_.PerformOps(&read_ops_);    }   private:    friend class CallbackClientStreamingHandler<RequestType, ResponseType>;    ServerCallbackReaderImpl(::grpc_impl::CallbackServerContext* ctx,                             ::grpc::internal::Call* call,                             std::function<void()> call_requester)        : ctx_(ctx), call_(*call), call_requester_(std::move(call_requester)) {}    void SetupReactor(ServerReadReactor<RequestType>* reactor) {      reactor_.store(reactor, std::memory_order_relaxed);      read_tag_.Set(call_.call(),                    [this](bool ok) {                      reactor_.load(std::memory_order_relaxed)->OnReadDone(ok);                      MaybeDone();                    },                    &read_ops_, false);      read_ops_.set_core_cq_tag(&read_tag_);      this->BindReactor(reactor);      this->MaybeCallOnCancel(reactor);      this->MaybeDone();    }    ~ServerCallbackReaderImpl() {}    ResponseType* response() { return &resp_; }    void MaybeDone() override {      if (GPR_UNLIKELY(this->Unref() == 1)) {        reactor_.load(std::memory_order_relaxed)->OnDone();        grpc_call* call = call_.call();        auto call_requester = std::move(call_requester_);        this->~ServerCallbackReaderImpl();  // explicitly call destructor        ::grpc::g_core_codegen_interface->grpc_call_unref(call);        call_requester();      }    }    ServerReactor* reactor() override {      return reactor_.load(std::memory_order_relaxed);    }    ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>        meta_ops_;    ::grpc::internal::CallbackWithSuccessTag meta_tag_;    ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,                                ::grpc::internal::CallOpSendMessage,                                ::grpc::internal::CallOpServerSendStatus>        finish_ops_;    ::grpc::internal::CallbackWithSuccessTag finish_tag_;    ::grpc::internal::CallOpSet<        ::grpc::internal::CallOpRecvMessage<RequestType>>        read_ops_;    ::grpc::internal::CallbackWithSuccessTag read_tag_;    ::grpc_impl::CallbackServerContext* const ctx_;    ::grpc::internal::Call call_;    ResponseType resp_;    std::function<void()> call_requester_;    // The memory ordering of reactor_ follows ServerCallbackUnaryImpl.    std::atomic<ServerReadReactor<RequestType>*> reactor_;    // callbacks_outstanding_ follows a refcount pattern    std::atomic<intptr_t> callbacks_outstanding_{        3};  // reserve for OnStarted, Finish, and CompletionOp  };};template <class RequestType, class ResponseType>class CallbackServerStreamingHandler : public ::grpc::internal::MethodHandler { public:  explicit CallbackServerStreamingHandler(      std::function<ServerWriteReactor<ResponseType>*(          ::grpc_impl::CallbackServerContext*, const RequestType*)>          get_reactor)      : get_reactor_(std::move(get_reactor)) {}  void RunHandler(const HandlerParameter& param) final {    // Arena allocate a writer structure    ::grpc::g_core_codegen_interface->grpc_call_ref(param.call->call());    auto* writer = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(        param.call->call(), sizeof(ServerCallbackWriterImpl)))        ServerCallbackWriterImpl(            static_cast<::grpc_impl::CallbackServerContext*>(                param.server_context),            param.call, static_cast<RequestType*>(param.request),            std::move(param.call_requester));    param.server_context->BeginCompletionOp(        param.call, [writer](bool) { writer->MaybeDone(); }, writer);    ServerWriteReactor<ResponseType>* reactor = nullptr;    if (param.status.ok()) {      reactor = ::grpc::internal::CatchingReactorGetter<          ServerWriteReactor<ResponseType>>(          get_reactor_,          static_cast<::grpc_impl::CallbackServerContext*>(              param.server_context),          writer->request());    }    if (reactor == nullptr) {      // if deserialization or reactor creator failed, we need to fail the call      reactor = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(          param.call->call(), sizeof(UnimplementedWriteReactor<ResponseType>)))          UnimplementedWriteReactor<ResponseType>(              ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""));    }    writer->SetupReactor(reactor);  }  void* Deserialize(grpc_call* call, grpc_byte_buffer* req,                    ::grpc::Status* status, void** /*handler_data*/) final {    ::grpc::ByteBuffer buf;    buf.set_buffer(req);    auto* request =        new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(            call, sizeof(RequestType))) RequestType();    *status =        ::grpc::SerializationTraits<RequestType>::Deserialize(&buf, request);    buf.Release();    if (status->ok()) {      return request;    }    request->~RequestType();    return nullptr;  } private:  std::function<ServerWriteReactor<ResponseType>*(      ::grpc_impl::CallbackServerContext*, const RequestType*)>      get_reactor_;  class ServerCallbackWriterImpl : public ServerCallbackWriter<ResponseType> {   public:    void Finish(::grpc::Status s) override {      finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, &finish_ops_,                      false);      finish_ops_.set_core_cq_tag(&finish_tag_);      if (!ctx_->sent_initial_metadata_) {        finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_,                                        ctx_->initial_metadata_flags());        if (ctx_->compression_level_set()) {          finish_ops_.set_compression_level(ctx_->compression_level());        }        ctx_->sent_initial_metadata_ = true;      }      finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s);      call_.PerformOps(&finish_ops_);    }    void SendInitialMetadata() override {      GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);      this->Ref();      meta_tag_.Set(call_.call(),                    [this](bool ok) {                      reactor_.load(std::memory_order_relaxed)                          ->OnSendInitialMetadataDone(ok);                      MaybeDone();                    },                    &meta_ops_, false);      meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,                                    ctx_->initial_metadata_flags());      if (ctx_->compression_level_set()) {        meta_ops_.set_compression_level(ctx_->compression_level());      }      ctx_->sent_initial_metadata_ = true;      meta_ops_.set_core_cq_tag(&meta_tag_);      call_.PerformOps(&meta_ops_);    }    void Write(const ResponseType* resp,               ::grpc::WriteOptions options) override {      this->Ref();      if (options.is_last_message()) {        options.set_buffer_hint();      }      if (!ctx_->sent_initial_metadata_) {        write_ops_.SendInitialMetadata(&ctx_->initial_metadata_,                                       ctx_->initial_metadata_flags());        if (ctx_->compression_level_set()) {          write_ops_.set_compression_level(ctx_->compression_level());        }        ctx_->sent_initial_metadata_ = true;      }      // TODO(vjpai): don't assert      GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(resp, options).ok());      call_.PerformOps(&write_ops_);    }    void WriteAndFinish(const ResponseType* resp, ::grpc::WriteOptions options,                        ::grpc::Status s) override {      // This combines the write into the finish callback      // Don't send any message if the status is bad      if (s.ok()) {        // TODO(vjpai): don't assert        GPR_CODEGEN_ASSERT(finish_ops_.SendMessagePtr(resp, options).ok());      }      Finish(std::move(s));    }   private:    friend class CallbackServerStreamingHandler<RequestType, ResponseType>;    ServerCallbackWriterImpl(::grpc_impl::CallbackServerContext* ctx,                             ::grpc::internal::Call* call,                             const RequestType* req,                             std::function<void()> call_requester)        : ctx_(ctx),          call_(*call),          req_(req),          call_requester_(std::move(call_requester)) {}    void SetupReactor(ServerWriteReactor<ResponseType>* reactor) {      reactor_.store(reactor, std::memory_order_relaxed);      write_tag_.Set(          call_.call(),          [this](bool ok) {            reactor_.load(std::memory_order_relaxed)->OnWriteDone(ok);            MaybeDone();          },          &write_ops_, false);      write_ops_.set_core_cq_tag(&write_tag_);      this->BindReactor(reactor);      this->MaybeCallOnCancel(reactor);      this->MaybeDone();    }    ~ServerCallbackWriterImpl() { req_->~RequestType(); }    const RequestType* request() { return req_; }    void MaybeDone() override {      if (GPR_UNLIKELY(this->Unref() == 1)) {        reactor_.load(std::memory_order_relaxed)->OnDone();        grpc_call* call = call_.call();        auto call_requester = std::move(call_requester_);        this->~ServerCallbackWriterImpl();  // explicitly call destructor        ::grpc::g_core_codegen_interface->grpc_call_unref(call);        call_requester();      }    }    ServerReactor* reactor() override {      return reactor_.load(std::memory_order_relaxed);    }    ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>        meta_ops_;    ::grpc::internal::CallbackWithSuccessTag meta_tag_;    ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,                                ::grpc::internal::CallOpSendMessage,                                ::grpc::internal::CallOpServerSendStatus>        finish_ops_;    ::grpc::internal::CallbackWithSuccessTag finish_tag_;    ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,                                ::grpc::internal::CallOpSendMessage>        write_ops_;    ::grpc::internal::CallbackWithSuccessTag write_tag_;    ::grpc_impl::CallbackServerContext* const ctx_;    ::grpc::internal::Call call_;    const RequestType* req_;    std::function<void()> call_requester_;    // The memory ordering of reactor_ follows ServerCallbackUnaryImpl.    std::atomic<ServerWriteReactor<ResponseType>*> reactor_;    // callbacks_outstanding_ follows a refcount pattern    std::atomic<intptr_t> callbacks_outstanding_{        3};  // reserve for OnStarted, Finish, and CompletionOp  };};template <class RequestType, class ResponseType>class CallbackBidiHandler : public ::grpc::internal::MethodHandler { public:  explicit CallbackBidiHandler(      std::function<ServerBidiReactor<RequestType, ResponseType>*(          ::grpc_impl::CallbackServerContext*)>          get_reactor)      : get_reactor_(std::move(get_reactor)) {}  void RunHandler(const HandlerParameter& param) final {    ::grpc::g_core_codegen_interface->grpc_call_ref(param.call->call());    auto* stream = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(        param.call->call(), sizeof(ServerCallbackReaderWriterImpl)))        ServerCallbackReaderWriterImpl(            static_cast<::grpc_impl::CallbackServerContext*>(                param.server_context),            param.call, std::move(param.call_requester));    param.server_context->BeginCompletionOp(        param.call, [stream](bool) { stream->MaybeDone(); }, stream);    ServerBidiReactor<RequestType, ResponseType>* reactor = nullptr;    if (param.status.ok()) {      reactor = ::grpc::internal::CatchingReactorGetter<          ServerBidiReactor<RequestType, ResponseType>>(          get_reactor_, static_cast<::grpc_impl::CallbackServerContext*>(                            param.server_context));    }    if (reactor == nullptr) {      // if deserialization or reactor creator failed, we need to fail the call      reactor = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(          param.call->call(),          sizeof(UnimplementedBidiReactor<RequestType, ResponseType>)))          UnimplementedBidiReactor<RequestType, ResponseType>(              ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""));    }    stream->SetupReactor(reactor);  } private:  std::function<ServerBidiReactor<RequestType, ResponseType>*(      ::grpc_impl::CallbackServerContext*)>      get_reactor_;  class ServerCallbackReaderWriterImpl      : public ServerCallbackReaderWriter<RequestType, ResponseType> {   public:    void Finish(::grpc::Status s) override {      finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, &finish_ops_,                      false);      finish_ops_.set_core_cq_tag(&finish_tag_);      if (!ctx_->sent_initial_metadata_) {        finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_,                                        ctx_->initial_metadata_flags());        if (ctx_->compression_level_set()) {          finish_ops_.set_compression_level(ctx_->compression_level());        }        ctx_->sent_initial_metadata_ = true;      }      finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s);      call_.PerformOps(&finish_ops_);    }    void SendInitialMetadata() override {      GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);      this->Ref();      meta_tag_.Set(call_.call(),                    [this](bool ok) {                      reactor_.load(std::memory_order_relaxed)                          ->OnSendInitialMetadataDone(ok);                      MaybeDone();                    },                    &meta_ops_, false);      meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,                                    ctx_->initial_metadata_flags());      if (ctx_->compression_level_set()) {        meta_ops_.set_compression_level(ctx_->compression_level());      }      ctx_->sent_initial_metadata_ = true;      meta_ops_.set_core_cq_tag(&meta_tag_);      call_.PerformOps(&meta_ops_);    }    void Write(const ResponseType* resp,               ::grpc::WriteOptions options) override {      this->Ref();      if (options.is_last_message()) {        options.set_buffer_hint();      }      if (!ctx_->sent_initial_metadata_) {        write_ops_.SendInitialMetadata(&ctx_->initial_metadata_,                                       ctx_->initial_metadata_flags());        if (ctx_->compression_level_set()) {          write_ops_.set_compression_level(ctx_->compression_level());        }        ctx_->sent_initial_metadata_ = true;      }      // TODO(vjpai): don't assert      GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(resp, options).ok());      call_.PerformOps(&write_ops_);    }    void WriteAndFinish(const ResponseType* resp, ::grpc::WriteOptions options,                        ::grpc::Status s) override {      // Don't send any message if the status is bad      if (s.ok()) {        // TODO(vjpai): don't assert        GPR_CODEGEN_ASSERT(finish_ops_.SendMessagePtr(resp, options).ok());      }      Finish(std::move(s));    }    void Read(RequestType* req) override {      this->Ref();      read_ops_.RecvMessage(req);      call_.PerformOps(&read_ops_);    }   private:    friend class CallbackBidiHandler<RequestType, ResponseType>;    ServerCallbackReaderWriterImpl(::grpc_impl::CallbackServerContext* ctx,                                   ::grpc::internal::Call* call,                                   std::function<void()> call_requester)        : ctx_(ctx), call_(*call), call_requester_(std::move(call_requester)) {}    void SetupReactor(ServerBidiReactor<RequestType, ResponseType>* reactor) {      reactor_.store(reactor, std::memory_order_relaxed);      write_tag_.Set(          call_.call(),          [this](bool ok) {            reactor_.load(std::memory_order_relaxed)->OnWriteDone(ok);            MaybeDone();          },          &write_ops_, false);      write_ops_.set_core_cq_tag(&write_tag_);      read_tag_.Set(call_.call(),                    [this](bool ok) {                      reactor_.load(std::memory_order_relaxed)->OnReadDone(ok);                      MaybeDone();                    },                    &read_ops_, false);      read_ops_.set_core_cq_tag(&read_tag_);      this->BindReactor(reactor);      this->MaybeCallOnCancel(reactor);      this->MaybeDone();    }    void MaybeDone() override {      if (GPR_UNLIKELY(this->Unref() == 1)) {        reactor_.load(std::memory_order_relaxed)->OnDone();        grpc_call* call = call_.call();        auto call_requester = std::move(call_requester_);        this->~ServerCallbackReaderWriterImpl();  // explicitly call destructor        ::grpc::g_core_codegen_interface->grpc_call_unref(call);        call_requester();      }    }    ServerReactor* reactor() override {      return reactor_.load(std::memory_order_relaxed);    }    ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>        meta_ops_;    ::grpc::internal::CallbackWithSuccessTag meta_tag_;    ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,                                ::grpc::internal::CallOpSendMessage,                                ::grpc::internal::CallOpServerSendStatus>        finish_ops_;    ::grpc::internal::CallbackWithSuccessTag finish_tag_;    ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,                                ::grpc::internal::CallOpSendMessage>        write_ops_;    ::grpc::internal::CallbackWithSuccessTag write_tag_;    ::grpc::internal::CallOpSet<        ::grpc::internal::CallOpRecvMessage<RequestType>>        read_ops_;    ::grpc::internal::CallbackWithSuccessTag read_tag_;    ::grpc_impl::CallbackServerContext* const ctx_;    ::grpc::internal::Call call_;    std::function<void()> call_requester_;    // The memory ordering of reactor_ follows ServerCallbackUnaryImpl.    std::atomic<ServerBidiReactor<RequestType, ResponseType>*> reactor_;    // callbacks_outstanding_ follows a refcount pattern    std::atomic<intptr_t> callbacks_outstanding_{        3};  // reserve for OnStarted, Finish, and CompletionOp  };};}  // namespace internal}  // namespace grpc_impl#endif  // GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_HANDLERS_H
 |