├── .gitmodules ├── CMakeLists.txt ├── include └── corio │ ├── as_receiver.hpp │ ├── await_sender.hpp │ ├── channel.hpp │ ├── concepts.hpp │ ├── corio.hpp │ ├── deadline.hpp │ ├── intrusive_linked_list.hpp │ ├── io_uring.hpp │ ├── io_uring │ ├── base.hpp │ ├── cancel.hpp │ ├── read.hpp │ └── schedule.hpp │ ├── meta.hpp │ ├── spawn.hpp │ ├── stop_token.hpp │ ├── tag_invoke.hpp │ ├── then.hpp │ ├── thread_pool.hpp │ └── wait.hpp └── src └── corio.cpp /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "cmcstl2"] 2 | path = cmcstl2 3 | url = https://github.com/CaseyCarter/cmcstl2 4 | [submodule "cppcoro"] 5 | path = cppcoro 6 | url = https://github.com/lewissbaker/cppcoro.git 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.14) 2 | 3 | project(corio) 4 | 5 | file(GLOB_RECURSE FILES 6 | ${PROJECT_SOURCE_DIR}/src/*.cpp 7 | ${PROJECT_SOURCE_DIR}/src/*.hpp 8 | ${PROJECT_SOURCE_DIR}/include/**.hpp 9 | ) 10 | 11 | add_executable(corio ${FILES}) 12 | target_include_directories(corio PUBLIC ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/cmcstl2/include) 13 | target_compile_options(corio PUBLIC -std=c++2a -Xclang -fconcepts-ts -stdlib=libc++ -lc++experimental) 14 | target_link_options(corio PUBLIC -stdlib=libc++ -lc++experimental -pthread -static -static -lc++abi -pthread -fuse-ld=lld) 15 | 16 | #Hack IOURING 17 | target_include_directories(corio PUBLIC /home/cor3ntin/dev-new/executors/uring/include) 18 | target_link_options(corio PRIVATE /home/cor3ntin/dev-new/executors/uring/lib/liburing.a) 19 | install(TARGETS corio) -------------------------------------------------------------------------------- /include/corio/as_receiver.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | 5 | namespace cor3ntin::corio { 6 | template 7 | struct as_receiver { 8 | private: 9 | using invocable_type = std::remove_cvref_t; 10 | invocable_type f_; 11 | 12 | public: 13 | explicit as_receiver( 14 | invocable_type&& f) requires std::is_nothrow_move_constructible_v 15 | : f_(std::move(f)) {} 16 | explicit as_receiver(const invocable_type& f) noexcept : f_(f) {} 17 | as_receiver(as_receiver&& other) noexcept = default; 18 | void set_value() { 19 | std::invoke(f_); 20 | } 21 | void set_error(std::exception_ptr) { 22 | std::terminate(); 23 | } 24 | void set_done() noexcept {} 25 | }; 26 | 27 | template 28 | as_receiver(F)->as_receiver; 29 | 30 | } // namespace cor3ntin::corio -------------------------------------------------------------------------------- /include/corio/await_sender.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace cor3ntin::corio { 8 | 9 | struct operation_cancelled : std::exception { 10 | virtual const char* what() const noexcept { 11 | return "operation cancelled"; 12 | } 13 | }; 14 | 15 | 16 | struct oneway_task { 17 | struct promise_type { 18 | std::experimental::suspend_never initial_suspend() { 19 | return {}; 20 | } 21 | std::experimental::suspend_never final_suspend() { 22 | return {}; 23 | } 24 | void unhandled_exception() { 25 | std::terminate(); 26 | } 27 | oneway_task get_return_object() { 28 | return {}; 29 | } 30 | void return_void() {} 31 | }; 32 | }; 33 | 34 | template 35 | struct sender_awaiter { 36 | private: 37 | struct internal_receiver { 38 | sender_awaiter* this_; 39 | 40 | template 41 | void set_value(Values&&... value) { 42 | this_->m_data.template emplace<1>(std::forward(value)...); 43 | this_->m_continuation.resume(); 44 | } 45 | template 46 | void set_error(Error&& error) { 47 | if constexpr(std::is_same_v) { 48 | this_->m_data.template emplace<2>(std::move(error)); 49 | } else { 50 | this_->m_data.template emplace<2>(std::make_exception_ptr(std::move(error))); 51 | } 52 | this_->m_continuation.resume(); 53 | } 54 | 55 | void set_done() { 56 | this_->m_data.template emplace<0>(std::monostate{}); 57 | this_->m_continuation.resume(); 58 | } 59 | }; 60 | 61 | 62 | using value_type = Value; 63 | using coro_handle = std::experimental::coroutine_handle<>; 64 | 65 | coro_handle m_continuation{}; 66 | using operation_type = decltype( 67 | corio::execution::connect(std::declval(), std::declval())); 68 | operation_type m_op; 69 | std::variant, std::exception_ptr> m_data; 70 | 71 | 72 | public: 73 | sender_awaiter(Sender sender) noexcept 74 | : m_op(corio::execution::connect(std::move(sender), internal_receiver{this})) {} 75 | sender_awaiter(sender_awaiter&& that) = default; 76 | ~sender_awaiter() {} 77 | 78 | 79 | static constexpr bool await_ready() noexcept { 80 | return false; 81 | } 82 | 83 | void await_suspend(coro_handle continuation) noexcept { 84 | m_continuation = continuation; 85 | corio::execution::start(m_op); 86 | return; 87 | } 88 | 89 | decltype(auto) await_resume() { 90 | switch(m_data.index()) { 91 | case 0: throw operation_cancelled{}; break; 92 | case 1: return std::get<1>(m_data); break; 93 | case 2: std::rethrow_exception(std::move(std::get<2>(m_data))); break; 94 | } 95 | return std::get<1>(m_data); 96 | } 97 | }; 98 | 99 | template 100 | auto operator co_await(S&& sender) { 101 | return cor3ntin::corio::sender_awaiter(std::forward(sender)); 102 | } 103 | template 104 | auto operator co_await(S&& sender) { 105 | return cor3ntin::corio::sender_awaiter>( 106 | std::forward(sender)); 107 | } 108 | 109 | } // namespace cor3ntin::corio -------------------------------------------------------------------------------- /include/corio/channel.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace cor3ntin::corio { 8 | 9 | struct channel_closed : std::exception { 10 | virtual const char* what() const noexcept { 11 | return "channel closed"; 12 | } 13 | }; 14 | 15 | 16 | namespace details { 17 | 18 | struct linked_list_node { 19 | linked_list_node* next = nullptr; 20 | }; 21 | 22 | template 23 | struct linked_list { 24 | T* pop() { 25 | std::unique_lock lock(m_mutex); 26 | T* n = tail; 27 | if(!n) 28 | return n; 29 | if(head == n) 30 | head = nullptr; 31 | tail = static_cast(n->next); 32 | n->next = nullptr; 33 | return n; 34 | } 35 | T* front() { 36 | return tail; 37 | } 38 | 39 | void push(T* node) { 40 | std::unique_lock lock(m_mutex); 41 | if(head != nullptr) 42 | head->next = node; 43 | head = node; 44 | if(tail == nullptr) 45 | tail = node; 46 | } 47 | 48 | private: 49 | std::mutex m_mutex; 50 | T* head = nullptr; 51 | T* tail = nullptr; 52 | }; 53 | 54 | template 55 | class channel { 56 | public: 57 | class read_operation_base : public linked_list_node { 58 | friend channel; 59 | 60 | protected: 61 | virtual void handle_error(std::error_code err) = 0; 62 | virtual void handle_value(T&& t) = 0; 63 | }; 64 | 65 | class write_operation_base : public linked_list_node { 66 | friend channel; 67 | 68 | protected: 69 | virtual void handle_error(std::error_code err) = 0; 70 | virtual void handle_value() = 0; 71 | virtual T& value() = 0; 72 | }; 73 | 74 | class read_channel { 75 | template 76 | class operation; 77 | template 78 | friend class operation; 79 | class sender { 80 | public: 81 | channel* m_channel; 82 | 83 | public: 84 | sender(channel* c) : m_channel(c) {} 85 | template