// // Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_DETAIL_COBALT_MAIN_HPP #define BOOST_DETAIL_COBALT_MAIN_HPP #include #include #include #include namespace boost::asio { template class basic_signal_set; } namespace boost::cobalt::detail { extern "C" { int main(int argc, char * argv[]); } struct signal_helper { asio::cancellation_signal signal; }; struct main_promise : signal_helper, promise_cancellation_base, promise_throw_if_cancelled_base, enable_awaitables, enable_await_allocator, enable_await_executor, enable_await_deferred { main_promise(int, char **) : promise_cancellation_base( signal_helper::signal.slot(), asio::enable_total_cancellation()) { [[maybe_unused]] volatile auto p = &detail::main; } #if !defined(BOOST_COBALT_NO_PMR) inline static pmr::memory_resource * my_resource = pmr::get_default_resource(); #if defined(__cpp_sized_deallocation) void * operator new(const std::size_t size) { return my_resource->allocate(size); } void operator delete(void * raw, const std::size_t size) { return my_resource->deallocate(raw, size); } #else void * operator new(const std::size_t size) { // embed the size at the end constexpr auto sz = (std::max)(alignof(std::max_align_t), sizeof(std::size_t)); auto data = my_resource->allocate(size + sz); return static_cast(data) + sz; } void operator delete(void * data) { constexpr auto sz = (std::max)(alignof(std::max_align_t), sizeof(std::size_t)); const auto size = *reinterpret_cast(static_cast(data) - sz); return my_resource->deallocate(data, size); } #endif #endif std::suspend_always initial_suspend() noexcept {return {};} BOOST_COBALT_DECL auto final_suspend() noexcept -> std::suspend_never; #if !defined(BOOST_NO_EXCEPTIONS) void unhandled_exception() { throw ; } #endif void return_value(int res = 0) { if (result) *result = res; } friend auto ::co_main (int argc, char * argv[]) -> boost::cobalt::main; BOOST_COBALT_DECL static int run_main( ::boost::cobalt::main mn); friend int main(int argc, char * argv[]) { #if !defined(BOOST_COBALT_NO_PMR) pmr::unsynchronized_pool_resource root_resource; struct reset_res { void operator()(pmr::memory_resource * res) { this_thread::set_default_resource(res); } }; std::unique_ptr pr{ boost::cobalt::this_thread::set_default_resource(&root_resource)}; char buffer[8096]; pmr::monotonic_buffer_resource main_res{buffer, 8096, &root_resource}; my_resource = &main_res; #endif return run_main(co_main(argc, argv)); } using executor_type = executor; const executor_type & get_executor() const {return *exec_;} #if !defined(BOOST_COBALT_NO_PMR) using allocator_type = pmr::polymorphic_allocator; using resource_type = pmr::unsynchronized_pool_resource; mutable resource_type resource{my_resource}; allocator_type get_allocator() const { return allocator_type(&resource); } #endif using promise_cancellation_base::await_transform; using promise_throw_if_cancelled_base::await_transform; using enable_awaitables::await_transform; using enable_await_allocator::await_transform; using enable_await_executor::await_transform; using enable_await_deferred::await_transform; private: int * result; std::optional> exec; std::optional exec_; asio::basic_signal_set * signal_set; ::boost::cobalt::main get_return_object() { return ::boost::cobalt::main{this}; } }; } namespace std { template struct coroutine_traits { using promise_type = boost::cobalt::detail::main_promise; }; } #endif //BOOST_DETAIL_COBALT_MAIN_HPP