main.hpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. //
  2. // Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. #ifndef BOOST_DETAIL_COBALT_MAIN_HPP
  8. #define BOOST_DETAIL_COBALT_MAIN_HPP
  9. #include <boost/cobalt/main.hpp>
  10. #include <boost/cobalt/op.hpp>
  11. #include <boost/cobalt/this_coro.hpp>
  12. #include <boost/config.hpp>
  13. namespace boost::asio
  14. {
  15. template<typename Executor>
  16. class basic_signal_set;
  17. }
  18. namespace boost::cobalt::detail
  19. {
  20. extern "C"
  21. {
  22. int main(int argc, char * argv[]);
  23. }
  24. struct signal_helper
  25. {
  26. asio::cancellation_signal signal;
  27. };
  28. struct main_promise : signal_helper,
  29. promise_cancellation_base<asio::cancellation_slot, asio::enable_total_cancellation>,
  30. promise_throw_if_cancelled_base,
  31. enable_awaitables<main_promise>,
  32. enable_await_allocator<main_promise>,
  33. enable_await_executor<main_promise>,
  34. enable_await_deferred
  35. {
  36. main_promise(int, char **) : promise_cancellation_base<asio::cancellation_slot, asio::enable_total_cancellation>(
  37. signal_helper::signal.slot(), asio::enable_total_cancellation())
  38. {
  39. [[maybe_unused]] volatile auto p = &detail::main;
  40. }
  41. #if !defined(BOOST_COBALT_NO_PMR)
  42. inline static pmr::memory_resource * my_resource = pmr::get_default_resource();
  43. #if defined(__cpp_sized_deallocation)
  44. void * operator new(const std::size_t size)
  45. {
  46. return my_resource->allocate(size);
  47. }
  48. void operator delete(void * raw, const std::size_t size)
  49. {
  50. return my_resource->deallocate(raw, size);
  51. }
  52. #else
  53. void * operator new(const std::size_t size)
  54. {
  55. // embed the size at the end
  56. constexpr auto sz = (std::max)(alignof(std::max_align_t), sizeof(std::size_t));
  57. auto data = my_resource->allocate(size + sz);
  58. return static_cast<char*>(data) + sz;
  59. }
  60. void operator delete(void * data)
  61. {
  62. constexpr auto sz = (std::max)(alignof(std::max_align_t), sizeof(std::size_t));
  63. const auto size = *reinterpret_cast<std::size_t*>(static_cast<char*>(data) - sz);
  64. return my_resource->deallocate(data, size);
  65. }
  66. #endif
  67. #endif
  68. std::suspend_always initial_suspend() noexcept {return {};}
  69. BOOST_COBALT_DECL
  70. auto final_suspend() noexcept -> std::suspend_never;
  71. #if !defined(BOOST_NO_EXCEPTIONS)
  72. void unhandled_exception() { throw ; }
  73. #endif
  74. void return_value(int res = 0)
  75. {
  76. if (result)
  77. *result = res;
  78. }
  79. friend auto ::co_main (int argc, char * argv[]) -> boost::cobalt::main;
  80. BOOST_COBALT_DECL
  81. static int run_main( ::boost::cobalt::main mn);
  82. friend int main(int argc, char * argv[])
  83. {
  84. #if !defined(BOOST_COBALT_NO_PMR)
  85. pmr::unsynchronized_pool_resource root_resource;
  86. struct reset_res
  87. {
  88. void operator()(pmr::memory_resource * res)
  89. {
  90. this_thread::set_default_resource(res);
  91. }
  92. };
  93. std::unique_ptr<pmr::memory_resource, reset_res> pr{
  94. boost::cobalt::this_thread::set_default_resource(&root_resource)};
  95. char buffer[8096];
  96. pmr::monotonic_buffer_resource main_res{buffer, 8096, &root_resource};
  97. my_resource = &main_res;
  98. #endif
  99. return run_main(co_main(argc, argv));
  100. }
  101. using executor_type = executor;
  102. const executor_type & get_executor() const {return *exec_;}
  103. #if !defined(BOOST_COBALT_NO_PMR)
  104. using allocator_type = pmr::polymorphic_allocator<void>;
  105. using resource_type = pmr::unsynchronized_pool_resource;
  106. mutable resource_type resource{my_resource};
  107. allocator_type get_allocator() const { return allocator_type(&resource); }
  108. #endif
  109. using promise_cancellation_base<asio::cancellation_slot, asio::enable_total_cancellation>::await_transform;
  110. using promise_throw_if_cancelled_base::await_transform;
  111. using enable_awaitables<main_promise>::await_transform;
  112. using enable_await_allocator<main_promise>::await_transform;
  113. using enable_await_executor<main_promise>::await_transform;
  114. using enable_await_deferred::await_transform;
  115. private:
  116. int * result;
  117. std::optional<asio::executor_work_guard<executor_type>> exec;
  118. std::optional<executor_type> exec_;
  119. asio::basic_signal_set<executor_type> * signal_set;
  120. ::boost::cobalt::main get_return_object()
  121. {
  122. return ::boost::cobalt::main{this};
  123. }
  124. };
  125. }
  126. namespace std
  127. {
  128. template<typename Char>
  129. struct coroutine_traits<boost::cobalt::main, int, Char>
  130. {
  131. using promise_type = boost::cobalt::detail::main_promise;
  132. };
  133. }
  134. #endif //BOOST_DETAIL_COBALT_MAIN_HPP