| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242 | /* * * 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_CLIENT_CALLBACK_H#define GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_H#include <atomic>#include <functional>#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/channel_interface.h>#include <grpcpp/impl/codegen/config.h>#include <grpcpp/impl/codegen/core_codegen_interface.h>#include <grpcpp/impl/codegen/status.h>namespace grpc {class Channel;class ClientContext;namespace internal {class RpcMethod;/// Perform a callback-based unary call.  May optionally specify the base/// class of the Request and Response so that the internal calls and structures/// below this may be based on those base classes and thus achieve code reuse/// across different RPCs (e.g., for protobuf, MessageLite would be a base/// class)./// TODO(vjpai): Combine as much as possible with the blocking unary call codetemplate <class InputMessage, class OutputMessage,          class BaseInputMessage = InputMessage,          class BaseOutputMessage = OutputMessage>void CallbackUnaryCall(::grpc::ChannelInterface* channel,                       const ::grpc::internal::RpcMethod& method,                       ::grpc::ClientContext* context,                       const InputMessage* request, OutputMessage* result,                       std::function<void(::grpc::Status)> on_completion) {  static_assert(std::is_base_of<BaseInputMessage, InputMessage>::value,                "Invalid input message specification");  static_assert(std::is_base_of<BaseOutputMessage, OutputMessage>::value,                "Invalid output message specification");  CallbackUnaryCallImpl<BaseInputMessage, BaseOutputMessage> x(      channel, method, context, request, result, on_completion);}template <class InputMessage, class OutputMessage>class CallbackUnaryCallImpl { public:  CallbackUnaryCallImpl(::grpc::ChannelInterface* channel,                        const ::grpc::internal::RpcMethod& method,                        ::grpc::ClientContext* context,                        const InputMessage* request, OutputMessage* result,                        std::function<void(::grpc::Status)> on_completion) {    ::grpc::CompletionQueue* cq = channel->CallbackCQ();    GPR_CODEGEN_ASSERT(cq != nullptr);    grpc::internal::Call call(channel->CreateCall(method, context, cq));    using FullCallOpSet = grpc::internal::CallOpSet<        ::grpc::internal::CallOpSendInitialMetadata,        grpc::internal::CallOpSendMessage,        grpc::internal::CallOpRecvInitialMetadata,        grpc::internal::CallOpRecvMessage<OutputMessage>,        grpc::internal::CallOpClientSendClose,        grpc::internal::CallOpClientRecvStatus>;    struct OpSetAndTag {      FullCallOpSet opset;      grpc::internal::CallbackWithStatusTag tag;    };    const size_t alloc_sz = sizeof(OpSetAndTag);    auto* const alloced = static_cast<OpSetAndTag*>(        ::grpc::g_core_codegen_interface->grpc_call_arena_alloc(call.call(),                                                                alloc_sz));    auto* ops = new (&alloced->opset) FullCallOpSet;    auto* tag = new (&alloced->tag)        grpc::internal::CallbackWithStatusTag(call.call(), on_completion, ops);    // TODO(vjpai): Unify code with sync API as much as possible    ::grpc::Status s = ops->SendMessagePtr(request);    if (!s.ok()) {      tag->force_run(s);      return;    }    ops->SendInitialMetadata(&context->send_initial_metadata_,                             context->initial_metadata_flags());    ops->RecvInitialMetadata(context);    ops->RecvMessage(result);    ops->AllowNoMessage();    ops->ClientSendClose();    ops->ClientRecvStatus(context, tag->status_ptr());    ops->set_core_cq_tag(tag);    call.PerformOps(ops);  }};// Base class for public API classes.class ClientReactor { public:  /// Called by the library when all operations associated with this RPC have  /// completed and all Holds have been removed. OnDone provides the RPC status  /// outcome for both successful and failed RPCs. If it is never called on an  /// RPC, it indicates an application-level problem (like failure to remove a  /// hold).  ///  /// \param[in] s The status outcome of this RPC  virtual void OnDone(const ::grpc::Status& /*s*/) = 0;  /// InternalScheduleOnDone is not part of the API and is not meant to be  /// overridden. It is virtual to allow successful builds for certain bazel  /// build users that only want to depend on gRPC codegen headers and not the  /// full library (although this is not a generally-supported option). Although  /// the virtual call is slower than a direct call, this function is  /// heavyweight and the cost of the virtual call is not much in comparison.  /// This function may be removed or devirtualized in the future.  virtual void InternalScheduleOnDone(::grpc::Status s);};}  // namespace internal// Forward declarationstemplate <class Request, class Response>class ClientBidiReactor;template <class Response>class ClientReadReactor;template <class Request>class ClientWriteReactor;class ClientUnaryReactor;// NOTE: The streaming objects are not actually implemented in the public API.//       These interfaces are provided for mocking only. Typical applications//       will interact exclusively with the reactors that they define.template <class Request, class Response>class ClientCallbackReaderWriter { public:  virtual ~ClientCallbackReaderWriter() {}  virtual void StartCall() = 0;  virtual void Write(const Request* req, ::grpc::WriteOptions options) = 0;  virtual void WritesDone() = 0;  virtual void Read(Response* resp) = 0;  virtual void AddHold(int holds) = 0;  virtual void RemoveHold() = 0; protected:  void BindReactor(ClientBidiReactor<Request, Response>* reactor) {    reactor->BindStream(this);  }};template <class Response>class ClientCallbackReader { public:  virtual ~ClientCallbackReader() {}  virtual void StartCall() = 0;  virtual void Read(Response* resp) = 0;  virtual void AddHold(int holds) = 0;  virtual void RemoveHold() = 0; protected:  void BindReactor(ClientReadReactor<Response>* reactor) {    reactor->BindReader(this);  }};template <class Request>class ClientCallbackWriter { public:  virtual ~ClientCallbackWriter() {}  virtual void StartCall() = 0;  void Write(const Request* req) { Write(req, ::grpc::WriteOptions()); }  virtual void Write(const Request* req, ::grpc::WriteOptions options) = 0;  void WriteLast(const Request* req, ::grpc::WriteOptions options) {    Write(req, options.set_last_message());  }  virtual void WritesDone() = 0;  virtual void AddHold(int holds) = 0;  virtual void RemoveHold() = 0; protected:  void BindReactor(ClientWriteReactor<Request>* reactor) {    reactor->BindWriter(this);  }};class ClientCallbackUnary { public:  virtual ~ClientCallbackUnary() {}  virtual void StartCall() = 0; protected:  void BindReactor(ClientUnaryReactor* reactor);};// The following classes are the reactor interfaces that are to be implemented// by the user. They are passed in to the library as an argument to a call on a// stub (either a codegen-ed call or a generic call). The streaming RPC is// activated by calling StartCall, possibly after initiating StartRead,// StartWrite, or AddHold operations on the streaming object. 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.// The reactor must be passed to the stub invocation before any of the below// operations can be called./// \a ClientBidiReactor is the interface for a bidirectional streaming RPC.template <class Request, class Response>class ClientBidiReactor : public internal::ClientReactor { public:  virtual ~ClientBidiReactor() {}  /// Activate the RPC and initiate any reads or writes that have been Start'ed  /// before this call. All streaming RPCs issued by the client MUST have  /// StartCall invoked on them (even if they are canceled) as this call is the  /// activation of their lifecycle.  void StartCall() { stream_->StartCall(); }  /// Initiate a read operation (or post it for later initiation if StartCall  /// has not yet been invoked).  ///  /// \param[out] resp Where to eventually store the read message. Valid when  ///                  the library calls OnReadDone  void StartRead(Response* resp) { stream_->Read(resp); }  /// Initiate a write operation (or post it for later initiation if StartCall  /// has not yet been invoked).  ///  /// \param[in] req The message to be written. The library does not take  ///                ownership but the caller must ensure that the message is  ///                not deleted or modified until OnWriteDone is called.  void StartWrite(const Request* req) {    StartWrite(req, ::grpc::WriteOptions());  }  /// Initiate/post a write operation with specified options.  ///  /// \param[in] req The message to be written. The library does not take  ///                ownership but the caller must ensure that the message is  ///                not deleted or modified until OnWriteDone is called.  /// \param[in] options The WriteOptions to use for writing this message  void StartWrite(const Request* req, ::grpc::WriteOptions options) {    stream_->Write(req, options);  }  /// Initiate/post a write operation with specified options and an indication  /// that this is the last write (like StartWrite and StartWritesDone, merged).  /// Note that calling this means that no more calls to StartWrite,  /// StartWriteLast, or StartWritesDone are allowed.  ///  /// \param[in] req The message to be written. The library does not take  ///                ownership but the caller must ensure that the message is  ///                not deleted or modified until OnWriteDone is called.  /// \param[in] options The WriteOptions to use for writing this message  void StartWriteLast(const Request* req, ::grpc::WriteOptions options) {    StartWrite(req, options.set_last_message());  }  /// Indicate that the RPC will have no more write operations. This can only be  /// issued once for a given RPC. This is not required or allowed if  /// StartWriteLast is used since that already has the same implication.  /// Note that calling this means that no more calls to StartWrite,  /// StartWriteLast, or StartWritesDone are allowed.  void StartWritesDone() { stream_->WritesDone(); }  /// Holds are needed if (and only if) this stream has operations that take  /// place on it after StartCall but from outside one of the reactions  /// (OnReadDone, etc). This is _not_ a common use of the streaming API.  ///  /// Holds must be added before calling StartCall. If a stream still has a hold  /// in place, its resources will not be destroyed even if the status has  /// already come in from the wire and there are currently no active callbacks  /// outstanding. Similarly, the stream will not call OnDone if there are still  /// holds on it.  ///  /// For example, if a StartRead or StartWrite operation is going to be  /// initiated from elsewhere in the application, the application should call  /// AddHold or AddMultipleHolds before StartCall.  If there is going to be,  /// for example, a read-flow and a write-flow taking place outside the  /// reactions, then call AddMultipleHolds(2) before StartCall. When the  /// application knows that it won't issue any more read operations (such as  /// when a read comes back as not ok), it should issue a RemoveHold(). It  /// should also call RemoveHold() again after it does StartWriteLast or  /// StartWritesDone that indicates that there will be no more write ops.  /// The number of RemoveHold calls must match the total number of AddHold  /// calls plus the number of holds added by AddMultipleHolds.  /// The argument to AddMultipleHolds must be positive.  void AddHold() { AddMultipleHolds(1); }  void AddMultipleHolds(int holds) {    GPR_CODEGEN_DEBUG_ASSERT(holds > 0);    stream_->AddHold(holds);  }  void RemoveHold() { stream_->RemoveHold(); }  /// Notifies the application that all operations associated with this RPC  /// have completed and all Holds have been removed. OnDone provides the RPC  /// status outcome for both successful and failed RPCs and will be called in  /// all cases. If it is not called, it indicates an application-level problem  /// (like failure to remove a hold).  ///  /// \param[in] s The status outcome of this RPC  void OnDone(const ::grpc::Status& /*s*/) override {}  /// Notifies the application that a read of initial metadata from the  /// server is done. If the application chooses not to implement this method,  /// it can assume that the initial metadata has been read before the first  /// call of OnReadDone or OnDone.  ///  /// \param[in] ok Was the initial metadata read successfully? If false, no  ///               new read/write operation will succeed, and any further  ///               Start* operations should not be called.  virtual void OnReadInitialMetadataDone(bool /*ok*/) {}  /// Notifies the application that a StartRead operation completed.  ///  /// \param[in] ok Was it successful? If false, no new read/write operation  ///               will succeed, and any further Start* should not be called.  virtual void OnReadDone(bool /*ok*/) {}  /// Notifies the application that a StartWrite or StartWriteLast operation  /// completed.  ///  /// \param[in] ok Was it successful? If false, no new read/write operation  ///               will succeed, and any further Start* should not be called.  virtual void OnWriteDone(bool /*ok*/) {}  /// Notifies the application that a StartWritesDone operation completed. Note  /// that this is only used on explicit StartWritesDone operations and not for  /// those that are implicitly invoked as part of a StartWriteLast.  ///  /// \param[in] ok Was it successful? If false, the application will later see  ///               the failure reflected as a bad status in OnDone and no  ///               further Start* should be called.  virtual void OnWritesDoneDone(bool /*ok*/) {} private:  friend class ClientCallbackReaderWriter<Request, Response>;  void BindStream(ClientCallbackReaderWriter<Request, Response>* stream) {    stream_ = stream;  }  ClientCallbackReaderWriter<Request, Response>* stream_;};/// \a ClientReadReactor is the interface for a server-streaming RPC./// All public methods behave as in ClientBidiReactor.template <class Response>class ClientReadReactor : public internal::ClientReactor { public:  virtual ~ClientReadReactor() {}  void StartCall() { reader_->StartCall(); }  void StartRead(Response* resp) { reader_->Read(resp); }  void AddHold() { AddMultipleHolds(1); }  void AddMultipleHolds(int holds) {    GPR_CODEGEN_DEBUG_ASSERT(holds > 0);    reader_->AddHold(holds);  }  void RemoveHold() { reader_->RemoveHold(); }  void OnDone(const ::grpc::Status& /*s*/) override {}  virtual void OnReadInitialMetadataDone(bool /*ok*/) {}  virtual void OnReadDone(bool /*ok*/) {} private:  friend class ClientCallbackReader<Response>;  void BindReader(ClientCallbackReader<Response>* reader) { reader_ = reader; }  ClientCallbackReader<Response>* reader_;};/// \a ClientWriteReactor is the interface for a client-streaming RPC./// All public methods behave as in ClientBidiReactor.template <class Request>class ClientWriteReactor : public internal::ClientReactor { public:  virtual ~ClientWriteReactor() {}  void StartCall() { writer_->StartCall(); }  void StartWrite(const Request* req) {    StartWrite(req, ::grpc::WriteOptions());  }  void StartWrite(const Request* req, ::grpc::WriteOptions options) {    writer_->Write(req, options);  }  void StartWriteLast(const Request* req, ::grpc::WriteOptions options) {    StartWrite(req, options.set_last_message());  }  void StartWritesDone() { writer_->WritesDone(); }  void AddHold() { AddMultipleHolds(1); }  void AddMultipleHolds(int holds) {    GPR_CODEGEN_DEBUG_ASSERT(holds > 0);    writer_->AddHold(holds);  }  void RemoveHold() { writer_->RemoveHold(); }  void OnDone(const ::grpc::Status& /*s*/) override {}  virtual void OnReadInitialMetadataDone(bool /*ok*/) {}  virtual void OnWriteDone(bool /*ok*/) {}  virtual void OnWritesDoneDone(bool /*ok*/) {} private:  friend class ClientCallbackWriter<Request>;  void BindWriter(ClientCallbackWriter<Request>* writer) { writer_ = writer; }  ClientCallbackWriter<Request>* writer_;};/// \a ClientUnaryReactor is a reactor-style interface for a unary RPC./// This is _not_ a common way of invoking a unary RPC. In practice, this/// option should be used only if the unary RPC wants to receive initial/// metadata without waiting for the response to complete. Most deployments of/// RPC systems do not use this option, but it is needed for generality./// All public methods behave as in ClientBidiReactor./// StartCall is included for consistency with the other reactor flavors: even/// though there are no StartRead or StartWrite operations to queue before the/// call (that is part of the unary call itself) and there is no reactor object/// being created as a result of this call, we keep a consistent 2-phase/// initiation API among all the reactor flavors.class ClientUnaryReactor : public internal::ClientReactor { public:  virtual ~ClientUnaryReactor() {}  void StartCall() { call_->StartCall(); }  void OnDone(const ::grpc::Status& /*s*/) override {}  virtual void OnReadInitialMetadataDone(bool /*ok*/) {} private:  friend class ClientCallbackUnary;  void BindCall(ClientCallbackUnary* call) { call_ = call; }  ClientCallbackUnary* call_;};// Define function out-of-line from class to avoid forward declaration issueinline void ClientCallbackUnary::BindReactor(ClientUnaryReactor* reactor) {  reactor->BindCall(this);}namespace internal {// Forward declare factory classes for friendshiptemplate <class Request, class Response>class ClientCallbackReaderWriterFactory;template <class Response>class ClientCallbackReaderFactory;template <class Request>class ClientCallbackWriterFactory;template <class Request, class Response>class ClientCallbackReaderWriterImpl    : public ClientCallbackReaderWriter<Request, Response> { public:  // always allocated against a call arena, no memory free required  static void operator delete(void* /*ptr*/, std::size_t size) {    GPR_CODEGEN_ASSERT(size == sizeof(ClientCallbackReaderWriterImpl));  }  // This operator should never be called as the memory should be freed as part  // of the arena destruction. It only exists to provide a matching operator  // delete to the operator new so that some compilers will not complain (see  // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this  // there are no tests catching the compiler warning.  static void operator delete(void*, void*) { GPR_CODEGEN_ASSERT(false); }  void StartCall() override {    // This call initiates two batches, plus any backlog, each with a callback    // 1. Send initial metadata (unless corked) + recv initial metadata    // 2. Any read backlog    // 3. Any write backlog    // 4. Recv trailing metadata (unless corked)    if (!start_corked_) {      start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,                                     context_->initial_metadata_flags());    }    call_.PerformOps(&start_ops_);    {      grpc::internal::MutexLock lock(&start_mu_);      if (backlog_.read_ops) {        call_.PerformOps(&read_ops_);      }      if (backlog_.write_ops) {        call_.PerformOps(&write_ops_);      }      if (backlog_.writes_done_ops) {        call_.PerformOps(&writes_done_ops_);      }      call_.PerformOps(&finish_ops_);      // The last thing in this critical section is to set started_ so that it      // can be used lock-free as well.      started_.store(true, std::memory_order_release);    }    // MaybeFinish outside the lock to make sure that destruction of this object    // doesn't take place while holding the lock (which would cause the lock to    // be released after destruction)    this->MaybeFinish(/*from_reaction=*/false);  }  void Read(Response* msg) override {    read_ops_.RecvMessage(msg);    callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);    if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {      grpc::internal::MutexLock lock(&start_mu_);      if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {        backlog_.read_ops = true;        return;      }    }    call_.PerformOps(&read_ops_);  }  void Write(const Request* msg, ::grpc::WriteOptions options) override {    if (options.is_last_message()) {      options.set_buffer_hint();      write_ops_.ClientSendClose();    }    // TODO(vjpai): don't assert    GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(msg, options).ok());    callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);    if (GPR_UNLIKELY(corked_write_needed_)) {      write_ops_.SendInitialMetadata(&context_->send_initial_metadata_,                                     context_->initial_metadata_flags());      corked_write_needed_ = false;    }    if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {      grpc::internal::MutexLock lock(&start_mu_);      if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {        backlog_.write_ops = true;        return;      }    }    call_.PerformOps(&write_ops_);  }  void WritesDone() override {    writes_done_ops_.ClientSendClose();    writes_done_tag_.Set(        call_.call(),        [this](bool ok) {          reactor_->OnWritesDoneDone(ok);          MaybeFinish(/*from_reaction=*/true);        },        &writes_done_ops_, /*can_inline=*/false);    writes_done_ops_.set_core_cq_tag(&writes_done_tag_);    callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);    if (GPR_UNLIKELY(corked_write_needed_)) {      writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_,                                           context_->initial_metadata_flags());      corked_write_needed_ = false;    }    if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {      grpc::internal::MutexLock lock(&start_mu_);      if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {        backlog_.writes_done_ops = true;        return;      }    }    call_.PerformOps(&writes_done_ops_);  }  void AddHold(int holds) override {    callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed);  }  void RemoveHold() override { MaybeFinish(/*from_reaction=*/false); } private:  friend class ClientCallbackReaderWriterFactory<Request, Response>;  ClientCallbackReaderWriterImpl(grpc::internal::Call call,                                 ::grpc::ClientContext* context,                                 ClientBidiReactor<Request, Response>* reactor)      : context_(context),        call_(call),        reactor_(reactor),        start_corked_(context_->initial_metadata_corked_),        corked_write_needed_(start_corked_) {    this->BindReactor(reactor);    // Set up the unchanging parts of the start, read, and write tags and ops.    start_tag_.Set(        call_.call(),        [this](bool ok) {          reactor_->OnReadInitialMetadataDone(ok);          MaybeFinish(/*from_reaction=*/true);        },        &start_ops_, /*can_inline=*/false);    start_ops_.RecvInitialMetadata(context_);    start_ops_.set_core_cq_tag(&start_tag_);    write_tag_.Set(        call_.call(),        [this](bool ok) {          reactor_->OnWriteDone(ok);          MaybeFinish(/*from_reaction=*/true);        },        &write_ops_, /*can_inline=*/false);    write_ops_.set_core_cq_tag(&write_tag_);    read_tag_.Set(        call_.call(),        [this](bool ok) {          reactor_->OnReadDone(ok);          MaybeFinish(/*from_reaction=*/true);        },        &read_ops_, /*can_inline=*/false);    read_ops_.set_core_cq_tag(&read_tag_);    // Also set up the Finish tag and op set.    finish_tag_.Set(        call_.call(),        [this](bool /*ok*/) { MaybeFinish(/*from_reaction=*/true); },        &finish_ops_,        /*can_inline=*/false);    finish_ops_.ClientRecvStatus(context_, &finish_status_);    finish_ops_.set_core_cq_tag(&finish_tag_);  }  // MaybeFinish can be called from reactions or from user-initiated operations  // like StartCall or RemoveHold. If this is the last operation or hold on this  // object, it will invoke the OnDone reaction. If MaybeFinish was called from  // a reaction, it can call OnDone directly. If not, it would need to schedule  // OnDone onto an executor thread to avoid the possibility of deadlocking with  // any locks in the user code that invoked it.  void MaybeFinish(bool from_reaction) {    if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(                         1, std::memory_order_acq_rel) == 1)) {      ::grpc::Status s = std::move(finish_status_);      auto* reactor = reactor_;      auto* call = call_.call();      this->~ClientCallbackReaderWriterImpl();      ::grpc::g_core_codegen_interface->grpc_call_unref(call);      if (GPR_LIKELY(from_reaction)) {        reactor->OnDone(s);      } else {        reactor->InternalScheduleOnDone(std::move(s));      }    }  }  ::grpc::ClientContext* const context_;  grpc::internal::Call call_;  ClientBidiReactor<Request, Response>* const reactor_;  grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,                            grpc::internal::CallOpRecvInitialMetadata>      start_ops_;  grpc::internal::CallbackWithSuccessTag start_tag_;  const bool start_corked_;  bool corked_write_needed_;  // no lock needed since only accessed in                              // Write/WritesDone which cannot be concurrent  grpc::internal::CallOpSet<grpc::internal::CallOpClientRecvStatus> finish_ops_;  grpc::internal::CallbackWithSuccessTag finish_tag_;  ::grpc::Status finish_status_;  grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,                            grpc::internal::CallOpSendMessage,                            grpc::internal::CallOpClientSendClose>      write_ops_;  grpc::internal::CallbackWithSuccessTag write_tag_;  grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,                            grpc::internal::CallOpClientSendClose>      writes_done_ops_;  grpc::internal::CallbackWithSuccessTag writes_done_tag_;  grpc::internal::CallOpSet<grpc::internal::CallOpRecvMessage<Response>>      read_ops_;  grpc::internal::CallbackWithSuccessTag read_tag_;  struct StartCallBacklog {    bool write_ops = false;    bool writes_done_ops = false;    bool read_ops = false;  };  StartCallBacklog backlog_ /* GUARDED_BY(start_mu_) */;  // Minimum of 3 callbacks to pre-register for start ops, StartCall, and finish  std::atomic<intptr_t> callbacks_outstanding_{3};  std::atomic_bool started_{false};  grpc::internal::Mutex start_mu_;};template <class Request, class Response>class ClientCallbackReaderWriterFactory { public:  static void Create(::grpc::ChannelInterface* channel,                     const ::grpc::internal::RpcMethod& method,                     ::grpc::ClientContext* context,                     ClientBidiReactor<Request, Response>* reactor) {    grpc::internal::Call call =        channel->CreateCall(method, context, channel->CallbackCQ());    ::grpc::g_core_codegen_interface->grpc_call_ref(call.call());    new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(        call.call(), sizeof(ClientCallbackReaderWriterImpl<Request, Response>)))        ClientCallbackReaderWriterImpl<Request, Response>(call, context,                                                          reactor);  }};template <class Response>class ClientCallbackReaderImpl : public ClientCallbackReader<Response> { public:  // always allocated against a call arena, no memory free required  static void operator delete(void* /*ptr*/, std::size_t size) {    GPR_CODEGEN_ASSERT(size == sizeof(ClientCallbackReaderImpl));  }  // This operator should never be called as the memory should be freed as part  // of the arena destruction. It only exists to provide a matching operator  // delete to the operator new so that some compilers will not complain (see  // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this  // there are no tests catching the compiler warning.  static void operator delete(void*, void*) { GPR_CODEGEN_ASSERT(false); }  void StartCall() override {    // This call initiates two batches, plus any backlog, each with a callback    // 1. Send initial metadata (unless corked) + recv initial metadata    // 2. Any backlog    // 3. Recv trailing metadata    start_tag_.Set(        call_.call(),        [this](bool ok) {          reactor_->OnReadInitialMetadataDone(ok);          MaybeFinish(/*from_reaction=*/true);        },        &start_ops_, /*can_inline=*/false);    start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,                                   context_->initial_metadata_flags());    start_ops_.RecvInitialMetadata(context_);    start_ops_.set_core_cq_tag(&start_tag_);    call_.PerformOps(&start_ops_);    // Also set up the read tag so it doesn't have to be set up each time    read_tag_.Set(        call_.call(),        [this](bool ok) {          reactor_->OnReadDone(ok);          MaybeFinish(/*from_reaction=*/true);        },        &read_ops_, /*can_inline=*/false);    read_ops_.set_core_cq_tag(&read_tag_);    {      grpc::internal::MutexLock lock(&start_mu_);      if (backlog_.read_ops) {        call_.PerformOps(&read_ops_);      }      started_.store(true, std::memory_order_release);    }    finish_tag_.Set(        call_.call(),        [this](bool /*ok*/) { MaybeFinish(/*from_reaction=*/true); },        &finish_ops_, /*can_inline=*/false);    finish_ops_.ClientRecvStatus(context_, &finish_status_);    finish_ops_.set_core_cq_tag(&finish_tag_);    call_.PerformOps(&finish_ops_);  }  void Read(Response* msg) override {    read_ops_.RecvMessage(msg);    callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);    if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {      grpc::internal::MutexLock lock(&start_mu_);      if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {        backlog_.read_ops = true;        return;      }    }    call_.PerformOps(&read_ops_);  }  void AddHold(int holds) override {    callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed);  }  void RemoveHold() override { MaybeFinish(/*from_reaction=*/false); } private:  friend class ClientCallbackReaderFactory<Response>;  template <class Request>  ClientCallbackReaderImpl(::grpc::internal::Call call,                           ::grpc::ClientContext* context, Request* request,                           ClientReadReactor<Response>* reactor)      : context_(context), call_(call), reactor_(reactor) {    this->BindReactor(reactor);    // TODO(vjpai): don't assert    GPR_CODEGEN_ASSERT(start_ops_.SendMessagePtr(request).ok());    start_ops_.ClientSendClose();  }  // MaybeFinish behaves as in ClientCallbackReaderWriterImpl.  void MaybeFinish(bool from_reaction) {    if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(                         1, std::memory_order_acq_rel) == 1)) {      ::grpc::Status s = std::move(finish_status_);      auto* reactor = reactor_;      auto* call = call_.call();      this->~ClientCallbackReaderImpl();      ::grpc::g_core_codegen_interface->grpc_call_unref(call);      if (GPR_LIKELY(from_reaction)) {        reactor->OnDone(s);      } else {        reactor->InternalScheduleOnDone(std::move(s));      }    }  }  ::grpc::ClientContext* const context_;  grpc::internal::Call call_;  ClientReadReactor<Response>* const reactor_;  grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,                            grpc::internal::CallOpSendMessage,                            grpc::internal::CallOpClientSendClose,                            grpc::internal::CallOpRecvInitialMetadata>      start_ops_;  grpc::internal::CallbackWithSuccessTag start_tag_;  grpc::internal::CallOpSet<grpc::internal::CallOpClientRecvStatus> finish_ops_;  grpc::internal::CallbackWithSuccessTag finish_tag_;  ::grpc::Status finish_status_;  grpc::internal::CallOpSet<grpc::internal::CallOpRecvMessage<Response>>      read_ops_;  grpc::internal::CallbackWithSuccessTag read_tag_;  struct StartCallBacklog {    bool read_ops = false;  };  StartCallBacklog backlog_ /* GUARDED_BY(start_mu_) */;  // Minimum of 2 callbacks to pre-register for start and finish  std::atomic<intptr_t> callbacks_outstanding_{2};  std::atomic_bool started_{false};  grpc::internal::Mutex start_mu_;};template <class Response>class ClientCallbackReaderFactory { public:  template <class Request>  static void Create(::grpc::ChannelInterface* channel,                     const ::grpc::internal::RpcMethod& method,                     ::grpc::ClientContext* context, const Request* request,                     ClientReadReactor<Response>* reactor) {    grpc::internal::Call call =        channel->CreateCall(method, context, channel->CallbackCQ());    ::grpc::g_core_codegen_interface->grpc_call_ref(call.call());    new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(        call.call(), sizeof(ClientCallbackReaderImpl<Response>)))        ClientCallbackReaderImpl<Response>(call, context, request, reactor);  }};template <class Request>class ClientCallbackWriterImpl : public ClientCallbackWriter<Request> { public:  // always allocated against a call arena, no memory free required  static void operator delete(void* /*ptr*/, std::size_t size) {    GPR_CODEGEN_ASSERT(size == sizeof(ClientCallbackWriterImpl));  }  // This operator should never be called as the memory should be freed as part  // of the arena destruction. It only exists to provide a matching operator  // delete to the operator new so that some compilers will not complain (see  // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this  // there are no tests catching the compiler warning.  static void operator delete(void*, void*) { GPR_CODEGEN_ASSERT(false); }  void StartCall() override {    // This call initiates two batches, plus any backlog, each with a callback    // 1. Send initial metadata (unless corked) + recv initial metadata    // 2. Any backlog    // 3. Recv trailing metadata    if (!start_corked_) {      start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,                                     context_->initial_metadata_flags());    }    call_.PerformOps(&start_ops_);    {      grpc::internal::MutexLock lock(&start_mu_);      if (backlog_.write_ops) {        call_.PerformOps(&write_ops_);      }      if (backlog_.writes_done_ops) {        call_.PerformOps(&writes_done_ops_);      }      call_.PerformOps(&finish_ops_);      // The last thing in this critical section is to set started_ so that it      // can be used lock-free as well.      started_.store(true, std::memory_order_release);    }    // MaybeFinish outside the lock to make sure that destruction of this object    // doesn't take place while holding the lock (which would cause the lock to    // be released after destruction)    this->MaybeFinish(/*from_reaction=*/false);  }  void Write(const Request* msg, ::grpc::WriteOptions options) override {    if (GPR_UNLIKELY(options.is_last_message())) {      options.set_buffer_hint();      write_ops_.ClientSendClose();    }    // TODO(vjpai): don't assert    GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(msg, options).ok());    callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);    if (GPR_UNLIKELY(corked_write_needed_)) {      write_ops_.SendInitialMetadata(&context_->send_initial_metadata_,                                     context_->initial_metadata_flags());      corked_write_needed_ = false;    }    if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {      grpc::internal::MutexLock lock(&start_mu_);      if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {        backlog_.write_ops = true;        return;      }    }    call_.PerformOps(&write_ops_);  }  void WritesDone() override {    writes_done_ops_.ClientSendClose();    writes_done_tag_.Set(        call_.call(),        [this](bool ok) {          reactor_->OnWritesDoneDone(ok);          MaybeFinish(/*from_reaction=*/true);        },        &writes_done_ops_, /*can_inline=*/false);    writes_done_ops_.set_core_cq_tag(&writes_done_tag_);    callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);    if (GPR_UNLIKELY(corked_write_needed_)) {      writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_,                                           context_->initial_metadata_flags());      corked_write_needed_ = false;    }    if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {      grpc::internal::MutexLock lock(&start_mu_);      if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {        backlog_.writes_done_ops = true;        return;      }    }    call_.PerformOps(&writes_done_ops_);  }  void AddHold(int holds) override {    callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed);  }  void RemoveHold() override { MaybeFinish(/*from_reaction=*/false); } private:  friend class ClientCallbackWriterFactory<Request>;  template <class Response>  ClientCallbackWriterImpl(::grpc::internal::Call call,                           ::grpc::ClientContext* context, Response* response,                           ClientWriteReactor<Request>* reactor)      : context_(context),        call_(call),        reactor_(reactor),        start_corked_(context_->initial_metadata_corked_),        corked_write_needed_(start_corked_) {    this->BindReactor(reactor);    // Set up the unchanging parts of the start and write tags and ops.    start_tag_.Set(        call_.call(),        [this](bool ok) {          reactor_->OnReadInitialMetadataDone(ok);          MaybeFinish(/*from_reaction=*/true);        },        &start_ops_, /*can_inline=*/false);    start_ops_.RecvInitialMetadata(context_);    start_ops_.set_core_cq_tag(&start_tag_);    write_tag_.Set(        call_.call(),        [this](bool ok) {          reactor_->OnWriteDone(ok);          MaybeFinish(/*from_reaction=*/true);        },        &write_ops_, /*can_inline=*/false);    write_ops_.set_core_cq_tag(&write_tag_);    // Also set up the Finish tag and op set.    finish_ops_.RecvMessage(response);    finish_ops_.AllowNoMessage();    finish_tag_.Set(        call_.call(),        [this](bool /*ok*/) { MaybeFinish(/*from_reaction=*/true); },        &finish_ops_,        /*can_inline=*/false);    finish_ops_.ClientRecvStatus(context_, &finish_status_);    finish_ops_.set_core_cq_tag(&finish_tag_);  }  // MaybeFinish behaves as in ClientCallbackReaderWriterImpl.  void MaybeFinish(bool from_reaction) {    if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(                         1, std::memory_order_acq_rel) == 1)) {      ::grpc::Status s = std::move(finish_status_);      auto* reactor = reactor_;      auto* call = call_.call();      this->~ClientCallbackWriterImpl();      ::grpc::g_core_codegen_interface->grpc_call_unref(call);      if (GPR_LIKELY(from_reaction)) {        reactor->OnDone(s);      } else {        reactor->InternalScheduleOnDone(std::move(s));      }    }  }  ::grpc::ClientContext* const context_;  grpc::internal::Call call_;  ClientWriteReactor<Request>* const reactor_;  grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,                            grpc::internal::CallOpRecvInitialMetadata>      start_ops_;  grpc::internal::CallbackWithSuccessTag start_tag_;  const bool start_corked_;  bool corked_write_needed_;  // no lock needed since only accessed in                              // Write/WritesDone which cannot be concurrent  grpc::internal::CallOpSet<grpc::internal::CallOpGenericRecvMessage,                            grpc::internal::CallOpClientRecvStatus>      finish_ops_;  grpc::internal::CallbackWithSuccessTag finish_tag_;  ::grpc::Status finish_status_;  grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,                            grpc::internal::CallOpSendMessage,                            grpc::internal::CallOpClientSendClose>      write_ops_;  grpc::internal::CallbackWithSuccessTag write_tag_;  grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,                            grpc::internal::CallOpClientSendClose>      writes_done_ops_;  grpc::internal::CallbackWithSuccessTag writes_done_tag_;  struct StartCallBacklog {    bool write_ops = false;    bool writes_done_ops = false;  };  StartCallBacklog backlog_ /* GUARDED_BY(start_mu_) */;  // Minimum of 3 callbacks to pre-register for start ops, StartCall, and finish  std::atomic<intptr_t> callbacks_outstanding_{3};  std::atomic_bool started_{false};  grpc::internal::Mutex start_mu_;};template <class Request>class ClientCallbackWriterFactory { public:  template <class Response>  static void Create(::grpc::ChannelInterface* channel,                     const ::grpc::internal::RpcMethod& method,                     ::grpc::ClientContext* context, Response* response,                     ClientWriteReactor<Request>* reactor) {    grpc::internal::Call call =        channel->CreateCall(method, context, channel->CallbackCQ());    ::grpc::g_core_codegen_interface->grpc_call_ref(call.call());    new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(        call.call(), sizeof(ClientCallbackWriterImpl<Request>)))        ClientCallbackWriterImpl<Request>(call, context, response, reactor);  }};class ClientCallbackUnaryImpl final : public ClientCallbackUnary { public:  // always allocated against a call arena, no memory free required  static void operator delete(void* /*ptr*/, std::size_t size) {    GPR_CODEGEN_ASSERT(size == sizeof(ClientCallbackUnaryImpl));  }  // This operator should never be called as the memory should be freed as part  // of the arena destruction. It only exists to provide a matching operator  // delete to the operator new so that some compilers will not complain (see  // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this  // there are no tests catching the compiler warning.  static void operator delete(void*, void*) { GPR_CODEGEN_ASSERT(false); }  void StartCall() override {    // This call initiates two batches, each with a callback    // 1. Send initial metadata + write + writes done + recv initial metadata    // 2. Read message, recv trailing metadata    start_tag_.Set(        call_.call(),        [this](bool ok) {          reactor_->OnReadInitialMetadataDone(ok);          MaybeFinish();        },        &start_ops_, /*can_inline=*/false);    start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,                                   context_->initial_metadata_flags());    start_ops_.RecvInitialMetadata(context_);    start_ops_.set_core_cq_tag(&start_tag_);    call_.PerformOps(&start_ops_);    finish_tag_.Set(        call_.call(), [this](bool /*ok*/) { MaybeFinish(); }, &finish_ops_,        /*can_inline=*/false);    finish_ops_.ClientRecvStatus(context_, &finish_status_);    finish_ops_.set_core_cq_tag(&finish_tag_);    call_.PerformOps(&finish_ops_);  } private:  friend class ClientCallbackUnaryFactory;  template <class Request, class Response>  ClientCallbackUnaryImpl(::grpc::internal::Call call,                          ::grpc::ClientContext* context, Request* request,                          Response* response, ClientUnaryReactor* reactor)      : context_(context), call_(call), reactor_(reactor) {    this->BindReactor(reactor);    // TODO(vjpai): don't assert    GPR_CODEGEN_ASSERT(start_ops_.SendMessagePtr(request).ok());    start_ops_.ClientSendClose();    finish_ops_.RecvMessage(response);    finish_ops_.AllowNoMessage();  }  // In the unary case, MaybeFinish is only ever invoked from a  // library-initiated reaction, so it will just directly call OnDone if this is  // the last reaction for this RPC.  void MaybeFinish() {    if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(                         1, std::memory_order_acq_rel) == 1)) {      ::grpc::Status s = std::move(finish_status_);      auto* reactor = reactor_;      auto* call = call_.call();      this->~ClientCallbackUnaryImpl();      ::grpc::g_core_codegen_interface->grpc_call_unref(call);      reactor->OnDone(s);    }  }  ::grpc::ClientContext* const context_;  grpc::internal::Call call_;  ClientUnaryReactor* const reactor_;  grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,                            grpc::internal::CallOpSendMessage,                            grpc::internal::CallOpClientSendClose,                            grpc::internal::CallOpRecvInitialMetadata>      start_ops_;  grpc::internal::CallbackWithSuccessTag start_tag_;  grpc::internal::CallOpSet<grpc::internal::CallOpGenericRecvMessage,                            grpc::internal::CallOpClientRecvStatus>      finish_ops_;  grpc::internal::CallbackWithSuccessTag finish_tag_;  ::grpc::Status finish_status_;  // This call will have 2 callbacks: start and finish  std::atomic<intptr_t> callbacks_outstanding_{2};};class ClientCallbackUnaryFactory { public:  template <class Request, class Response, class BaseRequest = Request,            class BaseResponse = Response>  static void Create(::grpc::ChannelInterface* channel,                     const ::grpc::internal::RpcMethod& method,                     ::grpc::ClientContext* context, const Request* request,                     Response* response, ClientUnaryReactor* reactor) {    grpc::internal::Call call =        channel->CreateCall(method, context, channel->CallbackCQ());    ::grpc::g_core_codegen_interface->grpc_call_ref(call.call());    new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(        call.call(), sizeof(ClientCallbackUnaryImpl)))        ClientCallbackUnaryImpl(call, context,                                static_cast<const BaseRequest*>(request),                                static_cast<BaseResponse*>(response), reactor);  }};}  // namespace internal// TODO(vjpai): Remove namespace experimental when de-experimentalized fully.namespace experimental {template <class Response>using ClientCallbackReader = ::grpc::ClientCallbackReader<Response>;template <class Request>using ClientCallbackWriter = ::grpc::ClientCallbackWriter<Request>;template <class Request, class Response>using ClientCallbackReaderWriter =    ::grpc::ClientCallbackReaderWriter<Request, Response>;template <class Response>using ClientReadReactor = ::grpc::ClientReadReactor<Response>;template <class Request>using ClientWriteReactor = ::grpc::ClientWriteReactor<Request>;template <class Request, class Response>using ClientBidiReactor = ::grpc::ClientBidiReactor<Request, Response>;typedef ::grpc::ClientUnaryReactor ClientUnaryReactor;}  // namespace experimental}  // namespace grpc#endif  // GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_H
 |