GRPC C++  1.64.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 <atomic>
23 #include <functional>
24 
25 #include "absl/log/check.h"
26 
27 #include <grpc/grpc.h>
28 #include <grpc/impl/call.h>
29 #include <grpc/support/log.h>
30 #include <grpcpp/impl/call.h>
32 #include <grpcpp/impl/sync.h>
34 #include <grpcpp/support/config.h>
35 #include <grpcpp/support/status.h>
36 
37 namespace grpc {
38 class Channel;
39 class ClientContext;
40 
41 namespace internal {
42 class RpcMethod;
43 
50 template <class InputMessage, class OutputMessage,
51  class BaseInputMessage = InputMessage,
52  class BaseOutputMessage = OutputMessage>
54  const grpc::internal::RpcMethod& method,
55  grpc::ClientContext* context,
56  const InputMessage* request, OutputMessage* result,
57  std::function<void(grpc::Status)> on_completion) {
58  static_assert(std::is_base_of<BaseInputMessage, InputMessage>::value,
59  "Invalid input message specification");
60  static_assert(std::is_base_of<BaseOutputMessage, OutputMessage>::value,
61  "Invalid output message specification");
63  channel, method, context, request, result, on_completion);
64 }
65 
66 template <class InputMessage, class OutputMessage>
67 class CallbackUnaryCallImpl {
68  public:
70  const grpc::internal::RpcMethod& method,
71  grpc::ClientContext* context,
72  const InputMessage* request, OutputMessage* result,
73  std::function<void(grpc::Status)> on_completion) {
74  grpc::CompletionQueue* cq = channel->CallbackCQ();
75  CHECK_NE(cq, nullptr);
76  grpc::internal::Call call(channel->CreateCall(method, context, cq));
77 
78  using FullCallOpSet = grpc::internal::CallOpSet<
85 
86  struct OpSetAndTag {
87  FullCallOpSet opset;
89  };
90  const size_t alloc_sz = sizeof(OpSetAndTag);
91  auto* const alloced =
92  static_cast<OpSetAndTag*>(grpc_call_arena_alloc(call.call(), alloc_sz));
93  auto* ops = new (&alloced->opset) FullCallOpSet;
94  auto* tag = new (&alloced->tag)
95  grpc::internal::CallbackWithStatusTag(call.call(), on_completion, ops);
96 
97  // TODO(vjpai): Unify code with sync API as much as possible
98  grpc::Status s = ops->SendMessagePtr(request);
99  if (!s.ok()) {
100  tag->force_run(s);
101  return;
102  }
103  ops->SendInitialMetadata(&context->send_initial_metadata_,
104  context->initial_metadata_flags());
105  ops->RecvInitialMetadata(context);
106  ops->RecvMessage(result);
107  ops->AllowNoMessage();
108  ops->ClientSendClose();
109  ops->ClientRecvStatus(context, tag->status_ptr());
110  ops->set_core_cq_tag(tag);
111  call.PerformOps(ops);
112  }
113 };
114 
115 // Base class for public API classes.
117  public:
118  virtual ~ClientReactor() = default;
119 
127  virtual void OnDone(const grpc::Status& /*s*/) = 0;
128 
136  virtual bool InternalTrailersOnly(const grpc_call* call) const;
137 };
138 
139 } // namespace internal
140 
141 // Forward declarations
142 template <class Request, class Response>
144 template <class Response>
146 template <class Request>
148 class ClientUnaryReactor;
149 
150 // NOTE: The streaming objects are not actually implemented in the public API.
151 // These interfaces are provided for mocking only. Typical applications
152 // will interact exclusively with the reactors that they define.
153 template <class Request, class Response>
155  public:
157  virtual void StartCall() = 0;
158  virtual void Write(const Request* req, grpc::WriteOptions options) = 0;
159  virtual void WritesDone() = 0;
160  virtual void Read(Response* resp) = 0;
161  virtual void AddHold(int holds) = 0;
162  virtual void RemoveHold() = 0;
163 
164  protected:
166  reactor->BindStream(this);
167  }
168 };
169 
170 template <class Response>
172  public:
174  virtual void StartCall() = 0;
175  virtual void Read(Response* resp) = 0;
176  virtual void AddHold(int holds) = 0;
177  virtual void RemoveHold() = 0;
178 
179  protected:
181  reactor->BindReader(this);
182  }
183 };
184 
185 template <class Request>
187  public:
189  virtual void StartCall() = 0;
190  void Write(const Request* req) { Write(req, grpc::WriteOptions()); }
191  virtual void Write(const Request* req, grpc::WriteOptions options) = 0;
192  void WriteLast(const Request* req, grpc::WriteOptions options) {
193  Write(req, options.set_last_message());
194  }
195  virtual void WritesDone() = 0;
196 
197  virtual void AddHold(int holds) = 0;
198  virtual void RemoveHold() = 0;
199 
200  protected:
202  reactor->BindWriter(this);
203  }
204 };
205 
207  public:
208  virtual ~ClientCallbackUnary() {}
209  virtual void StartCall() = 0;
210 
211  protected:
212  void BindReactor(ClientUnaryReactor* reactor);
213 };
214 
215 // The following classes are the reactor interfaces that are to be implemented
216 // by the user. They are passed in to the library as an argument to a call on a
217 // stub (either a codegen-ed call or a generic call). The streaming RPC is
218 // activated by calling StartCall, possibly after initiating StartRead,
219 // StartWrite, or AddHold operations on the streaming object. Note that none of
220 // the classes are pure; all reactions have a default empty reaction so that the
221 // user class only needs to override those reactions that it cares about.
222 // The reactor must be passed to the stub invocation before any of the below
223 // operations can be called and its reactions will be invoked by the library in
224 // response to the completion of various operations. Reactions must not include
225 // blocking operations (such as blocking I/O, starting synchronous RPCs, or
226 // waiting on condition variables). Reactions may be invoked concurrently,
227 // except that OnDone is called after all others (assuming proper API usage).
228 // The reactor may not be deleted until OnDone is called.
229 
231 template <class Request, class Response>
232 class ClientBidiReactor : public internal::ClientReactor {
233  public:
238  void StartCall() { stream_->StartCall(); }
239 
245  void StartRead(Response* resp) { stream_->Read(resp); }
246 
253  void StartWrite(const Request* req) { StartWrite(req, grpc::WriteOptions()); }
254 
261  void StartWrite(const Request* req, grpc::WriteOptions options) {
262  stream_->Write(req, options);
263  }
264 
274  void StartWriteLast(const Request* req, grpc::WriteOptions options) {
275  StartWrite(req, options.set_last_message());
276  }
277 
283  void StartWritesDone() { stream_->WritesDone(); }
284 
307  void AddHold() { AddMultipleHolds(1); }
308  void AddMultipleHolds(int holds) {
309  DCHECK_GT(holds, 0);
310  stream_->AddHold(holds);
311  }
312  void RemoveHold() { stream_->RemoveHold(); }
313 
321  void OnDone(const grpc::Status& /*s*/) override {}
322 
331  virtual void OnReadInitialMetadataDone(bool /*ok*/) {}
332 
337  virtual void OnReadDone(bool /*ok*/) {}
338 
344  virtual void OnWriteDone(bool /*ok*/) {}
345 
353  virtual void OnWritesDoneDone(bool /*ok*/) {}
354 
355  private:
356  friend class ClientCallbackReaderWriter<Request, Response>;
357  void BindStream(ClientCallbackReaderWriter<Request, Response>* stream) {
358  stream_ = stream;
359  }
361 };
362 
365 template <class Response>
366 class ClientReadReactor : public internal::ClientReactor {
367  public:
368  void StartCall() { reader_->StartCall(); }
369  void StartRead(Response* resp) { reader_->Read(resp); }
370 
371  void AddHold() { AddMultipleHolds(1); }
372  void AddMultipleHolds(int holds) {
373  DCHECK_GT(holds, 0);
374  reader_->AddHold(holds);
375  }
376  void RemoveHold() { reader_->RemoveHold(); }
377 
378  void OnDone(const grpc::Status& /*s*/) override {}
379  virtual void OnReadInitialMetadataDone(bool /*ok*/) {}
380  virtual void OnReadDone(bool /*ok*/) {}
381 
382  private:
383  friend class ClientCallbackReader<Response>;
384  void BindReader(ClientCallbackReader<Response>* reader) { reader_ = reader; }
386 };
387 
390 template <class Request>
391 class ClientWriteReactor : public internal::ClientReactor {
392  public:
393  void StartCall() { writer_->StartCall(); }
394  void StartWrite(const Request* req) { StartWrite(req, grpc::WriteOptions()); }
395  void StartWrite(const Request* req, grpc::WriteOptions options) {
396  writer_->Write(req, options);
397  }
398  void StartWriteLast(const Request* req, grpc::WriteOptions options) {
399  StartWrite(req, options.set_last_message());
400  }
401  void StartWritesDone() { writer_->WritesDone(); }
402 
403  void AddHold() { AddMultipleHolds(1); }
404  void AddMultipleHolds(int holds) {
405  DCHECK_GT(holds, 0);
406  writer_->AddHold(holds);
407  }
408  void RemoveHold() { writer_->RemoveHold(); }
409 
410  void OnDone(const grpc::Status& /*s*/) override {}
411  virtual void OnReadInitialMetadataDone(bool /*ok*/) {}
412  virtual void OnWriteDone(bool /*ok*/) {}
413  virtual void OnWritesDoneDone(bool /*ok*/) {}
414 
415  private:
416  friend class ClientCallbackWriter<Request>;
417  void BindWriter(ClientCallbackWriter<Request>* writer) { writer_ = writer; }
418 
420 };
421 
434  public:
435  void StartCall() { call_->StartCall(); }
436  void OnDone(const grpc::Status& /*s*/) override {}
437  virtual void OnReadInitialMetadataDone(bool /*ok*/) {}
438 
439  private:
440  friend class ClientCallbackUnary;
441  void BindCall(ClientCallbackUnary* call) { call_ = call; }
442  ClientCallbackUnary* call_;
443 };
444 
445 // Define function out-of-line from class to avoid forward declaration issue
447  reactor->BindCall(this);
448 }
449 
450 namespace internal {
451 
452 // Forward declare factory classes for friendship
453 template <class Request, class Response>
454 class ClientCallbackReaderWriterFactory;
455 template <class Response>
456 class ClientCallbackReaderFactory;
457 template <class Request>
458 class ClientCallbackWriterFactory;
459 
460 template <class Request, class Response>
461 class ClientCallbackReaderWriterImpl
462  : public ClientCallbackReaderWriter<Request, Response> {
463  public:
464  // always allocated against a call arena, no memory free required
465  static void operator delete(void* /*ptr*/, std::size_t size) {
466  CHECK_EQ(size, sizeof(ClientCallbackReaderWriterImpl));
467  }
468 
469  // This operator should never be called as the memory should be freed as part
470  // of the arena destruction. It only exists to provide a matching operator
471  // delete to the operator new so that some compilers will not complain (see
472  // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
473  // there are no tests catching the compiler warning.
474  static void operator delete(void*, void*) { CHECK(false); }
475 
476  void StartCall() ABSL_LOCKS_EXCLUDED(start_mu_) override {
477  // This call initiates two batches, plus any backlog, each with a callback
478  // 1. Send initial metadata (unless corked) + recv initial metadata
479  // 2. Any read backlog
480  // 3. Any write backlog
481  // 4. Recv trailing metadata (unless corked)
482  if (!start_corked_) {
483  start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
484  context_->initial_metadata_flags());
485  }
486 
487  call_.PerformOps(&start_ops_);
488 
489  {
490  grpc::internal::MutexLock lock(&start_mu_);
491 
492  if (backlog_.read_ops) {
493  call_.PerformOps(&read_ops_);
494  }
495  if (backlog_.write_ops) {
496  call_.PerformOps(&write_ops_);
497  }
498  if (backlog_.writes_done_ops) {
499  call_.PerformOps(&writes_done_ops_);
500  }
501  call_.PerformOps(&finish_ops_);
502  // The last thing in this critical section is to set started_ so that it
503  // can be used lock-free as well.
504  started_.store(true, std::memory_order_release);
505  }
506  // MaybeFinish outside the lock to make sure that destruction of this object
507  // doesn't take place while holding the lock (which would cause the lock to
508  // be released after destruction)
509  this->MaybeFinish(/*from_reaction=*/false);
510  }
511 
512  void Read(Response* msg) override {
513  read_ops_.RecvMessage(msg);
514  callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
515  if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
516  grpc::internal::MutexLock lock(&start_mu_);
517  if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
518  backlog_.read_ops = true;
519  return;
520  }
521  }
522  call_.PerformOps(&read_ops_);
523  }
524 
525  void Write(const Request* msg, grpc::WriteOptions options)
526  ABSL_LOCKS_EXCLUDED(start_mu_) override {
527  if (options.is_last_message()) {
528  options.set_buffer_hint();
529  write_ops_.ClientSendClose();
530  }
531  // TODO(vjpai): don't assert
532  CHECK(write_ops_.SendMessagePtr(msg, options).ok());
533  callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
534  if (GPR_UNLIKELY(corked_write_needed_)) {
535  write_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
536  context_->initial_metadata_flags());
537  corked_write_needed_ = false;
538  }
539 
540  if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
541  grpc::internal::MutexLock lock(&start_mu_);
542  if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
543  backlog_.write_ops = true;
544  return;
545  }
546  }
547  call_.PerformOps(&write_ops_);
548  }
549  void WritesDone() ABSL_LOCKS_EXCLUDED(start_mu_) override {
550  writes_done_ops_.ClientSendClose();
551  writes_done_tag_.Set(
552  call_.call(),
553  [this](bool ok) {
554  reactor_->OnWritesDoneDone(ok);
555  MaybeFinish(/*from_reaction=*/true);
556  },
557  &writes_done_ops_, /*can_inline=*/false);
558  writes_done_ops_.set_core_cq_tag(&writes_done_tag_);
559  callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
560  if (GPR_UNLIKELY(corked_write_needed_)) {
561  writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
562  context_->initial_metadata_flags());
563  corked_write_needed_ = false;
564  }
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_.writes_done_ops = true;
569  return;
570  }
571  }
572  call_.PerformOps(&writes_done_ops_);
573  }
574 
575  void AddHold(int holds) override {
576  callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed);
577  }
578  void RemoveHold() override { MaybeFinish(/*from_reaction=*/false); }
579 
580  private:
581  friend class ClientCallbackReaderWriterFactory<Request, Response>;
582 
584  grpc::ClientContext* context,
586  : context_(context),
587  call_(call),
588  reactor_(reactor),
589  start_corked_(context_->initial_metadata_corked_),
590  corked_write_needed_(start_corked_) {
591  this->BindReactor(reactor);
592 
593  // Set up the unchanging parts of the start, read, and write tags and ops.
594  start_tag_.Set(
595  call_.call(),
596  [this](bool ok) {
597  reactor_->OnReadInitialMetadataDone(
598  ok && !reactor_->InternalTrailersOnly(call_.call()));
599  MaybeFinish(/*from_reaction=*/true);
600  },
601  &start_ops_, /*can_inline=*/false);
602  start_ops_.RecvInitialMetadata(context_);
603  start_ops_.set_core_cq_tag(&start_tag_);
604 
605  write_tag_.Set(
606  call_.call(),
607  [this](bool ok) {
608  reactor_->OnWriteDone(ok);
609  MaybeFinish(/*from_reaction=*/true);
610  },
611  &write_ops_, /*can_inline=*/false);
612  write_ops_.set_core_cq_tag(&write_tag_);
613 
614  read_tag_.Set(
615  call_.call(),
616  [this](bool ok) {
617  reactor_->OnReadDone(ok);
618  MaybeFinish(/*from_reaction=*/true);
619  },
620  &read_ops_, /*can_inline=*/false);
621  read_ops_.set_core_cq_tag(&read_tag_);
622 
623  // Also set up the Finish tag and op set.
624  finish_tag_.Set(
625  call_.call(),
626  [this](bool /*ok*/) { MaybeFinish(/*from_reaction=*/true); },
627  &finish_ops_,
628  /*can_inline=*/false);
629  finish_ops_.ClientRecvStatus(context_, &finish_status_);
630  finish_ops_.set_core_cq_tag(&finish_tag_);
631  }
632 
633  // MaybeFinish can be called from reactions or from user-initiated operations
634  // like StartCall or RemoveHold. If this is the last operation or hold on this
635  // object, it will invoke the OnDone reaction. If MaybeFinish was called from
636  // a reaction, it can call OnDone directly. If not, it would need to schedule
637  // OnDone onto an executor thread to avoid the possibility of deadlocking with
638  // any locks in the user code that invoked it.
639  void MaybeFinish(bool from_reaction) {
640  if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(
641  1, std::memory_order_acq_rel) == 1)) {
642  grpc::Status s = std::move(finish_status_);
643  auto* reactor = reactor_;
644  auto* call = call_.call();
645  this->~ClientCallbackReaderWriterImpl();
646  if (GPR_LIKELY(from_reaction)) {
647  grpc_call_unref(call);
648  reactor->OnDone(s);
649  } else {
651  call, [reactor, s = std::move(s)]() { reactor->OnDone(s); });
652  grpc_call_unref(call);
653  }
654  }
655  }
656 
657  grpc::ClientContext* const context_;
658  grpc::internal::Call call_;
659  ClientBidiReactor<Request, Response>* const reactor_;
660 
663  start_ops_;
665  const bool start_corked_;
666  bool corked_write_needed_; // no lock needed since only accessed in
667  // Write/WritesDone which cannot be concurrent
668 
671  grpc::Status finish_status_;
672 
676  write_ops_;
678 
681  writes_done_ops_;
683 
685  read_ops_;
687 
688  struct StartCallBacklog {
689  bool write_ops = false;
690  bool writes_done_ops = false;
691  bool read_ops = false;
692  };
693  StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
694 
695  // Minimum of 3 callbacks to pre-register for start ops, StartCall, and finish
696  std::atomic<intptr_t> callbacks_outstanding_{3};
697  std::atomic_bool started_{false};
698  grpc::internal::Mutex start_mu_;
699 };
700 
701 template <class Request, class Response>
702 class ClientCallbackReaderWriterFactory {
703  public:
704  static void Create(grpc::ChannelInterface* channel,
705  const grpc::internal::RpcMethod& method,
706  grpc::ClientContext* context,
708  grpc::internal::Call call =
709  channel->CreateCall(method, context, channel->CallbackCQ());
710 
711  grpc_call_ref(call.call());
715  reactor);
716  }
717 };
718 
719 template <class Response>
720 class ClientCallbackReaderImpl : public ClientCallbackReader<Response> {
721  public:
722  // always allocated against a call arena, no memory free required
723  static void operator delete(void* /*ptr*/, std::size_t size) {
724  CHECK_EQ(size, sizeof(ClientCallbackReaderImpl));
725  }
726 
727  // This operator should never be called as the memory should be freed as part
728  // of the arena destruction. It only exists to provide a matching operator
729  // delete to the operator new so that some compilers will not complain (see
730  // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
731  // there are no tests catching the compiler warning.
732  static void operator delete(void*, void*) { CHECK(false); }
733 
734  void StartCall() override {
735  // This call initiates two batches, plus any backlog, each with a callback
736  // 1. Send initial metadata (unless corked) + recv initial metadata
737  // 2. Any backlog
738  // 3. Recv trailing metadata
739 
740  start_tag_.Set(
741  call_.call(),
742  [this](bool ok) {
743  reactor_->OnReadInitialMetadataDone(
744  ok && !reactor_->InternalTrailersOnly(call_.call()));
745  MaybeFinish(/*from_reaction=*/true);
746  },
747  &start_ops_, /*can_inline=*/false);
748  start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
749  context_->initial_metadata_flags());
750  start_ops_.RecvInitialMetadata(context_);
751  start_ops_.set_core_cq_tag(&start_tag_);
752  call_.PerformOps(&start_ops_);
753 
754  // Also set up the read tag so it doesn't have to be set up each time
755  read_tag_.Set(
756  call_.call(),
757  [this](bool ok) {
758  reactor_->OnReadDone(ok);
759  MaybeFinish(/*from_reaction=*/true);
760  },
761  &read_ops_, /*can_inline=*/false);
762  read_ops_.set_core_cq_tag(&read_tag_);
763 
764  {
765  grpc::internal::MutexLock lock(&start_mu_);
766  if (backlog_.read_ops) {
767  call_.PerformOps(&read_ops_);
768  }
769  started_.store(true, std::memory_order_release);
770  }
771 
772  finish_tag_.Set(
773  call_.call(),
774  [this](bool /*ok*/) { MaybeFinish(/*from_reaction=*/true); },
775  &finish_ops_, /*can_inline=*/false);
776  finish_ops_.ClientRecvStatus(context_, &finish_status_);
777  finish_ops_.set_core_cq_tag(&finish_tag_);
778  call_.PerformOps(&finish_ops_);
779  }
780 
781  void Read(Response* msg) override {
782  read_ops_.RecvMessage(msg);
783  callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
784  if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
785  grpc::internal::MutexLock lock(&start_mu_);
786  if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
787  backlog_.read_ops = true;
788  return;
789  }
790  }
791  call_.PerformOps(&read_ops_);
792  }
793 
794  void AddHold(int holds) override {
795  callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed);
796  }
797  void RemoveHold() override { MaybeFinish(/*from_reaction=*/false); }
798 
799  private:
800  friend class ClientCallbackReaderFactory<Response>;
801 
802  template <class Request>
804  grpc::ClientContext* context, Request* request,
806  : context_(context), call_(call), reactor_(reactor) {
807  this->BindReactor(reactor);
808  // TODO(vjpai): don't assert
809  CHECK(start_ops_.SendMessagePtr(request).ok());
810  start_ops_.ClientSendClose();
811  }
812 
813  // MaybeFinish behaves as in ClientCallbackReaderWriterImpl.
814  void MaybeFinish(bool from_reaction) {
815  if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(
816  1, std::memory_order_acq_rel) == 1)) {
817  grpc::Status s = std::move(finish_status_);
818  auto* reactor = reactor_;
819  auto* call = call_.call();
820  this->~ClientCallbackReaderImpl();
821  if (GPR_LIKELY(from_reaction)) {
822  grpc_call_unref(call);
823  reactor->OnDone(s);
824  } else {
826  call, [reactor, s = std::move(s)]() { reactor->OnDone(s); });
827  grpc_call_unref(call);
828  }
829  }
830  }
831 
832  grpc::ClientContext* const context_;
833  grpc::internal::Call call_;
834  ClientReadReactor<Response>* const reactor_;
835 
840  start_ops_;
842 
845  grpc::Status finish_status_;
846 
848  read_ops_;
850 
851  struct StartCallBacklog {
852  bool read_ops = false;
853  };
854  StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
855 
856  // Minimum of 2 callbacks to pre-register for start and finish
857  std::atomic<intptr_t> callbacks_outstanding_{2};
858  std::atomic_bool started_{false};
859  grpc::internal::Mutex start_mu_;
860 };
861 
862 template <class Response>
863 class ClientCallbackReaderFactory {
864  public:
865  template <class Request>
866  static void Create(grpc::ChannelInterface* channel,
867  const grpc::internal::RpcMethod& method,
868  grpc::ClientContext* context, const Request* request,
869  ClientReadReactor<Response>* reactor) {
870  grpc::internal::Call call =
871  channel->CreateCall(method, context, channel->CallbackCQ());
872 
873  grpc_call_ref(call.call());
874  new (grpc_call_arena_alloc(call.call(),
876  ClientCallbackReaderImpl<Response>(call, context, request, reactor);
877  }
878 };
879 
880 template <class Request>
881 class ClientCallbackWriterImpl : public ClientCallbackWriter<Request> {
882  public:
883  // always allocated against a call arena, no memory free required
884  static void operator delete(void* /*ptr*/, std::size_t size) {
885  CHECK_EQ(size, sizeof(ClientCallbackWriterImpl));
886  }
887 
888  // This operator should never be called as the memory should be freed as part
889  // of the arena destruction. It only exists to provide a matching operator
890  // delete to the operator new so that some compilers will not complain (see
891  // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
892  // there are no tests catching the compiler warning.
893  static void operator delete(void*, void*) { CHECK(false); }
894 
895  void StartCall() ABSL_LOCKS_EXCLUDED(start_mu_) override {
896  // This call initiates two batches, plus any backlog, each with a callback
897  // 1. Send initial metadata (unless corked) + recv initial metadata
898  // 2. Any backlog
899  // 3. Recv trailing metadata
900 
901  if (!start_corked_) {
902  start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
903  context_->initial_metadata_flags());
904  }
905  call_.PerformOps(&start_ops_);
906 
907  {
908  grpc::internal::MutexLock lock(&start_mu_);
909 
910  if (backlog_.write_ops) {
911  call_.PerformOps(&write_ops_);
912  }
913  if (backlog_.writes_done_ops) {
914  call_.PerformOps(&writes_done_ops_);
915  }
916  call_.PerformOps(&finish_ops_);
917  // The last thing in this critical section is to set started_ so that it
918  // can be used lock-free as well.
919  started_.store(true, std::memory_order_release);
920  }
921  // MaybeFinish outside the lock to make sure that destruction of this object
922  // doesn't take place while holding the lock (which would cause the lock to
923  // be released after destruction)
924  this->MaybeFinish(/*from_reaction=*/false);
925  }
926 
927  void Write(const Request* msg, grpc::WriteOptions options)
928  ABSL_LOCKS_EXCLUDED(start_mu_) override {
929  if (GPR_UNLIKELY(options.is_last_message())) {
930  options.set_buffer_hint();
931  write_ops_.ClientSendClose();
932  }
933  // TODO(vjpai): don't assert
934  CHECK(write_ops_.SendMessagePtr(msg, options).ok());
935  callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
936 
937  if (GPR_UNLIKELY(corked_write_needed_)) {
938  write_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
939  context_->initial_metadata_flags());
940  corked_write_needed_ = false;
941  }
942 
943  if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
944  grpc::internal::MutexLock lock(&start_mu_);
945  if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
946  backlog_.write_ops = true;
947  return;
948  }
949  }
950  call_.PerformOps(&write_ops_);
951  }
952 
953  void WritesDone() ABSL_LOCKS_EXCLUDED(start_mu_) override {
954  writes_done_ops_.ClientSendClose();
955  writes_done_tag_.Set(
956  call_.call(),
957  [this](bool ok) {
958  reactor_->OnWritesDoneDone(ok);
959  MaybeFinish(/*from_reaction=*/true);
960  },
961  &writes_done_ops_, /*can_inline=*/false);
962  writes_done_ops_.set_core_cq_tag(&writes_done_tag_);
963  callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
964 
965  if (GPR_UNLIKELY(corked_write_needed_)) {
966  writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
967  context_->initial_metadata_flags());
968  corked_write_needed_ = false;
969  }
970 
971  if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
972  grpc::internal::MutexLock lock(&start_mu_);
973  if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
974  backlog_.writes_done_ops = true;
975  return;
976  }
977  }
978  call_.PerformOps(&writes_done_ops_);
979  }
980 
981  void AddHold(int holds) override {
982  callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed);
983  }
984  void RemoveHold() override { MaybeFinish(/*from_reaction=*/false); }
985 
986  private:
987  friend class ClientCallbackWriterFactory<Request>;
988 
989  template <class Response>
991  grpc::ClientContext* context, Response* response,
993  : context_(context),
994  call_(call),
995  reactor_(reactor),
996  start_corked_(context_->initial_metadata_corked_),
997  corked_write_needed_(start_corked_) {
998  this->BindReactor(reactor);
999 
1000  // Set up the unchanging parts of the start and write tags and ops.
1001  start_tag_.Set(
1002  call_.call(),
1003  [this](bool ok) {
1004  reactor_->OnReadInitialMetadataDone(
1005  ok && !reactor_->InternalTrailersOnly(call_.call()));
1006  MaybeFinish(/*from_reaction=*/true);
1007  },
1008  &start_ops_, /*can_inline=*/false);
1009  start_ops_.RecvInitialMetadata(context_);
1010  start_ops_.set_core_cq_tag(&start_tag_);
1011 
1012  write_tag_.Set(
1013  call_.call(),
1014  [this](bool ok) {
1015  reactor_->OnWriteDone(ok);
1016  MaybeFinish(/*from_reaction=*/true);
1017  },
1018  &write_ops_, /*can_inline=*/false);
1019  write_ops_.set_core_cq_tag(&write_tag_);
1020 
1021  // Also set up the Finish tag and op set.
1022  finish_ops_.RecvMessage(response);
1023  finish_ops_.AllowNoMessage();
1024  finish_tag_.Set(
1025  call_.call(),
1026  [this](bool /*ok*/) { MaybeFinish(/*from_reaction=*/true); },
1027  &finish_ops_,
1028  /*can_inline=*/false);
1029  finish_ops_.ClientRecvStatus(context_, &finish_status_);
1030  finish_ops_.set_core_cq_tag(&finish_tag_);
1031  }
1032 
1033  // MaybeFinish behaves as in ClientCallbackReaderWriterImpl.
1034  void MaybeFinish(bool from_reaction) {
1035  if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(
1036  1, std::memory_order_acq_rel) == 1)) {
1037  grpc::Status s = std::move(finish_status_);
1038  auto* reactor = reactor_;
1039  auto* call = call_.call();
1040  this->~ClientCallbackWriterImpl();
1041  if (GPR_LIKELY(from_reaction)) {
1042  grpc_call_unref(call);
1043  reactor->OnDone(s);
1044  } else {
1046  call, [reactor, s = std::move(s)]() { reactor->OnDone(s); });
1047  grpc_call_unref(call);
1048  }
1049  }
1050  }
1051 
1052  grpc::ClientContext* const context_;
1053  grpc::internal::Call call_;
1054  ClientWriteReactor<Request>* const reactor_;
1055 
1058  start_ops_;
1060  const bool start_corked_;
1061  bool corked_write_needed_; // no lock needed since only accessed in
1062  // Write/WritesDone which cannot be concurrent
1063 
1066  finish_ops_;
1068  grpc::Status finish_status_;
1069 
1073  write_ops_;
1075 
1078  writes_done_ops_;
1079  grpc::internal::CallbackWithSuccessTag writes_done_tag_;
1080 
1081  struct StartCallBacklog {
1082  bool write_ops = false;
1083  bool writes_done_ops = false;
1084  };
1085  StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
1086 
1087  // Minimum of 3 callbacks to pre-register for start ops, StartCall, and finish
1088  std::atomic<intptr_t> callbacks_outstanding_{3};
1089  std::atomic_bool started_{false};
1090  grpc::internal::Mutex start_mu_;
1091 };
1092 
1093 template <class Request>
1094 class ClientCallbackWriterFactory {
1095  public:
1096  template <class Response>
1097  static void Create(grpc::ChannelInterface* channel,
1098  const grpc::internal::RpcMethod& method,
1099  grpc::ClientContext* context, Response* response,
1100  ClientWriteReactor<Request>* reactor) {
1101  grpc::internal::Call call =
1102  channel->CreateCall(method, context, channel->CallbackCQ());
1103 
1104  grpc_call_ref(call.call());
1105  new (grpc_call_arena_alloc(call.call(),
1107  ClientCallbackWriterImpl<Request>(call, context, response, reactor);
1108  }
1109 };
1110 
1112  public:
1113  // always allocated against a call arena, no memory free required
1114  static void operator delete(void* /*ptr*/, std::size_t size) {
1115  CHECK_EQ(size, sizeof(ClientCallbackUnaryImpl));
1116  }
1117 
1118  // This operator should never be called as the memory should be freed as part
1119  // of the arena destruction. It only exists to provide a matching operator
1120  // delete to the operator new so that some compilers will not complain (see
1121  // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
1122  // there are no tests catching the compiler warning.
1123  static void operator delete(void*, void*) { CHECK(false); }
1124 
1125  void StartCall() override {
1126  // This call initiates two batches, each with a callback
1127  // 1. Send initial metadata + write + writes done + recv initial metadata
1128  // 2. Read message, recv trailing metadata
1129 
1130  start_tag_.Set(
1131  call_.call(),
1132  [this](bool ok) {
1133  reactor_->OnReadInitialMetadataDone(
1134  ok && !reactor_->InternalTrailersOnly(call_.call()));
1135  MaybeFinish();
1136  },
1137  &start_ops_, /*can_inline=*/false);
1138  start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
1139  context_->initial_metadata_flags());
1140  start_ops_.RecvInitialMetadata(context_);
1141  start_ops_.set_core_cq_tag(&start_tag_);
1142  call_.PerformOps(&start_ops_);
1143 
1144  finish_tag_.Set(
1145  call_.call(), [this](bool /*ok*/) { MaybeFinish(); }, &finish_ops_,
1146  /*can_inline=*/false);
1147  finish_ops_.ClientRecvStatus(context_, &finish_status_);
1148  finish_ops_.set_core_cq_tag(&finish_tag_);
1149  call_.PerformOps(&finish_ops_);
1150  }
1151 
1152  private:
1154 
1155  template <class Request, class Response>
1157  grpc::ClientContext* context, Request* request,
1158  Response* response, ClientUnaryReactor* reactor)
1159  : context_(context), call_(call), reactor_(reactor) {
1160  this->BindReactor(reactor);
1161  // TODO(vjpai): don't assert
1162  CHECK(start_ops_.SendMessagePtr(request).ok());
1163  start_ops_.ClientSendClose();
1164  finish_ops_.RecvMessage(response);
1165  finish_ops_.AllowNoMessage();
1166  }
1167 
1168  // In the unary case, MaybeFinish is only ever invoked from a
1169  // library-initiated reaction, so it will just directly call OnDone if this is
1170  // the last reaction for this RPC.
1171  void MaybeFinish() {
1172  if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(
1173  1, std::memory_order_acq_rel) == 1)) {
1174  grpc::Status s = std::move(finish_status_);
1175  auto* reactor = reactor_;
1176  auto* call = call_.call();
1177  this->~ClientCallbackUnaryImpl();
1178  grpc_call_unref(call);
1179  reactor->OnDone(s);
1180  }
1181  }
1182 
1183  grpc::ClientContext* const context_;
1184  grpc::internal::Call call_;
1185  ClientUnaryReactor* const reactor_;
1186 
1191  start_ops_;
1193 
1196  finish_ops_;
1198  grpc::Status finish_status_;
1199 
1200  // This call will have 2 callbacks: start and finish
1201  std::atomic<intptr_t> callbacks_outstanding_{2};
1202 };
1203 
1205  public:
1206  template <class Request, class Response, class BaseRequest = Request,
1207  class BaseResponse = Response>
1208  static void Create(grpc::ChannelInterface* channel,
1209  const grpc::internal::RpcMethod& method,
1210  grpc::ClientContext* context, const Request* request,
1211  Response* response, ClientUnaryReactor* reactor) {
1212  grpc::internal::Call call =
1213  channel->CreateCall(method, context, channel->CallbackCQ());
1214 
1215  grpc_call_ref(call.call());
1216 
1217  new (grpc_call_arena_alloc(call.call(), sizeof(ClientCallbackUnaryImpl)))
1218  ClientCallbackUnaryImpl(call, context,
1219  static_cast<const BaseRequest*>(request),
1220  static_cast<BaseResponse*>(response), reactor);
1221  }
1222 };
1223 
1224 } // namespace internal
1225 } // namespace grpc
1226 
1227 #endif // GRPCPP_SUPPORT_CLIENT_CALLBACK_H
grpc::internal::ClientCallbackUnaryImpl
Definition: client_callback.h:1111
grpc::internal::CallbackWithSuccessTag
CallbackWithSuccessTag can be reused multiple times, and will be used in this fashion for streaming o...
Definition: callback_common.h:138
grpc::ClientReadReactor::OnReadInitialMetadataDone
virtual void OnReadInitialMetadataDone(bool)
Definition: client_callback.h:379
grpc::ClientWriteReactor::OnReadInitialMetadataDone
virtual void OnReadInitialMetadataDone(bool)
Definition: client_callback.h:411
grpc::ClientWriteReactor::StartWritesDone
void StartWritesDone()
Definition: client_callback.h:401
grpc::internal::CallOpRecvInitialMetadata
Definition: call_op_set.h:723
grpc::ClientCallbackWriter::~ClientCallbackWriter
virtual ~ClientCallbackWriter()
Definition: client_callback.h:188
grpc::internal::ClientCallbackReaderWriterImpl::Read
void Read(Response *msg) override
Definition: client_callback.h:512
grpc::internal::ClientCallbackWriterImpl::AddHold
void AddHold(int holds) override
Definition: client_callback.h:981
grpc::internal::ClientCallbackReaderWriterImpl::StartCall
void StartCall() ABSL_LOCKS_EXCLUDED(start_mu_) override
Definition: client_callback.h:476
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:253
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:307
grpc::internal::ClientCallbackReaderWriterImpl
Definition: client_context.h:70
grpc::ClientReadReactor::OnReadDone
virtual void OnReadDone(bool)
Definition: client_callback.h:380
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:98
grpc::internal::ClientCallbackReaderWriterImpl::Write
void Write(const Request *msg, grpc::WriteOptions options) ABSL_LOCKS_EXCLUDED(start_mu_) override
Definition: client_callback.h:525
grpc::internal::ClientCallbackReaderImpl::RemoveHold
void RemoveHold() override
Definition: client_callback.h:797
grpc::internal::CallOpSendMessage
Definition: call_op_set.h:288
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:69
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:157
grpc::ClientUnaryReactor
ClientUnaryReactor is a reactor-style interface for a unary RPC.
Definition: client_callback.h:433
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:704
grpc::ClientWriteReactor::StartWrite
void StartWrite(const Request *req, grpc::WriteOptions options)
Definition: client_callback.h:395
grpc::ClientWriteReactor::StartCall
void StartCall()
Definition: client_callback.h:393
grpc::ClientWriteReactor::OnDone
void OnDone(const grpc::Status &) override
Definition: client_callback.h:410
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:578
grpc::ClientReadReactor::OnDone
void OnDone(const grpc::Status &) override
Definition: client_callback.h:378
grpc::internal::Call
Straightforward wrapping of the C call object.
Definition: call.h:36
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:53
grpc::ClientCallbackReaderWriter::WritesDone
virtual void WritesDone()=0
grpc::internal::ClientCallbackWriterImpl::RemoveHold
void RemoveHold() override
Definition: client_callback.h:984
status.h
grpc::internal::CallOpSendInitialMetadata
Definition: call_op_set.h:218
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:1097
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:331
grpc::internal::CallbackWithStatusTag
Definition: callback_common.h:72
grpc::ClientCallbackReaderWriter::BindReactor
void BindReactor(ClientBidiReactor< Request, Response > *reactor)
Definition: client_callback.h:165
grpc::Status::ok
bool ok() const
Is the status OK?
Definition: status.h:125
grpc::ClientCallbackUnary::BindReactor
void BindReactor(ClientUnaryReactor *reactor)
Definition: client_callback.h:446
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:245
grpc::ClientReadReactor::AddMultipleHolds
void AddMultipleHolds(int holds)
Definition: client_callback.h:372
grpc::internal::ClientCallbackWriterImpl::StartCall
void StartCall() ABSL_LOCKS_EXCLUDED(start_mu_) override
Definition: client_callback.h:895
grpc::internal::ClientCallbackWriterImpl::Write
void Write(const Request *msg, grpc::WriteOptions options) ABSL_LOCKS_EXCLUDED(start_mu_) override
Definition: client_callback.h:927
grpc::ClientBidiReactor::StartWrite
void StartWrite(const Request *req, grpc::WriteOptions options)
Initiate/post a write operation with specified options.
Definition: client_callback.h:261
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:321
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:337
grpc::Status
Did it work? If it didn't, why?
Definition: status.h:34
GPR_UNLIKELY
#define GPR_UNLIKELY(x)
Definition: port_platform.h:828
grpc::ClientCallbackWriter::WritesDone
virtual void WritesDone()=0
log.h
grpc_call_unref
GRPCAPI void grpc_call_unref(grpc_call *call)
Unref a call.
grpc::internal::ClientCallbackWriterFactory
Definition: channel_interface.h:49
grpc::ClientReadReactor::StartCall
void StartCall()
Definition: client_callback.h:368
callback_common.h
grpc::ClientBidiReactor::OnWriteDone
virtual void OnWriteDone(bool)
Notifies the application that a StartWrite or StartWriteLast operation completed.
Definition: client_callback.h:344
grpc::ClientContext
A ClientContext allows the person implementing a service client to:
Definition: client_context.h:195
grpc::internal::ClientCallbackReaderImpl::StartCall
void StartCall() override
Definition: client_callback.h:734
grpc::internal::ClientCallbackReaderWriterFactory
Definition: channel_interface.h:45
grpc.h
grpc_call
struct grpc_call grpc_call
A Call represents an RPC.
Definition: grpc_types.h:69
grpc::internal::CallbackUnaryCallImpl
Definition: client_context.h:68
grpc::ClientUnaryReactor::OnReadInitialMetadataDone
virtual void OnReadInitialMetadataDone(bool)
Definition: client_callback.h:437
grpc::ClientCallbackWriter::BindReactor
void BindReactor(ClientWriteReactor< Request > *reactor)
Definition: client_callback.h:201
grpc::ClientCallbackReader::RemoveHold
virtual void RemoveHold()=0
grpc::ClientCallbackReaderWriter
Definition: client_callback.h:154
grpc::ClientBidiReactor::StartWritesDone
void StartWritesDone()
Indicate that the RPC will have no more write operations.
Definition: client_callback.h:283
grpc::ClientCallbackReader::Read
virtual void Read(Response *resp)=0
grpc::ClientReadReactor::StartRead
void StartRead(Response *resp)
Definition: client_callback.h:369
grpc::ChannelInterface
Codegen interface for grpc::Channel.
Definition: channel_interface.h:71
grpc::internal::ClientReactor
Definition: client_callback.h:116
grpc::internal::ClientCallbackUnaryFactory
Definition: client_callback.h:1204
grpc::internal::ClientCallbackReaderImpl::Read
void Read(Response *msg) override
Definition: client_callback.h:781
grpc::ClientWriteReactor::StartWriteLast
void StartWriteLast(const Request *req, grpc::WriteOptions options)
Definition: client_callback.h:398
grpc::internal::ClientCallbackWriterImpl
Definition: client_context.h:74
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:147
grpc_call_run_in_event_engine
void grpc_call_run_in_event_engine(const grpc_call *call, absl::AnyInvocable< void()> cb)
grpc::ClientCallbackUnary
Definition: client_callback.h:206
grpc::ClientBidiReactor::AddMultipleHolds
void AddMultipleHolds(int holds)
Definition: client_callback.h:308
grpc::ClientReadReactor::RemoveHold
void RemoveHold()
Definition: client_callback.h:376
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:1208
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:274
grpc::WriteOptions
Per-message write options.
Definition: call_op_set.h:80
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:353
grpc::internal::ClientCallbackWriterImpl::WritesDone
void WritesDone() ABSL_LOCKS_EXCLUDED(start_mu_) override
Definition: client_callback.h:953
grpc::ClientCallbackReader::~ClientCallbackReader
virtual ~ClientCallbackReader()
Definition: client_callback.h:173
grpc::internal::CallbackWithSuccessTag::Set
void Set(grpc_call *call, std::function< void(bool)> f, CompletionQueueTag *ops, bool can_inline)
Definition: callback_common.h:165
grpc::internal::ClientCallbackReaderImpl::AddHold
void AddHold(int holds) override
Definition: client_callback.h:794
grpc::ClientCallbackReader::BindReactor
void BindReactor(ClientReadReactor< Response > *reactor)
Definition: client_callback.h:180
grpc::internal::MutexLock
Definition: sync.h:81
grpc::ClientCallbackWriter
Definition: client_callback.h:186
grpc::ClientCallbackWriter::AddHold
virtual void AddHold(int holds)=0
grpc::ClientBidiReactor::RemoveHold
void RemoveHold()
Definition: client_callback.h:312
grpc::ClientCallbackReaderWriter::~ClientCallbackReaderWriter
virtual ~ClientCallbackReaderWriter()
Definition: client_callback.h:156
grpc::ClientCallbackReaderWriter::RemoveHold
virtual void RemoveHold()=0
grpc::ClientCallbackWriter::Write
void Write(const Request *req)
Definition: client_callback.h:190
config.h
grpc::ClientCallbackReader::StartCall
virtual void StartCall()=0
call.h
grpc::ClientWriteReactor::AddHold
void AddHold()
Definition: client_callback.h:403
grpc::internal::Call::PerformOps
void PerformOps(CallOpSetInterface *ops)
Definition: call.h:66
grpc::internal::Call::call
grpc_call * call() const
Definition: call.h:70
grpc::ClientUnaryReactor::StartCall
void StartCall()
Definition: client_callback.h:435
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:105
grpc::ClientBidiReactor
ClientBidiReactor is the interface for a bidirectional streaming RPC.
Definition: client_callback.h:143
grpc::internal::ClientCallbackReaderFactory
Definition: channel_interface.h:47
grpc::ClientCallbackWriter::WriteLast
void WriteLast(const Request *req, grpc::WriteOptions options)
Definition: client_callback.h:192
grpc::internal::ClientCallbackReaderImpl
Definition: client_context.h:72
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:1125
grpc::ClientWriteReactor::StartWrite
void StartWrite(const Request *req)
Definition: client_callback.h:394
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:238
grpc::ClientWriteReactor::OnWriteDone
virtual void OnWriteDone(bool)
Definition: client_callback.h:412
grpc::internal::CallOpRecvMessage
Definition: call_op_set.h:426
grpc::internal::Mutex
Definition: sync.h:58
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:404
grpc::ClientCallbackReader
Definition: client_callback.h:171
GPR_LIKELY
#define GPR_LIKELY(x)
Definition: port_platform.h:827
grpc::ClientCallbackUnary::~ClientCallbackUnary
virtual ~ClientCallbackUnary()
Definition: client_callback.h:208
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:945
sync.h
grpc::internal::ClientCallbackReaderWriterImpl::AddHold
void AddHold(int holds) override
Definition: client_callback.h:575
grpc::ClientWriteReactor::RemoveHold
void RemoveHold()
Definition: client_callback.h:408
grpc::ClientReadReactor
ClientReadReactor is the interface for a server-streaming RPC.
Definition: client_callback.h:145
grpc::internal::ClientCallbackReaderWriterImpl::WritesDone
void WritesDone() ABSL_LOCKS_EXCLUDED(start_mu_) override
Definition: client_callback.h:549
grpc::ClientReadReactor::AddHold
void AddHold()
Definition: client_callback.h:371
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:436
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:866
grpc::ClientWriteReactor::OnWritesDoneDone
virtual void OnWritesDoneDone(bool)
Definition: client_callback.h:413