client_callback.h 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233
  1. /*
  2. *
  3. * Copyright 2019 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. #ifndef GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_H
  18. #define GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_H
  19. // IWYU pragma: private, include <grpcpp/support/client_callback.h>
  20. #include <atomic>
  21. #include <functional>
  22. #include <grpcpp/impl/codegen/call.h>
  23. #include <grpcpp/impl/codegen/call_op_set.h>
  24. #include <grpcpp/impl/codegen/callback_common.h>
  25. #include <grpcpp/impl/codegen/channel_interface.h>
  26. #include <grpcpp/impl/codegen/config.h>
  27. #include <grpcpp/impl/codegen/core_codegen_interface.h>
  28. #include <grpcpp/impl/codegen/status.h>
  29. #include <grpcpp/impl/codegen/sync.h>
  30. namespace grpc {
  31. class Channel;
  32. class ClientContext;
  33. namespace internal {
  34. class RpcMethod;
  35. /// Perform a callback-based unary call. May optionally specify the base
  36. /// class of the Request and Response so that the internal calls and structures
  37. /// below this may be based on those base classes and thus achieve code reuse
  38. /// across different RPCs (e.g., for protobuf, MessageLite would be a base
  39. /// class).
  40. /// TODO(vjpai): Combine as much as possible with the blocking unary call code
  41. template <class InputMessage, class OutputMessage,
  42. class BaseInputMessage = InputMessage,
  43. class BaseOutputMessage = OutputMessage>
  44. void CallbackUnaryCall(::grpc::ChannelInterface* channel,
  45. const ::grpc::internal::RpcMethod& method,
  46. ::grpc::ClientContext* context,
  47. const InputMessage* request, OutputMessage* result,
  48. std::function<void(::grpc::Status)> on_completion) {
  49. static_assert(std::is_base_of<BaseInputMessage, InputMessage>::value,
  50. "Invalid input message specification");
  51. static_assert(std::is_base_of<BaseOutputMessage, OutputMessage>::value,
  52. "Invalid output message specification");
  53. CallbackUnaryCallImpl<BaseInputMessage, BaseOutputMessage> x(
  54. channel, method, context, request, result, on_completion);
  55. }
  56. template <class InputMessage, class OutputMessage>
  57. class CallbackUnaryCallImpl {
  58. public:
  59. CallbackUnaryCallImpl(::grpc::ChannelInterface* channel,
  60. const ::grpc::internal::RpcMethod& method,
  61. ::grpc::ClientContext* context,
  62. const InputMessage* request, OutputMessage* result,
  63. std::function<void(::grpc::Status)> on_completion) {
  64. ::grpc::CompletionQueue* cq = channel->CallbackCQ();
  65. GPR_CODEGEN_ASSERT(cq != nullptr);
  66. grpc::internal::Call call(channel->CreateCall(method, context, cq));
  67. using FullCallOpSet = grpc::internal::CallOpSet<
  68. ::grpc::internal::CallOpSendInitialMetadata,
  69. grpc::internal::CallOpSendMessage,
  70. grpc::internal::CallOpRecvInitialMetadata,
  71. grpc::internal::CallOpRecvMessage<OutputMessage>,
  72. grpc::internal::CallOpClientSendClose,
  73. grpc::internal::CallOpClientRecvStatus>;
  74. struct OpSetAndTag {
  75. FullCallOpSet opset;
  76. grpc::internal::CallbackWithStatusTag tag;
  77. };
  78. const size_t alloc_sz = sizeof(OpSetAndTag);
  79. auto* const alloced = static_cast<OpSetAndTag*>(
  80. ::grpc::g_core_codegen_interface->grpc_call_arena_alloc(call.call(),
  81. alloc_sz));
  82. auto* ops = new (&alloced->opset) FullCallOpSet;
  83. auto* tag = new (&alloced->tag)
  84. grpc::internal::CallbackWithStatusTag(call.call(), on_completion, ops);
  85. // TODO(vjpai): Unify code with sync API as much as possible
  86. ::grpc::Status s = ops->SendMessagePtr(request);
  87. if (!s.ok()) {
  88. tag->force_run(s);
  89. return;
  90. }
  91. ops->SendInitialMetadata(&context->send_initial_metadata_,
  92. context->initial_metadata_flags());
  93. ops->RecvInitialMetadata(context);
  94. ops->RecvMessage(result);
  95. ops->AllowNoMessage();
  96. ops->ClientSendClose();
  97. ops->ClientRecvStatus(context, tag->status_ptr());
  98. ops->set_core_cq_tag(tag);
  99. call.PerformOps(ops);
  100. }
  101. };
  102. // Base class for public API classes.
  103. class ClientReactor {
  104. public:
  105. virtual ~ClientReactor() = default;
  106. /// Called by the library when all operations associated with this RPC have
  107. /// completed and all Holds have been removed. OnDone provides the RPC status
  108. /// outcome for both successful and failed RPCs. If it is never called on an
  109. /// RPC, it indicates an application-level problem (like failure to remove a
  110. /// hold).
  111. ///
  112. /// \param[in] s The status outcome of this RPC
  113. virtual void OnDone(const ::grpc::Status& /*s*/) = 0;
  114. /// InternalScheduleOnDone is not part of the API and is not meant to be
  115. /// overridden. It is virtual to allow successful builds for certain bazel
  116. /// build users that only want to depend on gRPC codegen headers and not the
  117. /// full library (although this is not a generally-supported option). Although
  118. /// the virtual call is slower than a direct call, this function is
  119. /// heavyweight and the cost of the virtual call is not much in comparison.
  120. /// This function may be removed or devirtualized in the future.
  121. virtual void InternalScheduleOnDone(::grpc::Status s);
  122. /// InternalTrailersOnly is not part of the API and is not meant to be
  123. /// overridden. It is virtual to allow successful builds for certain bazel
  124. /// build users that only want to depend on gRPC codegen headers and not the
  125. /// full library (although this is not a generally-supported option). Although
  126. /// the virtual call is slower than a direct call, this function is
  127. /// heavyweight and the cost of the virtual call is not much in comparison.
  128. /// This function may be removed or devirtualized in the future.
  129. virtual bool InternalTrailersOnly(const grpc_call* call) const;
  130. };
  131. } // namespace internal
  132. // Forward declarations
  133. template <class Request, class Response>
  134. class ClientBidiReactor;
  135. template <class Response>
  136. class ClientReadReactor;
  137. template <class Request>
  138. class ClientWriteReactor;
  139. class ClientUnaryReactor;
  140. // NOTE: The streaming objects are not actually implemented in the public API.
  141. // These interfaces are provided for mocking only. Typical applications
  142. // will interact exclusively with the reactors that they define.
  143. template <class Request, class Response>
  144. class ClientCallbackReaderWriter {
  145. public:
  146. virtual ~ClientCallbackReaderWriter() {}
  147. virtual void StartCall() = 0;
  148. virtual void Write(const Request* req, ::grpc::WriteOptions options) = 0;
  149. virtual void WritesDone() = 0;
  150. virtual void Read(Response* resp) = 0;
  151. virtual void AddHold(int holds) = 0;
  152. virtual void RemoveHold() = 0;
  153. protected:
  154. void BindReactor(ClientBidiReactor<Request, Response>* reactor) {
  155. reactor->BindStream(this);
  156. }
  157. };
  158. template <class Response>
  159. class ClientCallbackReader {
  160. public:
  161. virtual ~ClientCallbackReader() {}
  162. virtual void StartCall() = 0;
  163. virtual void Read(Response* resp) = 0;
  164. virtual void AddHold(int holds) = 0;
  165. virtual void RemoveHold() = 0;
  166. protected:
  167. void BindReactor(ClientReadReactor<Response>* reactor) {
  168. reactor->BindReader(this);
  169. }
  170. };
  171. template <class Request>
  172. class ClientCallbackWriter {
  173. public:
  174. virtual ~ClientCallbackWriter() {}
  175. virtual void StartCall() = 0;
  176. void Write(const Request* req) { Write(req, ::grpc::WriteOptions()); }
  177. virtual void Write(const Request* req, ::grpc::WriteOptions options) = 0;
  178. void WriteLast(const Request* req, ::grpc::WriteOptions options) {
  179. Write(req, options.set_last_message());
  180. }
  181. virtual void WritesDone() = 0;
  182. virtual void AddHold(int holds) = 0;
  183. virtual void RemoveHold() = 0;
  184. protected:
  185. void BindReactor(ClientWriteReactor<Request>* reactor) {
  186. reactor->BindWriter(this);
  187. }
  188. };
  189. class ClientCallbackUnary {
  190. public:
  191. virtual ~ClientCallbackUnary() {}
  192. virtual void StartCall() = 0;
  193. protected:
  194. void BindReactor(ClientUnaryReactor* reactor);
  195. };
  196. // The following classes are the reactor interfaces that are to be implemented
  197. // by the user. They are passed in to the library as an argument to a call on a
  198. // stub (either a codegen-ed call or a generic call). The streaming RPC is
  199. // activated by calling StartCall, possibly after initiating StartRead,
  200. // StartWrite, or AddHold operations on the streaming object. Note that none of
  201. // the classes are pure; all reactions have a default empty reaction so that the
  202. // user class only needs to override those reactions that it cares about.
  203. // The reactor must be passed to the stub invocation before any of the below
  204. // operations can be called and its reactions will be invoked by the library in
  205. // response to the completion of various operations. Reactions must not include
  206. // blocking operations (such as blocking I/O, starting synchronous RPCs, or
  207. // waiting on condition variables). Reactions may be invoked concurrently,
  208. // except that OnDone is called after all others (assuming proper API usage).
  209. // The reactor may not be deleted until OnDone is called.
  210. /// \a ClientBidiReactor is the interface for a bidirectional streaming RPC.
  211. template <class Request, class Response>
  212. class ClientBidiReactor : public internal::ClientReactor {
  213. public:
  214. /// Activate the RPC and initiate any reads or writes that have been Start'ed
  215. /// before this call. All streaming RPCs issued by the client MUST have
  216. /// StartCall invoked on them (even if they are canceled) as this call is the
  217. /// activation of their lifecycle.
  218. void StartCall() { stream_->StartCall(); }
  219. /// Initiate a read operation (or post it for later initiation if StartCall
  220. /// has not yet been invoked).
  221. ///
  222. /// \param[out] resp Where to eventually store the read message. Valid when
  223. /// the library calls OnReadDone
  224. void StartRead(Response* resp) { stream_->Read(resp); }
  225. /// Initiate a write operation (or post it for later initiation if StartCall
  226. /// has not yet been invoked).
  227. ///
  228. /// \param[in] req The message to be written. The library does not take
  229. /// ownership but the caller must ensure that the message is
  230. /// not deleted or modified until OnWriteDone is called.
  231. void StartWrite(const Request* req) {
  232. StartWrite(req, ::grpc::WriteOptions());
  233. }
  234. /// Initiate/post a write operation with specified options.
  235. ///
  236. /// \param[in] req The message to be written. The library does not take
  237. /// ownership but the caller must ensure that the message is
  238. /// not deleted or modified until OnWriteDone is called.
  239. /// \param[in] options The WriteOptions to use for writing this message
  240. void StartWrite(const Request* req, ::grpc::WriteOptions options) {
  241. stream_->Write(req, options);
  242. }
  243. /// Initiate/post a write operation with specified options and an indication
  244. /// that this is the last write (like StartWrite and StartWritesDone, merged).
  245. /// Note that calling this means that no more calls to StartWrite,
  246. /// StartWriteLast, or StartWritesDone are allowed.
  247. ///
  248. /// \param[in] req The message to be written. The library does not take
  249. /// ownership but the caller must ensure that the message is
  250. /// not deleted or modified until OnWriteDone is called.
  251. /// \param[in] options The WriteOptions to use for writing this message
  252. void StartWriteLast(const Request* req, ::grpc::WriteOptions options) {
  253. StartWrite(req, options.set_last_message());
  254. }
  255. /// Indicate that the RPC will have no more write operations. This can only be
  256. /// issued once for a given RPC. This is not required or allowed if
  257. /// StartWriteLast is used since that already has the same implication.
  258. /// Note that calling this means that no more calls to StartWrite,
  259. /// StartWriteLast, or StartWritesDone are allowed.
  260. void StartWritesDone() { stream_->WritesDone(); }
  261. /// Holds are needed if (and only if) this stream has operations that take
  262. /// place on it after StartCall but from outside one of the reactions
  263. /// (OnReadDone, etc). This is _not_ a common use of the streaming API.
  264. ///
  265. /// Holds must be added before calling StartCall. If a stream still has a hold
  266. /// in place, its resources will not be destroyed even if the status has
  267. /// already come in from the wire and there are currently no active callbacks
  268. /// outstanding. Similarly, the stream will not call OnDone if there are still
  269. /// holds on it.
  270. ///
  271. /// For example, if a StartRead or StartWrite operation is going to be
  272. /// initiated from elsewhere in the application, the application should call
  273. /// AddHold or AddMultipleHolds before StartCall. If there is going to be,
  274. /// for example, a read-flow and a write-flow taking place outside the
  275. /// reactions, then call AddMultipleHolds(2) before StartCall. When the
  276. /// application knows that it won't issue any more read operations (such as
  277. /// when a read comes back as not ok), it should issue a RemoveHold(). It
  278. /// should also call RemoveHold() again after it does StartWriteLast or
  279. /// StartWritesDone that indicates that there will be no more write ops.
  280. /// The number of RemoveHold calls must match the total number of AddHold
  281. /// calls plus the number of holds added by AddMultipleHolds.
  282. /// The argument to AddMultipleHolds must be positive.
  283. void AddHold() { AddMultipleHolds(1); }
  284. void AddMultipleHolds(int holds) {
  285. GPR_CODEGEN_DEBUG_ASSERT(holds > 0);
  286. stream_->AddHold(holds);
  287. }
  288. void RemoveHold() { stream_->RemoveHold(); }
  289. /// Notifies the application that all operations associated with this RPC
  290. /// have completed and all Holds have been removed. OnDone provides the RPC
  291. /// status outcome for both successful and failed RPCs and will be called in
  292. /// all cases. If it is not called, it indicates an application-level problem
  293. /// (like failure to remove a hold).
  294. ///
  295. /// \param[in] s The status outcome of this RPC
  296. void OnDone(const ::grpc::Status& /*s*/) override {}
  297. /// Notifies the application that a read of initial metadata from the
  298. /// server is done. If the application chooses not to implement this method,
  299. /// it can assume that the initial metadata has been read before the first
  300. /// call of OnReadDone or OnDone.
  301. ///
  302. /// \param[in] ok Was the initial metadata read successfully? If false, no
  303. /// new read/write operation will succeed, and any further
  304. /// Start* operations should not be called.
  305. virtual void OnReadInitialMetadataDone(bool /*ok*/) {}
  306. /// Notifies the application that a StartRead operation completed.
  307. ///
  308. /// \param[in] ok Was it successful? If false, no new read/write operation
  309. /// will succeed, and any further Start* should not be called.
  310. virtual void OnReadDone(bool /*ok*/) {}
  311. /// Notifies the application that a StartWrite or StartWriteLast operation
  312. /// completed.
  313. ///
  314. /// \param[in] ok Was it successful? If false, no new read/write operation
  315. /// will succeed, and any further Start* should not be called.
  316. virtual void OnWriteDone(bool /*ok*/) {}
  317. /// Notifies the application that a StartWritesDone operation completed. Note
  318. /// that this is only used on explicit StartWritesDone operations and not for
  319. /// those that are implicitly invoked as part of a StartWriteLast.
  320. ///
  321. /// \param[in] ok Was it successful? If false, the application will later see
  322. /// the failure reflected as a bad status in OnDone and no
  323. /// further Start* should be called.
  324. virtual void OnWritesDoneDone(bool /*ok*/) {}
  325. private:
  326. friend class ClientCallbackReaderWriter<Request, Response>;
  327. void BindStream(ClientCallbackReaderWriter<Request, Response>* stream) {
  328. stream_ = stream;
  329. }
  330. ClientCallbackReaderWriter<Request, Response>* stream_;
  331. };
  332. /// \a ClientReadReactor is the interface for a server-streaming RPC.
  333. /// All public methods behave as in ClientBidiReactor.
  334. template <class Response>
  335. class ClientReadReactor : public internal::ClientReactor {
  336. public:
  337. void StartCall() { reader_->StartCall(); }
  338. void StartRead(Response* resp) { reader_->Read(resp); }
  339. void AddHold() { AddMultipleHolds(1); }
  340. void AddMultipleHolds(int holds) {
  341. GPR_CODEGEN_DEBUG_ASSERT(holds > 0);
  342. reader_->AddHold(holds);
  343. }
  344. void RemoveHold() { reader_->RemoveHold(); }
  345. void OnDone(const ::grpc::Status& /*s*/) override {}
  346. virtual void OnReadInitialMetadataDone(bool /*ok*/) {}
  347. virtual void OnReadDone(bool /*ok*/) {}
  348. private:
  349. friend class ClientCallbackReader<Response>;
  350. void BindReader(ClientCallbackReader<Response>* reader) { reader_ = reader; }
  351. ClientCallbackReader<Response>* reader_;
  352. };
  353. /// \a ClientWriteReactor is the interface for a client-streaming RPC.
  354. /// All public methods behave as in ClientBidiReactor.
  355. template <class Request>
  356. class ClientWriteReactor : public internal::ClientReactor {
  357. public:
  358. void StartCall() { writer_->StartCall(); }
  359. void StartWrite(const Request* req) {
  360. StartWrite(req, ::grpc::WriteOptions());
  361. }
  362. void StartWrite(const Request* req, ::grpc::WriteOptions options) {
  363. writer_->Write(req, options);
  364. }
  365. void StartWriteLast(const Request* req, ::grpc::WriteOptions options) {
  366. StartWrite(req, options.set_last_message());
  367. }
  368. void StartWritesDone() { writer_->WritesDone(); }
  369. void AddHold() { AddMultipleHolds(1); }
  370. void AddMultipleHolds(int holds) {
  371. GPR_CODEGEN_DEBUG_ASSERT(holds > 0);
  372. writer_->AddHold(holds);
  373. }
  374. void RemoveHold() { writer_->RemoveHold(); }
  375. void OnDone(const ::grpc::Status& /*s*/) override {}
  376. virtual void OnReadInitialMetadataDone(bool /*ok*/) {}
  377. virtual void OnWriteDone(bool /*ok*/) {}
  378. virtual void OnWritesDoneDone(bool /*ok*/) {}
  379. private:
  380. friend class ClientCallbackWriter<Request>;
  381. void BindWriter(ClientCallbackWriter<Request>* writer) { writer_ = writer; }
  382. ClientCallbackWriter<Request>* writer_;
  383. };
  384. /// \a ClientUnaryReactor is a reactor-style interface for a unary RPC.
  385. /// This is _not_ a common way of invoking a unary RPC. In practice, this
  386. /// option should be used only if the unary RPC wants to receive initial
  387. /// metadata without waiting for the response to complete. Most deployments of
  388. /// RPC systems do not use this option, but it is needed for generality.
  389. /// All public methods behave as in ClientBidiReactor.
  390. /// StartCall is included for consistency with the other reactor flavors: even
  391. /// though there are no StartRead or StartWrite operations to queue before the
  392. /// call (that is part of the unary call itself) and there is no reactor object
  393. /// being created as a result of this call, we keep a consistent 2-phase
  394. /// initiation API among all the reactor flavors.
  395. class ClientUnaryReactor : public internal::ClientReactor {
  396. public:
  397. void StartCall() { call_->StartCall(); }
  398. void OnDone(const ::grpc::Status& /*s*/) override {}
  399. virtual void OnReadInitialMetadataDone(bool /*ok*/) {}
  400. private:
  401. friend class ClientCallbackUnary;
  402. void BindCall(ClientCallbackUnary* call) { call_ = call; }
  403. ClientCallbackUnary* call_;
  404. };
  405. // Define function out-of-line from class to avoid forward declaration issue
  406. inline void ClientCallbackUnary::BindReactor(ClientUnaryReactor* reactor) {
  407. reactor->BindCall(this);
  408. }
  409. namespace internal {
  410. // Forward declare factory classes for friendship
  411. template <class Request, class Response>
  412. class ClientCallbackReaderWriterFactory;
  413. template <class Response>
  414. class ClientCallbackReaderFactory;
  415. template <class Request>
  416. class ClientCallbackWriterFactory;
  417. template <class Request, class Response>
  418. class ClientCallbackReaderWriterImpl
  419. : public ClientCallbackReaderWriter<Request, Response> {
  420. public:
  421. // always allocated against a call arena, no memory free required
  422. static void operator delete(void* /*ptr*/, std::size_t size) {
  423. GPR_CODEGEN_ASSERT(size == sizeof(ClientCallbackReaderWriterImpl));
  424. }
  425. // This operator should never be called as the memory should be freed as part
  426. // of the arena destruction. It only exists to provide a matching operator
  427. // delete to the operator new so that some compilers will not complain (see
  428. // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
  429. // there are no tests catching the compiler warning.
  430. static void operator delete(void*, void*) { GPR_CODEGEN_ASSERT(false); }
  431. void StartCall() ABSL_LOCKS_EXCLUDED(start_mu_) override {
  432. // This call initiates two batches, plus any backlog, each with a callback
  433. // 1. Send initial metadata (unless corked) + recv initial metadata
  434. // 2. Any read backlog
  435. // 3. Any write backlog
  436. // 4. Recv trailing metadata (unless corked)
  437. if (!start_corked_) {
  438. start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
  439. context_->initial_metadata_flags());
  440. }
  441. call_.PerformOps(&start_ops_);
  442. {
  443. grpc::internal::MutexLock lock(&start_mu_);
  444. if (backlog_.read_ops) {
  445. call_.PerformOps(&read_ops_);
  446. }
  447. if (backlog_.write_ops) {
  448. call_.PerformOps(&write_ops_);
  449. }
  450. if (backlog_.writes_done_ops) {
  451. call_.PerformOps(&writes_done_ops_);
  452. }
  453. call_.PerformOps(&finish_ops_);
  454. // The last thing in this critical section is to set started_ so that it
  455. // can be used lock-free as well.
  456. started_.store(true, std::memory_order_release);
  457. }
  458. // MaybeFinish outside the lock to make sure that destruction of this object
  459. // doesn't take place while holding the lock (which would cause the lock to
  460. // be released after destruction)
  461. this->MaybeFinish(/*from_reaction=*/false);
  462. }
  463. void Read(Response* msg) override {
  464. read_ops_.RecvMessage(msg);
  465. callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
  466. if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
  467. grpc::internal::MutexLock lock(&start_mu_);
  468. if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
  469. backlog_.read_ops = true;
  470. return;
  471. }
  472. }
  473. call_.PerformOps(&read_ops_);
  474. }
  475. void Write(const Request* msg, ::grpc::WriteOptions options)
  476. ABSL_LOCKS_EXCLUDED(start_mu_) override {
  477. if (options.is_last_message()) {
  478. options.set_buffer_hint();
  479. write_ops_.ClientSendClose();
  480. }
  481. // TODO(vjpai): don't assert
  482. GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(msg, options).ok());
  483. callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
  484. if (GPR_UNLIKELY(corked_write_needed_)) {
  485. write_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
  486. context_->initial_metadata_flags());
  487. corked_write_needed_ = false;
  488. }
  489. if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
  490. grpc::internal::MutexLock lock(&start_mu_);
  491. if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
  492. backlog_.write_ops = true;
  493. return;
  494. }
  495. }
  496. call_.PerformOps(&write_ops_);
  497. }
  498. void WritesDone() ABSL_LOCKS_EXCLUDED(start_mu_) override {
  499. writes_done_ops_.ClientSendClose();
  500. writes_done_tag_.Set(
  501. call_.call(),
  502. [this](bool ok) {
  503. reactor_->OnWritesDoneDone(ok);
  504. MaybeFinish(/*from_reaction=*/true);
  505. },
  506. &writes_done_ops_, /*can_inline=*/false);
  507. writes_done_ops_.set_core_cq_tag(&writes_done_tag_);
  508. callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
  509. if (GPR_UNLIKELY(corked_write_needed_)) {
  510. writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
  511. context_->initial_metadata_flags());
  512. corked_write_needed_ = false;
  513. }
  514. if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
  515. grpc::internal::MutexLock lock(&start_mu_);
  516. if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
  517. backlog_.writes_done_ops = true;
  518. return;
  519. }
  520. }
  521. call_.PerformOps(&writes_done_ops_);
  522. }
  523. void AddHold(int holds) override {
  524. callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed);
  525. }
  526. void RemoveHold() override { MaybeFinish(/*from_reaction=*/false); }
  527. private:
  528. friend class ClientCallbackReaderWriterFactory<Request, Response>;
  529. ClientCallbackReaderWriterImpl(grpc::internal::Call call,
  530. ::grpc::ClientContext* context,
  531. ClientBidiReactor<Request, Response>* reactor)
  532. : context_(context),
  533. call_(call),
  534. reactor_(reactor),
  535. start_corked_(context_->initial_metadata_corked_),
  536. corked_write_needed_(start_corked_) {
  537. this->BindReactor(reactor);
  538. // Set up the unchanging parts of the start, read, and write tags and ops.
  539. start_tag_.Set(
  540. call_.call(),
  541. [this](bool ok) {
  542. reactor_->OnReadInitialMetadataDone(
  543. ok && !reactor_->InternalTrailersOnly(call_.call()));
  544. MaybeFinish(/*from_reaction=*/true);
  545. },
  546. &start_ops_, /*can_inline=*/false);
  547. start_ops_.RecvInitialMetadata(context_);
  548. start_ops_.set_core_cq_tag(&start_tag_);
  549. write_tag_.Set(
  550. call_.call(),
  551. [this](bool ok) {
  552. reactor_->OnWriteDone(ok);
  553. MaybeFinish(/*from_reaction=*/true);
  554. },
  555. &write_ops_, /*can_inline=*/false);
  556. write_ops_.set_core_cq_tag(&write_tag_);
  557. read_tag_.Set(
  558. call_.call(),
  559. [this](bool ok) {
  560. reactor_->OnReadDone(ok);
  561. MaybeFinish(/*from_reaction=*/true);
  562. },
  563. &read_ops_, /*can_inline=*/false);
  564. read_ops_.set_core_cq_tag(&read_tag_);
  565. // Also set up the Finish tag and op set.
  566. finish_tag_.Set(
  567. call_.call(),
  568. [this](bool /*ok*/) { MaybeFinish(/*from_reaction=*/true); },
  569. &finish_ops_,
  570. /*can_inline=*/false);
  571. finish_ops_.ClientRecvStatus(context_, &finish_status_);
  572. finish_ops_.set_core_cq_tag(&finish_tag_);
  573. }
  574. // MaybeFinish can be called from reactions or from user-initiated operations
  575. // like StartCall or RemoveHold. If this is the last operation or hold on this
  576. // object, it will invoke the OnDone reaction. If MaybeFinish was called from
  577. // a reaction, it can call OnDone directly. If not, it would need to schedule
  578. // OnDone onto an executor thread to avoid the possibility of deadlocking with
  579. // any locks in the user code that invoked it.
  580. void MaybeFinish(bool from_reaction) {
  581. if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(
  582. 1, std::memory_order_acq_rel) == 1)) {
  583. ::grpc::Status s = std::move(finish_status_);
  584. auto* reactor = reactor_;
  585. auto* call = call_.call();
  586. this->~ClientCallbackReaderWriterImpl();
  587. ::grpc::g_core_codegen_interface->grpc_call_unref(call);
  588. if (GPR_LIKELY(from_reaction)) {
  589. reactor->OnDone(s);
  590. } else {
  591. reactor->InternalScheduleOnDone(std::move(s));
  592. }
  593. }
  594. }
  595. ::grpc::ClientContext* const context_;
  596. grpc::internal::Call call_;
  597. ClientBidiReactor<Request, Response>* const reactor_;
  598. grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
  599. grpc::internal::CallOpRecvInitialMetadata>
  600. start_ops_;
  601. grpc::internal::CallbackWithSuccessTag start_tag_;
  602. const bool start_corked_;
  603. bool corked_write_needed_; // no lock needed since only accessed in
  604. // Write/WritesDone which cannot be concurrent
  605. grpc::internal::CallOpSet<grpc::internal::CallOpClientRecvStatus> finish_ops_;
  606. grpc::internal::CallbackWithSuccessTag finish_tag_;
  607. ::grpc::Status finish_status_;
  608. grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
  609. grpc::internal::CallOpSendMessage,
  610. grpc::internal::CallOpClientSendClose>
  611. write_ops_;
  612. grpc::internal::CallbackWithSuccessTag write_tag_;
  613. grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
  614. grpc::internal::CallOpClientSendClose>
  615. writes_done_ops_;
  616. grpc::internal::CallbackWithSuccessTag writes_done_tag_;
  617. grpc::internal::CallOpSet<grpc::internal::CallOpRecvMessage<Response>>
  618. read_ops_;
  619. grpc::internal::CallbackWithSuccessTag read_tag_;
  620. struct StartCallBacklog {
  621. bool write_ops = false;
  622. bool writes_done_ops = false;
  623. bool read_ops = false;
  624. };
  625. StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
  626. // Minimum of 3 callbacks to pre-register for start ops, StartCall, and finish
  627. std::atomic<intptr_t> callbacks_outstanding_{3};
  628. std::atomic_bool started_{false};
  629. grpc::internal::Mutex start_mu_;
  630. };
  631. template <class Request, class Response>
  632. class ClientCallbackReaderWriterFactory {
  633. public:
  634. static void Create(::grpc::ChannelInterface* channel,
  635. const ::grpc::internal::RpcMethod& method,
  636. ::grpc::ClientContext* context,
  637. ClientBidiReactor<Request, Response>* reactor) {
  638. grpc::internal::Call call =
  639. channel->CreateCall(method, context, channel->CallbackCQ());
  640. ::grpc::g_core_codegen_interface->grpc_call_ref(call.call());
  641. new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
  642. call.call(), sizeof(ClientCallbackReaderWriterImpl<Request, Response>)))
  643. ClientCallbackReaderWriterImpl<Request, Response>(call, context,
  644. reactor);
  645. }
  646. };
  647. template <class Response>
  648. class ClientCallbackReaderImpl : public ClientCallbackReader<Response> {
  649. public:
  650. // always allocated against a call arena, no memory free required
  651. static void operator delete(void* /*ptr*/, std::size_t size) {
  652. GPR_CODEGEN_ASSERT(size == sizeof(ClientCallbackReaderImpl));
  653. }
  654. // This operator should never be called as the memory should be freed as part
  655. // of the arena destruction. It only exists to provide a matching operator
  656. // delete to the operator new so that some compilers will not complain (see
  657. // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
  658. // there are no tests catching the compiler warning.
  659. static void operator delete(void*, void*) { GPR_CODEGEN_ASSERT(false); }
  660. void StartCall() override {
  661. // This call initiates two batches, plus any backlog, each with a callback
  662. // 1. Send initial metadata (unless corked) + recv initial metadata
  663. // 2. Any backlog
  664. // 3. Recv trailing metadata
  665. start_tag_.Set(
  666. call_.call(),
  667. [this](bool ok) {
  668. reactor_->OnReadInitialMetadataDone(
  669. ok && !reactor_->InternalTrailersOnly(call_.call()));
  670. MaybeFinish(/*from_reaction=*/true);
  671. },
  672. &start_ops_, /*can_inline=*/false);
  673. start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
  674. context_->initial_metadata_flags());
  675. start_ops_.RecvInitialMetadata(context_);
  676. start_ops_.set_core_cq_tag(&start_tag_);
  677. call_.PerformOps(&start_ops_);
  678. // Also set up the read tag so it doesn't have to be set up each time
  679. read_tag_.Set(
  680. call_.call(),
  681. [this](bool ok) {
  682. reactor_->OnReadDone(ok);
  683. MaybeFinish(/*from_reaction=*/true);
  684. },
  685. &read_ops_, /*can_inline=*/false);
  686. read_ops_.set_core_cq_tag(&read_tag_);
  687. {
  688. grpc::internal::MutexLock lock(&start_mu_);
  689. if (backlog_.read_ops) {
  690. call_.PerformOps(&read_ops_);
  691. }
  692. started_.store(true, std::memory_order_release);
  693. }
  694. finish_tag_.Set(
  695. call_.call(),
  696. [this](bool /*ok*/) { MaybeFinish(/*from_reaction=*/true); },
  697. &finish_ops_, /*can_inline=*/false);
  698. finish_ops_.ClientRecvStatus(context_, &finish_status_);
  699. finish_ops_.set_core_cq_tag(&finish_tag_);
  700. call_.PerformOps(&finish_ops_);
  701. }
  702. void Read(Response* msg) override {
  703. read_ops_.RecvMessage(msg);
  704. callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
  705. if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
  706. grpc::internal::MutexLock lock(&start_mu_);
  707. if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
  708. backlog_.read_ops = true;
  709. return;
  710. }
  711. }
  712. call_.PerformOps(&read_ops_);
  713. }
  714. void AddHold(int holds) override {
  715. callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed);
  716. }
  717. void RemoveHold() override { MaybeFinish(/*from_reaction=*/false); }
  718. private:
  719. friend class ClientCallbackReaderFactory<Response>;
  720. template <class Request>
  721. ClientCallbackReaderImpl(::grpc::internal::Call call,
  722. ::grpc::ClientContext* context, Request* request,
  723. ClientReadReactor<Response>* reactor)
  724. : context_(context), call_(call), reactor_(reactor) {
  725. this->BindReactor(reactor);
  726. // TODO(vjpai): don't assert
  727. GPR_CODEGEN_ASSERT(start_ops_.SendMessagePtr(request).ok());
  728. start_ops_.ClientSendClose();
  729. }
  730. // MaybeFinish behaves as in ClientCallbackReaderWriterImpl.
  731. void MaybeFinish(bool from_reaction) {
  732. if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(
  733. 1, std::memory_order_acq_rel) == 1)) {
  734. ::grpc::Status s = std::move(finish_status_);
  735. auto* reactor = reactor_;
  736. auto* call = call_.call();
  737. this->~ClientCallbackReaderImpl();
  738. ::grpc::g_core_codegen_interface->grpc_call_unref(call);
  739. if (GPR_LIKELY(from_reaction)) {
  740. reactor->OnDone(s);
  741. } else {
  742. reactor->InternalScheduleOnDone(std::move(s));
  743. }
  744. }
  745. }
  746. ::grpc::ClientContext* const context_;
  747. grpc::internal::Call call_;
  748. ClientReadReactor<Response>* const reactor_;
  749. grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
  750. grpc::internal::CallOpSendMessage,
  751. grpc::internal::CallOpClientSendClose,
  752. grpc::internal::CallOpRecvInitialMetadata>
  753. start_ops_;
  754. grpc::internal::CallbackWithSuccessTag start_tag_;
  755. grpc::internal::CallOpSet<grpc::internal::CallOpClientRecvStatus> finish_ops_;
  756. grpc::internal::CallbackWithSuccessTag finish_tag_;
  757. ::grpc::Status finish_status_;
  758. grpc::internal::CallOpSet<grpc::internal::CallOpRecvMessage<Response>>
  759. read_ops_;
  760. grpc::internal::CallbackWithSuccessTag read_tag_;
  761. struct StartCallBacklog {
  762. bool read_ops = false;
  763. };
  764. StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
  765. // Minimum of 2 callbacks to pre-register for start and finish
  766. std::atomic<intptr_t> callbacks_outstanding_{2};
  767. std::atomic_bool started_{false};
  768. grpc::internal::Mutex start_mu_;
  769. };
  770. template <class Response>
  771. class ClientCallbackReaderFactory {
  772. public:
  773. template <class Request>
  774. static void Create(::grpc::ChannelInterface* channel,
  775. const ::grpc::internal::RpcMethod& method,
  776. ::grpc::ClientContext* context, const Request* request,
  777. ClientReadReactor<Response>* reactor) {
  778. grpc::internal::Call call =
  779. channel->CreateCall(method, context, channel->CallbackCQ());
  780. ::grpc::g_core_codegen_interface->grpc_call_ref(call.call());
  781. new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
  782. call.call(), sizeof(ClientCallbackReaderImpl<Response>)))
  783. ClientCallbackReaderImpl<Response>(call, context, request, reactor);
  784. }
  785. };
  786. template <class Request>
  787. class ClientCallbackWriterImpl : public ClientCallbackWriter<Request> {
  788. public:
  789. // always allocated against a call arena, no memory free required
  790. static void operator delete(void* /*ptr*/, std::size_t size) {
  791. GPR_CODEGEN_ASSERT(size == sizeof(ClientCallbackWriterImpl));
  792. }
  793. // This operator should never be called as the memory should be freed as part
  794. // of the arena destruction. It only exists to provide a matching operator
  795. // delete to the operator new so that some compilers will not complain (see
  796. // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
  797. // there are no tests catching the compiler warning.
  798. static void operator delete(void*, void*) { GPR_CODEGEN_ASSERT(false); }
  799. void StartCall() ABSL_LOCKS_EXCLUDED(start_mu_) override {
  800. // This call initiates two batches, plus any backlog, each with a callback
  801. // 1. Send initial metadata (unless corked) + recv initial metadata
  802. // 2. Any backlog
  803. // 3. Recv trailing metadata
  804. if (!start_corked_) {
  805. start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
  806. context_->initial_metadata_flags());
  807. }
  808. call_.PerformOps(&start_ops_);
  809. {
  810. grpc::internal::MutexLock lock(&start_mu_);
  811. if (backlog_.write_ops) {
  812. call_.PerformOps(&write_ops_);
  813. }
  814. if (backlog_.writes_done_ops) {
  815. call_.PerformOps(&writes_done_ops_);
  816. }
  817. call_.PerformOps(&finish_ops_);
  818. // The last thing in this critical section is to set started_ so that it
  819. // can be used lock-free as well.
  820. started_.store(true, std::memory_order_release);
  821. }
  822. // MaybeFinish outside the lock to make sure that destruction of this object
  823. // doesn't take place while holding the lock (which would cause the lock to
  824. // be released after destruction)
  825. this->MaybeFinish(/*from_reaction=*/false);
  826. }
  827. void Write(const Request* msg, ::grpc::WriteOptions options)
  828. ABSL_LOCKS_EXCLUDED(start_mu_) override {
  829. if (GPR_UNLIKELY(options.is_last_message())) {
  830. options.set_buffer_hint();
  831. write_ops_.ClientSendClose();
  832. }
  833. // TODO(vjpai): don't assert
  834. GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(msg, options).ok());
  835. callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
  836. if (GPR_UNLIKELY(corked_write_needed_)) {
  837. write_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
  838. context_->initial_metadata_flags());
  839. corked_write_needed_ = false;
  840. }
  841. if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
  842. grpc::internal::MutexLock lock(&start_mu_);
  843. if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
  844. backlog_.write_ops = true;
  845. return;
  846. }
  847. }
  848. call_.PerformOps(&write_ops_);
  849. }
  850. void WritesDone() ABSL_LOCKS_EXCLUDED(start_mu_) override {
  851. writes_done_ops_.ClientSendClose();
  852. writes_done_tag_.Set(
  853. call_.call(),
  854. [this](bool ok) {
  855. reactor_->OnWritesDoneDone(ok);
  856. MaybeFinish(/*from_reaction=*/true);
  857. },
  858. &writes_done_ops_, /*can_inline=*/false);
  859. writes_done_ops_.set_core_cq_tag(&writes_done_tag_);
  860. callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
  861. if (GPR_UNLIKELY(corked_write_needed_)) {
  862. writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
  863. context_->initial_metadata_flags());
  864. corked_write_needed_ = false;
  865. }
  866. if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
  867. grpc::internal::MutexLock lock(&start_mu_);
  868. if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
  869. backlog_.writes_done_ops = true;
  870. return;
  871. }
  872. }
  873. call_.PerformOps(&writes_done_ops_);
  874. }
  875. void AddHold(int holds) override {
  876. callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed);
  877. }
  878. void RemoveHold() override { MaybeFinish(/*from_reaction=*/false); }
  879. private:
  880. friend class ClientCallbackWriterFactory<Request>;
  881. template <class Response>
  882. ClientCallbackWriterImpl(::grpc::internal::Call call,
  883. ::grpc::ClientContext* context, Response* response,
  884. ClientWriteReactor<Request>* reactor)
  885. : context_(context),
  886. call_(call),
  887. reactor_(reactor),
  888. start_corked_(context_->initial_metadata_corked_),
  889. corked_write_needed_(start_corked_) {
  890. this->BindReactor(reactor);
  891. // Set up the unchanging parts of the start and write tags and ops.
  892. start_tag_.Set(
  893. call_.call(),
  894. [this](bool ok) {
  895. reactor_->OnReadInitialMetadataDone(
  896. ok && !reactor_->InternalTrailersOnly(call_.call()));
  897. MaybeFinish(/*from_reaction=*/true);
  898. },
  899. &start_ops_, /*can_inline=*/false);
  900. start_ops_.RecvInitialMetadata(context_);
  901. start_ops_.set_core_cq_tag(&start_tag_);
  902. write_tag_.Set(
  903. call_.call(),
  904. [this](bool ok) {
  905. reactor_->OnWriteDone(ok);
  906. MaybeFinish(/*from_reaction=*/true);
  907. },
  908. &write_ops_, /*can_inline=*/false);
  909. write_ops_.set_core_cq_tag(&write_tag_);
  910. // Also set up the Finish tag and op set.
  911. finish_ops_.RecvMessage(response);
  912. finish_ops_.AllowNoMessage();
  913. finish_tag_.Set(
  914. call_.call(),
  915. [this](bool /*ok*/) { MaybeFinish(/*from_reaction=*/true); },
  916. &finish_ops_,
  917. /*can_inline=*/false);
  918. finish_ops_.ClientRecvStatus(context_, &finish_status_);
  919. finish_ops_.set_core_cq_tag(&finish_tag_);
  920. }
  921. // MaybeFinish behaves as in ClientCallbackReaderWriterImpl.
  922. void MaybeFinish(bool from_reaction) {
  923. if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(
  924. 1, std::memory_order_acq_rel) == 1)) {
  925. ::grpc::Status s = std::move(finish_status_);
  926. auto* reactor = reactor_;
  927. auto* call = call_.call();
  928. this->~ClientCallbackWriterImpl();
  929. ::grpc::g_core_codegen_interface->grpc_call_unref(call);
  930. if (GPR_LIKELY(from_reaction)) {
  931. reactor->OnDone(s);
  932. } else {
  933. reactor->InternalScheduleOnDone(std::move(s));
  934. }
  935. }
  936. }
  937. ::grpc::ClientContext* const context_;
  938. grpc::internal::Call call_;
  939. ClientWriteReactor<Request>* const reactor_;
  940. grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
  941. grpc::internal::CallOpRecvInitialMetadata>
  942. start_ops_;
  943. grpc::internal::CallbackWithSuccessTag start_tag_;
  944. const bool start_corked_;
  945. bool corked_write_needed_; // no lock needed since only accessed in
  946. // Write/WritesDone which cannot be concurrent
  947. grpc::internal::CallOpSet<grpc::internal::CallOpGenericRecvMessage,
  948. grpc::internal::CallOpClientRecvStatus>
  949. finish_ops_;
  950. grpc::internal::CallbackWithSuccessTag finish_tag_;
  951. ::grpc::Status finish_status_;
  952. grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
  953. grpc::internal::CallOpSendMessage,
  954. grpc::internal::CallOpClientSendClose>
  955. write_ops_;
  956. grpc::internal::CallbackWithSuccessTag write_tag_;
  957. grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
  958. grpc::internal::CallOpClientSendClose>
  959. writes_done_ops_;
  960. grpc::internal::CallbackWithSuccessTag writes_done_tag_;
  961. struct StartCallBacklog {
  962. bool write_ops = false;
  963. bool writes_done_ops = false;
  964. };
  965. StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
  966. // Minimum of 3 callbacks to pre-register for start ops, StartCall, and finish
  967. std::atomic<intptr_t> callbacks_outstanding_{3};
  968. std::atomic_bool started_{false};
  969. grpc::internal::Mutex start_mu_;
  970. };
  971. template <class Request>
  972. class ClientCallbackWriterFactory {
  973. public:
  974. template <class Response>
  975. static void Create(::grpc::ChannelInterface* channel,
  976. const ::grpc::internal::RpcMethod& method,
  977. ::grpc::ClientContext* context, Response* response,
  978. ClientWriteReactor<Request>* reactor) {
  979. grpc::internal::Call call =
  980. channel->CreateCall(method, context, channel->CallbackCQ());
  981. ::grpc::g_core_codegen_interface->grpc_call_ref(call.call());
  982. new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
  983. call.call(), sizeof(ClientCallbackWriterImpl<Request>)))
  984. ClientCallbackWriterImpl<Request>(call, context, response, reactor);
  985. }
  986. };
  987. class ClientCallbackUnaryImpl final : public ClientCallbackUnary {
  988. public:
  989. // always allocated against a call arena, no memory free required
  990. static void operator delete(void* /*ptr*/, std::size_t size) {
  991. GPR_CODEGEN_ASSERT(size == sizeof(ClientCallbackUnaryImpl));
  992. }
  993. // This operator should never be called as the memory should be freed as part
  994. // of the arena destruction. It only exists to provide a matching operator
  995. // delete to the operator new so that some compilers will not complain (see
  996. // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
  997. // there are no tests catching the compiler warning.
  998. static void operator delete(void*, void*) { GPR_CODEGEN_ASSERT(false); }
  999. void StartCall() override {
  1000. // This call initiates two batches, each with a callback
  1001. // 1. Send initial metadata + write + writes done + recv initial metadata
  1002. // 2. Read message, recv trailing metadata
  1003. start_tag_.Set(
  1004. call_.call(),
  1005. [this](bool ok) {
  1006. reactor_->OnReadInitialMetadataDone(
  1007. ok && !reactor_->InternalTrailersOnly(call_.call()));
  1008. MaybeFinish();
  1009. },
  1010. &start_ops_, /*can_inline=*/false);
  1011. start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
  1012. context_->initial_metadata_flags());
  1013. start_ops_.RecvInitialMetadata(context_);
  1014. start_ops_.set_core_cq_tag(&start_tag_);
  1015. call_.PerformOps(&start_ops_);
  1016. finish_tag_.Set(
  1017. call_.call(), [this](bool /*ok*/) { MaybeFinish(); }, &finish_ops_,
  1018. /*can_inline=*/false);
  1019. finish_ops_.ClientRecvStatus(context_, &finish_status_);
  1020. finish_ops_.set_core_cq_tag(&finish_tag_);
  1021. call_.PerformOps(&finish_ops_);
  1022. }
  1023. private:
  1024. friend class ClientCallbackUnaryFactory;
  1025. template <class Request, class Response>
  1026. ClientCallbackUnaryImpl(::grpc::internal::Call call,
  1027. ::grpc::ClientContext* context, Request* request,
  1028. Response* response, ClientUnaryReactor* reactor)
  1029. : context_(context), call_(call), reactor_(reactor) {
  1030. this->BindReactor(reactor);
  1031. // TODO(vjpai): don't assert
  1032. GPR_CODEGEN_ASSERT(start_ops_.SendMessagePtr(request).ok());
  1033. start_ops_.ClientSendClose();
  1034. finish_ops_.RecvMessage(response);
  1035. finish_ops_.AllowNoMessage();
  1036. }
  1037. // In the unary case, MaybeFinish is only ever invoked from a
  1038. // library-initiated reaction, so it will just directly call OnDone if this is
  1039. // the last reaction for this RPC.
  1040. void MaybeFinish() {
  1041. if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(
  1042. 1, std::memory_order_acq_rel) == 1)) {
  1043. ::grpc::Status s = std::move(finish_status_);
  1044. auto* reactor = reactor_;
  1045. auto* call = call_.call();
  1046. this->~ClientCallbackUnaryImpl();
  1047. ::grpc::g_core_codegen_interface->grpc_call_unref(call);
  1048. reactor->OnDone(s);
  1049. }
  1050. }
  1051. ::grpc::ClientContext* const context_;
  1052. grpc::internal::Call call_;
  1053. ClientUnaryReactor* const reactor_;
  1054. grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
  1055. grpc::internal::CallOpSendMessage,
  1056. grpc::internal::CallOpClientSendClose,
  1057. grpc::internal::CallOpRecvInitialMetadata>
  1058. start_ops_;
  1059. grpc::internal::CallbackWithSuccessTag start_tag_;
  1060. grpc::internal::CallOpSet<grpc::internal::CallOpGenericRecvMessage,
  1061. grpc::internal::CallOpClientRecvStatus>
  1062. finish_ops_;
  1063. grpc::internal::CallbackWithSuccessTag finish_tag_;
  1064. ::grpc::Status finish_status_;
  1065. // This call will have 2 callbacks: start and finish
  1066. std::atomic<intptr_t> callbacks_outstanding_{2};
  1067. };
  1068. class ClientCallbackUnaryFactory {
  1069. public:
  1070. template <class Request, class Response, class BaseRequest = Request,
  1071. class BaseResponse = Response>
  1072. static void Create(::grpc::ChannelInterface* channel,
  1073. const ::grpc::internal::RpcMethod& method,
  1074. ::grpc::ClientContext* context, const Request* request,
  1075. Response* response, ClientUnaryReactor* reactor) {
  1076. grpc::internal::Call call =
  1077. channel->CreateCall(method, context, channel->CallbackCQ());
  1078. ::grpc::g_core_codegen_interface->grpc_call_ref(call.call());
  1079. new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
  1080. call.call(), sizeof(ClientCallbackUnaryImpl)))
  1081. ClientCallbackUnaryImpl(call, context,
  1082. static_cast<const BaseRequest*>(request),
  1083. static_cast<BaseResponse*>(response), reactor);
  1084. }
  1085. };
  1086. } // namespace internal
  1087. } // namespace grpc
  1088. #endif // GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_H