client_callback.h 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229
  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) { StartWrite(req, grpc::WriteOptions()); }
  232. /// Initiate/post a write operation with specified options.
  233. ///
  234. /// \param[in] req The message to be written. The library does not take
  235. /// ownership but the caller must ensure that the message is
  236. /// not deleted or modified until OnWriteDone is called.
  237. /// \param[in] options The WriteOptions to use for writing this message
  238. void StartWrite(const Request* req, grpc::WriteOptions options) {
  239. stream_->Write(req, options);
  240. }
  241. /// Initiate/post a write operation with specified options and an indication
  242. /// that this is the last write (like StartWrite and StartWritesDone, merged).
  243. /// Note that calling this means that no more calls to StartWrite,
  244. /// StartWriteLast, or StartWritesDone are allowed.
  245. ///
  246. /// \param[in] req The message to be written. The library does not take
  247. /// ownership but the caller must ensure that the message is
  248. /// not deleted or modified until OnWriteDone is called.
  249. /// \param[in] options The WriteOptions to use for writing this message
  250. void StartWriteLast(const Request* req, grpc::WriteOptions options) {
  251. StartWrite(req, options.set_last_message());
  252. }
  253. /// Indicate that the RPC will have no more write operations. This can only be
  254. /// issued once for a given RPC. This is not required or allowed if
  255. /// StartWriteLast is used since that already has the same implication.
  256. /// Note that calling this means that no more calls to StartWrite,
  257. /// StartWriteLast, or StartWritesDone are allowed.
  258. void StartWritesDone() { stream_->WritesDone(); }
  259. /// Holds are needed if (and only if) this stream has operations that take
  260. /// place on it after StartCall but from outside one of the reactions
  261. /// (OnReadDone, etc). This is _not_ a common use of the streaming API.
  262. ///
  263. /// Holds must be added before calling StartCall. If a stream still has a hold
  264. /// in place, its resources will not be destroyed even if the status has
  265. /// already come in from the wire and there are currently no active callbacks
  266. /// outstanding. Similarly, the stream will not call OnDone if there are still
  267. /// holds on it.
  268. ///
  269. /// For example, if a StartRead or StartWrite operation is going to be
  270. /// initiated from elsewhere in the application, the application should call
  271. /// AddHold or AddMultipleHolds before StartCall. If there is going to be,
  272. /// for example, a read-flow and a write-flow taking place outside the
  273. /// reactions, then call AddMultipleHolds(2) before StartCall. When the
  274. /// application knows that it won't issue any more read operations (such as
  275. /// when a read comes back as not ok), it should issue a RemoveHold(). It
  276. /// should also call RemoveHold() again after it does StartWriteLast or
  277. /// StartWritesDone that indicates that there will be no more write ops.
  278. /// The number of RemoveHold calls must match the total number of AddHold
  279. /// calls plus the number of holds added by AddMultipleHolds.
  280. /// The argument to AddMultipleHolds must be positive.
  281. void AddHold() { AddMultipleHolds(1); }
  282. void AddMultipleHolds(int holds) {
  283. GPR_CODEGEN_DEBUG_ASSERT(holds > 0);
  284. stream_->AddHold(holds);
  285. }
  286. void RemoveHold() { stream_->RemoveHold(); }
  287. /// Notifies the application that all operations associated with this RPC
  288. /// have completed and all Holds have been removed. OnDone provides the RPC
  289. /// status outcome for both successful and failed RPCs and will be called in
  290. /// all cases. If it is not called, it indicates an application-level problem
  291. /// (like failure to remove a hold).
  292. ///
  293. /// \param[in] s The status outcome of this RPC
  294. void OnDone(const grpc::Status& /*s*/) override {}
  295. /// Notifies the application that a read of initial metadata from the
  296. /// server is done. If the application chooses not to implement this method,
  297. /// it can assume that the initial metadata has been read before the first
  298. /// call of OnReadDone or OnDone.
  299. ///
  300. /// \param[in] ok Was the initial metadata read successfully? If false, no
  301. /// new read/write operation will succeed, and any further
  302. /// Start* operations should not be called.
  303. virtual void OnReadInitialMetadataDone(bool /*ok*/) {}
  304. /// Notifies the application that a StartRead operation completed.
  305. ///
  306. /// \param[in] ok Was it successful? If false, no new read/write operation
  307. /// will succeed, and any further Start* should not be called.
  308. virtual void OnReadDone(bool /*ok*/) {}
  309. /// Notifies the application that a StartWrite or StartWriteLast operation
  310. /// completed.
  311. ///
  312. /// \param[in] ok Was it successful? If false, no new read/write operation
  313. /// will succeed, and any further Start* should not be called.
  314. virtual void OnWriteDone(bool /*ok*/) {}
  315. /// Notifies the application that a StartWritesDone operation completed. Note
  316. /// that this is only used on explicit StartWritesDone operations and not for
  317. /// those that are implicitly invoked as part of a StartWriteLast.
  318. ///
  319. /// \param[in] ok Was it successful? If false, the application will later see
  320. /// the failure reflected as a bad status in OnDone and no
  321. /// further Start* should be called.
  322. virtual void OnWritesDoneDone(bool /*ok*/) {}
  323. private:
  324. friend class ClientCallbackReaderWriter<Request, Response>;
  325. void BindStream(ClientCallbackReaderWriter<Request, Response>* stream) {
  326. stream_ = stream;
  327. }
  328. ClientCallbackReaderWriter<Request, Response>* stream_;
  329. };
  330. /// \a ClientReadReactor is the interface for a server-streaming RPC.
  331. /// All public methods behave as in ClientBidiReactor.
  332. template <class Response>
  333. class ClientReadReactor : public internal::ClientReactor {
  334. public:
  335. void StartCall() { reader_->StartCall(); }
  336. void StartRead(Response* resp) { reader_->Read(resp); }
  337. void AddHold() { AddMultipleHolds(1); }
  338. void AddMultipleHolds(int holds) {
  339. GPR_CODEGEN_DEBUG_ASSERT(holds > 0);
  340. reader_->AddHold(holds);
  341. }
  342. void RemoveHold() { reader_->RemoveHold(); }
  343. void OnDone(const grpc::Status& /*s*/) override {}
  344. virtual void OnReadInitialMetadataDone(bool /*ok*/) {}
  345. virtual void OnReadDone(bool /*ok*/) {}
  346. private:
  347. friend class ClientCallbackReader<Response>;
  348. void BindReader(ClientCallbackReader<Response>* reader) { reader_ = reader; }
  349. ClientCallbackReader<Response>* reader_;
  350. };
  351. /// \a ClientWriteReactor is the interface for a client-streaming RPC.
  352. /// All public methods behave as in ClientBidiReactor.
  353. template <class Request>
  354. class ClientWriteReactor : public internal::ClientReactor {
  355. public:
  356. void StartCall() { writer_->StartCall(); }
  357. void StartWrite(const Request* req) { StartWrite(req, grpc::WriteOptions()); }
  358. void StartWrite(const Request* req, grpc::WriteOptions options) {
  359. writer_->Write(req, options);
  360. }
  361. void StartWriteLast(const Request* req, grpc::WriteOptions options) {
  362. StartWrite(req, options.set_last_message());
  363. }
  364. void StartWritesDone() { writer_->WritesDone(); }
  365. void AddHold() { AddMultipleHolds(1); }
  366. void AddMultipleHolds(int holds) {
  367. GPR_CODEGEN_DEBUG_ASSERT(holds > 0);
  368. writer_->AddHold(holds);
  369. }
  370. void RemoveHold() { writer_->RemoveHold(); }
  371. void OnDone(const grpc::Status& /*s*/) override {}
  372. virtual void OnReadInitialMetadataDone(bool /*ok*/) {}
  373. virtual void OnWriteDone(bool /*ok*/) {}
  374. virtual void OnWritesDoneDone(bool /*ok*/) {}
  375. private:
  376. friend class ClientCallbackWriter<Request>;
  377. void BindWriter(ClientCallbackWriter<Request>* writer) { writer_ = writer; }
  378. ClientCallbackWriter<Request>* writer_;
  379. };
  380. /// \a ClientUnaryReactor is a reactor-style interface for a unary RPC.
  381. /// This is _not_ a common way of invoking a unary RPC. In practice, this
  382. /// option should be used only if the unary RPC wants to receive initial
  383. /// metadata without waiting for the response to complete. Most deployments of
  384. /// RPC systems do not use this option, but it is needed for generality.
  385. /// All public methods behave as in ClientBidiReactor.
  386. /// StartCall is included for consistency with the other reactor flavors: even
  387. /// though there are no StartRead or StartWrite operations to queue before the
  388. /// call (that is part of the unary call itself) and there is no reactor object
  389. /// being created as a result of this call, we keep a consistent 2-phase
  390. /// initiation API among all the reactor flavors.
  391. class ClientUnaryReactor : public internal::ClientReactor {
  392. public:
  393. void StartCall() { call_->StartCall(); }
  394. void OnDone(const grpc::Status& /*s*/) override {}
  395. virtual void OnReadInitialMetadataDone(bool /*ok*/) {}
  396. private:
  397. friend class ClientCallbackUnary;
  398. void BindCall(ClientCallbackUnary* call) { call_ = call; }
  399. ClientCallbackUnary* call_;
  400. };
  401. // Define function out-of-line from class to avoid forward declaration issue
  402. inline void ClientCallbackUnary::BindReactor(ClientUnaryReactor* reactor) {
  403. reactor->BindCall(this);
  404. }
  405. namespace internal {
  406. // Forward declare factory classes for friendship
  407. template <class Request, class Response>
  408. class ClientCallbackReaderWriterFactory;
  409. template <class Response>
  410. class ClientCallbackReaderFactory;
  411. template <class Request>
  412. class ClientCallbackWriterFactory;
  413. template <class Request, class Response>
  414. class ClientCallbackReaderWriterImpl
  415. : public ClientCallbackReaderWriter<Request, Response> {
  416. public:
  417. // always allocated against a call arena, no memory free required
  418. static void operator delete(void* /*ptr*/, std::size_t size) {
  419. GPR_CODEGEN_ASSERT(size == sizeof(ClientCallbackReaderWriterImpl));
  420. }
  421. // This operator should never be called as the memory should be freed as part
  422. // of the arena destruction. It only exists to provide a matching operator
  423. // delete to the operator new so that some compilers will not complain (see
  424. // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
  425. // there are no tests catching the compiler warning.
  426. static void operator delete(void*, void*) { GPR_CODEGEN_ASSERT(false); }
  427. void StartCall() ABSL_LOCKS_EXCLUDED(start_mu_) override {
  428. // This call initiates two batches, plus any backlog, each with a callback
  429. // 1. Send initial metadata (unless corked) + recv initial metadata
  430. // 2. Any read backlog
  431. // 3. Any write backlog
  432. // 4. Recv trailing metadata (unless corked)
  433. if (!start_corked_) {
  434. start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
  435. context_->initial_metadata_flags());
  436. }
  437. call_.PerformOps(&start_ops_);
  438. {
  439. grpc::internal::MutexLock lock(&start_mu_);
  440. if (backlog_.read_ops) {
  441. call_.PerformOps(&read_ops_);
  442. }
  443. if (backlog_.write_ops) {
  444. call_.PerformOps(&write_ops_);
  445. }
  446. if (backlog_.writes_done_ops) {
  447. call_.PerformOps(&writes_done_ops_);
  448. }
  449. call_.PerformOps(&finish_ops_);
  450. // The last thing in this critical section is to set started_ so that it
  451. // can be used lock-free as well.
  452. started_.store(true, std::memory_order_release);
  453. }
  454. // MaybeFinish outside the lock to make sure that destruction of this object
  455. // doesn't take place while holding the lock (which would cause the lock to
  456. // be released after destruction)
  457. this->MaybeFinish(/*from_reaction=*/false);
  458. }
  459. void Read(Response* msg) override {
  460. read_ops_.RecvMessage(msg);
  461. callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
  462. if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
  463. grpc::internal::MutexLock lock(&start_mu_);
  464. if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
  465. backlog_.read_ops = true;
  466. return;
  467. }
  468. }
  469. call_.PerformOps(&read_ops_);
  470. }
  471. void Write(const Request* msg, grpc::WriteOptions options)
  472. ABSL_LOCKS_EXCLUDED(start_mu_) override {
  473. if (options.is_last_message()) {
  474. options.set_buffer_hint();
  475. write_ops_.ClientSendClose();
  476. }
  477. // TODO(vjpai): don't assert
  478. GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(msg, options).ok());
  479. callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
  480. if (GPR_UNLIKELY(corked_write_needed_)) {
  481. write_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
  482. context_->initial_metadata_flags());
  483. corked_write_needed_ = false;
  484. }
  485. if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
  486. grpc::internal::MutexLock lock(&start_mu_);
  487. if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
  488. backlog_.write_ops = true;
  489. return;
  490. }
  491. }
  492. call_.PerformOps(&write_ops_);
  493. }
  494. void WritesDone() ABSL_LOCKS_EXCLUDED(start_mu_) override {
  495. writes_done_ops_.ClientSendClose();
  496. writes_done_tag_.Set(
  497. call_.call(),
  498. [this](bool ok) {
  499. reactor_->OnWritesDoneDone(ok);
  500. MaybeFinish(/*from_reaction=*/true);
  501. },
  502. &writes_done_ops_, /*can_inline=*/false);
  503. writes_done_ops_.set_core_cq_tag(&writes_done_tag_);
  504. callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
  505. if (GPR_UNLIKELY(corked_write_needed_)) {
  506. writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
  507. context_->initial_metadata_flags());
  508. corked_write_needed_ = false;
  509. }
  510. if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
  511. grpc::internal::MutexLock lock(&start_mu_);
  512. if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
  513. backlog_.writes_done_ops = true;
  514. return;
  515. }
  516. }
  517. call_.PerformOps(&writes_done_ops_);
  518. }
  519. void AddHold(int holds) override {
  520. callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed);
  521. }
  522. void RemoveHold() override { MaybeFinish(/*from_reaction=*/false); }
  523. private:
  524. friend class ClientCallbackReaderWriterFactory<Request, Response>;
  525. ClientCallbackReaderWriterImpl(grpc::internal::Call call,
  526. grpc::ClientContext* context,
  527. ClientBidiReactor<Request, Response>* reactor)
  528. : context_(context),
  529. call_(call),
  530. reactor_(reactor),
  531. start_corked_(context_->initial_metadata_corked_),
  532. corked_write_needed_(start_corked_) {
  533. this->BindReactor(reactor);
  534. // Set up the unchanging parts of the start, read, and write tags and ops.
  535. start_tag_.Set(
  536. call_.call(),
  537. [this](bool ok) {
  538. reactor_->OnReadInitialMetadataDone(
  539. ok && !reactor_->InternalTrailersOnly(call_.call()));
  540. MaybeFinish(/*from_reaction=*/true);
  541. },
  542. &start_ops_, /*can_inline=*/false);
  543. start_ops_.RecvInitialMetadata(context_);
  544. start_ops_.set_core_cq_tag(&start_tag_);
  545. write_tag_.Set(
  546. call_.call(),
  547. [this](bool ok) {
  548. reactor_->OnWriteDone(ok);
  549. MaybeFinish(/*from_reaction=*/true);
  550. },
  551. &write_ops_, /*can_inline=*/false);
  552. write_ops_.set_core_cq_tag(&write_tag_);
  553. read_tag_.Set(
  554. call_.call(),
  555. [this](bool ok) {
  556. reactor_->OnReadDone(ok);
  557. MaybeFinish(/*from_reaction=*/true);
  558. },
  559. &read_ops_, /*can_inline=*/false);
  560. read_ops_.set_core_cq_tag(&read_tag_);
  561. // Also set up the Finish tag and op set.
  562. finish_tag_.Set(
  563. call_.call(),
  564. [this](bool /*ok*/) { MaybeFinish(/*from_reaction=*/true); },
  565. &finish_ops_,
  566. /*can_inline=*/false);
  567. finish_ops_.ClientRecvStatus(context_, &finish_status_);
  568. finish_ops_.set_core_cq_tag(&finish_tag_);
  569. }
  570. // MaybeFinish can be called from reactions or from user-initiated operations
  571. // like StartCall or RemoveHold. If this is the last operation or hold on this
  572. // object, it will invoke the OnDone reaction. If MaybeFinish was called from
  573. // a reaction, it can call OnDone directly. If not, it would need to schedule
  574. // OnDone onto an executor thread to avoid the possibility of deadlocking with
  575. // any locks in the user code that invoked it.
  576. void MaybeFinish(bool from_reaction) {
  577. if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(
  578. 1, std::memory_order_acq_rel) == 1)) {
  579. grpc::Status s = std::move(finish_status_);
  580. auto* reactor = reactor_;
  581. auto* call = call_.call();
  582. this->~ClientCallbackReaderWriterImpl();
  583. grpc::g_core_codegen_interface->grpc_call_unref(call);
  584. if (GPR_LIKELY(from_reaction)) {
  585. reactor->OnDone(s);
  586. } else {
  587. reactor->InternalScheduleOnDone(std::move(s));
  588. }
  589. }
  590. }
  591. grpc::ClientContext* const context_;
  592. grpc::internal::Call call_;
  593. ClientBidiReactor<Request, Response>* const reactor_;
  594. grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
  595. grpc::internal::CallOpRecvInitialMetadata>
  596. start_ops_;
  597. grpc::internal::CallbackWithSuccessTag start_tag_;
  598. const bool start_corked_;
  599. bool corked_write_needed_; // no lock needed since only accessed in
  600. // Write/WritesDone which cannot be concurrent
  601. grpc::internal::CallOpSet<grpc::internal::CallOpClientRecvStatus> finish_ops_;
  602. grpc::internal::CallbackWithSuccessTag finish_tag_;
  603. grpc::Status finish_status_;
  604. grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
  605. grpc::internal::CallOpSendMessage,
  606. grpc::internal::CallOpClientSendClose>
  607. write_ops_;
  608. grpc::internal::CallbackWithSuccessTag write_tag_;
  609. grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
  610. grpc::internal::CallOpClientSendClose>
  611. writes_done_ops_;
  612. grpc::internal::CallbackWithSuccessTag writes_done_tag_;
  613. grpc::internal::CallOpSet<grpc::internal::CallOpRecvMessage<Response>>
  614. read_ops_;
  615. grpc::internal::CallbackWithSuccessTag read_tag_;
  616. struct StartCallBacklog {
  617. bool write_ops = false;
  618. bool writes_done_ops = false;
  619. bool read_ops = false;
  620. };
  621. StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
  622. // Minimum of 3 callbacks to pre-register for start ops, StartCall, and finish
  623. std::atomic<intptr_t> callbacks_outstanding_{3};
  624. std::atomic_bool started_{false};
  625. grpc::internal::Mutex start_mu_;
  626. };
  627. template <class Request, class Response>
  628. class ClientCallbackReaderWriterFactory {
  629. public:
  630. static void Create(grpc::ChannelInterface* channel,
  631. const grpc::internal::RpcMethod& method,
  632. grpc::ClientContext* context,
  633. ClientBidiReactor<Request, Response>* reactor) {
  634. grpc::internal::Call call =
  635. channel->CreateCall(method, context, channel->CallbackCQ());
  636. grpc::g_core_codegen_interface->grpc_call_ref(call.call());
  637. new (grpc::g_core_codegen_interface->grpc_call_arena_alloc(
  638. call.call(), sizeof(ClientCallbackReaderWriterImpl<Request, Response>)))
  639. ClientCallbackReaderWriterImpl<Request, Response>(call, context,
  640. reactor);
  641. }
  642. };
  643. template <class Response>
  644. class ClientCallbackReaderImpl : public ClientCallbackReader<Response> {
  645. public:
  646. // always allocated against a call arena, no memory free required
  647. static void operator delete(void* /*ptr*/, std::size_t size) {
  648. GPR_CODEGEN_ASSERT(size == sizeof(ClientCallbackReaderImpl));
  649. }
  650. // This operator should never be called as the memory should be freed as part
  651. // of the arena destruction. It only exists to provide a matching operator
  652. // delete to the operator new so that some compilers will not complain (see
  653. // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
  654. // there are no tests catching the compiler warning.
  655. static void operator delete(void*, void*) { GPR_CODEGEN_ASSERT(false); }
  656. void StartCall() override {
  657. // This call initiates two batches, plus any backlog, each with a callback
  658. // 1. Send initial metadata (unless corked) + recv initial metadata
  659. // 2. Any backlog
  660. // 3. Recv trailing metadata
  661. start_tag_.Set(
  662. call_.call(),
  663. [this](bool ok) {
  664. reactor_->OnReadInitialMetadataDone(
  665. ok && !reactor_->InternalTrailersOnly(call_.call()));
  666. MaybeFinish(/*from_reaction=*/true);
  667. },
  668. &start_ops_, /*can_inline=*/false);
  669. start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
  670. context_->initial_metadata_flags());
  671. start_ops_.RecvInitialMetadata(context_);
  672. start_ops_.set_core_cq_tag(&start_tag_);
  673. call_.PerformOps(&start_ops_);
  674. // Also set up the read tag so it doesn't have to be set up each time
  675. read_tag_.Set(
  676. call_.call(),
  677. [this](bool ok) {
  678. reactor_->OnReadDone(ok);
  679. MaybeFinish(/*from_reaction=*/true);
  680. },
  681. &read_ops_, /*can_inline=*/false);
  682. read_ops_.set_core_cq_tag(&read_tag_);
  683. {
  684. grpc::internal::MutexLock lock(&start_mu_);
  685. if (backlog_.read_ops) {
  686. call_.PerformOps(&read_ops_);
  687. }
  688. started_.store(true, std::memory_order_release);
  689. }
  690. finish_tag_.Set(
  691. call_.call(),
  692. [this](bool /*ok*/) { MaybeFinish(/*from_reaction=*/true); },
  693. &finish_ops_, /*can_inline=*/false);
  694. finish_ops_.ClientRecvStatus(context_, &finish_status_);
  695. finish_ops_.set_core_cq_tag(&finish_tag_);
  696. call_.PerformOps(&finish_ops_);
  697. }
  698. void Read(Response* msg) override {
  699. read_ops_.RecvMessage(msg);
  700. callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
  701. if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
  702. grpc::internal::MutexLock lock(&start_mu_);
  703. if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
  704. backlog_.read_ops = true;
  705. return;
  706. }
  707. }
  708. call_.PerformOps(&read_ops_);
  709. }
  710. void AddHold(int holds) override {
  711. callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed);
  712. }
  713. void RemoveHold() override { MaybeFinish(/*from_reaction=*/false); }
  714. private:
  715. friend class ClientCallbackReaderFactory<Response>;
  716. template <class Request>
  717. ClientCallbackReaderImpl(grpc::internal::Call call,
  718. grpc::ClientContext* context, Request* request,
  719. ClientReadReactor<Response>* reactor)
  720. : context_(context), call_(call), reactor_(reactor) {
  721. this->BindReactor(reactor);
  722. // TODO(vjpai): don't assert
  723. GPR_CODEGEN_ASSERT(start_ops_.SendMessagePtr(request).ok());
  724. start_ops_.ClientSendClose();
  725. }
  726. // MaybeFinish behaves as in ClientCallbackReaderWriterImpl.
  727. void MaybeFinish(bool from_reaction) {
  728. if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(
  729. 1, std::memory_order_acq_rel) == 1)) {
  730. grpc::Status s = std::move(finish_status_);
  731. auto* reactor = reactor_;
  732. auto* call = call_.call();
  733. this->~ClientCallbackReaderImpl();
  734. grpc::g_core_codegen_interface->grpc_call_unref(call);
  735. if (GPR_LIKELY(from_reaction)) {
  736. reactor->OnDone(s);
  737. } else {
  738. reactor->InternalScheduleOnDone(std::move(s));
  739. }
  740. }
  741. }
  742. grpc::ClientContext* const context_;
  743. grpc::internal::Call call_;
  744. ClientReadReactor<Response>* const reactor_;
  745. grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
  746. grpc::internal::CallOpSendMessage,
  747. grpc::internal::CallOpClientSendClose,
  748. grpc::internal::CallOpRecvInitialMetadata>
  749. start_ops_;
  750. grpc::internal::CallbackWithSuccessTag start_tag_;
  751. grpc::internal::CallOpSet<grpc::internal::CallOpClientRecvStatus> finish_ops_;
  752. grpc::internal::CallbackWithSuccessTag finish_tag_;
  753. grpc::Status finish_status_;
  754. grpc::internal::CallOpSet<grpc::internal::CallOpRecvMessage<Response>>
  755. read_ops_;
  756. grpc::internal::CallbackWithSuccessTag read_tag_;
  757. struct StartCallBacklog {
  758. bool read_ops = false;
  759. };
  760. StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
  761. // Minimum of 2 callbacks to pre-register for start and finish
  762. std::atomic<intptr_t> callbacks_outstanding_{2};
  763. std::atomic_bool started_{false};
  764. grpc::internal::Mutex start_mu_;
  765. };
  766. template <class Response>
  767. class ClientCallbackReaderFactory {
  768. public:
  769. template <class Request>
  770. static void Create(grpc::ChannelInterface* channel,
  771. const grpc::internal::RpcMethod& method,
  772. grpc::ClientContext* context, const Request* request,
  773. ClientReadReactor<Response>* reactor) {
  774. grpc::internal::Call call =
  775. channel->CreateCall(method, context, channel->CallbackCQ());
  776. grpc::g_core_codegen_interface->grpc_call_ref(call.call());
  777. new (grpc::g_core_codegen_interface->grpc_call_arena_alloc(
  778. call.call(), sizeof(ClientCallbackReaderImpl<Response>)))
  779. ClientCallbackReaderImpl<Response>(call, context, request, reactor);
  780. }
  781. };
  782. template <class Request>
  783. class ClientCallbackWriterImpl : public ClientCallbackWriter<Request> {
  784. public:
  785. // always allocated against a call arena, no memory free required
  786. static void operator delete(void* /*ptr*/, std::size_t size) {
  787. GPR_CODEGEN_ASSERT(size == sizeof(ClientCallbackWriterImpl));
  788. }
  789. // This operator should never be called as the memory should be freed as part
  790. // of the arena destruction. It only exists to provide a matching operator
  791. // delete to the operator new so that some compilers will not complain (see
  792. // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
  793. // there are no tests catching the compiler warning.
  794. static void operator delete(void*, void*) { GPR_CODEGEN_ASSERT(false); }
  795. void StartCall() ABSL_LOCKS_EXCLUDED(start_mu_) override {
  796. // This call initiates two batches, plus any backlog, each with a callback
  797. // 1. Send initial metadata (unless corked) + recv initial metadata
  798. // 2. Any backlog
  799. // 3. Recv trailing metadata
  800. if (!start_corked_) {
  801. start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
  802. context_->initial_metadata_flags());
  803. }
  804. call_.PerformOps(&start_ops_);
  805. {
  806. grpc::internal::MutexLock lock(&start_mu_);
  807. if (backlog_.write_ops) {
  808. call_.PerformOps(&write_ops_);
  809. }
  810. if (backlog_.writes_done_ops) {
  811. call_.PerformOps(&writes_done_ops_);
  812. }
  813. call_.PerformOps(&finish_ops_);
  814. // The last thing in this critical section is to set started_ so that it
  815. // can be used lock-free as well.
  816. started_.store(true, std::memory_order_release);
  817. }
  818. // MaybeFinish outside the lock to make sure that destruction of this object
  819. // doesn't take place while holding the lock (which would cause the lock to
  820. // be released after destruction)
  821. this->MaybeFinish(/*from_reaction=*/false);
  822. }
  823. void Write(const Request* msg, grpc::WriteOptions options)
  824. ABSL_LOCKS_EXCLUDED(start_mu_) override {
  825. if (GPR_UNLIKELY(options.is_last_message())) {
  826. options.set_buffer_hint();
  827. write_ops_.ClientSendClose();
  828. }
  829. // TODO(vjpai): don't assert
  830. GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(msg, options).ok());
  831. callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
  832. if (GPR_UNLIKELY(corked_write_needed_)) {
  833. write_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
  834. context_->initial_metadata_flags());
  835. corked_write_needed_ = false;
  836. }
  837. if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
  838. grpc::internal::MutexLock lock(&start_mu_);
  839. if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
  840. backlog_.write_ops = true;
  841. return;
  842. }
  843. }
  844. call_.PerformOps(&write_ops_);
  845. }
  846. void WritesDone() ABSL_LOCKS_EXCLUDED(start_mu_) override {
  847. writes_done_ops_.ClientSendClose();
  848. writes_done_tag_.Set(
  849. call_.call(),
  850. [this](bool ok) {
  851. reactor_->OnWritesDoneDone(ok);
  852. MaybeFinish(/*from_reaction=*/true);
  853. },
  854. &writes_done_ops_, /*can_inline=*/false);
  855. writes_done_ops_.set_core_cq_tag(&writes_done_tag_);
  856. callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
  857. if (GPR_UNLIKELY(corked_write_needed_)) {
  858. writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
  859. context_->initial_metadata_flags());
  860. corked_write_needed_ = false;
  861. }
  862. if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
  863. grpc::internal::MutexLock lock(&start_mu_);
  864. if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
  865. backlog_.writes_done_ops = true;
  866. return;
  867. }
  868. }
  869. call_.PerformOps(&writes_done_ops_);
  870. }
  871. void AddHold(int holds) override {
  872. callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed);
  873. }
  874. void RemoveHold() override { MaybeFinish(/*from_reaction=*/false); }
  875. private:
  876. friend class ClientCallbackWriterFactory<Request>;
  877. template <class Response>
  878. ClientCallbackWriterImpl(grpc::internal::Call call,
  879. grpc::ClientContext* context, Response* response,
  880. ClientWriteReactor<Request>* reactor)
  881. : context_(context),
  882. call_(call),
  883. reactor_(reactor),
  884. start_corked_(context_->initial_metadata_corked_),
  885. corked_write_needed_(start_corked_) {
  886. this->BindReactor(reactor);
  887. // Set up the unchanging parts of the start and write tags and ops.
  888. start_tag_.Set(
  889. call_.call(),
  890. [this](bool ok) {
  891. reactor_->OnReadInitialMetadataDone(
  892. ok && !reactor_->InternalTrailersOnly(call_.call()));
  893. MaybeFinish(/*from_reaction=*/true);
  894. },
  895. &start_ops_, /*can_inline=*/false);
  896. start_ops_.RecvInitialMetadata(context_);
  897. start_ops_.set_core_cq_tag(&start_tag_);
  898. write_tag_.Set(
  899. call_.call(),
  900. [this](bool ok) {
  901. reactor_->OnWriteDone(ok);
  902. MaybeFinish(/*from_reaction=*/true);
  903. },
  904. &write_ops_, /*can_inline=*/false);
  905. write_ops_.set_core_cq_tag(&write_tag_);
  906. // Also set up the Finish tag and op set.
  907. finish_ops_.RecvMessage(response);
  908. finish_ops_.AllowNoMessage();
  909. finish_tag_.Set(
  910. call_.call(),
  911. [this](bool /*ok*/) { MaybeFinish(/*from_reaction=*/true); },
  912. &finish_ops_,
  913. /*can_inline=*/false);
  914. finish_ops_.ClientRecvStatus(context_, &finish_status_);
  915. finish_ops_.set_core_cq_tag(&finish_tag_);
  916. }
  917. // MaybeFinish behaves as in ClientCallbackReaderWriterImpl.
  918. void MaybeFinish(bool from_reaction) {
  919. if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(
  920. 1, std::memory_order_acq_rel) == 1)) {
  921. grpc::Status s = std::move(finish_status_);
  922. auto* reactor = reactor_;
  923. auto* call = call_.call();
  924. this->~ClientCallbackWriterImpl();
  925. grpc::g_core_codegen_interface->grpc_call_unref(call);
  926. if (GPR_LIKELY(from_reaction)) {
  927. reactor->OnDone(s);
  928. } else {
  929. reactor->InternalScheduleOnDone(std::move(s));
  930. }
  931. }
  932. }
  933. grpc::ClientContext* const context_;
  934. grpc::internal::Call call_;
  935. ClientWriteReactor<Request>* const reactor_;
  936. grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
  937. grpc::internal::CallOpRecvInitialMetadata>
  938. start_ops_;
  939. grpc::internal::CallbackWithSuccessTag start_tag_;
  940. const bool start_corked_;
  941. bool corked_write_needed_; // no lock needed since only accessed in
  942. // Write/WritesDone which cannot be concurrent
  943. grpc::internal::CallOpSet<grpc::internal::CallOpGenericRecvMessage,
  944. grpc::internal::CallOpClientRecvStatus>
  945. finish_ops_;
  946. grpc::internal::CallbackWithSuccessTag finish_tag_;
  947. grpc::Status finish_status_;
  948. grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
  949. grpc::internal::CallOpSendMessage,
  950. grpc::internal::CallOpClientSendClose>
  951. write_ops_;
  952. grpc::internal::CallbackWithSuccessTag write_tag_;
  953. grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
  954. grpc::internal::CallOpClientSendClose>
  955. writes_done_ops_;
  956. grpc::internal::CallbackWithSuccessTag writes_done_tag_;
  957. struct StartCallBacklog {
  958. bool write_ops = false;
  959. bool writes_done_ops = false;
  960. };
  961. StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
  962. // Minimum of 3 callbacks to pre-register for start ops, StartCall, and finish
  963. std::atomic<intptr_t> callbacks_outstanding_{3};
  964. std::atomic_bool started_{false};
  965. grpc::internal::Mutex start_mu_;
  966. };
  967. template <class Request>
  968. class ClientCallbackWriterFactory {
  969. public:
  970. template <class Response>
  971. static void Create(grpc::ChannelInterface* channel,
  972. const grpc::internal::RpcMethod& method,
  973. grpc::ClientContext* context, Response* response,
  974. ClientWriteReactor<Request>* reactor) {
  975. grpc::internal::Call call =
  976. channel->CreateCall(method, context, channel->CallbackCQ());
  977. grpc::g_core_codegen_interface->grpc_call_ref(call.call());
  978. new (grpc::g_core_codegen_interface->grpc_call_arena_alloc(
  979. call.call(), sizeof(ClientCallbackWriterImpl<Request>)))
  980. ClientCallbackWriterImpl<Request>(call, context, response, reactor);
  981. }
  982. };
  983. class ClientCallbackUnaryImpl final : public ClientCallbackUnary {
  984. public:
  985. // always allocated against a call arena, no memory free required
  986. static void operator delete(void* /*ptr*/, std::size_t size) {
  987. GPR_CODEGEN_ASSERT(size == sizeof(ClientCallbackUnaryImpl));
  988. }
  989. // This operator should never be called as the memory should be freed as part
  990. // of the arena destruction. It only exists to provide a matching operator
  991. // delete to the operator new so that some compilers will not complain (see
  992. // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
  993. // there are no tests catching the compiler warning.
  994. static void operator delete(void*, void*) { GPR_CODEGEN_ASSERT(false); }
  995. void StartCall() override {
  996. // This call initiates two batches, each with a callback
  997. // 1. Send initial metadata + write + writes done + recv initial metadata
  998. // 2. Read message, recv trailing metadata
  999. start_tag_.Set(
  1000. call_.call(),
  1001. [this](bool ok) {
  1002. reactor_->OnReadInitialMetadataDone(
  1003. ok && !reactor_->InternalTrailersOnly(call_.call()));
  1004. MaybeFinish();
  1005. },
  1006. &start_ops_, /*can_inline=*/false);
  1007. start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
  1008. context_->initial_metadata_flags());
  1009. start_ops_.RecvInitialMetadata(context_);
  1010. start_ops_.set_core_cq_tag(&start_tag_);
  1011. call_.PerformOps(&start_ops_);
  1012. finish_tag_.Set(
  1013. call_.call(), [this](bool /*ok*/) { MaybeFinish(); }, &finish_ops_,
  1014. /*can_inline=*/false);
  1015. finish_ops_.ClientRecvStatus(context_, &finish_status_);
  1016. finish_ops_.set_core_cq_tag(&finish_tag_);
  1017. call_.PerformOps(&finish_ops_);
  1018. }
  1019. private:
  1020. friend class ClientCallbackUnaryFactory;
  1021. template <class Request, class Response>
  1022. ClientCallbackUnaryImpl(grpc::internal::Call call,
  1023. grpc::ClientContext* context, Request* request,
  1024. Response* response, ClientUnaryReactor* reactor)
  1025. : context_(context), call_(call), reactor_(reactor) {
  1026. this->BindReactor(reactor);
  1027. // TODO(vjpai): don't assert
  1028. GPR_CODEGEN_ASSERT(start_ops_.SendMessagePtr(request).ok());
  1029. start_ops_.ClientSendClose();
  1030. finish_ops_.RecvMessage(response);
  1031. finish_ops_.AllowNoMessage();
  1032. }
  1033. // In the unary case, MaybeFinish is only ever invoked from a
  1034. // library-initiated reaction, so it will just directly call OnDone if this is
  1035. // the last reaction for this RPC.
  1036. void MaybeFinish() {
  1037. if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(
  1038. 1, std::memory_order_acq_rel) == 1)) {
  1039. grpc::Status s = std::move(finish_status_);
  1040. auto* reactor = reactor_;
  1041. auto* call = call_.call();
  1042. this->~ClientCallbackUnaryImpl();
  1043. grpc::g_core_codegen_interface->grpc_call_unref(call);
  1044. reactor->OnDone(s);
  1045. }
  1046. }
  1047. grpc::ClientContext* const context_;
  1048. grpc::internal::Call call_;
  1049. ClientUnaryReactor* const reactor_;
  1050. grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
  1051. grpc::internal::CallOpSendMessage,
  1052. grpc::internal::CallOpClientSendClose,
  1053. grpc::internal::CallOpRecvInitialMetadata>
  1054. start_ops_;
  1055. grpc::internal::CallbackWithSuccessTag start_tag_;
  1056. grpc::internal::CallOpSet<grpc::internal::CallOpGenericRecvMessage,
  1057. grpc::internal::CallOpClientRecvStatus>
  1058. finish_ops_;
  1059. grpc::internal::CallbackWithSuccessTag finish_tag_;
  1060. grpc::Status finish_status_;
  1061. // This call will have 2 callbacks: start and finish
  1062. std::atomic<intptr_t> callbacks_outstanding_{2};
  1063. };
  1064. class ClientCallbackUnaryFactory {
  1065. public:
  1066. template <class Request, class Response, class BaseRequest = Request,
  1067. class BaseResponse = Response>
  1068. static void Create(grpc::ChannelInterface* channel,
  1069. const grpc::internal::RpcMethod& method,
  1070. grpc::ClientContext* context, const Request* request,
  1071. Response* response, ClientUnaryReactor* reactor) {
  1072. grpc::internal::Call call =
  1073. channel->CreateCall(method, context, channel->CallbackCQ());
  1074. grpc::g_core_codegen_interface->grpc_call_ref(call.call());
  1075. new (grpc::g_core_codegen_interface->grpc_call_arena_alloc(
  1076. call.call(), sizeof(ClientCallbackUnaryImpl)))
  1077. ClientCallbackUnaryImpl(call, context,
  1078. static_cast<const BaseRequest*>(request),
  1079. static_cast<BaseResponse*>(response), reactor);
  1080. }
  1081. };
  1082. } // namespace internal
  1083. } // namespace grpc
  1084. #endif // GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_H