| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093 | /* * * Copyright 2018 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_H#define GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_H#include <atomic>#include <functional>#include <type_traits>#include <grpcpp/impl/codegen/call.h>#include <grpcpp/impl/codegen/call_op_set.h>#include <grpcpp/impl/codegen/callback_common.h>#include <grpcpp/impl/codegen/config.h>#include <grpcpp/impl/codegen/core_codegen_interface.h>#include <grpcpp/impl/codegen/server_context.h>#include <grpcpp/impl/codegen/server_interface.h>#include <grpcpp/impl/codegen/status.h>namespace grpc {// Declare base class of all reactors as internalnamespace internal {// Forward declarationstemplate <class Request, class Response>class CallbackClientStreamingHandler;template <class Request, class Response>class CallbackServerStreamingHandler;template <class Request, class Response>class CallbackBidiHandler;class ServerReactor { public:  virtual ~ServerReactor() = default;  virtual void OnDone() = 0;  virtual void OnCancel() = 0; private:  friend class ::grpc::ServerContext;  template <class Request, class Response>  friend class CallbackClientStreamingHandler;  template <class Request, class Response>  friend class CallbackServerStreamingHandler;  template <class Request, class Response>  friend class CallbackBidiHandler;  // The ServerReactor is responsible for tracking when it is safe to call  // OnCancel. This function should not be called until after OnStarted is done  // and the RPC has completed with a cancellation. This is tracked by counting  // how many of these conditions have been met and calling OnCancel when none  // remain unmet.  void MaybeCallOnCancel() {    if (on_cancel_conditions_remaining_.fetch_sub(            1, std::memory_order_acq_rel) == 1) {      OnCancel();    }  }  std::atomic_int on_cancel_conditions_remaining_{2};};}  // namespace internalnamespace experimental {// Forward declarationstemplate <class Request, class Response>class ServerReadReactor;template <class Request, class Response>class ServerWriteReactor;template <class Request, class Response>class ServerBidiReactor;// For unary RPCs, the exposed controller class is only an interface// and the actual implementation is an internal class.class ServerCallbackRpcController { public:  virtual ~ServerCallbackRpcController() = default;  // The method handler must call this function when it is done so that  // the library knows to free its resources  virtual void Finish(Status s) = 0;  // Allow the method handler to push out the initial metadata before  // the response and status are ready  virtual void SendInitialMetadata(std::function<void(bool)>) = 0;  /// SetCancelCallback passes in a callback to be called when the RPC is  /// canceled for whatever reason (streaming calls have OnCancel instead). This  /// is an advanced and uncommon use with several important restrictions. This  /// function may not be called more than once on the same RPC.  ///  /// If code calls SetCancelCallback on an RPC, it must also call  /// ClearCancelCallback before calling Finish on the RPC controller. That  /// method makes sure that no cancellation callback is executed for this RPC  /// beyond the point of its return. ClearCancelCallback may be called even if  /// SetCancelCallback was not called for this RPC, and it may be called  /// multiple times. It _must_ be called if SetCancelCallback was called for  /// this RPC.  ///  /// The callback should generally be lightweight and nonblocking and primarily  /// concerned with clearing application state related to the RPC or causing  /// operations (such as cancellations) to happen on dependent RPCs.  ///  /// If the RPC is already canceled at the time that SetCancelCallback is  /// called, the callback is invoked immediately.  ///  /// The cancellation callback may be executed concurrently with the method  /// handler that invokes it but will certainly not issue or execute after the  /// return of ClearCancelCallback. If ClearCancelCallback is invoked while the  /// callback is already executing, the callback will complete its execution  /// before ClearCancelCallback takes effect.  ///  /// To preserve the orderings described above, the callback may be called  /// under a lock that is also used for ClearCancelCallback and  /// ServerContext::IsCancelled, so the callback CANNOT call either of those  /// operations on this RPC or any other function that causes those operations  /// to be called before the callback completes.  virtual void SetCancelCallback(std::function<void()> callback) = 0;  virtual void ClearCancelCallback() = 0;};// NOTE: The actual streaming object classes are provided// as API only to support mocking. There are no implementations of// these class interfaces in the API.template <class Request>class ServerCallbackReader { public:  virtual ~ServerCallbackReader() {}  virtual void Finish(Status s) = 0;  virtual void SendInitialMetadata() = 0;  virtual void Read(Request* msg) = 0; protected:  template <class Response>  void BindReactor(ServerReadReactor<Request, Response>* reactor) {    reactor->BindReader(this);  }};template <class Response>class ServerCallbackWriter { public:  virtual ~ServerCallbackWriter() {}  virtual void Finish(Status s) = 0;  virtual void SendInitialMetadata() = 0;  virtual void Write(const Response* msg, WriteOptions options) = 0;  virtual void WriteAndFinish(const Response* msg, WriteOptions options,                              Status s) {    // Default implementation that can/should be overridden    Write(msg, std::move(options));    Finish(std::move(s));  } protected:  template <class Request>  void BindReactor(ServerWriteReactor<Request, Response>* reactor) {    reactor->BindWriter(this);  }};template <class Request, class Response>class ServerCallbackReaderWriter { public:  virtual ~ServerCallbackReaderWriter() {}  virtual void Finish(Status s) = 0;  virtual void SendInitialMetadata() = 0;  virtual void Read(Request* msg) = 0;  virtual void Write(const Response* msg, WriteOptions options) = 0;  virtual void WriteAndFinish(const Response* msg, WriteOptions options,                              Status s) {    // Default implementation that can/should be overridden    Write(msg, std::move(options));    Finish(std::move(s));  } protected:  void BindReactor(ServerBidiReactor<Request, Response>* reactor) {    reactor->BindStream(this);  }};// The following classes are the reactor interfaces that are to be implemented// by the user, returned as the result of the method handler for a callback// method, and activated by the call to OnStarted. The library guarantees that// OnStarted will be called for any reactor that has been created using a// method handler registered on a service. No operation initiation method may be// called until after the call to OnStarted.// Note that none of the classes are pure; all reactions have a default empty// reaction so that the user class only needs to override those classes that it// cares about./// \a ServerBidiReactor is the interface for a bidirectional streaming RPC.template <class Request, class Response>class ServerBidiReactor : public internal::ServerReactor { public:  ~ServerBidiReactor() = default;  /// Do NOT call any operation initiation method (names that start with Start)  /// until after the library has called OnStarted on this object.  /// Send any initial metadata stored in the RPC context. If not invoked,  /// any initial metadata will be passed along with the first Write or the  /// Finish (if there are no writes).  void StartSendInitialMetadata() { stream_->SendInitialMetadata(); }  /// Initiate a read operation.  ///  /// \param[out] req Where to eventually store the read message. Valid when  ///                 the library calls OnReadDone  void StartRead(Request* req) { stream_->Read(req); }  /// Initiate a write operation.  ///  /// \param[in] resp The message to be written. The library takes temporary  ///                 ownership until OnWriteDone, at which point the  ///                 application regains ownership of resp.  void StartWrite(const Response* resp) { StartWrite(resp, WriteOptions()); }  /// Initiate a write operation with specified options.  ///  /// \param[in] resp The message to be written. The library takes temporary  ///                 ownership until OnWriteDone, at which point the  ///                 application regains ownership of resp.  /// \param[in] options The WriteOptions to use for writing this message  void StartWrite(const Response* resp, WriteOptions options) {    stream_->Write(resp, std::move(options));  }  /// Initiate a write operation with specified options and final RPC Status,  /// which also causes any trailing metadata for this RPC to be sent out.  /// StartWriteAndFinish is like merging StartWriteLast and Finish into a  /// single step. A key difference, though, is that this operation doesn't have  /// an OnWriteDone reaction - it is considered complete only when OnDone is  /// available. An RPC can either have StartWriteAndFinish or Finish, but not  /// both.  ///  /// \param[in] resp The message to be written. The library takes temporary  ///                 ownership until Onone, at which point the application  ///                 regains ownership of resp.  /// \param[in] options The WriteOptions to use for writing this message  /// \param[in] s The status outcome of this RPC  void StartWriteAndFinish(const Response* resp, WriteOptions options,                           Status s) {    stream_->WriteAndFinish(resp, std::move(options), std::move(s));  }  /// Inform system of a planned write operation with specified options, but  /// allow the library to schedule the actual write coalesced with the writing  /// of trailing metadata (which takes place on a Finish call).  ///  /// \param[in] resp The message to be written. The library takes temporary  ///                 ownership until OnWriteDone, at which point the  ///                 application regains ownership of resp.  /// \param[in] options The WriteOptions to use for writing this message  void StartWriteLast(const Response* resp, WriteOptions options) {    StartWrite(resp, std::move(options.set_last_message()));  }  /// Indicate that the stream is to be finished and the trailing metadata and  /// RPC status are to be sent. Every RPC MUST be finished using either Finish  /// or StartWriteAndFinish (but not both), even if the RPC is already  /// cancelled.  ///  /// \param[in] s The status outcome of this RPC  void Finish(Status s) { stream_->Finish(std::move(s)); }  /// Notify the application that a streaming RPC has started and that it is now  /// ok to call any operation initiation method. An RPC is considered started  /// after the server has received all initial metadata from the client, which  /// is a result of the client calling StartCall().  ///  /// \param[in] context The context object now associated with this RPC  virtual void OnStarted(ServerContext* context) {}  /// Notifies the application that an explicit StartSendInitialMetadata  /// operation completed. Not used when the sending of initial metadata  /// piggybacks onto the first write.  ///  /// \param[in] ok Was it successful? If false, no further write-side operation  ///               will succeed.  virtual void OnSendInitialMetadataDone(bool ok) {}  /// Notifies the application that a StartRead operation completed.  ///  /// \param[in] ok Was it successful? If false, no further read-side operation  ///               will succeed.  virtual void OnReadDone(bool ok) {}  /// Notifies the application that a StartWrite (or StartWriteLast) operation  /// completed.  ///  /// \param[in] ok Was it successful? If false, no further write-side operation  ///               will succeed.  virtual void OnWriteDone(bool ok) {}  /// Notifies the application that all operations associated with this RPC  /// have completed. This is an override (from the internal base class) but not  /// final, so derived classes should override it if they want to take action.  void OnDone() override {}  /// Notifies the application that this RPC has been cancelled. This is an  /// override (from the internal base class) but not final, so derived classes  /// should override it if they want to take action.  void OnCancel() override {} private:  friend class ServerCallbackReaderWriter<Request, Response>;  void BindStream(ServerCallbackReaderWriter<Request, Response>* stream) {    stream_ = stream;  }  ServerCallbackReaderWriter<Request, Response>* stream_;};/// \a ServerReadReactor is the interface for a client-streaming RPC.template <class Request, class Response>class ServerReadReactor : public internal::ServerReactor { public:  ~ServerReadReactor() = default;  /// The following operation initiations are exactly like ServerBidiReactor.  void StartSendInitialMetadata() { reader_->SendInitialMetadata(); }  void StartRead(Request* req) { reader_->Read(req); }  void Finish(Status s) { reader_->Finish(std::move(s)); }  /// Similar to ServerBidiReactor::OnStarted, except that this also provides  /// the response object that the stream fills in before calling Finish.  /// (It must be filled in if status is OK, but it may be filled in otherwise.)  ///  /// \param[in] context The context object now associated with this RPC  /// \param[in] resp The response object to be used by this RPC  virtual void OnStarted(ServerContext* context, Response* resp) {}  /// The following notifications are exactly like ServerBidiReactor.  virtual void OnSendInitialMetadataDone(bool ok) {}  virtual void OnReadDone(bool ok) {}  void OnDone() override {}  void OnCancel() override {} private:  friend class ServerCallbackReader<Request>;  void BindReader(ServerCallbackReader<Request>* reader) { reader_ = reader; }  ServerCallbackReader<Request>* reader_;};/// \a ServerWriteReactor is the interface for a server-streaming RPC.template <class Request, class Response>class ServerWriteReactor : public internal::ServerReactor { public:  ~ServerWriteReactor() = default;  /// The following operation initiations are exactly like ServerBidiReactor.  void StartSendInitialMetadata() { writer_->SendInitialMetadata(); }  void StartWrite(const Response* resp) { StartWrite(resp, WriteOptions()); }  void StartWrite(const Response* resp, WriteOptions options) {    writer_->Write(resp, std::move(options));  }  void StartWriteAndFinish(const Response* resp, WriteOptions options,                           Status s) {    writer_->WriteAndFinish(resp, std::move(options), std::move(s));  }  void StartWriteLast(const Response* resp, WriteOptions options) {    StartWrite(resp, std::move(options.set_last_message()));  }  void Finish(Status s) { writer_->Finish(std::move(s)); }  /// Similar to ServerBidiReactor::OnStarted, except that this also provides  /// the request object sent by the client.  ///  /// \param[in] context The context object now associated with this RPC  /// \param[in] req The request object sent by the client  virtual void OnStarted(ServerContext* context, const Request* req) {}  /// The following notifications are exactly like ServerBidiReactor.  virtual void OnSendInitialMetadataDone(bool ok) {}  virtual void OnWriteDone(bool ok) {}  void OnDone() override {}  void OnCancel() override {} private:  friend class ServerCallbackWriter<Response>;  void BindWriter(ServerCallbackWriter<Response>* writer) { writer_ = writer; }  ServerCallbackWriter<Response>* writer_;};}  // namespace experimentalnamespace internal {template <class Request, class Response>class UnimplementedReadReactor    : public experimental::ServerReadReactor<Request, Response> { public:  void OnDone() override { delete this; }  void OnStarted(ServerContext*, Response*) override {    this->Finish(Status(StatusCode::UNIMPLEMENTED, ""));  }};template <class Request, class Response>class UnimplementedWriteReactor    : public experimental::ServerWriteReactor<Request, Response> { public:  void OnDone() override { delete this; }  void OnStarted(ServerContext*, const Request*) override {    this->Finish(Status(StatusCode::UNIMPLEMENTED, ""));  }};template <class Request, class Response>class UnimplementedBidiReactor    : public experimental::ServerBidiReactor<Request, Response> { public:  void OnDone() override { delete this; }  void OnStarted(ServerContext*) override {    this->Finish(Status(StatusCode::UNIMPLEMENTED, ""));  }};template <class RequestType, class ResponseType>class CallbackUnaryHandler : public MethodHandler { public:  CallbackUnaryHandler(      std::function<void(ServerContext*, const RequestType*, ResponseType*,                         experimental::ServerCallbackRpcController*)>          func)      : func_(func) {}  void RunHandler(const HandlerParameter& param) final {    // Arena allocate a controller structure (that includes request/response)    g_core_codegen_interface->grpc_call_ref(param.call->call());    auto* controller = new (g_core_codegen_interface->grpc_call_arena_alloc(        param.call->call(), sizeof(ServerCallbackRpcControllerImpl)))        ServerCallbackRpcControllerImpl(            param.server_context, param.call,            static_cast<RequestType*>(param.request),            std::move(param.call_requester));    Status status = param.status;    if (status.ok()) {      // Call the actual function handler and expect the user to call finish      CatchingCallback(func_, param.server_context, controller->request(),                       controller->response(), controller);    } else {      // if deserialization failed, we need to fail the call      controller->Finish(status);    }  }  void* Deserialize(grpc_call* call, grpc_byte_buffer* req,                    Status* status) final {    ByteBuffer buf;    buf.set_buffer(req);    auto* request = new (g_core_codegen_interface->grpc_call_arena_alloc(        call, sizeof(RequestType))) RequestType();    *status = SerializationTraits<RequestType>::Deserialize(&buf, request);    buf.Release();    if (status->ok()) {      return request;    }    request->~RequestType();    return nullptr;  } private:  std::function<void(ServerContext*, const RequestType*, ResponseType*,                     experimental::ServerCallbackRpcController*)>      func_;  // The implementation class of ServerCallbackRpcController is a private member  // of CallbackUnaryHandler since it is never exposed anywhere, and this allows  // it to take advantage of CallbackUnaryHandler's friendships.  class ServerCallbackRpcControllerImpl      : public experimental::ServerCallbackRpcController {   public:    void Finish(Status s) override {      finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); },                      &finish_ops_);      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(std::function<void(bool)> f) override {      GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);      callbacks_outstanding_++;      // TODO(vjpai): Consider taking f as a move-capture if we adopt C++14      //              and if performance of this operation matters      meta_tag_.Set(call_.call(),                    [this, f](bool ok) {                      f(ok);                      MaybeDone();                    },                    &meta_ops_);      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_);    }    // Neither SetCancelCallback nor ClearCancelCallback should affect the    // callbacks_outstanding_ count since they are paired and both must precede    // the invocation of Finish (if they are used at all)    void SetCancelCallback(std::function<void()> callback) override {      ctx_->SetCancelCallback(std::move(callback));    }    void ClearCancelCallback() override { ctx_->ClearCancelCallback(); }   private:    friend class CallbackUnaryHandler<RequestType, ResponseType>;    ServerCallbackRpcControllerImpl(ServerContext* ctx, Call* call,                                    const RequestType* req,                                    std::function<void()> call_requester)        : ctx_(ctx),          call_(*call),          req_(req),          call_requester_(std::move(call_requester)) {      ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, nullptr);    }    ~ServerCallbackRpcControllerImpl() { req_->~RequestType(); }    const RequestType* request() { return req_; }    ResponseType* response() { return &resp_; }    void MaybeDone() {      if (--callbacks_outstanding_ == 0) {        grpc_call* call = call_.call();        auto call_requester = std::move(call_requester_);        this->~ServerCallbackRpcControllerImpl();  // explicitly call destructor        g_core_codegen_interface->grpc_call_unref(call);        call_requester();      }    }    CallOpSet<CallOpSendInitialMetadata> meta_ops_;    CallbackWithSuccessTag meta_tag_;    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,              CallOpServerSendStatus>        finish_ops_;    CallbackWithSuccessTag finish_tag_;    ServerContext* ctx_;    Call call_;    const RequestType* req_;    ResponseType resp_;    std::function<void()> call_requester_;    std::atomic_int callbacks_outstanding_{        2};  // reserve for Finish and CompletionOp  };};template <class RequestType, class ResponseType>class CallbackClientStreamingHandler : public MethodHandler { public:  CallbackClientStreamingHandler(      std::function<          experimental::ServerReadReactor<RequestType, ResponseType>*()>          func)      : func_(std::move(func)) {}  void RunHandler(const HandlerParameter& param) final {    // Arena allocate a reader structure (that includes response)    g_core_codegen_interface->grpc_call_ref(param.call->call());    experimental::ServerReadReactor<RequestType, ResponseType>* reactor =        param.status.ok()            ? CatchingReactorCreator<                  experimental::ServerReadReactor<RequestType, ResponseType>>(                  func_)            : nullptr;    if (reactor == nullptr) {      // if deserialization or reactor creator failed, we need to fail the call      reactor = new UnimplementedReadReactor<RequestType, ResponseType>;    }    auto* reader = new (g_core_codegen_interface->grpc_call_arena_alloc(        param.call->call(), sizeof(ServerCallbackReaderImpl)))        ServerCallbackReaderImpl(param.server_context, param.call,                                 std::move(param.call_requester), reactor);    reader->BindReactor(reactor);    reactor->OnStarted(param.server_context, reader->response());    // The earliest that OnCancel can be called is after OnStarted is done.    reactor->MaybeCallOnCancel();    reader->MaybeDone();  } private:  std::function<experimental::ServerReadReactor<RequestType, ResponseType>*()>      func_;  class ServerCallbackReaderImpl      : public experimental::ServerCallbackReader<RequestType> {   public:    void Finish(Status s) override {      finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); },                      &finish_ops_);      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_);      callbacks_outstanding_++;      meta_tag_.Set(call_.call(),                    [this](bool ok) {                      reactor_->OnSendInitialMetadataDone(ok);                      MaybeDone();                    },                    &meta_ops_);      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 {      callbacks_outstanding_++;      read_ops_.RecvMessage(req);      call_.PerformOps(&read_ops_);    }   private:    friend class CallbackClientStreamingHandler<RequestType, ResponseType>;    ServerCallbackReaderImpl(        ServerContext* ctx, Call* call, std::function<void()> call_requester,        experimental::ServerReadReactor<RequestType, ResponseType>* reactor)        : ctx_(ctx),          call_(*call),          call_requester_(std::move(call_requester)),          reactor_(reactor) {      ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, reactor);      read_tag_.Set(call_.call(),                    [this](bool ok) {                      reactor_->OnReadDone(ok);                      MaybeDone();                    },                    &read_ops_);      read_ops_.set_core_cq_tag(&read_tag_);    }    ~ServerCallbackReaderImpl() {}    ResponseType* response() { return &resp_; }    void MaybeDone() {      if (--callbacks_outstanding_ == 0) {        reactor_->OnDone();        grpc_call* call = call_.call();        auto call_requester = std::move(call_requester_);        this->~ServerCallbackReaderImpl();  // explicitly call destructor        g_core_codegen_interface->grpc_call_unref(call);        call_requester();      }    }    CallOpSet<CallOpSendInitialMetadata> meta_ops_;    CallbackWithSuccessTag meta_tag_;    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,              CallOpServerSendStatus>        finish_ops_;    CallbackWithSuccessTag finish_tag_;    CallOpSet<CallOpRecvMessage<RequestType>> read_ops_;    CallbackWithSuccessTag read_tag_;    ServerContext* ctx_;    Call call_;    ResponseType resp_;    std::function<void()> call_requester_;    experimental::ServerReadReactor<RequestType, ResponseType>* reactor_;    std::atomic_int callbacks_outstanding_{        3};  // reserve for OnStarted, Finish, and CompletionOp  };};template <class RequestType, class ResponseType>class CallbackServerStreamingHandler : public MethodHandler { public:  CallbackServerStreamingHandler(      std::function<          experimental::ServerWriteReactor<RequestType, ResponseType>*()>          func)      : func_(std::move(func)) {}  void RunHandler(const HandlerParameter& param) final {    // Arena allocate a writer structure    g_core_codegen_interface->grpc_call_ref(param.call->call());    experimental::ServerWriteReactor<RequestType, ResponseType>* reactor =        param.status.ok()            ? CatchingReactorCreator<                  experimental::ServerWriteReactor<RequestType, ResponseType>>(                  func_)            : nullptr;    if (reactor == nullptr) {      // if deserialization or reactor creator failed, we need to fail the call      reactor = new UnimplementedWriteReactor<RequestType, ResponseType>;    }    auto* writer = new (g_core_codegen_interface->grpc_call_arena_alloc(        param.call->call(), sizeof(ServerCallbackWriterImpl)))        ServerCallbackWriterImpl(param.server_context, param.call,                                 static_cast<RequestType*>(param.request),                                 std::move(param.call_requester), reactor);    writer->BindReactor(reactor);    reactor->OnStarted(param.server_context, writer->request());    // The earliest that OnCancel can be called is after OnStarted is done.    reactor->MaybeCallOnCancel();    writer->MaybeDone();  }  void* Deserialize(grpc_call* call, grpc_byte_buffer* req,                    Status* status) final {    ByteBuffer buf;    buf.set_buffer(req);    auto* request = new (g_core_codegen_interface->grpc_call_arena_alloc(        call, sizeof(RequestType))) RequestType();    *status = SerializationTraits<RequestType>::Deserialize(&buf, request);    buf.Release();    if (status->ok()) {      return request;    }    request->~RequestType();    return nullptr;  } private:  std::function<experimental::ServerWriteReactor<RequestType, ResponseType>*()>      func_;  class ServerCallbackWriterImpl      : public experimental::ServerCallbackWriter<ResponseType> {   public:    void Finish(Status s) override {      finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); },                      &finish_ops_);      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_);      callbacks_outstanding_++;      meta_tag_.Set(call_.call(),                    [this](bool ok) {                      reactor_->OnSendInitialMetadataDone(ok);                      MaybeDone();                    },                    &meta_ops_);      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, WriteOptions options) override {      callbacks_outstanding_++;      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, WriteOptions options,                        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(        ServerContext* ctx, Call* call, const RequestType* req,        std::function<void()> call_requester,        experimental::ServerWriteReactor<RequestType, ResponseType>* reactor)        : ctx_(ctx),          call_(*call),          req_(req),          call_requester_(std::move(call_requester)),          reactor_(reactor) {      ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, reactor);      write_tag_.Set(call_.call(),                     [this](bool ok) {                       reactor_->OnWriteDone(ok);                       MaybeDone();                     },                     &write_ops_);      write_ops_.set_core_cq_tag(&write_tag_);    }    ~ServerCallbackWriterImpl() { req_->~RequestType(); }    const RequestType* request() { return req_; }    void MaybeDone() {      if (--callbacks_outstanding_ == 0) {        reactor_->OnDone();        grpc_call* call = call_.call();        auto call_requester = std::move(call_requester_);        this->~ServerCallbackWriterImpl();  // explicitly call destructor        g_core_codegen_interface->grpc_call_unref(call);        call_requester();      }    }    CallOpSet<CallOpSendInitialMetadata> meta_ops_;    CallbackWithSuccessTag meta_tag_;    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,              CallOpServerSendStatus>        finish_ops_;    CallbackWithSuccessTag finish_tag_;    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> write_ops_;    CallbackWithSuccessTag write_tag_;    ServerContext* ctx_;    Call call_;    const RequestType* req_;    std::function<void()> call_requester_;    experimental::ServerWriteReactor<RequestType, ResponseType>* reactor_;    std::atomic_int callbacks_outstanding_{        3};  // reserve for OnStarted, Finish, and CompletionOp  };};template <class RequestType, class ResponseType>class CallbackBidiHandler : public MethodHandler { public:  CallbackBidiHandler(      std::function<          experimental::ServerBidiReactor<RequestType, ResponseType>*()>          func)      : func_(std::move(func)) {}  void RunHandler(const HandlerParameter& param) final {    g_core_codegen_interface->grpc_call_ref(param.call->call());    experimental::ServerBidiReactor<RequestType, ResponseType>* reactor =        param.status.ok()            ? CatchingReactorCreator<                  experimental::ServerBidiReactor<RequestType, ResponseType>>(                  func_)            : nullptr;    if (reactor == nullptr) {      // if deserialization or reactor creator failed, we need to fail the call      reactor = new UnimplementedBidiReactor<RequestType, ResponseType>;    }    auto* stream = new (g_core_codegen_interface->grpc_call_arena_alloc(        param.call->call(), sizeof(ServerCallbackReaderWriterImpl)))        ServerCallbackReaderWriterImpl(param.server_context, param.call,                                       std::move(param.call_requester),                                       reactor);    stream->BindReactor(reactor);    reactor->OnStarted(param.server_context);    // The earliest that OnCancel can be called is after OnStarted is done.    reactor->MaybeCallOnCancel();    stream->MaybeDone();  } private:  std::function<experimental::ServerBidiReactor<RequestType, ResponseType>*()>      func_;  class ServerCallbackReaderWriterImpl      : public experimental::ServerCallbackReaderWriter<RequestType,                                                        ResponseType> {   public:    void Finish(Status s) override {      finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); },                      &finish_ops_);      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_);      callbacks_outstanding_++;      meta_tag_.Set(call_.call(),                    [this](bool ok) {                      reactor_->OnSendInitialMetadataDone(ok);                      MaybeDone();                    },                    &meta_ops_);      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, WriteOptions options) override {      callbacks_outstanding_++;      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, WriteOptions options,                        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 {      callbacks_outstanding_++;      read_ops_.RecvMessage(req);      call_.PerformOps(&read_ops_);    }   private:    friend class CallbackBidiHandler<RequestType, ResponseType>;    ServerCallbackReaderWriterImpl(        ServerContext* ctx, Call* call, std::function<void()> call_requester,        experimental::ServerBidiReactor<RequestType, ResponseType>* reactor)        : ctx_(ctx),          call_(*call),          call_requester_(std::move(call_requester)),          reactor_(reactor) {      ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, reactor);      write_tag_.Set(call_.call(),                     [this](bool ok) {                       reactor_->OnWriteDone(ok);                       MaybeDone();                     },                     &write_ops_);      write_ops_.set_core_cq_tag(&write_tag_);      read_tag_.Set(call_.call(),                    [this](bool ok) {                      reactor_->OnReadDone(ok);                      MaybeDone();                    },                    &read_ops_);      read_ops_.set_core_cq_tag(&read_tag_);    }    ~ServerCallbackReaderWriterImpl() {}    void MaybeDone() {      if (--callbacks_outstanding_ == 0) {        reactor_->OnDone();        grpc_call* call = call_.call();        auto call_requester = std::move(call_requester_);        this->~ServerCallbackReaderWriterImpl();  // explicitly call destructor        g_core_codegen_interface->grpc_call_unref(call);        call_requester();      }    }    CallOpSet<CallOpSendInitialMetadata> meta_ops_;    CallbackWithSuccessTag meta_tag_;    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,              CallOpServerSendStatus>        finish_ops_;    CallbackWithSuccessTag finish_tag_;    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> write_ops_;    CallbackWithSuccessTag write_tag_;    CallOpSet<CallOpRecvMessage<RequestType>> read_ops_;    CallbackWithSuccessTag read_tag_;    ServerContext* ctx_;    Call call_;    std::function<void()> call_requester_;    experimental::ServerBidiReactor<RequestType, ResponseType>* reactor_;    std::atomic_int callbacks_outstanding_{        3};  // reserve for OnStarted, Finish, and CompletionOp  };};}  // namespace internal}  // namespace grpc#endif  // GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_H
 |