callback_common.h 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. //
  2. //
  3. // Copyright 2018 gRPC authors.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. //
  17. //
  18. #ifndef GRPCPP_SUPPORT_CALLBACK_COMMON_H
  19. #define GRPCPP_SUPPORT_CALLBACK_COMMON_H
  20. #include <functional>
  21. #include <grpc/grpc.h>
  22. #include <grpc/impl/grpc_types.h>
  23. #include <grpc/support/log.h>
  24. #include <grpcpp/impl/call.h>
  25. #include <grpcpp/impl/codegen/channel_interface.h>
  26. #include <grpcpp/impl/completion_queue_tag.h>
  27. #include <grpcpp/support/config.h>
  28. #include <grpcpp/support/status.h>
  29. namespace grpc {
  30. namespace internal {
  31. /// An exception-safe way of invoking a user-specified callback function
  32. // TODO(vjpai): decide whether it is better for this to take a const lvalue
  33. // parameter or an rvalue parameter, or if it even matters
  34. template <class Func, class... Args>
  35. void CatchingCallback(Func&& func, Args&&... args) {
  36. #if GRPC_ALLOW_EXCEPTIONS
  37. try {
  38. func(std::forward<Args>(args)...);
  39. } catch (...) {
  40. // nothing to return or change here, just don't crash the library
  41. }
  42. #else // GRPC_ALLOW_EXCEPTIONS
  43. func(std::forward<Args>(args)...);
  44. #endif // GRPC_ALLOW_EXCEPTIONS
  45. }
  46. template <class Reactor, class Func, class... Args>
  47. Reactor* CatchingReactorGetter(Func&& func, Args&&... args) {
  48. #if GRPC_ALLOW_EXCEPTIONS
  49. try {
  50. return func(std::forward<Args>(args)...);
  51. } catch (...) {
  52. // fail the RPC, don't crash the library
  53. return nullptr;
  54. }
  55. #else // GRPC_ALLOW_EXCEPTIONS
  56. return func(std::forward<Args>(args)...);
  57. #endif // GRPC_ALLOW_EXCEPTIONS
  58. }
  59. // The contract on these tags is that they are single-shot. They must be
  60. // constructed and then fired at exactly one point. There is no expectation
  61. // that they can be reused without reconstruction.
  62. class CallbackWithStatusTag : public grpc_completion_queue_functor {
  63. public:
  64. // always allocated against a call arena, no memory free required
  65. static void operator delete(void* /*ptr*/, std::size_t size) {
  66. GPR_ASSERT(size == sizeof(CallbackWithStatusTag));
  67. }
  68. // This operator should never be called as the memory should be freed as part
  69. // of the arena destruction. It only exists to provide a matching operator
  70. // delete to the operator new so that some compilers will not complain (see
  71. // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
  72. // there are no tests catching the compiler warning.
  73. static void operator delete(void*, void*) { GPR_ASSERT(false); }
  74. CallbackWithStatusTag(grpc_call* call, std::function<void(Status)> f,
  75. CompletionQueueTag* ops)
  76. : call_(call), func_(std::move(f)), ops_(ops) {
  77. grpc_call_ref(call);
  78. functor_run = &CallbackWithStatusTag::StaticRun;
  79. // A client-side callback should never be run inline since they will always
  80. // have work to do from the user application. So, set the parent's
  81. // inlineable field to false
  82. inlineable = false;
  83. }
  84. ~CallbackWithStatusTag() {}
  85. Status* status_ptr() { return &status_; }
  86. // force_run can not be performed on a tag if operations using this tag
  87. // have been sent to PerformOpsOnCall. It is intended for error conditions
  88. // that are detected before the operations are internally processed.
  89. void force_run(Status s) {
  90. status_ = std::move(s);
  91. Run(true);
  92. }
  93. private:
  94. grpc_call* call_;
  95. std::function<void(Status)> func_;
  96. CompletionQueueTag* ops_;
  97. Status status_;
  98. static void StaticRun(grpc_completion_queue_functor* cb, int ok) {
  99. static_cast<CallbackWithStatusTag*>(cb)->Run(static_cast<bool>(ok));
  100. }
  101. void Run(bool ok) {
  102. void* ignored = ops_;
  103. if (!ops_->FinalizeResult(&ignored, &ok)) {
  104. // The tag was swallowed
  105. return;
  106. }
  107. GPR_ASSERT(ignored == ops_);
  108. // Last use of func_ or status_, so ok to move them out
  109. auto func = std::move(func_);
  110. auto status = std::move(status_);
  111. func_ = nullptr; // reset to clear this out for sure
  112. status_ = Status(); // reset to clear this out for sure
  113. CatchingCallback(std::move(func), std::move(status));
  114. grpc_call_unref(call_);
  115. }
  116. };
  117. /// CallbackWithSuccessTag can be reused multiple times, and will be used in
  118. /// this fashion for streaming operations. As a result, it shouldn't clear
  119. /// anything up until its destructor
  120. class CallbackWithSuccessTag : public grpc_completion_queue_functor {
  121. public:
  122. // always allocated against a call arena, no memory free required
  123. static void operator delete(void* /*ptr*/, std::size_t size) {
  124. GPR_ASSERT(size == sizeof(CallbackWithSuccessTag));
  125. }
  126. // This operator should never be called as the memory should be freed as part
  127. // of the arena destruction. It only exists to provide a matching operator
  128. // delete to the operator new so that some compilers will not complain (see
  129. // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
  130. // there are no tests catching the compiler warning.
  131. static void operator delete(void*, void*) { GPR_ASSERT(false); }
  132. CallbackWithSuccessTag() : call_(nullptr) {}
  133. CallbackWithSuccessTag(const CallbackWithSuccessTag&) = delete;
  134. CallbackWithSuccessTag& operator=(const CallbackWithSuccessTag&) = delete;
  135. ~CallbackWithSuccessTag() { Clear(); }
  136. // Set can only be called on a default-constructed or Clear'ed tag.
  137. // It should never be called on a tag that was constructed with arguments
  138. // or on a tag that has been Set before unless the tag has been cleared.
  139. // can_inline indicates that this particular callback can be executed inline
  140. // (without needing a thread hop) and is only used for library-provided server
  141. // callbacks.
  142. void Set(grpc_call* call, std::function<void(bool)> f,
  143. CompletionQueueTag* ops, bool can_inline) {
  144. GPR_ASSERT(call_ == nullptr);
  145. grpc_call_ref(call);
  146. call_ = call;
  147. func_ = std::move(f);
  148. ops_ = ops;
  149. functor_run = &CallbackWithSuccessTag::StaticRun;
  150. inlineable = can_inline;
  151. }
  152. void Clear() {
  153. if (call_ != nullptr) {
  154. grpc_call* call = call_;
  155. call_ = nullptr;
  156. func_ = nullptr;
  157. grpc_call_unref(call);
  158. }
  159. }
  160. CompletionQueueTag* ops() { return ops_; }
  161. // force_run can not be performed on a tag if operations using this tag
  162. // have been sent to PerformOpsOnCall. It is intended for error conditions
  163. // that are detected before the operations are internally processed.
  164. void force_run(bool ok) { Run(ok); }
  165. /// check if this tag is currently set
  166. // NOLINTNEXTLINE(google-explicit-constructor)
  167. operator bool() const { return call_ != nullptr; }
  168. private:
  169. grpc_call* call_;
  170. std::function<void(bool)> func_;
  171. CompletionQueueTag* ops_;
  172. static void StaticRun(grpc_completion_queue_functor* cb, int ok) {
  173. static_cast<CallbackWithSuccessTag*>(cb)->Run(static_cast<bool>(ok));
  174. }
  175. void Run(bool ok) {
  176. void* ignored = ops_;
  177. // Allow a "false" return value from FinalizeResult to silence the
  178. // callback, just as it silences a CQ tag in the async cases
  179. #ifndef NDEBUG
  180. auto* ops = ops_;
  181. #endif
  182. bool do_callback = ops_->FinalizeResult(&ignored, &ok);
  183. GPR_DEBUG_ASSERT(ignored == ops);
  184. if (do_callback) {
  185. CatchingCallback(func_, ok);
  186. }
  187. }
  188. };
  189. } // namespace internal
  190. } // namespace grpc
  191. #endif // GRPCPP_SUPPORT_CALLBACK_COMMON_H