GRPC C++  1.82.0
client_callback.h
Go to the documentation of this file.
1 //
2 //
3 // Copyright 2018 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 #ifndef GRPCPP_SUPPORT_CLIENT_CALLBACK_H
20 #define GRPCPP_SUPPORT_CLIENT_CALLBACK_H
21 
22 #include <grpc/grpc.h>
23 #include <grpc/impl/call.h>
24 #include <grpcpp/impl/call.h>
27 #include <grpcpp/impl/sync.h>
29 #include <grpcpp/support/config.h>
30 #include <grpcpp/support/status.h>
31 
32 #include <atomic>
33 #include <cstddef>
34 #include <functional>
35 #include <memory>
36 #include <type_traits>
37 #include <utility>
38 
39 #include "absl/log/absl_check.h"
40 
41 namespace grpc {
42 class Channel;
43 class ClientContext;
44 
45 namespace internal {
46 class RpcMethod;
47 
54 template <class InputMessage, class OutputMessage,
55  class BaseInputMessage = InputMessage,
56  class BaseOutputMessage = OutputMessage>
58  const grpc::internal::RpcMethod& method,
59  grpc::ClientContext* context,
60  const InputMessage* request, OutputMessage* result,
61  std::function<void(grpc::Status)>&& on_completion) {
62  static_assert(std::is_base_of<BaseInputMessage, InputMessage>::value,
63  "Invalid input message specification");
64  static_assert(std::is_base_of<BaseOutputMessage, OutputMessage>::value,
65  "Invalid output message specification");
67  channel, method, context, request, result, std::move(on_completion));
68 }
69 
70 template <class InputMessage, class OutputMessage>
71 class CallbackUnaryCallImpl {
72  public:
74  const grpc::internal::RpcMethod& method,
75  grpc::ClientContext* context,
76  const InputMessage* request, OutputMessage* result,
77  std::function<void(grpc::Status)>&& on_completion) {
78  grpc::CompletionQueue* cq = channel->CallbackCQ();
79  ABSL_CHECK_NE(cq, nullptr);
80  grpc::internal::Call call(channel->CreateCall(method, context, cq));
81 
82  using FullCallOpSet = grpc::internal::CallOpSet<
89 
90  struct OpSetAndTag {
91  FullCallOpSet opset;
93  };
94  const size_t alloc_sz = sizeof(OpSetAndTag);
95  auto* const alloced =
96  static_cast<OpSetAndTag*>(grpc_call_arena_alloc(call.call(), alloc_sz));
97  auto* ops = new (&alloced->opset) FullCallOpSet;
98  auto* tag = new (&alloced->tag) grpc::internal::CallbackWithStatusTag(
99  call.call(), std::move(on_completion), ops);
100 
101  // TODO(vjpai): Unify code with sync API as much as possible
102  grpc::Status s = ops->SendMessagePtr(request, channel->memory_allocator());
103  if (!s.ok()) {
104  tag->force_run(s);
105  return;
106  }
107  ops->SendInitialMetadata(&context->send_initial_metadata_,
108  context->initial_metadata_flags());
109  ops->RecvInitialMetadata(context);
110  ops->RecvMessage(result);
111  ops->AllowNoMessage();
112  ops->ClientSendClose();
113  ops->ClientRecvStatus(context, tag->status_ptr());
114  ops->set_core_cq_tag(tag);
115  ops->FillOps(&call);
116  }
117 };
118 
119 // Base class for public API classes.
121  public:
122  virtual ~ClientReactor() = default;
123 
131  virtual void OnDone(const grpc::Status& /*s*/) = 0;
132 
140  virtual bool InternalTrailersOnly(const grpc_call* call) const;
141 };
142 
143 } // namespace internal
144 
145 namespace experimental {
146 template <class RequestType, class ResponseType>
148 
151 } // namespace experimental
152 
153 // Forward declarations
154 template <class Request, class Response>
156 template <class Response>
158 template <class Request>
160 class ClientUnaryReactor;
161 
162 // NOTE: The streaming objects are not actually implemented in the public API.
163 // These interfaces are provided for mocking only. Typical applications
164 // will interact exclusively with the reactors that they define.
165 template <class Request, class Response>
167  public:
169  virtual void StartCall() = 0;
170  virtual void Write(const Request* req, grpc::WriteOptions options) = 0;
171  virtual void WritesDone() = 0;
172  virtual void Read(Response* resp) = 0;
173  virtual void AddHold(int holds) = 0;
174  virtual void RemoveHold() = 0;
175 
176  protected:
178  reactor->BindStream(this);
179  }
180 };
181 
182 template <class Response>
184  public:
186  virtual void StartCall() = 0;
187  virtual void Read(Response* resp) = 0;
188  virtual void AddHold(int holds) = 0;
189  virtual void RemoveHold() = 0;
190 
191  protected:
193  reactor->BindReader(this);
194  }
195 };
196 
197 template <class Request>
199  public:
201  virtual void StartCall() = 0;
202  void Write(const Request* req) { Write(req, grpc::WriteOptions()); }
203  virtual void Write(const Request* req, grpc::WriteOptions options) = 0;
204  void WriteLast(const Request* req, grpc::WriteOptions options) {
205  Write(req, options.set_last_message());
206  }
207  virtual void WritesDone() = 0;
208 
209  virtual void AddHold(int holds) = 0;
210  virtual void RemoveHold() = 0;
211 
212  protected:
214  reactor->BindWriter(this);
215  }
216 };
217 
219  public:
220  virtual ~ClientCallbackUnary() {}
221  virtual void StartCall() = 0;
222 
223  protected:
224  void BindReactor(ClientUnaryReactor* reactor);
225 };
226 
227 namespace experimental {
229  public:
231  virtual void StartCall() = 0;
232 
233  protected:
234  void BindReactor(ClientSessionReactor* reactor);
235 };
236 } // namespace experimental
237 
238 // The following classes are the reactor interfaces that are to be implemented
239 // by the user. They are passed in to the library as an argument to a call on a
240 // stub (either a codegen-ed call or a generic call). The streaming RPC is
241 // activated by calling StartCall, possibly after initiating StartRead,
242 // StartWrite, or AddHold operations on the streaming object. Note that none of
243 // the classes are pure; all reactions have a default empty reaction so that the
244 // user class only needs to override those reactions that it cares about.
245 // The reactor must be passed to the stub invocation before any of the below
246 // operations can be called and its reactions will be invoked by the library in
247 // response to the completion of various operations. Reactions must not include
248 // blocking operations (such as blocking I/O, starting synchronous RPCs, or
249 // waiting on condition variables). Reactions may be invoked concurrently,
250 // except that OnDone is called after all others (assuming proper API usage).
251 // The reactor may not be deleted until OnDone is called.
252 
254 template <class Request, class Response>
255 class ClientBidiReactor : public internal::ClientReactor {
256  public:
261  void StartCall() { stream_->StartCall(); }
262 
268  void StartRead(Response* resp) { stream_->Read(resp); }
269 
276  void StartWrite(const Request* req) { StartWrite(req, grpc::WriteOptions()); }
277 
284  void StartWrite(const Request* req, grpc::WriteOptions options) {
285  stream_->Write(req, options);
286  }
287 
297  void StartWriteLast(const Request* req, grpc::WriteOptions options) {
298  StartWrite(req, options.set_last_message());
299  }
300 
306  void StartWritesDone() { stream_->WritesDone(); }
307 
330  void AddHold() { AddMultipleHolds(1); }
331  void AddMultipleHolds(int holds) {
332  ABSL_DCHECK_GT(holds, 0);
333  stream_->AddHold(holds);
334  }
335  void RemoveHold() { stream_->RemoveHold(); }
336 
348  void OnDone(const grpc::Status& /*s*/) override {}
349 
357  virtual void OnReadInitialMetadataDone(bool /*ok*/) {}
358 
363  virtual void OnReadDone(bool /*ok*/) {}
364 
370  virtual void OnWriteDone(bool /*ok*/) {}
371 
379  virtual void OnWritesDoneDone(bool /*ok*/) {}
380 
381  private:
382  friend class ClientCallbackReaderWriter<Request, Response>;
383  void BindStream(ClientCallbackReaderWriter<Request, Response>* stream) {
384  stream_ = stream;
385  }
387 };
388 
391 template <class Response>
392 class ClientReadReactor : public internal::ClientReactor {
393  public:
394  void StartCall() { reader_->StartCall(); }
395  void StartRead(Response* resp) { reader_->Read(resp); }
396 
397  void AddHold() { AddMultipleHolds(1); }
398  void AddMultipleHolds(int holds) {
399  ABSL_DCHECK_GT(holds, 0);
400  reader_->AddHold(holds);
401  }
402  void RemoveHold() { reader_->RemoveHold(); }
403 
404  void OnDone(const grpc::Status& /*s*/) override {}
405  virtual void OnReadInitialMetadataDone(bool /*ok*/) {}
406  virtual void OnReadDone(bool /*ok*/) {}
407 
408  private:
409  friend class ClientCallbackReader<Response>;
410  void BindReader(ClientCallbackReader<Response>* reader) { reader_ = reader; }
412 };
413 
416 template <class Request>
417 class ClientWriteReactor : public internal::ClientReactor {
418  public:
419  void StartCall() { writer_->StartCall(); }
420  void StartWrite(const Request* req) { StartWrite(req, grpc::WriteOptions()); }
421  void StartWrite(const Request* req, grpc::WriteOptions options) {
422  writer_->Write(req, options);
423  }
424  void StartWriteLast(const Request* req, grpc::WriteOptions options) {
425  StartWrite(req, options.set_last_message());
426  }
427  void StartWritesDone() { writer_->WritesDone(); }
428 
429  void AddHold() { AddMultipleHolds(1); }
430  void AddMultipleHolds(int holds) {
431  ABSL_DCHECK_GT(holds, 0);
432  writer_->AddHold(holds);
433  }
434  void RemoveHold() { writer_->RemoveHold(); }
435 
436  void OnDone(const grpc::Status& /*s*/) override {}
437  virtual void OnReadInitialMetadataDone(bool /*ok*/) {}
438  virtual void OnWriteDone(bool /*ok*/) {}
439  virtual void OnWritesDoneDone(bool /*ok*/) {}
440 
441  private:
442  friend class ClientCallbackWriter<Request>;
443  void BindWriter(ClientCallbackWriter<Request>* writer) { writer_ = writer; }
444 
446 };
447 
460  public:
461  void StartCall() { call_->StartCall(); }
462  void OnDone(const grpc::Status& /*s*/) override {}
463  virtual void OnReadInitialMetadataDone(bool /*ok*/) {}
464 
465  private:
466  friend class ClientCallbackUnary;
467  void BindCall(ClientCallbackUnary* call) { call_ = call; }
468  ClientCallbackUnary* call_;
469 };
470 
471 // Define function out-of-line from class to avoid forward declaration issue
473  reactor->BindCall(this);
474 }
475 
476 namespace experimental {
481  public:
482  void StartCall() { call_->StartCall(); }
483  void OnDone(const grpc::Status& /*s*/) override {}
484  virtual void OnSessionReady(grpc::internal::Call call) = 0;
485  virtual void OnSessionAcknowledged(bool /*ok*/) {}
486  virtual void OnGracefulShutdown() {}
487 
488  private:
489  friend class ClientCallbackSession;
490  void BindCall(ClientCallbackSession* call) { call_ = call; }
491  ClientCallbackSession* call_;
492 };
493 
494 // Define function out-of-line from class to avoid forward declaration issue
496  reactor->BindCall(this);
497 }
498 } // namespace experimental
499 
500 namespace internal {
501 
502 // Forward declare factory classes for friendship
503 template <class Request, class Response>
504 class ClientCallbackReaderWriterFactory;
505 template <class Response>
506 class ClientCallbackReaderFactory;
507 template <class Request>
508 class ClientCallbackWriterFactory;
509 
510 template <class Request, class Response>
511 class ClientCallbackReaderWriterImpl
512  : public ClientCallbackReaderWriter<Request, Response> {
513  public:
514  // always allocated against a call arena, no memory free required
515  static void operator delete(void* /*ptr*/, std::size_t size) {
516  ABSL_CHECK_EQ(size, sizeof(ClientCallbackReaderWriterImpl));
517  }
518 
519  // This operator should never be called as the memory should be freed as part
520  // of the arena destruction. It only exists to provide a matching operator
521  // delete to the operator new so that some compilers will not complain (see
522  // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
523  // there are no tests catching the compiler warning.
524  static void operator delete(void*, void*) { ABSL_CHECK(false); }
525 
526  void StartCall() ABSL_LOCKS_EXCLUDED(start_mu_) override {
527  // This call initiates two batches, plus any backlog, each with a callback
528  // 1. Send initial metadata (unless corked) + recv initial metadata
529  // 2. Any read backlog
530  // 3. Any write backlog
531  // 4. Recv trailing metadata (unless corked)
532  if (!start_corked_) {
533  start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
534  context_->initial_metadata_flags());
535  }
536 
537  start_ops_.FillOps(&call_);
538 
539  {
540  grpc::internal::MutexLock lock(&start_mu_);
541 
542  if (backlog_.read_ops) {
543  read_ops_.FillOps(&call_);
544  }
545  if (backlog_.write_ops) {
546  write_ops_.FillOps(&call_);
547  }
548  if (backlog_.writes_done_ops) {
549  writes_done_ops_.FillOps(&call_);
550  }
551  finish_ops_.FillOps(&call_);
552  // The last thing in this critical section is to set started_ so that it
553  // can be used lock-free as well.
554  started_.store(true, std::memory_order_release);
555  }
556  // MaybeFinish outside the lock to make sure that destruction of this object
557  // doesn't take place while holding the lock (which would cause the lock to
558  // be released after destruction)
559  this->MaybeFinish(/*from_reaction=*/false);
560  }
561 
562  void Read(Response* msg) override {
563  read_ops_.RecvMessage(msg);
564  callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
565  if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
566  grpc::internal::MutexLock lock(&start_mu_);
567  if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
568  backlog_.read_ops = true;
569  return;
570  }
571  }
572  read_ops_.FillOps(&call_);
573  }
574 
575  void Write(const Request* msg, grpc::WriteOptions options)
576  ABSL_LOCKS_EXCLUDED(start_mu_) override {
577  if (options.is_last_message()) {
578  options.set_buffer_hint();
579  write_ops_.ClientSendClose();
580  }
581 
582  // TODO(vjpai): don't assert
583  ABSL_CHECK(
584  write_ops_.SendMessagePtr(msg, options, channel_->memory_allocator())
585  .ok());
586  callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
587  if (GPR_UNLIKELY(corked_write_needed_)) {
588  write_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
589  context_->initial_metadata_flags());
590  corked_write_needed_ = false;
591  }
592 
593  if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
594  grpc::internal::MutexLock lock(&start_mu_);
595  if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
596  backlog_.write_ops = true;
597  return;
598  }
599  }
600  write_ops_.FillOps(&call_);
601  }
602  void WritesDone() ABSL_LOCKS_EXCLUDED(start_mu_) override {
603  writes_done_ops_.ClientSendClose();
604  writes_done_tag_.Set(
605  call_.call(),
606  [this](bool ok) {
607  reactor_->OnWritesDoneDone(ok);
608  MaybeFinish(/*from_reaction=*/true);
609  },
610  &writes_done_ops_, /*can_inline=*/false);
611  writes_done_ops_.set_core_cq_tag(&writes_done_tag_);
612  callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
613  if (GPR_UNLIKELY(corked_write_needed_)) {
614  writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
615  context_->initial_metadata_flags());
616  corked_write_needed_ = false;
617  }
618  if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
619  grpc::internal::MutexLock lock(&start_mu_);
620  if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
621  backlog_.writes_done_ops = true;
622  return;
623  }
624  }
625  writes_done_ops_.FillOps(&call_);
626  }
627 
628  void AddHold(int holds) override {
629  callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed);
630  }
631  void RemoveHold() override { MaybeFinish(/*from_reaction=*/false); }
632 
633  private:
634  friend class ClientCallbackReaderWriterFactory<Request, Response>;
635 
638  grpc::ClientContext* context,
640  : channel_(channel),
641  context_(context),
642  call_(call),
643  reactor_(reactor),
644  start_corked_(context_->initial_metadata_corked_),
645  corked_write_needed_(start_corked_) {
646  this->BindReactor(reactor);
647 
648  // Set up the unchanging parts of the start, read, and write tags and ops.
649  start_tag_.Set(
650  call_.call(),
651  [this](bool ok) {
652  reactor_->OnReadInitialMetadataDone(
653  ok && !reactor_->InternalTrailersOnly(call_.call()));
654  MaybeFinish(/*from_reaction=*/true);
655  },
656  &start_ops_, /*can_inline=*/false);
657  start_ops_.RecvInitialMetadata(context_);
658  start_ops_.set_core_cq_tag(&start_tag_);
659 
660  write_tag_.Set(
661  call_.call(),
662  [this](bool ok) {
663  reactor_->OnWriteDone(ok);
664  MaybeFinish(/*from_reaction=*/true);
665  },
666  &write_ops_, /*can_inline=*/false);
667  write_ops_.set_core_cq_tag(&write_tag_);
668 
669  read_tag_.Set(
670  call_.call(),
671  [this](bool ok) {
672  reactor_->OnReadDone(ok);
673  MaybeFinish(/*from_reaction=*/true);
674  },
675  &read_ops_, /*can_inline=*/false);
676  read_ops_.set_core_cq_tag(&read_tag_);
677 
678  // Also set up the Finish tag and op set.
679  finish_tag_.Set(
680  call_.call(),
681  [this](bool /*ok*/) { MaybeFinish(/*from_reaction=*/true); },
682  &finish_ops_,
683  /*can_inline=*/false);
684  finish_ops_.ClientRecvStatus(context_, &finish_status_);
685  finish_ops_.set_core_cq_tag(&finish_tag_);
686  }
687 
688  // MaybeFinish can be called from reactions or from user-initiated operations
689  // like StartCall or RemoveHold. If this is the last operation or hold on this
690  // object, it will invoke the OnDone reaction. If MaybeFinish was called from
691  // a reaction, it can call OnDone directly. If not, it would need to schedule
692  // OnDone onto an EventEngine thread to avoid the possibility of deadlocking
693  // with any locks in the user code that invoked it.
694  void MaybeFinish(bool from_reaction) {
695  if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(
696  1, std::memory_order_acq_rel) == 1)) {
697  grpc::Status s = std::move(finish_status_);
698  auto* reactor = reactor_;
699  auto* call = call_.call();
700  this->~ClientCallbackReaderWriterImpl();
701  if (GPR_LIKELY(from_reaction)) {
702  grpc_call_unref(call);
703  reactor->OnDone(s);
704  } else {
706  call, [reactor, s = std::move(s)]() { reactor->OnDone(s); });
707  grpc_call_unref(call);
708  }
709  }
710  }
711 
712  grpc::ChannelInterface* const channel_;
713  grpc::ClientContext* const context_;
714  grpc::internal::Call call_;
715  ClientBidiReactor<Request, Response>* const reactor_;
716 
719  start_ops_;
721  const bool start_corked_;
722  bool corked_write_needed_; // no lock needed since only accessed in
723  // Write/WritesDone which cannot be concurrent
724 
727  grpc::Status finish_status_;
728 
732  write_ops_;
734 
737  writes_done_ops_;
739 
741  read_ops_;
743 
744  struct StartCallBacklog {
745  bool write_ops = false;
746  bool writes_done_ops = false;
747  bool read_ops = false;
748  };
749  StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
750 
751  // Minimum of 3 callbacks to pre-register for start ops, StartCall, and finish
752  std::atomic<intptr_t> callbacks_outstanding_{3};
753  std::atomic_bool started_{false};
754  grpc::internal::Mutex start_mu_;
755 };
756 
757 template <class Request, class Response>
758 class ClientCallbackReaderWriterFactory {
759  public:
760  static void Create(grpc::ChannelInterface* channel,
761  const grpc::internal::RpcMethod& method,
762  grpc::ClientContext* context,
764  grpc::internal::Call call =
765  channel->CreateCall(method, context, channel->CallbackCQ());
766 
767  grpc_call_ref(call.call());
771  context, reactor);
772  }
773 };
774 
775 template <class Response>
776 class ClientCallbackReaderImpl : public ClientCallbackReader<Response> {
777  public:
778  // always allocated against a call arena, no memory free required
779  static void operator delete(void* /*ptr*/, std::size_t size) {
780  ABSL_CHECK_EQ(size, sizeof(ClientCallbackReaderImpl));
781  }
782 
783  // This operator should never be called as the memory should be freed as part
784  // of the arena destruction. It only exists to provide a matching operator
785  // delete to the operator new so that some compilers will not complain (see
786  // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
787  // there are no tests catching the compiler warning.
788  static void operator delete(void*, void*) { ABSL_CHECK(false); }
789 
790  void StartCall() override {
791  // This call initiates two batches, plus any backlog, each with a callback
792  // 1. Send initial metadata (unless corked) + recv initial metadata
793  // 2. Any backlog
794  // 3. Recv trailing metadata
795 
796  start_tag_.Set(
797  call_.call(),
798  [this](bool ok) {
799  reactor_->OnReadInitialMetadataDone(
800  ok && !reactor_->InternalTrailersOnly(call_.call()));
801  MaybeFinish(/*from_reaction=*/true);
802  },
803  &start_ops_, /*can_inline=*/false);
804  start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
805  context_->initial_metadata_flags());
806  start_ops_.RecvInitialMetadata(context_);
807  start_ops_.set_core_cq_tag(&start_tag_);
808  start_ops_.FillOps(&call_);
809 
810  // Also set up the read tag so it doesn't have to be set up each time
811  read_tag_.Set(
812  call_.call(),
813  [this](bool ok) {
814  reactor_->OnReadDone(ok);
815  MaybeFinish(/*from_reaction=*/true);
816  },
817  &read_ops_, /*can_inline=*/false);
818  read_ops_.set_core_cq_tag(&read_tag_);
819 
820  {
821  grpc::internal::MutexLock lock(&start_mu_);
822  if (backlog_.read_ops) {
823  read_ops_.FillOps(&call_);
824  }
825  started_.store(true, std::memory_order_release);
826  }
827 
828  finish_tag_.Set(
829  call_.call(),
830  [this](bool /*ok*/) { MaybeFinish(/*from_reaction=*/true); },
831  &finish_ops_, /*can_inline=*/false);
832  finish_ops_.ClientRecvStatus(context_, &finish_status_);
833  finish_ops_.set_core_cq_tag(&finish_tag_);
834  finish_ops_.FillOps(&call_);
835  }
836 
837  void Read(Response* msg) override {
838  read_ops_.RecvMessage(msg);
839  callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
840  if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
841  grpc::internal::MutexLock lock(&start_mu_);
842  if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
843  backlog_.read_ops = true;
844  return;
845  }
846  }
847  read_ops_.FillOps(&call_);
848  }
849 
850  void AddHold(int holds) override {
851  callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed);
852  }
853  void RemoveHold() override { MaybeFinish(/*from_reaction=*/false); }
854 
855  private:
856  friend class ClientCallbackReaderFactory<Response>;
857 
858  template <class Request>
861  grpc::ClientContext* context, Request* request,
863  : context_(context), call_(call), reactor_(reactor) {
864  this->BindReactor(reactor);
865  // TODO(vjpai): don't assert
866  ABSL_CHECK(
867  start_ops_.SendMessagePtr(request, channel->memory_allocator()).ok());
868  start_ops_.ClientSendClose();
869  }
870 
871  // MaybeFinish behaves as in ClientCallbackReaderWriterImpl.
872  void MaybeFinish(bool from_reaction) {
873  if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(
874  1, std::memory_order_acq_rel) == 1)) {
875  grpc::Status s = std::move(finish_status_);
876  auto* reactor = reactor_;
877  auto* call = call_.call();
878  this->~ClientCallbackReaderImpl();
879  if (GPR_LIKELY(from_reaction)) {
880  grpc_call_unref(call);
881  reactor->OnDone(s);
882  } else {
884  call, [reactor, s = std::move(s)]() { reactor->OnDone(s); });
885  grpc_call_unref(call);
886  }
887  }
888  }
889 
890  grpc::ClientContext* const context_;
891  grpc::internal::Call call_;
892  ClientReadReactor<Response>* const reactor_;
893 
898  start_ops_;
900 
903  grpc::Status finish_status_;
904 
906  read_ops_;
908 
909  struct StartCallBacklog {
910  bool read_ops = false;
911  };
912  StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
913 
914  // Minimum of 2 callbacks to pre-register for start and finish
915  std::atomic<intptr_t> callbacks_outstanding_{2};
916  std::atomic_bool started_{false};
917  grpc::internal::Mutex start_mu_;
918 };
919 
920 template <class Response>
921 class ClientCallbackReaderFactory {
922  public:
923  template <class Request>
924  static void Create(grpc::ChannelInterface* channel,
925  const grpc::internal::RpcMethod& method,
926  grpc::ClientContext* context, const Request* request,
927  ClientReadReactor<Response>* reactor) {
928  grpc::internal::Call call =
929  channel->CreateCall(method, context, channel->CallbackCQ());
930 
931  grpc_call_ref(call.call());
932  new (grpc_call_arena_alloc(call.call(),
934  ClientCallbackReaderImpl<Response>(channel, call, context, request,
935  reactor);
936  }
937 };
938 
939 template <class Request>
940 class ClientCallbackWriterImpl : public ClientCallbackWriter<Request> {
941  public:
942  // always allocated against a call arena, no memory free required
943  static void operator delete(void* /*ptr*/, std::size_t size) {
944  ABSL_CHECK_EQ(size, sizeof(ClientCallbackWriterImpl));
945  }
946 
947  // This operator should never be called as the memory should be freed as part
948  // of the arena destruction. It only exists to provide a matching operator
949  // delete to the operator new so that some compilers will not complain (see
950  // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
951  // there are no tests catching the compiler warning.
952  static void operator delete(void*, void*) { ABSL_CHECK(false); }
953 
954  void StartCall() ABSL_LOCKS_EXCLUDED(start_mu_) override {
955  // This call initiates two batches, plus any backlog, each with a callback
956  // 1. Send initial metadata (unless corked) + recv initial metadata
957  // 2. Any backlog
958  // 3. Recv trailing metadata
959 
960  if (!start_corked_) {
961  start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
962  context_->initial_metadata_flags());
963  }
964  start_ops_.FillOps(&call_);
965 
966  {
967  grpc::internal::MutexLock lock(&start_mu_);
968 
969  if (backlog_.write_ops) {
970  write_ops_.FillOps(&call_);
971  }
972  if (backlog_.writes_done_ops) {
973  writes_done_ops_.FillOps(&call_);
974  }
975  finish_ops_.FillOps(&call_);
976  // The last thing in this critical section is to set started_ so that it
977  // can be used lock-free as well.
978  started_.store(true, std::memory_order_release);
979  }
980  // MaybeFinish outside the lock to make sure that destruction of this object
981  // doesn't take place while holding the lock (which would cause the lock to
982  // be released after destruction)
983  this->MaybeFinish(/*from_reaction=*/false);
984  }
985 
986  void Write(const Request* msg, grpc::WriteOptions options)
987  ABSL_LOCKS_EXCLUDED(start_mu_) override {
988  if (GPR_UNLIKELY(options.is_last_message())) {
989  options.set_buffer_hint();
990  write_ops_.ClientSendClose();
991  }
992 
993  // TODO(vjpai): don't assert
994  ABSL_CHECK(
995  write_ops_.SendMessagePtr(msg, options, channel_->memory_allocator())
996  .ok());
997  callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
998 
999  if (GPR_UNLIKELY(corked_write_needed_)) {
1000  write_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
1001  context_->initial_metadata_flags());
1002  corked_write_needed_ = false;
1003  }
1004 
1005  if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
1006  grpc::internal::MutexLock lock(&start_mu_);
1007  if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
1008  backlog_.write_ops = true;
1009  return;
1010  }
1011  }
1012  write_ops_.FillOps(&call_);
1013  }
1014 
1015  void WritesDone() ABSL_LOCKS_EXCLUDED(start_mu_) override {
1016  writes_done_ops_.ClientSendClose();
1017  writes_done_tag_.Set(
1018  call_.call(),
1019  [this](bool ok) {
1020  reactor_->OnWritesDoneDone(ok);
1021  MaybeFinish(/*from_reaction=*/true);
1022  },
1023  &writes_done_ops_, /*can_inline=*/false);
1024  writes_done_ops_.set_core_cq_tag(&writes_done_tag_);
1025  callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
1026 
1027  if (GPR_UNLIKELY(corked_write_needed_)) {
1028  writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
1029  context_->initial_metadata_flags());
1030  corked_write_needed_ = false;
1031  }
1032 
1033  if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
1034  grpc::internal::MutexLock lock(&start_mu_);
1035  if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
1036  backlog_.writes_done_ops = true;
1037  return;
1038  }
1039  }
1040  writes_done_ops_.FillOps(&call_);
1041  }
1042 
1043  void AddHold(int holds) override {
1044  callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed);
1045  }
1046  void RemoveHold() override { MaybeFinish(/*from_reaction=*/false); }
1047 
1048  private:
1049  friend class ClientCallbackWriterFactory<Request>;
1050 
1051  template <class Response>
1053  grpc::internal::Call call,
1054  grpc::ClientContext* context, Response* response,
1055  ClientWriteReactor<Request>* reactor)
1056  : channel_(channel),
1057  context_(context),
1058  call_(call),
1059  reactor_(reactor),
1060  start_corked_(context_->initial_metadata_corked_),
1061  corked_write_needed_(start_corked_) {
1062  this->BindReactor(reactor);
1063 
1064  // Set up the unchanging parts of the start and write tags and ops.
1065  start_tag_.Set(
1066  call_.call(),
1067  [this](bool ok) {
1068  reactor_->OnReadInitialMetadataDone(
1069  ok && !reactor_->InternalTrailersOnly(call_.call()));
1070  MaybeFinish(/*from_reaction=*/true);
1071  },
1072  &start_ops_, /*can_inline=*/false);
1073  start_ops_.RecvInitialMetadata(context_);
1074  start_ops_.set_core_cq_tag(&start_tag_);
1075 
1076  write_tag_.Set(
1077  call_.call(),
1078  [this](bool ok) {
1079  reactor_->OnWriteDone(ok);
1080  MaybeFinish(/*from_reaction=*/true);
1081  },
1082  &write_ops_, /*can_inline=*/false);
1083  write_ops_.set_core_cq_tag(&write_tag_);
1084 
1085  // Also set up the Finish tag and op set.
1086  finish_ops_.RecvMessage(response);
1087  finish_ops_.AllowNoMessage();
1088  finish_tag_.Set(
1089  call_.call(),
1090  [this](bool /*ok*/) { MaybeFinish(/*from_reaction=*/true); },
1091  &finish_ops_,
1092  /*can_inline=*/false);
1093  finish_ops_.ClientRecvStatus(context_, &finish_status_);
1094  finish_ops_.set_core_cq_tag(&finish_tag_);
1095  }
1096 
1097  // MaybeFinish behaves as in ClientCallbackReaderWriterImpl.
1098  void MaybeFinish(bool from_reaction) {
1099  if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(
1100  1, std::memory_order_acq_rel) == 1)) {
1101  grpc::Status s = std::move(finish_status_);
1102  auto* reactor = reactor_;
1103  auto* call = call_.call();
1104  this->~ClientCallbackWriterImpl();
1105  if (GPR_LIKELY(from_reaction)) {
1106  grpc_call_unref(call);
1107  reactor->OnDone(s);
1108  } else {
1110  call, [reactor, s = std::move(s)]() { reactor->OnDone(s); });
1111  grpc_call_unref(call);
1112  }
1113  }
1114  }
1115 
1116  grpc::ChannelInterface* const channel_;
1117  grpc::ClientContext* const context_;
1118  grpc::internal::Call call_;
1119  ClientWriteReactor<Request>* const reactor_;
1120 
1123  start_ops_;
1125  const bool start_corked_;
1126  bool corked_write_needed_; // no lock needed since only accessed in
1127  // Write/WritesDone which cannot be concurrent
1128 
1131  finish_ops_;
1133  grpc::Status finish_status_;
1134 
1138  write_ops_;
1140 
1143  writes_done_ops_;
1144  grpc::internal::CallbackWithSuccessTag writes_done_tag_;
1145 
1146  struct StartCallBacklog {
1147  bool write_ops = false;
1148  bool writes_done_ops = false;
1149  };
1150  StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
1151 
1152  // Minimum of 3 callbacks to pre-register for start ops, StartCall, and finish
1153  std::atomic<intptr_t> callbacks_outstanding_{3};
1154  std::atomic_bool started_{false};
1155  grpc::internal::Mutex start_mu_;
1156 };
1157 
1158 template <class Request>
1159 class ClientCallbackWriterFactory {
1160  public:
1161  template <class Response>
1162  static void Create(grpc::ChannelInterface* channel,
1163  const grpc::internal::RpcMethod& method,
1164  grpc::ClientContext* context, Response* response,
1165  ClientWriteReactor<Request>* reactor) {
1166  grpc::internal::Call call =
1167  channel->CreateCall(method, context, channel->CallbackCQ());
1168 
1169  grpc_call_ref(call.call());
1170  new (grpc_call_arena_alloc(call.call(),
1172  ClientCallbackWriterImpl<Request>(channel, call, context, response,
1173  reactor);
1174  }
1175 };
1176 
1178  public:
1179  // always allocated against a call arena, no memory free required
1180  static void operator delete(void* /*ptr*/, std::size_t size) {
1181  ABSL_CHECK_EQ(size, sizeof(ClientCallbackUnaryImpl));
1182  }
1183 
1184  // This operator should never be called as the memory should be freed as part
1185  // of the arena destruction. It only exists to provide a matching operator
1186  // delete to the operator new so that some compilers will not complain (see
1187  // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
1188  // there are no tests catching the compiler warning.
1189  static void operator delete(void*, void*) { ABSL_CHECK(false); }
1190 
1191  void StartCall() override {
1192  // This call initiates two batches, each with a callback
1193  // 1. Send initial metadata + write + writes done + recv initial metadata
1194  // 2. Read message, recv trailing metadata
1195 
1196  start_tag_.Set(
1197  call_.call(),
1198  [this](bool ok) {
1199  reactor_->OnReadInitialMetadataDone(
1200  ok && !reactor_->InternalTrailersOnly(call_.call()));
1201  MaybeFinish();
1202  },
1203  &start_ops_, /*can_inline=*/false);
1204  start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
1205  context_->initial_metadata_flags());
1206  start_ops_.RecvInitialMetadata(context_);
1207  start_ops_.set_core_cq_tag(&start_tag_);
1208  start_ops_.FillOps(&call_);
1209 
1210  finish_tag_.Set(
1211  call_.call(), [this](bool /*ok*/) { MaybeFinish(); }, &finish_ops_,
1212  /*can_inline=*/false);
1213  finish_ops_.ClientRecvStatus(context_, &finish_status_);
1214  finish_ops_.set_core_cq_tag(&finish_tag_);
1215  finish_ops_.FillOps(&call_);
1216  }
1217 
1218  private:
1220 
1221  template <class Request, class Response>
1223  grpc::internal::Call call,
1224  grpc::ClientContext* context, Request* request,
1225  Response* response, ClientUnaryReactor* reactor)
1226  : context_(context), call_(call), reactor_(reactor) {
1227  this->BindReactor(reactor);
1228 
1229  // TODO(vjpai): don't assert
1230  ABSL_CHECK(
1231  start_ops_.SendMessagePtr(request, channel->memory_allocator()).ok());
1232  start_ops_.ClientSendClose();
1233  finish_ops_.RecvMessage(response);
1234  finish_ops_.AllowNoMessage();
1235  }
1236 
1237  // In the unary case, MaybeFinish is only ever invoked from a
1238  // library-initiated reaction, so it will just directly call OnDone if this is
1239  // the last reaction for this RPC.
1240  void MaybeFinish() {
1241  if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(
1242  1, std::memory_order_acq_rel) == 1)) {
1243  grpc::Status s = std::move(finish_status_);
1244  auto* reactor = reactor_;
1245  auto* call = call_.call();
1246  this->~ClientCallbackUnaryImpl();
1247  grpc_call_unref(call);
1248  reactor->OnDone(s);
1249  }
1250  }
1251 
1252  grpc::ClientContext* const context_;
1253  grpc::internal::Call call_;
1254  ClientUnaryReactor* const reactor_;
1255 
1260  start_ops_;
1262 
1265  finish_ops_;
1267  grpc::Status finish_status_;
1268 
1269  // This call will have 2 callbacks: start and finish
1270  std::atomic<intptr_t> callbacks_outstanding_{2};
1271 };
1272 
1274  public:
1275  template <class Request, class Response, class BaseRequest = Request,
1276  class BaseResponse = Response>
1277  static void Create(grpc::ChannelInterface* channel,
1278  const grpc::internal::RpcMethod& method,
1279  grpc::ClientContext* context, const Request* request,
1280  Response* response, ClientUnaryReactor* reactor) {
1281  grpc::internal::Call call =
1282  channel->CreateCall(method, context, channel->CallbackCQ());
1283 
1284  grpc_call_ref(call.call());
1285 
1286  new (grpc_call_arena_alloc(call.call(), sizeof(ClientCallbackUnaryImpl)))
1287  ClientCallbackUnaryImpl(channel, call, context,
1288  static_cast<const BaseRequest*>(request),
1289  static_cast<BaseResponse*>(response), reactor);
1290  }
1291 };
1292 
1293 } // namespace internal
1294 
1295 namespace experimental {
1296 namespace internal {
1298  public:
1299  // always allocated against a call arena, no memory free required
1300  static void operator delete(void* /*ptr*/, std::size_t size) {
1301  ABSL_CHECK_EQ(size, sizeof(ClientCallbackSessionImpl));
1302  }
1303 
1304  // This operator should never be called as the memory should be freed as part
1305  // of the arena destruction. It only exists to provide a matching operator
1306  // delete to the operator new so that some compilers will not complain (see
1307  // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
1308  // there are no tests catching the compiler warning.
1309  static void operator delete(void*, void*) { ABSL_CHECK(false); }
1310 
1311  void StartCall() override {
1312  send_tag_.Set(
1313  call_.call(), [this](bool ok) { OnSendDone(ok); }, &send_ops_,
1314  /*can_inline=*/false);
1315 
1316  send_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
1317  context_->initial_metadata_flags());
1318  send_ops_.set_core_cq_tag(&send_tag_);
1319  send_ops_.FillOps(&call_);
1320 
1321  // Also start the receive status op
1322  meta_tag_.Set(
1323  call_.call(), [this](bool ok) { OnRecvInitialMetadataDone(ok); },
1324  &meta_ops_,
1325  /*can_inline=*/false);
1326  meta_ops_.RecvInitialMetadata(context_);
1327  meta_ops_.set_core_cq_tag(&meta_tag_);
1328  meta_ops_.FillOps(&call_);
1329  finish_tag_.Set(
1330  call_.call(), [this](bool ok) { OnFinishDone(ok); }, &finish_ops_,
1331  /*can_inline=*/false);
1332  finish_ops_.ClientRecvStatus(context_, &status_);
1333  finish_ops_.set_core_cq_tag(&finish_tag_);
1334  finish_ops_.FillOps(&call_);
1335  }
1336 
1337  private:
1339 
1340  template <class Request>
1342  grpc::internal::Call call,
1343  grpc::ClientContext* context,
1344  const Request* request,
1346  : context_(context), call_(call), reactor_(reactor) {
1347  this->BindReactor(reactor);
1348  ABSL_CHECK(
1349  send_ops_.SendMessagePtr(request, channel->memory_allocator()).ok());
1350  }
1351 
1352  void OnSendDone(bool ok) {
1353  if (ok) {
1354  reactor_->OnSessionReady(call_);
1355  }
1356  MaybeFinish();
1357  }
1358 
1359  void OnRecvInitialMetadataDone(bool ok) {
1360  reactor_->OnSessionAcknowledged(
1361  ok && !reactor_->InternalTrailersOnly(call_.call()));
1362  MaybeFinish();
1363  }
1364 
1365  void OnFinishDone(bool /*ok*/) { MaybeFinish(); }
1366 
1367  void MaybeFinish() {
1368  if (--ops_outstanding_ == 0) {
1369  grpc::Status s = std::move(status_);
1370  auto* reactor = reactor_;
1371  auto* call = call_.call();
1372  this->~ClientCallbackSessionImpl();
1374  [reactor, s]() { reactor->OnDone(s); });
1375  grpc_call_unref(call);
1376  }
1377  }
1378 
1379  grpc::ClientContext* context_;
1380  grpc::internal::Call call_;
1384  send_ops_;
1387  meta_ops_;
1391  grpc::Status status_;
1392  std::atomic<int> ops_outstanding_{3};
1393 };
1394 
1395 // ClientCallbackSessionFactory is an experimental API for creating a
1396 // ClientCallbackSession. It is not part of the public API and may be removed or
1397 // changed without notice.
1399  private:
1400  template <class Request, class BaseRequest = Request>
1401  static void Create(grpc::ChannelInterface* channel,
1402  const grpc::internal::RpcMethod& method,
1403  grpc::ClientContext* context, const Request* request,
1405  grpc::internal::Call call =
1406  channel->CreateCall(method, context, channel->CallbackCQ());
1407 
1408  grpc_call_ref(call.call());
1409 
1411  ClientCallbackSessionImpl(channel, call, context,
1412  static_cast<const BaseRequest*>(request),
1413  reactor);
1414  }
1415 
1416  template <class RequestType, class ResponseType>
1418 };
1419 } // namespace internal
1420 } // namespace experimental
1421 } // namespace grpc
1422 
1423 #endif // GRPCPP_SUPPORT_CLIENT_CALLBACK_H
grpc::internal::ClientCallbackUnaryImpl
Definition: client_callback.h:1177
grpc::internal::CallbackWithSuccessTag
CallbackWithSuccessTag can be reused multiple times, and will be used in this fashion for streaming o...
Definition: callback_common.h:153
grpc::ClientReadReactor::OnReadInitialMetadataDone
virtual void OnReadInitialMetadataDone(bool)
Definition: client_callback.h:405
grpc::ClientWriteReactor::OnReadInitialMetadataDone
virtual void OnReadInitialMetadataDone(bool)
Definition: client_callback.h:437
grpc::ClientWriteReactor::StartWritesDone
void StartWritesDone()
Definition: client_callback.h:427
grpc::internal::CallOpRecvInitialMetadata
Definition: call_op_set.h:723
grpc::ClientCallbackWriter::~ClientCallbackWriter
virtual ~ClientCallbackWriter()
Definition: client_callback.h:200
grpc::internal::ClientCallbackReaderWriterImpl::Read
void Read(Response *msg) override
Definition: client_callback.h:562
grpc::internal::ClientCallbackWriterImpl::AddHold
void AddHold(int holds) override
Definition: client_callback.h:1043
grpc::internal::ClientCallbackReaderWriterImpl::StartCall
void StartCall() ABSL_LOCKS_EXCLUDED(start_mu_) override
Definition: client_callback.h:526
grpc::internal::CallbackUnaryCallImpl::CallbackUnaryCallImpl
CallbackUnaryCallImpl(grpc::ChannelInterface *channel, const grpc::internal::RpcMethod &method, grpc::ClientContext *context, const InputMessage *request, OutputMessage *result, std::function< void(grpc::Status)> &&on_completion)
Definition: client_callback.h:73
grpc::internal::CallOpClientSendClose
Definition: call_op_set.h:621
grpc::ClientBidiReactor::StartWrite
void StartWrite(const Request *req)
Initiate a write operation (or post it for later initiation if StartCall has not yet been invoked).
Definition: client_callback.h:276
grpc_call_arena_alloc
GRPCAPI void * grpc_call_arena_alloc(grpc_call *call, size_t size)
Allocate memory in the grpc_call arena: this memory is automatically discarded at call completion.
grpc::internal::CallOpGenericRecvMessage
Definition: call_op_set.h:528
grpc::ClientBidiReactor::AddHold
void AddHold()
Holds are needed if (and only if) this stream has operations that take place on it after StartCall bu...
Definition: client_callback.h:330
grpc::internal::ClientCallbackReaderWriterImpl
Definition: client_context.h:72
grpc::ClientReadReactor::OnReadDone
virtual void OnReadDone(bool)
Definition: client_callback.h:406
grpc
An Alarm posts the user-provided tag to its associated completion queue or invokes the user-provided ...
Definition: alarm.h:33
grpc::internal::CallOpSet
Primary implementation of CallOpSetInterface.
Definition: completion_queue.h:97
grpc::internal::ClientCallbackReaderWriterImpl::Write
void Write(const Request *msg, grpc::WriteOptions options) ABSL_LOCKS_EXCLUDED(start_mu_) override
Definition: client_callback.h:575
grpc::internal::ClientCallbackReaderImpl::RemoveHold
void RemoveHold() override
Definition: client_callback.h:853
grpc::internal::CallOpSendMessage
Definition: call_op_set.h:287
grpc::WriteOptions::set_last_message
WriteOptions & set_last_message()
last-message bit: indicates this is the last message in a stream client-side: makes Write the equival...
Definition: call_op_set.h:156
grpc::ClientUnaryReactor
ClientUnaryReactor is a reactor-style interface for a unary RPC.
Definition: client_callback.h:459
grpc::ClientCallbackReaderWriter::Read
virtual void Read(Response *resp)=0
grpc::internal::ClientCallbackReaderWriterFactory::Create
static void Create(grpc::ChannelInterface *channel, const grpc::internal::RpcMethod &method, grpc::ClientContext *context, ClientBidiReactor< Request, Response > *reactor)
Definition: client_callback.h:760
grpc::ClientWriteReactor::StartWrite
void StartWrite(const Request *req, grpc::WriteOptions options)
Definition: client_callback.h:421
grpc::internal::CallOpSet::FillOps
void FillOps(Call *call) override
Definition: call_op_set.h:895
grpc::ClientWriteReactor::StartCall
void StartCall()
Definition: client_callback.h:419
grpc::ClientWriteReactor::OnDone
void OnDone(const grpc::Status &) override
Definition: client_callback.h:436
grpc::internal::ClientReactor::OnDone
virtual void OnDone(const grpc::Status &)=0
Called by the library when all operations associated with this RPC have completed and all Holds have ...
grpc::internal::ClientCallbackReaderWriterImpl::RemoveHold
void RemoveHold() override
Definition: client_callback.h:631
grpc::ClientReadReactor::OnDone
void OnDone(const grpc::Status &) override
Definition: client_callback.h:404
grpc::experimental::ClientCallbackSession
Definition: client_callback.h:228
grpc::internal::Call
Straightforward wrapping of the C call object.
Definition: call.h:34
grpc::ClientCallbackReaderWriter::WritesDone
virtual void WritesDone()=0
grpc::internal::ClientCallbackWriterImpl::RemoveHold
void RemoveHold() override
Definition: client_callback.h:1046
status.h
grpc::internal::CallOpSendInitialMetadata
Definition: call_op_set.h:217
grpc::experimental::ClientCallbackSession::StartCall
virtual void StartCall()=0
grpc::internal::ClientCallbackWriterFactory::Create
static void Create(grpc::ChannelInterface *channel, const grpc::internal::RpcMethod &method, grpc::ClientContext *context, Response *response, ClientWriteReactor< Request > *reactor)
Definition: client_callback.h:1162
grpc::ClientBidiReactor::OnReadInitialMetadataDone
virtual void OnReadInitialMetadataDone(bool)
Notifies the application that a read of initial metadata from the server is done.
Definition: client_callback.h:357
grpc::internal::CallbackWithStatusTag
Definition: callback_common.h:74
grpc::ClientCallbackReaderWriter::BindReactor
void BindReactor(ClientBidiReactor< Request, Response > *reactor)
Definition: client_callback.h:177
grpc::internal::CallbackUnaryCall
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)
Perform a callback-based unary call.
Definition: client_callback.h:57
grpc::Status::ok
bool ok() const
Is the status OK?
Definition: status.h:124
grpc::ClientCallbackUnary::BindReactor
void BindReactor(ClientUnaryReactor *reactor)
Definition: client_callback.h:472
grpc_call_ref
GRPCAPI void grpc_call_ref(grpc_call *call)
Ref a call.
grpc::ClientBidiReactor::StartRead
void StartRead(Response *resp)
Initiate a read operation (or post it for later initiation if StartCall has not yet been invoked).
Definition: client_callback.h:268
grpc::ClientReadReactor::AddMultipleHolds
void AddMultipleHolds(int holds)
Definition: client_callback.h:398
grpc::internal::ClientCallbackWriterImpl::StartCall
void StartCall() ABSL_LOCKS_EXCLUDED(start_mu_) override
Definition: client_callback.h:954
grpc::internal::ClientCallbackWriterImpl::Write
void Write(const Request *msg, grpc::WriteOptions options) ABSL_LOCKS_EXCLUDED(start_mu_) override
Definition: client_callback.h:986
grpc::ClientBidiReactor::StartWrite
void StartWrite(const Request *req, grpc::WriteOptions options)
Initiate/post a write operation with specified options.
Definition: client_callback.h:284
grpc::ClientBidiReactor::OnDone
void OnDone(const grpc::Status &) override
Notifies the application that all operations associated with this RPC have completed and all Holds ha...
Definition: client_callback.h:348
grpc::experimental::ClientSessionReactor::StartCall
void StartCall()
Definition: client_callback.h:482
grpc::internal::ClientReactor::~ClientReactor
virtual ~ClientReactor()=default
grpc::ClientCallbackUnary::StartCall
virtual void StartCall()=0
grpc::ClientCallbackReaderWriter::AddHold
virtual void AddHold(int holds)=0
grpc::ClientBidiReactor::OnReadDone
virtual void OnReadDone(bool)
Notifies the application that a StartRead operation completed.
Definition: client_callback.h:363
grpc::Status
Did it work? If it didn't, why?
Definition: status.h:34
GPR_UNLIKELY
#define GPR_UNLIKELY(x)
Definition: port_platform.h:861
grpc::ClientCallbackWriter::WritesDone
virtual void WritesDone()=0
grpc_call_unref
GRPCAPI void grpc_call_unref(grpc_call *call)
Unref a call.
grpc::internal::ClientCallbackWriterFactory
Definition: channel_interface.h:52
grpc::ClientReadReactor::StartCall
void StartCall()
Definition: client_callback.h:394
callback_common.h
grpc::ClientBidiReactor::OnWriteDone
virtual void OnWriteDone(bool)
Notifies the application that a StartWrite or StartWriteLast operation completed.
Definition: client_callback.h:370
grpc::ClientContext
A ClientContext allows the person implementing a service client to:
Definition: client_context.h:203
grpc::internal::ClientCallbackReaderImpl::StartCall
void StartCall() override
Definition: client_callback.h:790
grpc::internal::ClientCallbackReaderWriterFactory
Definition: channel_interface.h:48
grpc.h
grpc_call
struct grpc_call grpc_call
A Call represents an RPC.
Definition: grpc_types.h:68
grpc::internal::CallbackUnaryCallImpl
Definition: client_context.h:69
grpc::ClientUnaryReactor::OnReadInitialMetadataDone
virtual void OnReadInitialMetadataDone(bool)
Definition: client_callback.h:463
grpc::ClientCallbackWriter::BindReactor
void BindReactor(ClientWriteReactor< Request > *reactor)
Definition: client_callback.h:213
grpc::ClientCallbackReader::RemoveHold
virtual void RemoveHold()=0
grpc::ClientCallbackReaderWriter
Definition: client_callback.h:166
grpc::ClientBidiReactor::StartWritesDone
void StartWritesDone()
Indicate that the RPC will have no more write operations.
Definition: client_callback.h:306
grpc::ClientCallbackReader::Read
virtual void Read(Response *resp)=0
grpc::ClientReadReactor::StartRead
void StartRead(Response *resp)
Definition: client_callback.h:395
channel_interface.h
grpc::ChannelInterface
Codegen interface for grpc::Channel.
Definition: channel_interface.h:79
grpc::experimental::ClientSessionReactor::OnSessionReady
virtual void OnSessionReady(grpc::internal::Call call)=0
grpc::internal::ClientReactor
Definition: client_callback.h:120
grpc::experimental::internal::ClientCallbackSessionImpl::StartCall
void StartCall() override
Definition: client_callback.h:1311
grpc::internal::ClientCallbackUnaryFactory
Definition: client_callback.h:1273
grpc::internal::ClientCallbackReaderImpl::Read
void Read(Response *msg) override
Definition: client_callback.h:837
grpc::ClientWriteReactor::StartWriteLast
void StartWriteLast(const Request *req, grpc::WriteOptions options)
Definition: client_callback.h:424
grpc::internal::ClientCallbackWriterImpl
Definition: client_context.h:76
grpc::ClientCallbackReaderWriter::Write
virtual void Write(const Request *req, grpc::WriteOptions options)=0
grpc::ClientWriteReactor
ClientWriteReactor is the interface for a client-streaming RPC.
Definition: client_callback.h:159
grpc_call_run_in_event_engine
void grpc_call_run_in_event_engine(const grpc_call *call, absl::AnyInvocable< void()> cb)
grpc::experimental::ClientSessionReactor
ClientSessionReactor is a reactor-style interface for a session RPC.
Definition: client_callback.h:480
grpc::ClientCallbackUnary
Definition: client_callback.h:218
grpc::ClientBidiReactor::AddMultipleHolds
void AddMultipleHolds(int holds)
Definition: client_callback.h:331
grpc::experimental::ClientCallbackSession::~ClientCallbackSession
virtual ~ClientCallbackSession()
Definition: client_callback.h:230
grpc::ClientReadReactor::RemoveHold
void RemoveHold()
Definition: client_callback.h:402
grpc::internal::ClientCallbackUnaryFactory::Create
static void Create(grpc::ChannelInterface *channel, const grpc::internal::RpcMethod &method, grpc::ClientContext *context, const Request *request, Response *response, ClientUnaryReactor *reactor)
Definition: client_callback.h:1277
grpc::ClientBidiReactor::StartWriteLast
void StartWriteLast(const Request *req, grpc::WriteOptions options)
Initiate/post a write operation with specified options and an indication that this is the last write ...
Definition: client_callback.h:297
grpc::WriteOptions
Per-message write options.
Definition: call_op_set.h:79
grpc::ClientCallbackWriter::RemoveHold
virtual void RemoveHold()=0
grpc::ClientBidiReactor::OnWritesDoneDone
virtual void OnWritesDoneDone(bool)
Notifies the application that a StartWritesDone operation completed.
Definition: client_callback.h:379
grpc::internal::ClientCallbackWriterImpl::WritesDone
void WritesDone() ABSL_LOCKS_EXCLUDED(start_mu_) override
Definition: client_callback.h:1015
grpc::ClientCallbackReader::~ClientCallbackReader
virtual ~ClientCallbackReader()
Definition: client_callback.h:185
grpc::experimental::GenericStubSession
Definition: client_callback.h:147
grpc::internal::CallbackWithSuccessTag::Set
void Set(grpc_call *call, std::function< void(bool)> f, CompletionQueueTag *ops, bool can_inline)
Definition: callback_common.h:180
grpc::internal::ClientCallbackReaderImpl::AddHold
void AddHold(int holds) override
Definition: client_callback.h:850
grpc::ClientCallbackReader::BindReactor
void BindReactor(ClientReadReactor< Response > *reactor)
Definition: client_callback.h:192
grpc::internal::MutexLock
Definition: sync.h:80
grpc::experimental::ClientSessionReactor::OnGracefulShutdown
virtual void OnGracefulShutdown()
Definition: client_callback.h:486
grpc::ClientCallbackWriter
Definition: client_callback.h:198
grpc::ClientCallbackWriter::AddHold
virtual void AddHold(int holds)=0
grpc::ClientBidiReactor::RemoveHold
void RemoveHold()
Definition: client_callback.h:335
grpc::ClientCallbackReaderWriter::~ClientCallbackReaderWriter
virtual ~ClientCallbackReaderWriter()
Definition: client_callback.h:168
grpc::ClientCallbackReaderWriter::RemoveHold
virtual void RemoveHold()=0
grpc::ClientCallbackWriter::Write
void Write(const Request *req)
Definition: client_callback.h:202
config.h
grpc::ClientCallbackReader::StartCall
virtual void StartCall()=0
call.h
grpc::ClientWriteReactor::AddHold
void AddHold()
Definition: client_callback.h:429
grpc::experimental::ClientCallbackSession::BindReactor
void BindReactor(ClientSessionReactor *reactor)
Definition: client_callback.h:495
grpc::internal::Call::call
grpc_call * call() const
Definition: call.h:55
grpc::ClientUnaryReactor::StartCall
void StartCall()
Definition: client_callback.h:461
grpc::ClientCallbackReaderWriter::StartCall
virtual void StartCall()=0
call_op_set.h
call.h
grpc::internal::CallOpClientRecvStatus
Definition: call_op_set.h:771
grpc::CompletionQueue
A thin wrapper around grpc_completion_queue (see src/core/lib/surface/completion_queue....
Definition: completion_queue.h:104
grpc::ClientBidiReactor
ClientBidiReactor is the interface for a bidirectional streaming RPC.
Definition: client_callback.h:155
grpc::internal::ClientCallbackReaderFactory
Definition: channel_interface.h:50
grpc::experimental::internal::ClientCallbackSessionImpl
Definition: client_callback.h:1297
grpc::experimental::internal::ClientCallbackSessionFactory
Definition: client_callback.h:1398
grpc::ClientCallbackWriter::WriteLast
void WriteLast(const Request *req, grpc::WriteOptions options)
Definition: client_callback.h:204
grpc::internal::ClientCallbackReaderImpl
Definition: client_context.h:74
grpc::internal::ClientReactor::InternalTrailersOnly
virtual bool InternalTrailersOnly(const grpc_call *call) const
InternalTrailersOnly is not part of the API and is not meant to be overridden.
grpc::ClientCallbackWriter::StartCall
virtual void StartCall()=0
grpc::internal::ClientCallbackUnaryImpl::StartCall
void StartCall() override
Definition: client_callback.h:1191
grpc::ClientWriteReactor::StartWrite
void StartWrite(const Request *req)
Definition: client_callback.h:420
grpc::experimental::ClientSessionReactor::OnSessionAcknowledged
virtual void OnSessionAcknowledged(bool)
Definition: client_callback.h:485
grpc::ClientBidiReactor::StartCall
void StartCall()
Activate the RPC and initiate any reads or writes that have been Start'ed before this call.
Definition: client_callback.h:261
grpc::ClientWriteReactor::OnWriteDone
virtual void OnWriteDone(bool)
Definition: client_callback.h:438
grpc::internal::CallOpRecvMessage
Definition: call_op_set.h:427
grpc::internal::Mutex
Definition: sync.h:57
grpc::internal::RpcMethod
Descriptor of an RPC method.
Definition: rpc_method.h:29
grpc::ClientCallbackReader::AddHold
virtual void AddHold(int holds)=0
grpc::ClientWriteReactor::AddMultipleHolds
void AddMultipleHolds(int holds)
Definition: client_callback.h:430
grpc::ClientCallbackReader
Definition: client_callback.h:183
GPR_LIKELY
#define GPR_LIKELY(x)
Definition: port_platform.h:860
grpc::ClientCallbackUnary::~ClientCallbackUnary
virtual ~ClientCallbackUnary()
Definition: client_callback.h:220
grpc::internal::CallOpSet::set_core_cq_tag
void set_core_cq_tag(void *core_cq_tag)
set_core_cq_tag is used to provide a different core CQ tag than "this".
Definition: call_op_set.h:947
sync.h
grpc::internal::ClientCallbackReaderWriterImpl::AddHold
void AddHold(int holds) override
Definition: client_callback.h:628
grpc::experimental::ClientSessionReactor::OnDone
void OnDone(const grpc::Status &) override
Called by the library when all operations associated with this RPC have completed and all Holds have ...
Definition: client_callback.h:483
grpc::ClientWriteReactor::RemoveHold
void RemoveHold()
Definition: client_callback.h:434
grpc::ClientReadReactor
ClientReadReactor is the interface for a server-streaming RPC.
Definition: client_callback.h:157
grpc::internal::ClientCallbackReaderWriterImpl::WritesDone
void WritesDone() ABSL_LOCKS_EXCLUDED(start_mu_) override
Definition: client_callback.h:602
grpc::ClientReadReactor::AddHold
void AddHold()
Definition: client_callback.h:397
grpc::ClientUnaryReactor::OnDone
void OnDone(const grpc::Status &) override
Called by the library when all operations associated with this RPC have completed and all Holds have ...
Definition: client_callback.h:462
grpc::ChannelInterface::memory_allocator
virtual grpc_event_engine::experimental::MemoryAllocator * memory_allocator() const
Definition: channel_interface.h:113
grpc::internal::ClientCallbackReaderFactory::Create
static void Create(grpc::ChannelInterface *channel, const grpc::internal::RpcMethod &method, grpc::ClientContext *context, const Request *request, ClientReadReactor< Response > *reactor)
Definition: client_callback.h:924
grpc::ClientWriteReactor::OnWritesDoneDone
virtual void OnWritesDoneDone(bool)
Definition: client_callback.h:439