diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 63611179..06cdc6e1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -223,7 +223,7 @@ jobs: run: cmake --build ${{ github.workspace }}/build-12 --config Release --parallel $(nproc) - name: Clang 12 Configure CMake - run: cmake --preset default -B ${{ github.workspace }}/build-12 -DCMAKE_CXX_COMPILER=$(which clang++-12) -DDOXYGEN_EXECUTABLE=${{ runner.workspace }}/doxygen/bin/doxygen -DVCPKG_INSTALLED_DIR=${{ runner.workspace }}/vcpkg_installed -DCMAKE_DISABLE_PRECOMPILE_HEADERS=on -DASIO_GRPC_ENABLE_STDEXEC_TESTS=on ${{ env.CMAKE_EXTRA_ARGS }} ${{ env.CMAKE_ARGS }} + run: cmake --preset default -B ${{ github.workspace }}/build-12 -DCMAKE_CXX_COMPILER=$(which clang++-12) -DDOXYGEN_EXECUTABLE=${{ runner.workspace }}/doxygen/bin/doxygen -DVCPKG_INSTALLED_DIR=${{ runner.workspace }}/vcpkg_installed -DCMAKE_DISABLE_PRECOMPILE_HEADERS=on ${{ env.CMAKE_EXTRA_ARGS }} ${{ env.CMAKE_ARGS }} - name: Clang 12 Build run: cmake --build ${{ github.workspace }}/build-12 --config Release --parallel $(nproc) --target asio-grpc-check-header-syntax all diff --git a/example/file-transfer-client.cpp b/example/file-transfer-client.cpp index f64cc6f2..f184b5dc 100644 --- a/example/file-transfer-client.cpp +++ b/example/file-transfer-client.cpp @@ -15,6 +15,7 @@ #include "buffer.hpp" #include "example/v1/example_ext.grpc.pb.h" #include "helper.hpp" +#include "rethrow_first_arg.hpp" #include "scope_guard.hpp" #include @@ -176,13 +177,7 @@ int main(int argc, const char** argv) abort_if_not( co_await make_double_buffered_send_file_request(grpc_context, io_context, stub_ext, file_path)); }, - [](auto&& ep) - { - if (ep) - { - std::rethrow_exception(ep); - } - }); + example::RethrowFirstArg{}); std::thread io_context_thread{&run_io_context, std::ref(io_context)}; example::ScopeGuard on_exit{[&] diff --git a/example/file-transfer-server.cpp b/example/file-transfer-server.cpp index f84b027f..e1ee3f36 100644 --- a/example/file-transfer-server.cpp +++ b/example/file-transfer-server.cpp @@ -16,6 +16,7 @@ #include "example/v1/example.grpc.pb.h" #include "example/v1/example_ext.grpc.pb.h" #include "helper.hpp" +#include "rethrow_first_arg.hpp" #include "scope_guard.hpp" #include "server_shutdown_asio.hpp" @@ -118,14 +119,6 @@ asio::awaitable handle_send_file_request(asio::io_con co_return co_await rpc.finish({}, grpc::Status::OK, buffer1.bind_allocator(USE_AWAITABLE)); } -void rethrow_first_arg(const std::exception_ptr& ep) -{ - if (ep) - { - std::rethrow_exception(ep); - } -} - void run_io_context(asio::io_context& io_context) { try @@ -172,7 +165,7 @@ int main(int argc, const char** argv) abort_if_not(co_await handle_send_file_request(io_context, rpc, file_path)); shutdown.shutdown(); }, - &rethrow_first_arg); + example::RethrowFirstArg{}); std::thread io_context_thread{&run_io_context, std::ref(io_context)}; example::ScopeGuard on_exit{[&] diff --git a/example/generic-server.cpp b/example/generic-server.cpp index e822b5e2..4a191887 100644 --- a/example/generic-server.cpp +++ b/example/generic-server.cpp @@ -241,11 +241,11 @@ int main(int argc, const char** argv) server_shutdown.shutdown(); } }, - asio::detached); + example::RethrowFirstArg{}); asio::thread_pool thread_pool{1}; agrpc::register_yield_rpc_handler( - grpc_context, service, GenericRequestHandler{grpc_context, thread_pool}, asio::detached); + grpc_context, service, GenericRequestHandler{grpc_context, thread_pool}, example::RethrowFirstArg{}); grpc_context.run(); } \ No newline at end of file diff --git a/example/hello-world-client.cpp b/example/hello-world-client.cpp index 7be18dc1..2782f2f0 100644 --- a/example/hello-world-client.cpp +++ b/example/hello-world-client.cpp @@ -15,6 +15,7 @@ #include "awaitable_client_rpc.hpp" #include "helloworld/helloworld.grpc.pb.h" #include "helper.hpp" +#include "rethrow_first_arg.hpp" #include #include @@ -46,7 +47,7 @@ int main(int argc, const char** argv) status = co_await RPC::request(grpc_context, stub, client_context, request, response); std::cout << status.ok() << " response: " << response.message() << std::endl; }, - asio::detached); + example::RethrowFirstArg{}); grpc_context.run(); diff --git a/example/hello-world-server.cpp b/example/hello-world-server.cpp index 948ed2b0..0f82dc1f 100644 --- a/example/hello-world-server.cpp +++ b/example/hello-world-server.cpp @@ -14,6 +14,7 @@ #include "awaitable_server_rpc.hpp" #include "helloworld/helloworld.grpc.pb.h" +#include "rethrow_first_arg.hpp" #include #include @@ -53,7 +54,7 @@ int main(int argc, const char** argv) co_await rpc.finish(response, grpc::Status::OK); server->Shutdown(); }, - asio::detached); + example::RethrowFirstArg{}); grpc_context.run(); } \ No newline at end of file diff --git a/example/helper/rethrow_first_arg.hpp b/example/helper/rethrow_first_arg.hpp new file mode 100644 index 00000000..5f5217b1 --- /dev/null +++ b/example/helper/rethrow_first_arg.hpp @@ -0,0 +1,42 @@ +// Copyright 2023 Dennis Hezel +// +// 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 AGRPC_HELPER_RETHROW_FIRST_ARG_HPP +#define AGRPC_HELPER_RETHROW_FIRST_ARG_HPP + +#include + +namespace example +{ +// Using this as the completion token to functions like asio::co_spawn ensures that exceptions thrown by the coroutine +// are rethrown from grpc_context.run(). +struct RethrowFirstArg +{ + template + void operator()(std::exception_ptr ep, T&&...) + { + if (ep) + { + std::rethrow_exception(ep); + } + } + + template + void operator()(T&&...) + { + } +}; +} // namespace example + +#endif // AGRPC_HELPER_RETHROW_FIRST_ARG_HPP diff --git a/example/helper/yield_helper.hpp b/example/helper/yield_helper.hpp index c360075b..712ffb35 100644 --- a/example/helper/yield_helper.hpp +++ b/example/helper/yield_helper.hpp @@ -15,6 +15,8 @@ #ifndef AGRPC_HELPER_YIELD_HELPER_HPP #define AGRPC_HELPER_YIELD_HELPER_HPP +#include "rethrow_first_arg.hpp" + #include #include #include @@ -30,7 +32,7 @@ template void spawn(Executor&& executor, Function&& function) { #if (BOOST_VERSION >= 108000) - boost::asio::spawn(std::forward(executor), std::forward(function), boost::asio::detached); + boost::asio::spawn(std::forward(executor), std::forward(function), example::RethrowFirstArg{}); #else boost::asio::spawn(std::forward(executor), std::forward(function)); #endif @@ -54,19 +56,6 @@ auto initiate_spawn(Executor&& executor, Function&& function, CompletionToken&& #endif } -inline void rethrow_exception_ptr(std::exception_ptr ep) -{ - if (ep) - { - std::rethrow_exception(ep); - } -} - -template -void rethrow_exception_ptr(T&&) -{ -} - template struct SpawnAllVoid { @@ -104,7 +93,7 @@ struct SpawnAllVoid template void operator()(Self& self, T&&... t) { - (example::rethrow_exception_ptr(t), ...); + (example::RethrowFirstArg{}(t), ...); self.complete(); } }; diff --git a/example/multi-threaded-client.cpp b/example/multi-threaded-client.cpp index bf4171bd..a1703f32 100644 --- a/example/multi-threaded-client.cpp +++ b/example/multi-threaded-client.cpp @@ -15,6 +15,7 @@ #include "awaitable_client_rpc.hpp" #include "helloworld/helloworld.grpc.pb.h" #include "helper.hpp" +#include "rethrow_first_arg.hpp" #include #include @@ -106,7 +107,7 @@ int main(int argc, const char** argv) for (size_t i{}; i < 20; ++i) { auto& grpc_context = round_robin_grpc_contexts.next()->context; - boost::asio::co_spawn(grpc_context, make_request(grpc_context, stub), boost::asio::detached); + asio::co_spawn(grpc_context, make_request(grpc_context, stub), example::RethrowFirstArg{}); } for (auto& grpc_context : grpc_contexts) diff --git a/example/multi-threaded-server.cpp b/example/multi-threaded-server.cpp index feaf7735..b25a5609 100644 --- a/example/multi-threaded-server.cpp +++ b/example/multi-threaded-server.cpp @@ -14,6 +14,7 @@ #include "grpc/health/v1/health.grpc.pb.h" #include "helloworld/helloworld.grpc.pb.h" +#include "rethrow_first_arg.hpp" #include "server_shutdown_asio.hpp" #include @@ -56,7 +57,7 @@ void register_request_handler(agrpc::GrpcContext& grpc_context, helloworld::Gree } }); }, - asio::detached); + example::RethrowFirstArg{}); } int main(int argc, const char** argv) diff --git a/example/share-io-context-client.cpp b/example/share-io-context-client.cpp index 61a3ce5e..bf258a02 100644 --- a/example/share-io-context-client.cpp +++ b/example/share-io-context-client.cpp @@ -15,6 +15,7 @@ #include "awaitable_client_rpc.hpp" #include "example/v1/example.grpc.pb.h" #include "helper.hpp" +#include "rethrow_first_arg.hpp" #include #include @@ -85,7 +86,7 @@ int main(int argc, const char** argv) co_await (make_grpc_request(grpc_context, stub) && make_tcp_request(tcp_port)); grpc_context_work_guard.reset(); }, - asio::detached); + example::RethrowFirstArg{}); /* [co_spawn_io_context_and_grpc_context] */ /* [agrpc_run_io_context_shared_work_tracking] */ diff --git a/example/share-io-context-server.cpp b/example/share-io-context-server.cpp index 4c408169..0513a2c6 100644 --- a/example/share-io-context-server.cpp +++ b/example/share-io-context-server.cpp @@ -15,6 +15,7 @@ #include "awaitable_server_rpc.hpp" #include "example/v1/example.grpc.pb.h" #include "helper.hpp" +#include "rethrow_first_arg.hpp" #include "server_shutdown_asio.hpp" #include @@ -83,9 +84,9 @@ int main(int argc, const char** argv) co_await rpc.finish(response, grpc::Status::OK); server_shutdown.shutdown(); }, - asio::detached); + example::RethrowFirstArg{}); - asio::co_spawn(io_context, handle_tcp_request(tcp_port), asio::detached); + asio::co_spawn(io_context, handle_tcp_request(tcp_port), example::RethrowFirstArg{}); // First, initiate the io_context's thread_local variables by posting on it. The io_context uses them to optimize // dynamic memory allocations. This is an optional step but it can improve performance. diff --git a/example/streaming-client.cpp b/example/streaming-client.cpp index cf77ef75..3aeb66f3 100644 --- a/example/streaming-client.cpp +++ b/example/streaming-client.cpp @@ -16,6 +16,7 @@ #include "example/v1/example.grpc.pb.h" #include "example/v1/example_ext.grpc.pb.h" #include "helper.hpp" +#include "rethrow_first_arg.hpp" #include #include @@ -231,7 +232,7 @@ int main(int argc, const char** argv) co_await make_and_cancel_unary_request(grpc_context, stub_ext); co_await make_shutdown_request(grpc_context, stub_ext); }, - asio::detached); + example::RethrowFirstArg{}); grpc_context.run(); } \ No newline at end of file diff --git a/example/streaming-server.cpp b/example/streaming-server.cpp index bb9b852e..dd372823 100644 --- a/example/streaming-server.cpp +++ b/example/streaming-server.cpp @@ -16,6 +16,7 @@ #include "example/v1/example.grpc.pb.h" #include "example/v1/example_ext.grpc.pb.h" #include "helper.hpp" +#include "rethrow_first_arg.hpp" #include "server_shutdown_asio.hpp" #include @@ -214,16 +215,16 @@ int main(int argc, const char** argv) asio::thread_pool thread_pool{1}; agrpc::register_awaitable_rpc_handler(grpc_context, service, &handle_client_streaming_request, - asio::detached); + example::RethrowFirstArg{}); agrpc::register_awaitable_rpc_handler(grpc_context, service, &handle_server_streaming_request, - asio::detached); + example::RethrowFirstArg{}); agrpc::register_awaitable_rpc_handler( - grpc_context, service, bidirectional_streaming_rpc_handler(thread_pool), asio::detached); + grpc_context, service, bidirectional_streaming_rpc_handler(thread_pool), example::RethrowFirstArg{}); agrpc::register_awaitable_rpc_handler(grpc_context, service_ext, &handle_slow_unary_request, - asio::detached); + example::RethrowFirstArg{}); agrpc::register_awaitable_rpc_handler( grpc_context, service_ext, @@ -235,7 +236,7 @@ int main(int argc, const char** argv) server_shutdown.shutdown(); } }, - asio::detached); + example::RethrowFirstArg{}); grpc_context.run(); std::cout << "Shutdown completed\n";