169 lines
4.6 KiB
C++
169 lines
4.6 KiB
C++
//
|
|
// 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 <boost/cobalt/main.hpp>
|
|
#include <boost/cobalt/op.hpp>
|
|
#include <boost/cobalt/this_coro.hpp>
|
|
|
|
#include <boost/config.hpp>
|
|
|
|
|
|
namespace boost::asio
|
|
{
|
|
|
|
template<typename Executor>
|
|
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<asio::cancellation_slot, asio::enable_total_cancellation>,
|
|
promise_throw_if_cancelled_base,
|
|
enable_awaitables<main_promise>,
|
|
enable_await_allocator<main_promise>,
|
|
enable_await_executor<main_promise>,
|
|
enable_await_deferred
|
|
{
|
|
main_promise(int, char **) : promise_cancellation_base<asio::cancellation_slot, asio::enable_total_cancellation>(
|
|
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<char*>(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<std::size_t*>(static_cast<char*>(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<pmr::memory_resource, reset_res> 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<void>;
|
|
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<asio::cancellation_slot, asio::enable_total_cancellation>::await_transform;
|
|
using promise_throw_if_cancelled_base::await_transform;
|
|
using enable_awaitables<main_promise>::await_transform;
|
|
using enable_await_allocator<main_promise>::await_transform;
|
|
using enable_await_executor<main_promise>::await_transform;
|
|
using enable_await_deferred::await_transform;
|
|
|
|
private:
|
|
int * result;
|
|
std::optional<asio::executor_work_guard<executor_type>> exec;
|
|
std::optional<executor_type> exec_;
|
|
asio::basic_signal_set<executor_type> * signal_set;
|
|
::boost::cobalt::main get_return_object()
|
|
{
|
|
return ::boost::cobalt::main{this};
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
namespace std
|
|
{
|
|
|
|
template<typename Char>
|
|
struct coroutine_traits<boost::cobalt::main, int, Char>
|
|
{
|
|
using promise_type = boost::cobalt::detail::main_promise;
|
|
};
|
|
|
|
}
|
|
|
|
#endif //BOOST_DETAIL_COBALT_MAIN_HPP
|