diff --git a/BUILD b/BUILD index 4fe26fc1ebb..b38344cf53c 100644 --- a/BUILD +++ b/BUILD @@ -366,6 +366,7 @@ GRPCXX_PUBLIC_HDRS = [ "include/grpcpp/support/async_stream.h", "include/grpcpp/support/async_unary_call.h", "include/grpcpp/support/byte_buffer.h", + "include/grpcpp/support/callback_common.h", "include/grpcpp/support/channel_arguments.h", "include/grpcpp/support/client_callback.h", "include/grpcpp/support/client_interceptor.h", diff --git a/CMakeLists.txt b/CMakeLists.txt index 90772b89e4a..06561be561b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3447,6 +3447,7 @@ foreach(_hdr include/grpcpp/support/async_stream.h include/grpcpp/support/async_unary_call.h include/grpcpp/support/byte_buffer.h + include/grpcpp/support/callback_common.h include/grpcpp/support/channel_arguments.h include/grpcpp/support/client_callback.h include/grpcpp/support/client_interceptor.h @@ -4118,6 +4119,7 @@ foreach(_hdr include/grpcpp/support/async_stream.h include/grpcpp/support/async_unary_call.h include/grpcpp/support/byte_buffer.h + include/grpcpp/support/callback_common.h include/grpcpp/support/channel_arguments.h include/grpcpp/support/client_callback.h include/grpcpp/support/client_interceptor.h diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index 1ed7a6198c1..6217907388f 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -2828,6 +2828,7 @@ libs: - include/grpcpp/support/async_stream.h - include/grpcpp/support/async_unary_call.h - include/grpcpp/support/byte_buffer.h + - include/grpcpp/support/callback_common.h - include/grpcpp/support/channel_arguments.h - include/grpcpp/support/client_callback.h - include/grpcpp/support/client_interceptor.h @@ -3242,6 +3243,7 @@ libs: - include/grpcpp/support/async_stream.h - include/grpcpp/support/async_unary_call.h - include/grpcpp/support/byte_buffer.h + - include/grpcpp/support/callback_common.h - include/grpcpp/support/channel_arguments.h - include/grpcpp/support/client_callback.h - include/grpcpp/support/client_interceptor.h diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index c753f12ba33..03cc8be75cd 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -174,6 +174,7 @@ Pod::Spec.new do |s| 'include/grpcpp/support/async_stream.h', 'include/grpcpp/support/async_unary_call.h', 'include/grpcpp/support/byte_buffer.h', + 'include/grpcpp/support/callback_common.h', 'include/grpcpp/support/channel_arguments.h', 'include/grpcpp/support/client_callback.h', 'include/grpcpp/support/client_interceptor.h', diff --git a/include/grpcpp/impl/codegen/callback_common.h b/include/grpcpp/impl/codegen/callback_common.h index c0f605ac44a..3057e2aed42 100644 --- a/include/grpcpp/impl/codegen/callback_common.h +++ b/include/grpcpp/impl/codegen/callback_common.h @@ -21,202 +21,7 @@ // IWYU pragma: private -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace grpc { -namespace internal { - -/// An exception-safe way of invoking a user-specified callback function -// TODO(vjpai): decide whether it is better for this to take a const lvalue -// parameter or an rvalue parameter, or if it even matters -template -void CatchingCallback(Func&& func, Args&&... args) { -#if GRPC_ALLOW_EXCEPTIONS - try { - func(std::forward(args)...); - } catch (...) { - // nothing to return or change here, just don't crash the library - } -#else // GRPC_ALLOW_EXCEPTIONS - func(std::forward(args)...); -#endif // GRPC_ALLOW_EXCEPTIONS -} - -template -Reactor* CatchingReactorGetter(Func&& func, Args&&... args) { -#if GRPC_ALLOW_EXCEPTIONS - try { - return func(std::forward(args)...); - } catch (...) { - // fail the RPC, don't crash the library - return nullptr; - } -#else // GRPC_ALLOW_EXCEPTIONS - return func(std::forward(args)...); -#endif // GRPC_ALLOW_EXCEPTIONS -} - -// The contract on these tags is that they are single-shot. They must be -// constructed and then fired at exactly one point. There is no expectation -// that they can be reused without reconstruction. - -class CallbackWithStatusTag : public grpc_completion_queue_functor { - public: - // always allocated against a call arena, no memory free required - static void operator delete(void* /*ptr*/, std::size_t size) { - GPR_CODEGEN_ASSERT(size == sizeof(CallbackWithStatusTag)); - } - - // This operator should never be called as the memory should be freed as part - // of the arena destruction. It only exists to provide a matching operator - // delete to the operator new so that some compilers will not complain (see - // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this - // there are no tests catching the compiler warning. - static void operator delete(void*, void*) { GPR_CODEGEN_ASSERT(false); } - - CallbackWithStatusTag(grpc_call* call, std::function f, - CompletionQueueTag* ops) - : call_(call), func_(std::move(f)), ops_(ops) { - g_core_codegen_interface->grpc_call_ref(call); - functor_run = &CallbackWithStatusTag::StaticRun; - // A client-side callback should never be run inline since they will always - // have work to do from the user application. So, set the parent's - // inlineable field to false - inlineable = false; - } - ~CallbackWithStatusTag() {} - Status* status_ptr() { return &status_; } - - // force_run can not be performed on a tag if operations using this tag - // have been sent to PerformOpsOnCall. It is intended for error conditions - // that are detected before the operations are internally processed. - void force_run(Status s) { - status_ = std::move(s); - Run(true); - } - - private: - grpc_call* call_; - std::function func_; - CompletionQueueTag* ops_; - Status status_; - - static void StaticRun(grpc_completion_queue_functor* cb, int ok) { - static_cast(cb)->Run(static_cast(ok)); - } - void Run(bool ok) { - void* ignored = ops_; - - if (!ops_->FinalizeResult(&ignored, &ok)) { - // The tag was swallowed - return; - } - GPR_CODEGEN_ASSERT(ignored == ops_); - - // Last use of func_ or status_, so ok to move them out - auto func = std::move(func_); - auto status = std::move(status_); - func_ = nullptr; // reset to clear this out for sure - status_ = Status(); // reset to clear this out for sure - CatchingCallback(std::move(func), std::move(status)); - g_core_codegen_interface->grpc_call_unref(call_); - } -}; - -/// CallbackWithSuccessTag can be reused multiple times, and will be used in -/// this fashion for streaming operations. As a result, it shouldn't clear -/// anything up until its destructor -class CallbackWithSuccessTag : public grpc_completion_queue_functor { - public: - // always allocated against a call arena, no memory free required - static void operator delete(void* /*ptr*/, std::size_t size) { - GPR_CODEGEN_ASSERT(size == sizeof(CallbackWithSuccessTag)); - } - - // This operator should never be called as the memory should be freed as part - // of the arena destruction. It only exists to provide a matching operator - // delete to the operator new so that some compilers will not complain (see - // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this - // there are no tests catching the compiler warning. - static void operator delete(void*, void*) { GPR_CODEGEN_ASSERT(false); } - - CallbackWithSuccessTag() : call_(nullptr) {} - - CallbackWithSuccessTag(const CallbackWithSuccessTag&) = delete; - CallbackWithSuccessTag& operator=(const CallbackWithSuccessTag&) = delete; - - ~CallbackWithSuccessTag() { Clear(); } - - // Set can only be called on a default-constructed or Clear'ed tag. - // It should never be called on a tag that was constructed with arguments - // or on a tag that has been Set before unless the tag has been cleared. - // can_inline indicates that this particular callback can be executed inline - // (without needing a thread hop) and is only used for library-provided server - // callbacks. - void Set(grpc_call* call, std::function f, - CompletionQueueTag* ops, bool can_inline) { - GPR_CODEGEN_ASSERT(call_ == nullptr); - g_core_codegen_interface->grpc_call_ref(call); - call_ = call; - func_ = std::move(f); - ops_ = ops; - functor_run = &CallbackWithSuccessTag::StaticRun; - inlineable = can_inline; - } - - void Clear() { - if (call_ != nullptr) { - grpc_call* call = call_; - call_ = nullptr; - func_ = nullptr; - g_core_codegen_interface->grpc_call_unref(call); - } - } - - CompletionQueueTag* ops() { return ops_; } - - // force_run can not be performed on a tag if operations using this tag - // have been sent to PerformOpsOnCall. It is intended for error conditions - // that are detected before the operations are internally processed. - void force_run(bool ok) { Run(ok); } - - /// check if this tag is currently set - /* NOLINTNEXTLINE(google-explicit-constructor) */ - operator bool() const { return call_ != nullptr; } - - private: - grpc_call* call_; - std::function func_; - CompletionQueueTag* ops_; - - static void StaticRun(grpc_completion_queue_functor* cb, int ok) { - static_cast(cb)->Run(static_cast(ok)); - } - void Run(bool ok) { - void* ignored = ops_; - // Allow a "false" return value from FinalizeResult to silence the - // callback, just as it silences a CQ tag in the async cases -#ifndef NDEBUG - auto* ops = ops_; -#endif - bool do_callback = ops_->FinalizeResult(&ignored, &ok); - GPR_CODEGEN_DEBUG_ASSERT(ignored == ops); - - if (do_callback) { - CatchingCallback(func_, ok); - } - } -}; - -} // namespace internal -} // namespace grpc +/// TODO(chengyuc): Remove this file after solving compatibility. +#include #endif // GRPCPP_IMPL_CODEGEN_CALLBACK_COMMON_H diff --git a/include/grpcpp/server_context.h b/include/grpcpp/server_context.h index 2d9e2504aef..4ebe8fa42c6 100644 --- a/include/grpcpp/server_context.h +++ b/include/grpcpp/server_context.h @@ -31,12 +31,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include #include diff --git a/include/grpcpp/support/callback_common.h b/include/grpcpp/support/callback_common.h new file mode 100644 index 00000000000..2ff18e2fe54 --- /dev/null +++ b/include/grpcpp/support/callback_common.h @@ -0,0 +1,220 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPCPP_SUPPORT_CALLBACK_COMMON_H +#define GRPCPP_SUPPORT_CALLBACK_COMMON_H + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace grpc { +namespace internal { + +/// An exception-safe way of invoking a user-specified callback function +// TODO(vjpai): decide whether it is better for this to take a const lvalue +// parameter or an rvalue parameter, or if it even matters +template +void CatchingCallback(Func&& func, Args&&... args) { +#if GRPC_ALLOW_EXCEPTIONS + try { + func(std::forward(args)...); + } catch (...) { + // nothing to return or change here, just don't crash the library + } +#else // GRPC_ALLOW_EXCEPTIONS + func(std::forward(args)...); +#endif // GRPC_ALLOW_EXCEPTIONS +} + +template +Reactor* CatchingReactorGetter(Func&& func, Args&&... args) { +#if GRPC_ALLOW_EXCEPTIONS + try { + return func(std::forward(args)...); + } catch (...) { + // fail the RPC, don't crash the library + return nullptr; + } +#else // GRPC_ALLOW_EXCEPTIONS + return func(std::forward(args)...); +#endif // GRPC_ALLOW_EXCEPTIONS +} + +// The contract on these tags is that they are single-shot. They must be +// constructed and then fired at exactly one point. There is no expectation +// that they can be reused without reconstruction. + +class CallbackWithStatusTag : public grpc_completion_queue_functor { + public: + // always allocated against a call arena, no memory free required + static void operator delete(void* /*ptr*/, std::size_t size) { + GPR_CODEGEN_ASSERT(size == sizeof(CallbackWithStatusTag)); + } + + // This operator should never be called as the memory should be freed as part + // of the arena destruction. It only exists to provide a matching operator + // delete to the operator new so that some compilers will not complain (see + // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this + // there are no tests catching the compiler warning. + static void operator delete(void*, void*) { GPR_CODEGEN_ASSERT(false); } + + CallbackWithStatusTag(grpc_call* call, std::function f, + CompletionQueueTag* ops) + : call_(call), func_(std::move(f)), ops_(ops) { + g_core_codegen_interface->grpc_call_ref(call); + functor_run = &CallbackWithStatusTag::StaticRun; + // A client-side callback should never be run inline since they will always + // have work to do from the user application. So, set the parent's + // inlineable field to false + inlineable = false; + } + ~CallbackWithStatusTag() {} + Status* status_ptr() { return &status_; } + + // force_run can not be performed on a tag if operations using this tag + // have been sent to PerformOpsOnCall. It is intended for error conditions + // that are detected before the operations are internally processed. + void force_run(Status s) { + status_ = std::move(s); + Run(true); + } + + private: + grpc_call* call_; + std::function func_; + CompletionQueueTag* ops_; + Status status_; + + static void StaticRun(grpc_completion_queue_functor* cb, int ok) { + static_cast(cb)->Run(static_cast(ok)); + } + void Run(bool ok) { + void* ignored = ops_; + + if (!ops_->FinalizeResult(&ignored, &ok)) { + // The tag was swallowed + return; + } + GPR_CODEGEN_ASSERT(ignored == ops_); + + // Last use of func_ or status_, so ok to move them out + auto func = std::move(func_); + auto status = std::move(status_); + func_ = nullptr; // reset to clear this out for sure + status_ = Status(); // reset to clear this out for sure + CatchingCallback(std::move(func), std::move(status)); + g_core_codegen_interface->grpc_call_unref(call_); + } +}; + +/// CallbackWithSuccessTag can be reused multiple times, and will be used in +/// this fashion for streaming operations. As a result, it shouldn't clear +/// anything up until its destructor +class CallbackWithSuccessTag : public grpc_completion_queue_functor { + public: + // always allocated against a call arena, no memory free required + static void operator delete(void* /*ptr*/, std::size_t size) { + GPR_CODEGEN_ASSERT(size == sizeof(CallbackWithSuccessTag)); + } + + // This operator should never be called as the memory should be freed as part + // of the arena destruction. It only exists to provide a matching operator + // delete to the operator new so that some compilers will not complain (see + // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this + // there are no tests catching the compiler warning. + static void operator delete(void*, void*) { GPR_CODEGEN_ASSERT(false); } + + CallbackWithSuccessTag() : call_(nullptr) {} + + CallbackWithSuccessTag(const CallbackWithSuccessTag&) = delete; + CallbackWithSuccessTag& operator=(const CallbackWithSuccessTag&) = delete; + + ~CallbackWithSuccessTag() { Clear(); } + + // Set can only be called on a default-constructed or Clear'ed tag. + // It should never be called on a tag that was constructed with arguments + // or on a tag that has been Set before unless the tag has been cleared. + // can_inline indicates that this particular callback can be executed inline + // (without needing a thread hop) and is only used for library-provided server + // callbacks. + void Set(grpc_call* call, std::function f, + CompletionQueueTag* ops, bool can_inline) { + GPR_CODEGEN_ASSERT(call_ == nullptr); + g_core_codegen_interface->grpc_call_ref(call); + call_ = call; + func_ = std::move(f); + ops_ = ops; + functor_run = &CallbackWithSuccessTag::StaticRun; + inlineable = can_inline; + } + + void Clear() { + if (call_ != nullptr) { + grpc_call* call = call_; + call_ = nullptr; + func_ = nullptr; + g_core_codegen_interface->grpc_call_unref(call); + } + } + + CompletionQueueTag* ops() { return ops_; } + + // force_run can not be performed on a tag if operations using this tag + // have been sent to PerformOpsOnCall. It is intended for error conditions + // that are detected before the operations are internally processed. + void force_run(bool ok) { Run(ok); } + + /// check if this tag is currently set + /* NOLINTNEXTLINE(google-explicit-constructor) */ + operator bool() const { return call_ != nullptr; } + + private: + grpc_call* call_; + std::function func_; + CompletionQueueTag* ops_; + + static void StaticRun(grpc_completion_queue_functor* cb, int ok) { + static_cast(cb)->Run(static_cast(ok)); + } + void Run(bool ok) { + void* ignored = ops_; + // Allow a "false" return value from FinalizeResult to silence the + // callback, just as it silences a CQ tag in the async cases +#ifndef NDEBUG + auto* ops = ops_; +#endif + bool do_callback = ops_->FinalizeResult(&ignored, &ok); + GPR_CODEGEN_DEBUG_ASSERT(ignored == ops); + + if (do_callback) { + CatchingCallback(func_, ok); + } + } +}; + +} // namespace internal +} // namespace grpc + +#endif // GRPCPP_SUPPORT_CALLBACK_COMMON_H diff --git a/include/grpcpp/support/client_callback.h b/include/grpcpp/support/client_callback.h index 873fdb6a689..708960ba04f 100644 --- a/include/grpcpp/support/client_callback.h +++ b/include/grpcpp/support/client_callback.h @@ -24,9 +24,9 @@ #include #include -#include #include #include +#include #include #include diff --git a/include/grpcpp/support/server_callback.h b/include/grpcpp/support/server_callback.h index e96079e355f..4da80582460 100644 --- a/include/grpcpp/support/server_callback.h +++ b/include/grpcpp/support/server_callback.h @@ -25,9 +25,9 @@ #include #include -#include #include #include +#include #include #include #include diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc index d3bf5f01f31..0d72874e870 100644 --- a/src/cpp/server/server_context.cc +++ b/src/cpp/server/server_context.cc @@ -44,12 +44,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include #include diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index c49e754da12..f055a843843 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -1039,6 +1039,7 @@ include/grpcpp/server_posix.h \ include/grpcpp/support/async_stream.h \ include/grpcpp/support/async_unary_call.h \ include/grpcpp/support/byte_buffer.h \ +include/grpcpp/support/callback_common.h \ include/grpcpp/support/channel_arguments.h \ include/grpcpp/support/client_callback.h \ include/grpcpp/support/client_interceptor.h \ diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 9f8168ceb15..34754794938 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -1039,6 +1039,7 @@ include/grpcpp/server_posix.h \ include/grpcpp/support/async_stream.h \ include/grpcpp/support/async_unary_call.h \ include/grpcpp/support/byte_buffer.h \ +include/grpcpp/support/callback_common.h \ include/grpcpp/support/channel_arguments.h \ include/grpcpp/support/client_callback.h \ include/grpcpp/support/client_interceptor.h \