From bbeaa887cddd4065f72401cd4f39cb95ea757666 Mon Sep 17 00:00:00 2001 From: jeanlemotan Date: Tue, 2 Jul 2024 18:13:47 +0200 Subject: [PATCH] First --- .clang-format | 81 + .editorconfig | 16 + .gitignore | 5 + .gitmodules | 0 CMakeLists.txt | 43 + LICENSE.txt | 19 + README.md | 3019 ++++++++ cmake/CMakeLists.txt | 0 cmake/FindCoroutines.cmake | 282 + cmake/cppcoroConfig.cmake | 6 + include/cppcoro/async_auto_reset_event.hpp | 98 + include/cppcoro/async_generator.hpp | 1088 +++ include/cppcoro/async_latch.hpp | 75 + include/cppcoro/async_manual_reset_event.hpp | 104 + include/cppcoro/async_mutex.hpp | 200 + include/cppcoro/async_scope.hpp | 102 + include/cppcoro/awaitable_traits.hpp | 27 + include/cppcoro/broken_promise.hpp | 24 + include/cppcoro/cancellation_registration.hpp | 87 + include/cppcoro/cancellation_source.hpp | 71 + include/cppcoro/cancellation_token.hpp | 72 + include/cppcoro/config.hpp | 166 + include/cppcoro/coroutine.hpp | 35 + include/cppcoro/detail/any.hpp | 22 + include/cppcoro/detail/get_awaiter.hpp | 49 + include/cppcoro/detail/is_awaiter.hpp | 55 + .../detail/lightweight_manual_reset_event.hpp | 65 + include/cppcoro/detail/manual_lifetime.hpp | 120 + .../detail/remove_rvalue_reference.hpp | 29 + include/cppcoro/detail/sync_wait_task.hpp | 300 + include/cppcoro/detail/unwrap_reference.hpp | 31 + include/cppcoro/detail/void_value.hpp | 16 + include/cppcoro/detail/when_all_counter.hpp | 55 + .../detail/when_all_ready_awaitable.hpp | 258 + include/cppcoro/detail/when_all_task.hpp | 357 + include/cppcoro/detail/win32.hpp | 179 + .../detail/win32_overlapped_operation.hpp | 376 + include/cppcoro/file.hpp | 54 + include/cppcoro/file_buffering_mode.hpp | 32 + include/cppcoro/file_open_mode.hpp | 40 + include/cppcoro/file_read_operation.hpp | 99 + include/cppcoro/file_share_mode.hpp | 45 + include/cppcoro/file_write_operation.hpp | 98 + include/cppcoro/filesystem.hpp | 24 + include/cppcoro/fmap.hpp | 169 + include/cppcoro/generator.hpp | 260 + include/cppcoro/inline_scheduler.hpp | 25 + include/cppcoro/io_service.hpp | 321 + include/cppcoro/is_awaitable.hpp | 26 + include/cppcoro/multi_producer_sequencer.hpp | 829 +++ include/cppcoro/net/ip_address.hpp | 147 + include/cppcoro/net/ip_endpoint.hpp | 161 + include/cppcoro/net/ipv4_address.hpp | 134 + include/cppcoro/net/ipv4_endpoint.hpp | 82 + include/cppcoro/net/ipv6_address.hpp | 245 + include/cppcoro/net/ipv6_endpoint.hpp | 82 + include/cppcoro/net/socket.hpp | 268 + .../cppcoro/net/socket_accept_operation.hpp | 108 + .../cppcoro/net/socket_connect_operation.hpp | 95 + .../net/socket_disconnect_operation.hpp | 85 + .../net/socket_recv_from_operation.hpp | 106 + include/cppcoro/net/socket_recv_operation.hpp | 94 + include/cppcoro/net/socket_send_operation.hpp | 94 + .../cppcoro/net/socket_send_to_operation.hpp | 100 + include/cppcoro/on_scope_exit.hpp | 147 + include/cppcoro/operation_cancelled.hpp | 24 + include/cppcoro/read_only_file.hpp | 59 + include/cppcoro/read_write_file.hpp | 66 + include/cppcoro/readable_file.hpp | 65 + include/cppcoro/recursive_generator.hpp | 345 + include/cppcoro/resume_on.hpp | 129 + include/cppcoro/round_robin_scheduler.hpp | 124 + include/cppcoro/schedule_on.hpp | 69 + include/cppcoro/sequence_barrier.hpp | 470 ++ include/cppcoro/sequence_range.hpp | 107 + include/cppcoro/sequence_traits.hpp | 33 + include/cppcoro/shared_task.hpp | 511 ++ ...single_consumer_async_auto_reset_event.hpp | 101 + include/cppcoro/single_consumer_event.hpp | 128 + include/cppcoro/single_producer_sequencer.hpp | 246 + include/cppcoro/static_thread_pool.hpp | 116 + include/cppcoro/sync_wait.hpp | 50 + include/cppcoro/task.hpp | 481 ++ include/cppcoro/when_all.hpp | 91 + include/cppcoro/when_all_ready.hpp | 56 + include/cppcoro/writable_file.hpp | 71 + include/cppcoro/write_only_file.hpp | 65 + lib/CMakeLists.txt | 178 + lib/async_auto_reset_event.cpp | 285 + lib/async_manual_reset_event.cpp | 99 + lib/async_mutex.cpp | 122 + lib/auto_reset_event.cpp | 97 + lib/auto_reset_event.hpp | 44 + lib/build.cake | 182 + lib/cancellation_registration.cpp | 41 + lib/cancellation_source.cpp | 97 + lib/cancellation_state.cpp | 624 ++ lib/cancellation_state.hpp | 108 + lib/cancellation_token.cpp | 108 + lib/file.cpp | 168 + lib/file_read_operation.cpp | 53 + lib/file_write_operation.cpp | 53 + lib/io_service.cpp | 1020 +++ lib/ip_address.cpp | 27 + lib/ip_endpoint.cpp | 27 + lib/ipv4_address.cpp | 174 + lib/ipv4_endpoint.cpp | 71 + lib/ipv6_address.cpp | 362 + lib/ipv6_endpoint.cpp | 84 + lib/lightweight_manual_reset_event.cpp | 254 + lib/read_only_file.cpp | 36 + lib/read_write_file.cpp | 38 + lib/readable_file.cpp | 36 + lib/socket.cpp | 493 ++ lib/socket_accept_operation.cpp | 129 + lib/socket_connect_operation.cpp | 178 + lib/socket_disconnect_operation.cpp | 107 + lib/socket_helpers.cpp | 85 + lib/socket_helpers.hpp | 47 + lib/socket_recv_from_operation.cpp | 96 + lib/socket_recv_operation.cpp | 66 + lib/socket_send_operation.cpp | 64 + lib/socket_send_to_operation.cpp | 72 + lib/spin_mutex.cpp | 37 + lib/spin_mutex.hpp | 47 + lib/spin_wait.cpp | 101 + lib/spin_wait.hpp | 31 + lib/static_thread_pool.cpp | 754 ++ lib/use.cake | 20 + lib/win32.cpp | 20 + lib/writable_file.cpp | 75 + lib/write_only_file.cpp | 37 + release/lib/vs2022/Debug/cppcoro.lib | Bin 0 -> 3189190 bytes release/lib/vs2022/Debug/cppcoro.pdb | Bin 0 -> 1044480 bytes release/lib/vs2022/Release/cppcoro.lib | Bin 0 -> 422626 bytes test/CMakeLists.txt | 62 + test/async_auto_reset_event_tests.cpp | 140 + test/async_generator_tests.cpp | 330 + test/async_latch_tests.cpp | 113 + test/async_manual_reset_event_tests.cpp | 96 + test/async_mutex_tests.cpp | 90 + test/build.cake | 93 + test/cancellation_token_tests.cpp | 342 + test/counted.cpp | 11 + test/counted.hpp | 42 + test/doctest/cppcoro_doctest.h | 12 + test/doctest/doctest.cmake | 175 + test/doctest/doctest.h | 6205 +++++++++++++++++ test/doctest/doctestAddTests.cmake | 81 + test/file_tests.cpp | 215 + test/generator_tests.cpp | 412 ++ test/io_service_fixture.hpp | 71 + test/io_service_tests.cpp | 230 + test/ip_address_tests.cpp | 45 + test/ip_endpoint_tests.cpp | 56 + test/ipv4_address_tests.cpp | 90 + test/ipv4_endpoint_tests.cpp | 33 + test/ipv6_address_tests.cpp | 154 + test/ipv6_endpoint_tests.cpp | 55 + test/main.cpp | 7 + test/multi_producer_sequencer_tests.cpp | 205 + test/recursive_generator_tests.cpp | 424 ++ test/scheduling_operator_tests.cpp | 290 + test/sequence_barrier_tests.cpp | 213 + test/shared_task_tests.cpp | 248 + ..._consumer_async_auto_reset_event_tests.cpp | 93 + test/single_producer_sequencer_tests.cpp | 95 + test/socket_tests.cpp | 474 ++ test/static_thread_pool_tests.cpp | 290 + test/sync_wait_tests.cpp | 76 + test/task_tests.cpp | 349 + test/when_all_ready_tests.cpp | 265 + test/when_all_tests.cpp | 427 ++ 173 files changed, 34365 insertions(+) create mode 100644 .clang-format create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 CMakeLists.txt create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 cmake/CMakeLists.txt create mode 100644 cmake/FindCoroutines.cmake create mode 100644 cmake/cppcoroConfig.cmake create mode 100644 include/cppcoro/async_auto_reset_event.hpp create mode 100644 include/cppcoro/async_generator.hpp create mode 100644 include/cppcoro/async_latch.hpp create mode 100644 include/cppcoro/async_manual_reset_event.hpp create mode 100644 include/cppcoro/async_mutex.hpp create mode 100644 include/cppcoro/async_scope.hpp create mode 100644 include/cppcoro/awaitable_traits.hpp create mode 100644 include/cppcoro/broken_promise.hpp create mode 100644 include/cppcoro/cancellation_registration.hpp create mode 100644 include/cppcoro/cancellation_source.hpp create mode 100644 include/cppcoro/cancellation_token.hpp create mode 100644 include/cppcoro/config.hpp create mode 100644 include/cppcoro/coroutine.hpp create mode 100644 include/cppcoro/detail/any.hpp create mode 100644 include/cppcoro/detail/get_awaiter.hpp create mode 100644 include/cppcoro/detail/is_awaiter.hpp create mode 100644 include/cppcoro/detail/lightweight_manual_reset_event.hpp create mode 100644 include/cppcoro/detail/manual_lifetime.hpp create mode 100644 include/cppcoro/detail/remove_rvalue_reference.hpp create mode 100644 include/cppcoro/detail/sync_wait_task.hpp create mode 100644 include/cppcoro/detail/unwrap_reference.hpp create mode 100644 include/cppcoro/detail/void_value.hpp create mode 100644 include/cppcoro/detail/when_all_counter.hpp create mode 100644 include/cppcoro/detail/when_all_ready_awaitable.hpp create mode 100644 include/cppcoro/detail/when_all_task.hpp create mode 100644 include/cppcoro/detail/win32.hpp create mode 100644 include/cppcoro/detail/win32_overlapped_operation.hpp create mode 100644 include/cppcoro/file.hpp create mode 100644 include/cppcoro/file_buffering_mode.hpp create mode 100644 include/cppcoro/file_open_mode.hpp create mode 100644 include/cppcoro/file_read_operation.hpp create mode 100644 include/cppcoro/file_share_mode.hpp create mode 100644 include/cppcoro/file_write_operation.hpp create mode 100644 include/cppcoro/filesystem.hpp create mode 100644 include/cppcoro/fmap.hpp create mode 100644 include/cppcoro/generator.hpp create mode 100644 include/cppcoro/inline_scheduler.hpp create mode 100644 include/cppcoro/io_service.hpp create mode 100644 include/cppcoro/is_awaitable.hpp create mode 100644 include/cppcoro/multi_producer_sequencer.hpp create mode 100644 include/cppcoro/net/ip_address.hpp create mode 100644 include/cppcoro/net/ip_endpoint.hpp create mode 100644 include/cppcoro/net/ipv4_address.hpp create mode 100644 include/cppcoro/net/ipv4_endpoint.hpp create mode 100644 include/cppcoro/net/ipv6_address.hpp create mode 100644 include/cppcoro/net/ipv6_endpoint.hpp create mode 100644 include/cppcoro/net/socket.hpp create mode 100644 include/cppcoro/net/socket_accept_operation.hpp create mode 100644 include/cppcoro/net/socket_connect_operation.hpp create mode 100644 include/cppcoro/net/socket_disconnect_operation.hpp create mode 100644 include/cppcoro/net/socket_recv_from_operation.hpp create mode 100644 include/cppcoro/net/socket_recv_operation.hpp create mode 100644 include/cppcoro/net/socket_send_operation.hpp create mode 100644 include/cppcoro/net/socket_send_to_operation.hpp create mode 100644 include/cppcoro/on_scope_exit.hpp create mode 100644 include/cppcoro/operation_cancelled.hpp create mode 100644 include/cppcoro/read_only_file.hpp create mode 100644 include/cppcoro/read_write_file.hpp create mode 100644 include/cppcoro/readable_file.hpp create mode 100644 include/cppcoro/recursive_generator.hpp create mode 100644 include/cppcoro/resume_on.hpp create mode 100644 include/cppcoro/round_robin_scheduler.hpp create mode 100644 include/cppcoro/schedule_on.hpp create mode 100644 include/cppcoro/sequence_barrier.hpp create mode 100644 include/cppcoro/sequence_range.hpp create mode 100644 include/cppcoro/sequence_traits.hpp create mode 100644 include/cppcoro/shared_task.hpp create mode 100644 include/cppcoro/single_consumer_async_auto_reset_event.hpp create mode 100644 include/cppcoro/single_consumer_event.hpp create mode 100644 include/cppcoro/single_producer_sequencer.hpp create mode 100644 include/cppcoro/static_thread_pool.hpp create mode 100644 include/cppcoro/sync_wait.hpp create mode 100644 include/cppcoro/task.hpp create mode 100644 include/cppcoro/when_all.hpp create mode 100644 include/cppcoro/when_all_ready.hpp create mode 100644 include/cppcoro/writable_file.hpp create mode 100644 include/cppcoro/write_only_file.hpp create mode 100644 lib/CMakeLists.txt create mode 100644 lib/async_auto_reset_event.cpp create mode 100644 lib/async_manual_reset_event.cpp create mode 100644 lib/async_mutex.cpp create mode 100644 lib/auto_reset_event.cpp create mode 100644 lib/auto_reset_event.hpp create mode 100644 lib/build.cake create mode 100644 lib/cancellation_registration.cpp create mode 100644 lib/cancellation_source.cpp create mode 100644 lib/cancellation_state.cpp create mode 100644 lib/cancellation_state.hpp create mode 100644 lib/cancellation_token.cpp create mode 100644 lib/file.cpp create mode 100644 lib/file_read_operation.cpp create mode 100644 lib/file_write_operation.cpp create mode 100644 lib/io_service.cpp create mode 100644 lib/ip_address.cpp create mode 100644 lib/ip_endpoint.cpp create mode 100644 lib/ipv4_address.cpp create mode 100644 lib/ipv4_endpoint.cpp create mode 100644 lib/ipv6_address.cpp create mode 100644 lib/ipv6_endpoint.cpp create mode 100644 lib/lightweight_manual_reset_event.cpp create mode 100644 lib/read_only_file.cpp create mode 100644 lib/read_write_file.cpp create mode 100644 lib/readable_file.cpp create mode 100644 lib/socket.cpp create mode 100644 lib/socket_accept_operation.cpp create mode 100644 lib/socket_connect_operation.cpp create mode 100644 lib/socket_disconnect_operation.cpp create mode 100644 lib/socket_helpers.cpp create mode 100644 lib/socket_helpers.hpp create mode 100644 lib/socket_recv_from_operation.cpp create mode 100644 lib/socket_recv_operation.cpp create mode 100644 lib/socket_send_operation.cpp create mode 100644 lib/socket_send_to_operation.cpp create mode 100644 lib/spin_mutex.cpp create mode 100644 lib/spin_mutex.hpp create mode 100644 lib/spin_wait.cpp create mode 100644 lib/spin_wait.hpp create mode 100644 lib/static_thread_pool.cpp create mode 100644 lib/use.cake create mode 100644 lib/win32.cpp create mode 100644 lib/writable_file.cpp create mode 100644 lib/write_only_file.cpp create mode 100644 release/lib/vs2022/Debug/cppcoro.lib create mode 100644 release/lib/vs2022/Debug/cppcoro.pdb create mode 100644 release/lib/vs2022/Release/cppcoro.lib create mode 100644 test/CMakeLists.txt create mode 100644 test/async_auto_reset_event_tests.cpp create mode 100644 test/async_generator_tests.cpp create mode 100644 test/async_latch_tests.cpp create mode 100644 test/async_manual_reset_event_tests.cpp create mode 100644 test/async_mutex_tests.cpp create mode 100644 test/build.cake create mode 100644 test/cancellation_token_tests.cpp create mode 100644 test/counted.cpp create mode 100644 test/counted.hpp create mode 100644 test/doctest/cppcoro_doctest.h create mode 100644 test/doctest/doctest.cmake create mode 100644 test/doctest/doctest.h create mode 100644 test/doctest/doctestAddTests.cmake create mode 100644 test/file_tests.cpp create mode 100644 test/generator_tests.cpp create mode 100644 test/io_service_fixture.hpp create mode 100644 test/io_service_tests.cpp create mode 100644 test/ip_address_tests.cpp create mode 100644 test/ip_endpoint_tests.cpp create mode 100644 test/ipv4_address_tests.cpp create mode 100644 test/ipv4_endpoint_tests.cpp create mode 100644 test/ipv6_address_tests.cpp create mode 100644 test/ipv6_endpoint_tests.cpp create mode 100644 test/main.cpp create mode 100644 test/multi_producer_sequencer_tests.cpp create mode 100644 test/recursive_generator_tests.cpp create mode 100644 test/scheduling_operator_tests.cpp create mode 100644 test/sequence_barrier_tests.cpp create mode 100644 test/shared_task_tests.cpp create mode 100644 test/single_consumer_async_auto_reset_event_tests.cpp create mode 100644 test/single_producer_sequencer_tests.cpp create mode 100644 test/socket_tests.cpp create mode 100644 test/static_thread_pool_tests.cpp create mode 100644 test/sync_wait_tests.cpp create mode 100644 test/task_tests.cpp create mode 100644 test/when_all_ready_tests.cpp create mode 100644 test/when_all_tests.cpp diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..d2edd51 --- /dev/null +++ b/.clang-format @@ -0,0 +1,81 @@ +--- +BasedOnStyle: LLVM +--- +Language: Cpp +Standard: Cpp11 +ColumnLimit: 100 +TabWidth: 4 +IndentWidth: 4 +UseTab: ForContinuationAndIndentation +AccessModifierOffset: -4 +AlignAfterOpenBracket: AlwaysBreak +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: false +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: false +AllowShortFunctionsOnASingleLine: InlineOnly +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakTemplateDeclarations: true +BinPackArguments: false +BinPackParameters: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BraceWrapping: { + AfterClass: true, + AfterControlStatement: true, + AfterEnum: true, + AfterFunction: true, + AfterNamespace: true, + AfterStruct: true, + AfterUnion: true, + BeforeCatch: true, + BeforeElse: true, + IndentBraces: false, + #SplitEmptyFunctionBody: false +} +BreakBeforeInheritanceComma: true +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeComma +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: false +IncludeCategories: +- Regex: '^$' + Priority: 1 +- Regex: '^`](#taskt) + * [`shared_task`](#shared_taskt) + * [`generator`](#generatort) + * [`recursive_generator`](#recursive_generatort) + * [`async_generator`](#async_generatort) +* Awaitable Types + * [`single_consumer_event`](#single_consumer_event) + * [`single_consumer_async_auto_reset_event`](#single_consumer_async_auto_reset_event) + * [`async_mutex`](#async_mutex) + * [`async_manual_reset_event`](#async_manual_reset_event) + * [`async_auto_reset_event`](#async_auto_reset_event) + * [`async_latch`](#async_latch) + * [`sequence_barrier`](#sequence_barrier) + * [`multi_producer_sequencer`](#multi_producer_sequencer) + * [`single_producer_sequencer`](#single_producer_sequencer) +* Functions + * [`sync_wait()`](#sync_wait) + * [`when_all()`](#when_all) + * [`when_all_ready()`](#when_all_ready) + * [`fmap()`](#fmap) + * [`schedule_on()`](#schedule_on) + * [`resume_on()`](#resume_on) +* [Cancellation](#Cancellation) + * `cancellation_token` + * `cancellation_source` + * `cancellation_registration` +* Schedulers and I/O + * [`static_thread_pool`](#static_thread_pool) + * [`io_service` and `io_work_scope`](#io_service-and-io_work_scope) + * [`file`, `readable_file`, `writable_file`](#file-readable_file-writable_file) + * [`read_only_file`, `write_only_file`, `read_write_file`](#read_only_file-write_only_file-read_write_file) +* Networking + * [`socket`](#socket) + * [`ip_address`, `ipv4_address`, `ipv6_address`](#ip_address-ipv4_address-ipv6_address) + * [`ip_endpoint`, `ipv4_endpoint`, `ipv6_endpoint`](#ip_endpoint-ipv4_endpoint-ipv6_endpoint) +* Metafunctions + * [`is_awaitable`](#is_awaitablet) + * [`awaitable_traits`](#awaitable_traitst) +* Concepts + * [`Awaitable`](#Awaitablet-concept) + * [`Awaiter`](#Awaitert-concept) + * [`Scheduler`](#Scheduler-concept) + * [`DelayedScheduler`](#DelayedScheduler-concept) + +This library is an experimental library that is exploring the space of high-performance, +scalable asynchronous programming abstractions that can be built on top of the C++ coroutines +proposal. + +It has been open-sourced in the hope that others will find it useful and that the C++ community +can provide feedback on it and ways to improve it. + +The Linux version is functional except for the `io_context` and file I/O related classes which have not yet been implemented for Linux (see issue [#15](https://github.com/lewissbaker/cppcoro/issues/15) for more info). + +# Class Details + +## `task` + +A task represents an asynchronous computation that is executed lazily in +that the execution of the coroutine does not start until the task is awaited. + +Example: +```c++ +#include +#include + +cppcoro::task count_lines(std::string path) +{ + auto file = co_await cppcoro::read_only_file::open(path); + + int lineCount = 0; + + char buffer[1024]; + size_t bytesRead; + std::uint64_t offset = 0; + do + { + bytesRead = co_await file.read(offset, buffer, sizeof(buffer)); + lineCount += std::count(buffer, buffer + bytesRead, '\n'); + offset += bytesRead; + } while (bytesRead > 0); + + co_return lineCount; +} + +cppcoro::task<> usage_example() +{ + // Calling function creates a new task but doesn't start + // executing the coroutine yet. + cppcoro::task countTask = count_lines("foo.txt"); + + // ... + + // Coroutine is only started when we later co_await the task. + int lineCount = co_await countTask; + + std::cout << "line count = " << lineCount << std::endl; +} +``` + +API Overview: +```c++ +// +namespace cppcoro +{ + template + class task + { + public: + + using promise_type = ; + using value_type = T; + + task() noexcept; + + task(task&& other) noexcept; + task& operator=(task&& other); + + // task is a move-only type. + task(const task& other) = delete; + task& operator=(const task& other) = delete; + + // Query if the task result is ready. + bool is_ready() const noexcept; + + // Wait for the task to complete and return the result or rethrow the + // exception if the operation completed with an unhandled exception. + // + // If the task is not yet ready then the awaiting coroutine will be + // suspended until the task completes. If the the task is_ready() then + // this operation will return the result synchronously without suspending. + Awaiter operator co_await() const & noexcept; + Awaiter operator co_await() const && noexcept; + + // Returns an awaitable that can be co_await'ed to suspend the current + // coroutine until the task completes. + // + // The 'co_await t.when_ready()' expression differs from 'co_await t' in + // that when_ready() only performs synchronization, it does not return + // the result or rethrow the exception. + // + // This can be useful if you want to synchronize with the task without + // the possibility of it throwing an exception. + Awaitable when_ready() const noexcept; + }; + + template + void swap(task& a, task& b); + + // Creates a task that yields the result of co_await'ing the specified awaitable. + // + // This can be used as a form of type-erasure of the concrete awaitable, allowing + // different awaitables that return the same await-result type to be stored in + // the same task type. + template< + typename AWAITABLE, + typename RESULT = typename awaitable_traits::await_result_t> + task make_task(AWAITABLE awaitable); +} +``` + +You can create a `task` object by calling a coroutine function that returns +a `task`. + +The coroutine must contain a usage of either `co_await` or `co_return`. +Note that a `task` coroutine may not use the `co_yield` keyword. + +When a coroutine that returns a `task` is called, a coroutine frame +is allocated if necessary and the parameters are captured in the coroutine +frame. The coroutine is suspended at the start of the coroutine body and +execution is returned to the caller and a `task` value that represents +the asynchronous computation is returned from the function call. + +The coroutine body will start executing when the `task` value is +`co_await`ed. This will suspend the awaiting coroutine and start execution +of the coroutine associated with the awaited `task` value. + +The awaiting coroutine will later be resumed on the thread that completes +execution of the awaited `task`'s coroutine. ie. the thread that +executes the `co_return` or that throws an unhandled exception that terminates +execution of the coroutine. + +If the task has already run to completion then awaiting it again will obtain +the already-computed result without suspending the awaiting coroutine. + +If the `task` object is destroyed before it is awaited then the coroutine +never executes and the destructor simply destructs the captured parameters +and frees any memory used by the coroutine frame. + +## `shared_task` + +The `shared_task` class is a coroutine type that yields a single value +asynchronously. + +It is 'lazy' in that execution of the task does not start until it is awaited by some +coroutine. + +It is 'shared' in that the task value can be copied, allowing multiple references to +the result of the task to be created. It also allows multiple coroutines to +concurrently await the result. + +The task will start executing on the thread that first `co_await`s the task. +Subsequent awaiters will either be suspended and be queued for resumption +when the task completes or will continue synchronously if the task has +already run to completion. + +If an awaiter is suspended while waiting for the task to complete then +it will be resumed on the thread that completes execution of the task. +ie. the thread that executes the `co_return` or that throws the unhandled +exception that terminates execution of the coroutine. + +API Summary +```c++ +namespace cppcoro +{ + template + class shared_task + { + public: + + using promise_type = ; + using value_type = T; + + shared_task() noexcept; + shared_task(const shared_task& other) noexcept; + shared_task(shared_task&& other) noexcept; + shared_task& operator=(const shared_task& other) noexcept; + shared_task& operator=(shared_task&& other) noexcept; + + void swap(shared_task& other) noexcept; + + // Query if the task has completed and the result is ready. + bool is_ready() const noexcept; + + // Returns an operation that when awaited will suspend the + // current coroutine until the task completes and the result + // is available. + // + // The type of the result of the 'co_await someTask' expression + // is an l-value reference to the task's result value (unless T + // is void in which case the expression has type 'void'). + // If the task completed with an unhandled exception then the + // exception will be rethrown by the co_await expression. + Awaiter operator co_await() const noexcept; + + // Returns an operation that when awaited will suspend the + // calling coroutine until the task completes and the result + // is available. + // + // The result is not returned from the co_await expression. + // This can be used to synchronize with the task without the + // possibility of the co_await expression throwing an exception. + Awaiter when_ready() const noexcept; + + }; + + template + bool operator==(const shared_task& a, const shared_task& b) noexcept; + template + bool operator!=(const shared_task& a, const shared_task& b) noexcept; + + template + void swap(shared_task& a, shared_task& b) noexcept; + + // Wrap an awaitable value in a shared_task to allow multiple coroutines + // to concurrently await the result. + template< + typename AWAITABLE, + typename RESULT = typename awaitable_traits::await_result_t> + shared_task make_shared_task(AWAITABLE awaitable); +} +``` + +All const-methods on `shared_task` are safe to call concurrently with other +const-methods on the same instance from multiple threads. It is not safe to call +non-const methods of `shared_task` concurrently with any other method on the +same instance of a `shared_task`. + +### Comparison to `task` + +The `shared_task` class is similar to `task` in that the task does +not start execution immediately upon the coroutine function being called. +The task only starts executing when it is first awaited. + +It differs from `task` in that the resulting task object can be copied, +allowing multiple task objects to reference the same asynchronous result. +It also supports multiple coroutines concurrently awaiting the result of the task. + +The trade-off is that the result is always an l-value reference to the +result, never an r-value reference (since the result may be shared) which +may limit ability to move-construct the result into a local variable. +It also has a slightly higher run-time cost due to the need to maintain +a reference count and support multiple awaiters. + +## `generator` + +A `generator` represents a coroutine type that produces a sequence of values of type, `T`, +where values are produced lazily and synchronously. + +The coroutine body is able to yield values of type `T` using the `co_yield` keyword. +Note, however, that the coroutine body is not able to use the `co_await` keyword; +values must be produced synchronously. + +For example: +```c++ +cppcoro::generator fibonacci() +{ + std::uint64_t a = 0, b = 1; + while (true) + { + co_yield b; + auto tmp = a; + a = b; + b += tmp; + } +} + +void usage() +{ + for (auto i : fibonacci()) + { + if (i > 1'000'000) break; + std::cout << i << std::endl; + } +} +``` + +When a coroutine function returning a `generator` is called the coroutine is created initially suspended. +Execution of the coroutine enters the coroutine body when the `generator::begin()` method is called and continues until +either the first `co_yield` statement is reached or the coroutine runs to completion. + +If the returned iterator is not equal to the `end()` iterator then dereferencing the iterator will +return a reference to the value passed to the `co_yield` statement. + +Calling `operator++()` on the iterator will resume execution of the coroutine and continue until +either the next `co_yield` point is reached or the coroutine runs to completion(). + +Any unhandled exceptions thrown by the coroutine will propagate out of the `begin()` or +`operator++()` calls to the caller. + +API Summary: +```c++ +namespace cppcoro +{ + template + class generator + { + public: + + using promise_type = ; + + class iterator + { + public: + using iterator_category = std::input_iterator_tag; + using value_type = std::remove_reference_t; + using reference = value_type&; + using pointer = value_type*; + using difference_type = std::size_t; + + iterator(const iterator& other) noexcept; + iterator& operator=(const iterator& other) noexcept; + + // If the generator coroutine throws an unhandled exception before producing + // the next element then the exception will propagate out of this call. + iterator& operator++(); + + reference operator*() const noexcept; + pointer operator->() const noexcept; + + bool operator==(const iterator& other) const noexcept; + bool operator!=(const iterator& other) const noexcept; + }; + + // Constructs to the empty sequence. + generator() noexcept; + + generator(generator&& other) noexcept; + generator& operator=(generator&& other) noexcept; + + generator(const generator& other) = delete; + generator& operator=(const generator&) = delete; + + ~generator(); + + // Starts executing the generator coroutine which runs until either a value is yielded + // or the coroutine runs to completion or an unhandled exception propagates out of the + // the coroutine. + iterator begin(); + + iterator end() noexcept; + + // Swap the contents of two generators. + void swap(generator& other) noexcept; + + }; + + template + void swap(generator& a, generator& b) noexcept; + + // Apply function, func, lazily to each element of the source generator + // and yield a sequence of the results of calls to func(). + template + generator> fmap(FUNC func, generator source); +} +``` + +## `recursive_generator` + +A `recursive_generator` is similar to a `generator` except that it is designed to more efficiently +support yielding the elements of a nested sequence as elements of an outer sequence. + +In addition to being able to `co_yield` a value of type `T` you can also `co_yield` a value of type `recursive_generator`. + +When you `co_yield` a `recursive_generator` value the all elements of the yielded generator are yielded as elements of the current generator. +The current coroutine is suspended until the consumer has finished consuming all elements of the nested generator, after which point execution +of the current coroutine will resume execution to produce the next element. + +The benefit of `recursive_generator` over `generator` for iterating over recursive data-structures is that the `iterator::operator++()` +is able to directly resume the leaf-most coroutine to produce the next element, rather than having to resume/suspend O(depth) coroutines for each element. +The down-side is that there is additional overhead + +For example: +```c++ +// Lists the immediate contents of a directory. +cppcoro::generator list_directory(std::filesystem::path path); + +cppcoro::recursive_generator list_directory_recursive(std::filesystem::path path) +{ + for (auto& entry : list_directory(path)) + { + co_yield entry; + if (entry.is_directory()) + { + co_yield list_directory_recursive(entry.path()); + } + } +} +``` + +Note that applying the `fmap()` operator to a `recursive_generator` will yield a `generator` +type rather than a `recursive_generator`. This is because uses of `fmap` are generally not used +in recursive contexts and we try to avoid the extra overhead incurred by `recursive_generator`. + +## `async_generator` + +An `async_generator` represents a coroutine type that produces a sequence of values of type, `T`, where values are produced lazily and values may be produced asynchronously. + +The coroutine body is able to use both `co_await` and `co_yield` expressions. + +Consumers of the generator can use a `for co_await` range-based for-loop to consume the values. + +Example +```c++ +cppcoro::async_generator ticker(int count, threadpool& tp) +{ + for (int i = 0; i < count; ++i) + { + co_await tp.delay(std::chrono::seconds(1)); + co_yield i; + } +} + +cppcoro::task<> consumer(threadpool& tp) +{ + auto sequence = ticker(10, tp); + for co_await(std::uint32_t i : sequence) + { + std::cout << "Tick " << i << std::endl; + } +} +``` + +API Summary +```c++ +// +namespace cppcoro +{ + template + class async_generator + { + public: + + class iterator + { + public: + using iterator_tag = std::forward_iterator_tag; + using difference_type = std::size_t; + using value_type = std::remove_reference_t; + using reference = value_type&; + using pointer = value_type*; + + iterator(const iterator& other) noexcept; + iterator& operator=(const iterator& other) noexcept; + + // Resumes the generator coroutine if suspended + // Returns an operation object that must be awaited to wait + // for the increment operation to complete. + // If the coroutine runs to completion then the iterator + // will subsequently become equal to the end() iterator. + // If the coroutine completes with an unhandled exception then + // that exception will be rethrown from the co_await expression. + Awaitable operator++() noexcept; + + // Dereference the iterator. + pointer operator->() const noexcept; + reference operator*() const noexcept; + + bool operator==(const iterator& other) const noexcept; + bool operator!=(const iterator& other) const noexcept; + }; + + // Construct to the empty sequence. + async_generator() noexcept; + async_generator(const async_generator&) = delete; + async_generator(async_generator&& other) noexcept; + ~async_generator(); + + async_generator& operator=(const async_generator&) = delete; + async_generator& operator=(async_generator&& other) noexcept; + + void swap(async_generator& other) noexcept; + + // Starts execution of the coroutine and returns an operation object + // that must be awaited to wait for the first value to become available. + // The result of co_await'ing the returned object is an iterator that + // can be used to advance to subsequent elements of the sequence. + // + // This method is not valid to be called once the coroutine has + // run to completion. + Awaitable begin() noexcept; + iterator end() noexcept; + + }; + + template + void swap(async_generator& a, async_generator& b); + + // Apply 'func' to each element of the source generator, yielding a sequence of + // the results of calling 'func' on the source elements. + template + async_generator> fmap(FUNC func, async_generator source); +} +``` + +### Early termination of an async_generator + +When the `async_generator` object is destructed it requests cancellation of the underlying coroutine. +If the coroutine has already run to completion or is currently suspended in a `co_yield` expression +then the coroutine is destroyed immediately. Otherwise, the coroutine will continue execution until +it either runs to completion or reaches the next `co_yield` expression. + +When the coroutine frame is destroyed the destructors of all variables in scope at that point will be +executed to ensure the resources of the generator are cleaned up. + +Note that the caller must ensure that the `async_generator` object must not be destroyed while a +consumer coroutine is executing a `co_await` expression waiting for the next item to be produced. + +## `single_consumer_event` + +This is a simple manual-reset event type that supports only a single +coroutine awaiting it at a time. +This can be used to + +API Summary: +```c++ +// +namespace cppcoro +{ + class single_consumer_event + { + public: + single_consumer_event(bool initiallySet = false) noexcept; + bool is_set() const noexcept; + void set(); + void reset() noexcept; + Awaiter operator co_await() const noexcept; + }; +} +``` + +Example: +```c++ +#include + +cppcoro::single_consumer_event event; +std::string value; + +cppcoro::task<> consumer() +{ + // Coroutine will suspend here until some thread calls event.set() + // eg. inside the producer() function below. + co_await event; + + std::cout << value << std::endl; +} + +void producer() +{ + value = "foo"; + + // This will resume the consumer() coroutine inside the call to set() + // if it is currently suspended. + event.set(); +} +``` + +## `single_consumer_async_auto_reset_event` + +This class provides an async synchronization primitive that allows a single coroutine to +wait until the event is signalled by a call to the `set()` method. + +Once the coroutine that is awaiting the event is released by either a prior or subsequent call to `set()` +the event is automatically reset back to the 'not set' state. + +This class is a more efficient version of `async_auto_reset_event` that can be used in cases where +only a single coroutine will be awaiting the event at a time. If you need to support multiple concurrent +awaiting coroutines on the event then use the `async_auto_reset_event` class instead. + +API Summary: +```c++ +// +namespace cppcoro +{ + class single_consumer_async_auto_reset_event + { + public: + + single_consumer_async_auto_reset_event( + bool initiallySet = false) noexcept; + + // Change the event to the 'set' state. If a coroutine is awaiting the + // event then the event is immediately transitioned back to the 'not set' + // state and the coroutine is resumed. + void set() noexcept; + + // Returns an Awaitable type that can be awaited to wait until + // the event becomes 'set' via a call to the .set() method. If + // the event is already in the 'set' state then the coroutine + // continues without suspending. + // The event is automatically reset back to the 'not set' state + // before resuming the coroutine. + Awaiter operator co_await() const noexcept; + + }; +} +``` + +Example Usage: +```c++ +std::atomic value; +cppcoro::single_consumer_async_auto_reset_event valueDecreasedEvent; + +cppcoro::task<> wait_until_value_is_below(int limit) +{ + while (value.load(std::memory_order_relaxed) >= limit) + { + // Wait until there has been some change that we're interested in. + co_await valueDecreasedEvent; + } +} + +void change_value(int delta) +{ + value.fetch_add(delta, std::memory_order_relaxed); + // Notify the waiter if there has been some change. + if (delta < 0) valueDecreasedEvent.set(); +} +``` + +## `async_mutex` + +Provides a simple mutual exclusion abstraction that allows the caller to 'co_await' the mutex +from within a coroutine to suspend the coroutine until the mutex lock is acquired. + +The implementation is lock-free in that a coroutine that awaits the mutex will not +block the thread but will instead suspend the coroutine and later resume it inside +the call to `unlock()` by the previous lock-holder. + +API Summary: +```c++ +// +namespace cppcoro +{ + class async_mutex_lock; + class async_mutex_lock_operation; + class async_mutex_scoped_lock_operation; + + class async_mutex + { + public: + async_mutex() noexcept; + ~async_mutex(); + + async_mutex(const async_mutex&) = delete; + async_mutex& operator(const async_mutex&) = delete; + + bool try_lock() noexcept; + async_mutex_lock_operation lock_async() noexcept; + async_mutex_scoped_lock_operation scoped_lock_async() noexcept; + void unlock(); + }; + + class async_mutex_lock_operation + { + public: + bool await_ready() const noexcept; + bool await_suspend(cppcoro::coroutine_handle<> awaiter) noexcept; + void await_resume() const noexcept; + }; + + class async_mutex_scoped_lock_operation + { + public: + bool await_ready() const noexcept; + bool await_suspend(cppcoro::coroutine_handle<> awaiter) noexcept; + [[nodiscard]] async_mutex_lock await_resume() const noexcept; + }; + + class async_mutex_lock + { + public: + // Takes ownership of the lock. + async_mutex_lock(async_mutex& mutex, std::adopt_lock_t) noexcept; + + // Transfer ownership of the lock. + async_mutex_lock(async_mutex_lock&& other) noexcept; + + async_mutex_lock(const async_mutex_lock&) = delete; + async_mutex_lock& operator=(const async_mutex_lock&) = delete; + + // Releases the lock by calling unlock() on the mutex. + ~async_mutex_lock(); + }; +} +``` + +Example usage: +```c++ +#include +#include +#include +#include + +cppcoro::async_mutex mutex; +std::set values; + +cppcoro::task<> add_item(std::string value) +{ + cppcoro::async_mutex_lock lock = co_await mutex.scoped_lock_async(); + values.insert(std::move(value)); +} +``` + +## `async_manual_reset_event` + +A manual-reset event is a coroutine/thread-synchronization primitive that allows one or more threads +to wait until the event is signalled by a thread that calls `set()`. + +The event is in one of two states; *'set'* and *'not set'*. + +If the event is in the *'set'* state when a coroutine awaits the event then the coroutine +continues without suspending. However if the coroutine is in the *'not set'* state then the +coroutine is suspended until some thread subsequently calls the `set()` method. + +Any threads that were suspended while waiting for the event to become *'set'* will be resumed +inside the next call to `set()` by some thread. + +Note that you must ensure that no coroutines are awaiting a *'not set'* event when the +event is destructed as they will not be resumed. + +Example: +```c++ +cppcoro::async_manual_reset_event event; +std::string value; + +void producer() +{ + value = get_some_string_value(); + + // Publish a value by setting the event. + event.set(); +} + +// Can be called many times to create many tasks. +// All consumer tasks will wait until value has been published. +cppcoro::task<> consumer() +{ + // Wait until value has been published by awaiting event. + co_await event; + + consume_value(value); +} +``` + +API Summary: +```c++ +namespace cppcoro +{ + class async_manual_reset_event_operation; + + class async_manual_reset_event + { + public: + async_manual_reset_event(bool initiallySet = false) noexcept; + ~async_manual_reset_event(); + + async_manual_reset_event(const async_manual_reset_event&) = delete; + async_manual_reset_event(async_manual_reset_event&&) = delete; + async_manual_reset_event& operator=(const async_manual_reset_event&) = delete; + async_manual_reset_event& operator=(async_manual_reset_event&&) = delete; + + // Wait until the event becomes set. + async_manual_reset_event_operation operator co_await() const noexcept; + + bool is_set() const noexcept; + + void set() noexcept; + + void reset() noexcept; + + }; + + class async_manual_reset_event_operation + { + public: + async_manual_reset_event_operation(async_manual_reset_event& event) noexcept; + + bool await_ready() const noexcept; + bool await_suspend(cppcoro::coroutine_handle<> awaiter) noexcept; + void await_resume() const noexcept; + }; +} +``` + +## `async_auto_reset_event` + +An auto-reset event is a coroutine/thread-synchronization primitive that allows one or more threads +to wait until the event is signalled by a thread by calling `set()`. + +Once a coroutine that is awaiting the event is released by either a prior or subsequent call to `set()` +the event is automatically reset back to the 'not set' state. + +API Summary: +```c++ +// +namespace cppcoro +{ + class async_auto_reset_event_operation; + + class async_auto_reset_event + { + public: + + async_auto_reset_event(bool initiallySet = false) noexcept; + + ~async_auto_reset_event(); + + async_auto_reset_event(const async_auto_reset_event&) = delete; + async_auto_reset_event(async_auto_reset_event&&) = delete; + async_auto_reset_event& operator=(const async_auto_reset_event&) = delete; + async_auto_reset_event& operator=(async_auto_reset_event&&) = delete; + + // Wait for the event to enter the 'set' state. + // + // If the event is already 'set' then the event is set to the 'not set' + // state and the awaiting coroutine continues without suspending. + // Otherwise, the coroutine is suspended and later resumed when some + // thread calls 'set()'. + // + // Note that the coroutine may be resumed inside a call to 'set()' + // or inside another thread's call to 'operator co_await()'. + async_auto_reset_event_operation operator co_await() const noexcept; + + // Set the state of the event to 'set'. + // + // If there are pending coroutines awaiting the event then one + // pending coroutine is resumed and the state is immediately + // set back to the 'not set' state. + // + // This operation is a no-op if the event was already 'set'. + void set() noexcept; + + // Set the state of the event to 'not-set'. + // + // This is a no-op if the state was already 'not set'. + void reset() noexcept; + + }; + + class async_auto_reset_event_operation + { + public: + explicit async_auto_reset_event_operation(async_auto_reset_event& event) noexcept; + async_auto_reset_event_operation(const async_auto_reset_event_operation& other) noexcept; + + bool await_ready() const noexcept; + bool await_suspend(cppcoro::coroutine_handle<> awaiter) noexcept; + void await_resume() const noexcept; + + }; +} +``` + +## `async_latch` + +An async latch is a synchronization primitive that allows coroutines to asynchronously +wait until a counter has been decremented to zero. + +The latch is a single-use object. Once the counter reaches zero the latch becomes 'ready' +and will remain ready until the latch is destroyed. + +API Summary: +```c++ +// +namespace cppcoro +{ + class async_latch + { + public: + + // Initialise the latch with the specified count. + async_latch(std::ptrdiff_t initialCount) noexcept; + + // Query if the count has reached zero yet. + bool is_ready() const noexcept; + + // Decrement the count by n. + // This will resume any waiting coroutines if the count reaches zero + // as a result of this call. + // It is undefined behaviour to decrement the count below zero. + void count_down(std::ptrdiff_t n = 1) noexcept; + + // Wait until the latch becomes ready. + // If the latch count is not yet zero then the awaiting coroutine will + // be suspended and later resumed by a call to count_down() that decrements + // the count to zero. If the latch count was already zero then the coroutine + // continues without suspending. + Awaiter operator co_await() const noexcept; + + }; +} +``` + +## `sequence_barrier` + +A `sequence_barrier` is a synchronization primitive that allows a single-producer +and multiple consumers to coordinate with respect to a monotonically increasing +sequence number. + +A single producer advances the sequence number by publishing new sequence numbers +in a monotonically increasing order. One or more consumers can query the last +published sequence number and can wait until a particular sequence number has been +published. + +A sequence barrier can be used to represent a cursor into a thread-safe producer/consumer +ring-buffer + +See the LMAX Disruptor pattern for more background: +https://lmax-exchange.github.io/disruptor/files/Disruptor-1.0.pdf + +API Synopsis: +```c++ +namespace cppcoro +{ + template> + class sequence_barrier + { + public: + sequence_barrier(SEQUENCE initialSequence = TRAITS::initial_sequence) noexcept; + ~sequence_barrier(); + + SEQUENCE last_published() const noexcept; + + // Wait until the specified targetSequence number has been published. + // + // If the operation does not complete synchronously then the awaiting + // coroutine is resumed on the specified scheduler. Otherwise, the + // coroutine continues without suspending. + // + // The co_await expression resumes with the updated last_published() + // value, which is guaranteed to be at least 'targetSequence'. + template + [[nodiscard]] + Awaitable wait_until_published(SEQUENCE targetSequence, + SCHEDULER& scheduler) const noexcept; + + void publish(SEQUENCE sequence) noexcept; + }; +} +``` + +## `single_producer_sequencer` + +A `single_producer_sequencer` is a synchronization primitive that can be used to +coordinate access to a ring-buffer for a single producer and one or more consumers. + +A producer first acquires one or more slots in a ring-buffer, writes to the ring-buffer +elements corresponding to those slots, and then finally publishes the values written to +those slots. A producer can never produce more than 'bufferSize' elements in advance +of where the consumer has consumed up to. + +A consumer then waits for certain elements to be published, processes the items and +then notifies the producer when it has finished processing items by publishing the +sequence number it has finished consuming in a `sequence_barrier` object. + + +API Synopsis: +```c++ +// +namespace cppcoro +{ + template< + typename SEQUENCE = std::size_t, + typename TRAITS = sequence_traits> + class single_producer_sequencer + { + public: + using size_type = typename sequence_range::size_type; + + single_producer_sequencer( + const sequence_barrier& consumerBarrier, + std::size_t bufferSize, + SEQUENCE initialSequence = TRAITS::initial_sequence) noexcept; + + // Publisher API: + + template + [[nodiscard]] + Awaitable claim_one(SCHEDULER& scheduler) noexcept; + + template + [[nodiscard]] + Awaitable> claim_up_to( + std::size_t count, + SCHEDULER& scheduler) noexcept; + + void publish(SEQUENCE sequence) noexcept; + + // Consumer API: + + SEQUENCE last_published() const noexcept; + + template + [[nodiscard]] + Awaitable wait_until_published( + SEQUENCE targetSequence, + SCHEDULER& scheduler) const noexcept; + + }; +} +``` + +Example usage: +```c++ +using namespace cppcoro; +using namespace std::chrono; + +struct message +{ + int id; + steady_clock::time_point timestamp; + float data; +}; + +constexpr size_t bufferSize = 16384; // Must be power-of-two +constexpr size_t indexMask = bufferSize - 1; +message buffer[bufferSize]; + +task producer( + io_service& ioSvc, + single_producer_sequencer& sequencer) +{ + auto start = steady_clock::now(); + for (int i = 0; i < 1'000'000; ++i) + { + // Wait until a slot is free in the buffer. + size_t seq = co_await sequencer.claim_one(ioSvc); + + // Populate the message. + auto& msg = buffer[seq & indexMask]; + msg.id = i; + msg.timestamp = steady_clock::now(); + msg.data = 123; + + // Publish the message. + sequencer.publish(seq); + } + + // Publish a sentinel + auto seq = co_await sequencer.claim_one(ioSvc); + auto& msg = buffer[seq & indexMask]; + msg.id = -1; + sequencer.publish(seq); +} + +task consumer( + static_thread_pool& threadPool, + const single_producer_sequencer& sequencer, + sequence_barrier& consumerBarrier) +{ + size_t nextToRead = 0; + while (true) + { + // Wait until the next message is available + // There may be more than one available. + const size_t available = co_await sequencer.wait_until_published(nextToRead, threadPool); + do { + auto& msg = buffer[nextToRead & indexMask]; + if (msg.id == -1) + { + consumerBarrier.publish(nextToRead); + co_return; + } + + processMessage(msg); + } while (nextToRead++ != available); + + // Notify the producer that we've finished processing + // up to 'nextToRead - 1'. + consumerBarrier.publish(available); + } +} + +task example(io_service& ioSvc, static_thread_pool& threadPool) +{ + sequence_barrier barrier; + single_producer_sequencer sequencer{barrier, bufferSize}; + + co_await when_all( + producer(tp, sequencer), + consumer(tp, sequencer, barrier)); +} +``` + +## `multi_producer_sequencer` + +The `multi_producer_sequencer` class is a synchronization primitive that coordinates +access to a ring-buffer for multiple producers and one or more consumers. + +For a single-producer variant see the `single_producer_sequencer` class. + +Note that the ring-buffer must have a size that is a power-of-two. This is because +the implementation uses bitmasks instead of integer division/modulo to calculate +the offset into the buffer. Also, this allows the sequence number to safely wrap +around the 32-bit/64-bit value. + +API Summary: +```c++ +// +namespace cppcoro +{ + template> + class multi_producer_sequencer + { + public: + multi_producer_sequencer( + const sequence_barrier& consumerBarrier, + SEQUENCE initialSequence = TRAITS::initial_sequence); + + std::size_t buffer_size() const noexcept; + + // Consumer interface + // + // Each consumer keeps track of their own 'lastKnownPublished' value + // and must pass this to the methods that query for an updated last-known + // published sequence number. + + SEQUENCE last_published_after(SEQUENCE lastKnownPublished) const noexcept; + + template + Awaitable wait_until_published( + SEQUENCE targetSequence, + SEQUENCE lastKnownPublished, + SCHEDULER& scheduler) const noexcept; + + // Producer interface + + // Query whether any slots available for claiming (approx.) + bool any_available() const noexcept; + + template + Awaitable claim_one(SCHEDULER& scheduler) noexcept; + + template + Awaitable> claim_up_to( + std::size_t count, + SCHEDULER& scheduler) noexcept; + + // Mark the specified sequence number as published. + void publish(SEQUENCE sequence) noexcept; + + // Mark all sequence numbers in the specified range as published. + void publish(const sequence_range& range) noexcept; + }; +} +``` + +## Cancellation + +A `cancellation_token` is a value that can be passed to a function that allows the caller to subsequently communicate a request to cancel the operation to that function. + +To obtain a `cancellation_token` that is able to be cancelled you must first create a `cancellation_source` object. +The `cancellation_source::token()` method can be used to manufacture new `cancellation_token` values that are linked to that `cancellation_source` object. + +When you want to later request cancellation of an operation you have passed a `cancellation_token` to +you can call `cancellation_source::request_cancellation()` on an associated `cancellation_source` object. + +Functions can respond to a request for cancellation in one of two ways: +1. Poll for cancellation at regular intervals by calling either `cancellation_token::is_cancellation_requested()` or `cancellation_token::throw_if_cancellation_requested()`. +2. Register a callback to be executed when cancellation is requested using the `cancellation_registration` class. + +API Summary: +```c++ +namespace cppcoro +{ + class cancellation_source + { + public: + // Construct a new, independently cancellable cancellation source. + cancellation_source(); + + // Construct a new reference to the same cancellation state. + cancellation_source(const cancellation_source& other) noexcept; + cancellation_source(cancellation_source&& other) noexcept; + + ~cancellation_source(); + + cancellation_source& operator=(const cancellation_source& other) noexcept; + cancellation_source& operator=(cancellation_source&& other) noexcept; + + bool is_cancellation_requested() const noexcept; + bool can_be_cancelled() const noexcept; + void request_cancellation(); + + cancellation_token token() const noexcept; + }; + + class cancellation_token + { + public: + // Construct a token that can't be cancelled. + cancellation_token() noexcept; + + cancellation_token(const cancellation_token& other) noexcept; + cancellation_token(cancellation_token&& other) noexcept; + + ~cancellation_token(); + + cancellation_token& operator=(const cancellation_token& other) noexcept; + cancellation_token& operator=(cancellation_token&& other) noexcept; + + bool is_cancellation_requested() const noexcept; + void throw_if_cancellation_requested() const; + + // Query if this token can ever have cancellation requested. + // Code can use this to take a more efficient code-path in cases + // that the operation does not need to handle cancellation. + bool can_be_cancelled() const noexcept; + }; + + // RAII class for registering a callback to be executed if cancellation + // is requested on a particular cancellation token. + class cancellation_registration + { + public: + + // Register a callback to be executed if cancellation is requested. + // Callback will be called with no arguments on the thread that calls + // request_cancellation() if cancellation is not yet requested, or + // called immediately if cancellation has already been requested. + // Callback must not throw an unhandled exception when called. + template + cancellation_registration(cancellation_token token, CALLBACK&& callback); + + cancellation_registration(const cancellation_registration& other) = delete; + + ~cancellation_registration(); + }; + + class operation_cancelled : public std::exception + { + public: + operation_cancelled(); + const char* what() const override; + }; +} +``` + +Example: Polling Approach +```c++ +cppcoro::task<> do_something_async(cppcoro::cancellation_token token) +{ + // Explicitly define cancellation points within the function + // by calling throw_if_cancellation_requested(). + token.throw_if_cancellation_requested(); + + co_await do_step_1(); + + token.throw_if_cancellation_requested(); + + do_step_2(); + + // Alternatively, you can query if cancellation has been + // requested to allow yourself to do some cleanup before + // returning. + if (token.is_cancellation_requested()) + { + display_message_to_user("Cancelling operation..."); + do_cleanup(); + throw cppcoro::operation_cancelled{}; + } + + do_final_step(); +} +``` + +Example: Callback Approach +```c++ +// Say we already have a timer abstraction that supports being +// cancelled but it doesn't support cancellation_tokens natively. +// You can use a cancellation_registration to register a callback +// that calls the existing cancellation API. e.g. +cppcoro::task<> cancellable_timer_wait(cppcoro::cancellation_token token) +{ + auto timer = create_timer(10s); + + cppcoro::cancellation_registration registration(token, [&] + { + // Call existing timer cancellation API. + timer.cancel(); + }); + + co_await timer; +} +``` + +## `static_thread_pool` + +The `static_thread_pool` class provides an abstraction that lets you schedule work +on a fixed-size pool of threads. + +This class implements the **Scheduler** concept (see below). + +You can enqueue work to the thread-pool by executing `co_await threadPool.schedule()`. +This operation will suspend the current coroutine, enqueue it for execution on the +thread-pool and the thread pool will then resume the coroutine when a thread in the +thread-pool is next free to run the coroutine. **This operation is guaranteed not +to throw and, in the common case, will not allocate any memory**. + +This class makes use of a work-stealing algorithm to load-balance work across multiple +threads. Work enqueued to the thread-pool from a thread-pool thread will be scheduled +for execution on the same thread in a LIFO queue. Work enqueued to the thread-pool from +a remote thread will be enqueued to a global FIFO queue. When a worker thread runs out +of work from its local queue it first tries to dequeue work from the global queue. If +that queue is empty then it next tries to steal work from the back of the queues of +the other worker threads. + +API Summary: +```c++ +namespace cppcoro +{ + class static_thread_pool + { + public: + // Initialise the thread-pool with a number of threads equal to + // std::thread::hardware_concurrency(). + static_thread_pool(); + + // Initialise the thread pool with the specified number of threads. + explicit static_thread_pool(std::uint32_t threadCount); + + std::uint32_t thread_count() const noexcept; + + class schedule_operation + { + public: + schedule_operation(static_thread_pool* tp) noexcept; + + bool await_ready() noexcept; + bool await_suspend(cppcoro::coroutine_handle<> h) noexcept; + bool await_resume() noexcept; + + private: + // unspecified + }; + + // Return an operation that can be awaited by a coroutine. + // + // + [[nodiscard]] + schedule_operation schedule() noexcept; + + private: + + // Unspecified + + }; +} +``` + +Example usage: Simple +```c++ +cppcoro::task do_something_on_threadpool(cppcoro::static_thread_pool& tp) +{ + // First schedule the coroutine onto the threadpool. + co_await tp.schedule(); + + // When it resumes, this coroutine is now running on the threadpool. + do_something(); +} +``` + +Example usage: Doing things in parallel - using `schedule_on()` operator with `static_thread_pool`. +```c++ +cppcoro::task dot_product(static_thread_pool& tp, double a[], double b[], size_t count) +{ + if (count > 1000) + { + // Subdivide the work recursively into two equal tasks + // The first half is scheduled to the thread pool so it can run concurrently + // with the second half which continues on this thread. + size_t halfCount = count / 2; + auto [first, second] = co_await when_all( + schedule_on(tp, dot_product(tp, a, b, halfCount), + dot_product(tp, a + halfCount, b + halfCount, count - halfCount)); + co_return first + second; + } + else + { + double sum = 0.0; + for (size_t i = 0; i < count; ++i) + { + sum += a[i] * b[i]; + } + co_return sum; + } +} +``` + +## `io_service` and `io_work_scope` + +The `io_service` class provides an abstraction for processing I/O completion events +from asynchronous I/O operations. + +When an asynchronous I/O operation completes, the coroutine that was awaiting +that operation will be resumed on an I/O thread inside a call to one of the +event-processing methods: `process_events()`, `process_pending_events()`, +`process_one_event()` or `process_one_pending_event()`. + +The `io_service` class does not manage any I/O threads. +You must ensure that some thread calls one of the event-processing methods for coroutines awaiting I/O +completion events to be dispatched. This can either be a dedicated thread that calls `process_events()` +or mixed in with some other event loop (e.g. a UI event loop) by periodically polling for new events +via a call to `process_pending_events()` or `process_one_pending_event()`. + +This allows integration of the `io_service` event-loop with other event loops, such as a user-interface event loop. + +You can multiplex processing of events across multiple threads by having multiple threads call +`process_events()`. You can specify a hint as to the maximum number of threads to have actively +processing events via an optional `io_service` constructor parameter. + +On Windows, the implementation makes use of the Windows I/O Completion Port facility to dispatch +events to I/O threads in a scalable manner. + +API Summary: +```c++ +namespace cppcoro +{ + class io_service + { + public: + + class schedule_operation; + class timed_schedule_operation; + + io_service(); + io_service(std::uint32_t concurrencyHint); + + io_service(io_service&&) = delete; + io_service(const io_service&) = delete; + io_service& operator=(io_service&&) = delete; + io_service& operator=(const io_service&) = delete; + + ~io_service(); + + // Scheduler methods + + [[nodiscard]] + schedule_operation schedule() noexcept; + + template + [[nodiscard]] + timed_schedule_operation schedule_after( + std::chrono::duration delay, + cppcoro::cancellation_token cancellationToken = {}) noexcept; + + // Event-loop methods + // + // I/O threads must call these to process I/O events and execute + // scheduled coroutines. + + std::uint64_t process_events(); + std::uint64_t process_pending_events(); + std::uint64_t process_one_event(); + std::uint64_t process_one_pending_event(); + + // Request that all threads processing events exit their event loops. + void stop() noexcept; + + // Query if some thread has called stop() + bool is_stop_requested() const noexcept; + + // Reset the event-loop after a call to stop() so that threads can + // start processing events again. + void reset(); + + // Reference-counting methods for tracking outstanding references + // to the io_service. + // + // The io_service::stop() method will be called when the last work + // reference is decremented. + // + // Use the io_work_scope RAII class to manage calling these methods on + // entry-to and exit-from a scope. + void notify_work_started() noexcept; + void notify_work_finished() noexcept; + + }; + + class io_service::schedule_operation + { + public: + schedule_operation(const schedule_operation&) noexcept; + schedule_operation& operator=(const schedule_operation&) noexcept; + + bool await_ready() const noexcept; + void await_suspend(cppcoro::coroutine_handle<> awaiter) noexcept; + void await_resume() noexcept; + }; + + class io_service::timed_schedule_operation + { + public: + timed_schedule_operation(timed_schedule_operation&&) noexcept; + + timed_schedule_operation(const timed_schedule_operation&) = delete; + timed_schedule_operation& operator=(const timed_schedule_operation&) = delete; + timed_schedule_operation& operator=(timed_schedule_operation&&) = delete; + + bool await_ready() const noexcept; + void await_suspend(cppcoro::coroutine_handle<> awaiter); + void await_resume(); + }; + + class io_work_scope + { + public: + + io_work_scope(io_service& ioService) noexcept; + + io_work_scope(const io_work_scope& other) noexcept; + io_work_scope(io_work_scope&& other) noexcept; + + ~io_work_scope(); + + io_work_scope& operator=(const io_work_scope& other) noexcept; + io_work_scope& operator=(io_work_scope&& other) noexcept; + + io_service& service() const noexcept; + }; + +} +``` + +Example: +```c++ +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace fs = cppcoro::filesystem; + +cppcoro::task count_lines(cppcoro::io_service& ioService, fs::path path) +{ + auto file = cppcoro::read_only_file::open(ioService, path); + + constexpr size_t bufferSize = 4096; + auto buffer = std::make_unique(bufferSize); + + std::uint64_t newlineCount = 0; + + for (std::uint64_t offset = 0, fileSize = file.size(); offset < fileSize;) + { + const auto bytesToRead = static_cast( + std::min(bufferSize, fileSize - offset)); + + const auto bytesRead = co_await file.read(offset, buffer.get(), bytesToRead); + + newlineCount += std::count(buffer.get(), buffer.get() + bytesRead, '\n'); + + offset += bytesRead; + } + + co_return newlineCount; +} + +cppcoro::task<> run(cppcoro::io_service& ioService) +{ + cppcoro::io_work_scope ioScope(ioService); + + auto lineCount = co_await count_lines(ioService, fs::path{"foo.txt"}); + + std::cout << "foo.txt has " << lineCount << " lines." << std::endl;; +} + +cppcoro::task<> process_events(cppcoro::io_service& ioService) +{ + // Process events until the io_service is stopped. + // ie. when the last io_work_scope goes out of scope. + ioService.process_events(); + co_return; +} + +int main() +{ + cppcoro::io_service ioService; + + cppcoro::sync_wait(cppcoro::when_all_ready( + run(ioService), + process_events(ioService))); + + return 0; +} +``` + +### `io_service` as a scheduler + +An `io_service` class implements the interfaces for the `Scheduler` and `DelayedScheduler` concepts. + +This allows a coroutine to suspend execution on the current thread and schedule itself for resumption +on an I/O thread associated with a particular `io_service` object. + +Example: +```c++ +cppcoro::task<> do_something(cppcoro::io_service& ioService) +{ + // Coroutine starts execution on the thread of the task awaiter. + + // A coroutine can transfer execution to an I/O thread by awaiting the + // result of io_service::schedule(). + co_await ioService.schedule(); + + // At this point, the coroutine is now executing on an I/O thread + // inside a call to one of the io_service event processing methods. + + // A coroutine can also perform a delayed-schedule that will suspend + // the coroutine for a specified duration of time before scheduling + // it for resumption on an I/O thread. + co_await ioService.schedule_after(100ms); + + // At this point, the coroutine is executing on a potentially different I/O thread. +} +``` + +## `file`, `readable_file`, `writable_file` + +These types are abstract base-classes for performing concrete file I/O. + +API Summary: +```c++ +namespace cppcoro +{ + class file_read_operation; + class file_write_operation; + + class file + { + public: + + virtual ~file(); + + std::uint64_t size() const; + + protected: + + file(file&& other) noexcept; + + }; + + class readable_file : public virtual file + { + public: + + [[nodiscard]] + file_read_operation read( + std::uint64_t offset, + void* buffer, + std::size_t byteCount, + cancellation_token ct = {}) const noexcept; + + }; + + class writable_file : public virtual file + { + public: + + void set_size(std::uint64_t fileSize); + + [[nodiscard]] + file_write_operation write( + std::uint64_t offset, + const void* buffer, + std::size_t byteCount, + cancellation_token ct = {}) noexcept; + + }; + + class file_read_operation + { + public: + + file_read_operation(file_read_operation&& other) noexcept; + + bool await_ready() const noexcept; + bool await_suspend(cppcoro::coroutine_handle<> awaiter); + std::size_t await_resume(); + + }; + + class file_write_operation + { + public: + + file_write_operation(file_write_operation&& other) noexcept; + + bool await_ready() const noexcept; + bool await_suspend(cppcoro::coroutine_handle<> awaiter); + std::size_t await_resume(); + + }; +} +``` + +## `read_only_file`, `write_only_file`, `read_write_file` + +These types represent concrete file I/O classes. + +API Summary: +```c++ +namespace cppcoro +{ + class read_only_file : public readable_file + { + public: + + [[nodiscard]] + static read_only_file open( + io_service& ioService, + const cppcoro::filesystem::path& path, + file_share_mode shareMode = file_share_mode::read, + file_buffering_mode bufferingMode = file_buffering_mode::default_); + + }; + + class write_only_file : public writable_file + { + public: + + [[nodiscard]] + static write_only_file open( + io_service& ioService, + const cppcoro::filesystem::path& path, + file_open_mode openMode = file_open_mode::create_or_open, + file_share_mode shareMode = file_share_mode::none, + file_buffering_mode bufferingMode = file_buffering_mode::default_); + + }; + + class read_write_file : public readable_file, public writable_file + { + public: + + [[nodiscard]] + static read_write_file open( + io_service& ioService, + const cppcoro::filesystem::path& path, + file_open_mode openMode = file_open_mode::create_or_open, + file_share_mode shareMode = file_share_mode::none, + file_buffering_mode bufferingMode = file_buffering_mode::default_); + + }; +} +``` + +All `open()` functions throw `std::system_error` on failure. + +# Networking + +NOTE: Networking abstractions are currently only supported on the Windows platform. +Linux support will be coming soon. + +## `socket` + +The socket class can be used to send/receive data over the network asynchronously. + +Currently only supports TCP/IP, UDP/IP over IPv4 and IPv6. + +API Summary: +```c++ +// +namespace cppcoro::net +{ + class socket + { + public: + + static socket create_tcpv4(ip_service& ioSvc); + static socket create_tcpv6(ip_service& ioSvc); + static socket create_updv4(ip_service& ioSvc); + static socket create_udpv6(ip_service& ioSvc); + + socket(socket&& other) noexcept; + + ~socket(); + + socket& operator=(socket&& other) noexcept; + + // Return the native socket handle for the socket + native_handle() noexcept; + + const ip_endpoint& local_endpoint() const noexcept; + const ip_endpoint& remote_endpoint() const noexcept; + + void bind(const ip_endpoint& localEndPoint); + + void listen(); + + [[nodiscard]] + Awaitable connect(const ip_endpoint& remoteEndPoint) noexcept; + [[nodiscard]] + Awaitable connect(const ip_endpoint& remoteEndPoint, + cancellation_token ct) noexcept; + + [[nodiscard]] + Awaitable accept(socket& acceptingSocket) noexcept; + [[nodiscard]] + Awaitable accept(socket& acceptingSocket, + cancellation_token ct) noexcept; + + [[nodiscard]] + Awaitable disconnect() noexcept; + [[nodiscard]] + Awaitable disconnect(cancellation_token ct) noexcept; + + [[nodiscard]] + Awaitable send(const void* buffer, std::size_t size) noexcept; + [[nodiscard]] + Awaitable send(const void* buffer, + std::size_t size, + cancellation_token ct) noexcept; + + [[nodiscard]] + Awaitable recv(void* buffer, std::size_t size) noexcept; + [[nodiscard]] + Awaitable recv(void* buffer, + std::size_t size, + cancellation_token ct) noexcept; + + [[nodiscard]] + socket_recv_from_operation recv_from( + void* buffer, + std::size_t size) noexcept; + [[nodiscard]] + socket_recv_from_operation_cancellable recv_from( + void* buffer, + std::size_t size, + cancellation_token ct) noexcept; + + [[nodiscard]] + socket_send_to_operation send_to( + const ip_endpoint& destination, + const void* buffer, + std::size_t size) noexcept; + [[nodiscard]] + socket_send_to_operation_cancellable send_to( + const ip_endpoint& destination, + const void* buffer, + std::size_t size, + cancellation_token ct) noexcept; + + void close_send(); + void close_recv(); + + }; +} +``` + +Example: Echo Server +```c++ +#include +#include +#include +#include +#include + +#include +#include + +cppcoro::task handle_connection(socket s) +{ + try + { + const size_t bufferSize = 16384; + auto buffer = std::make_unique(bufferSize); + size_t bytesRead; + do { + // Read some bytes + bytesRead = co_await s.recv(buffer.get(), bufferSize); + + // Write some bytes + size_t bytesWritten = 0; + while (bytesWritten < bytesRead) { + bytesWritten += co_await s.send( + buffer.get() + bytesWritten, + bytesRead - bytesWritten); + } + } while (bytesRead != 0); + + s.close_send(); + + co_await s.disconnect(); + } + catch (...) + { + std::cout << "connection failed" << std:: + } +} + +cppcoro::task echo_server( + cppcoro::net::ipv4_endpoint endpoint, + cppcoro::io_service& ioSvc, + cancellation_token ct) +{ + cppcoro::async_scope scope; + + std::exception_ptr ex; + try + { + auto listeningSocket = cppcoro::net::socket::create_tcpv4(ioSvc); + listeningSocket.bind(endpoint); + listeningSocket.listen(); + + while (true) { + auto connection = cppcoro::net::socket::create_tcpv4(ioSvc); + co_await listeningSocket.accept(connection, ct); + scope.spawn(handle_connection(std::move(connection))); + } + } + catch (cppcoro::operation_cancelled) + { + } + catch (...) + { + ex = std::current_exception(); + } + + // Wait until all handle_connection tasks have finished. + co_await scope.join(); + + if (ex) std::rethrow_exception(ex); +} + +int main(int argc, const char* argv[]) +{ + cppcoro::io_service ioSvc; + + if (argc != 2) return -1; + + auto endpoint = cppcoro::ipv4_endpoint::from_string(argv[1]); + if (!endpoint) return -1; + + (void)cppcoro::sync_wait(cppcoro::when_all( + [&]() -> task<> + { + // Shutdown the event loop once finished. + auto stopOnExit = cppcoro::on_scope_exit([&] { ioSvc.stop(); }); + + cppcoro::cancellation_source canceller; + co_await cppcoro::when_all( + [&]() -> task<> + { + // Run for 30s then stop accepting new connections. + co_await ioSvc.schedule_after(std::chrono::seconds(30)); + canceller.request_cancellation(); + }(), + echo_server(*endpoint, ioSvc, canceller.token())); + }(), + [&]() -> task<> + { + ioSvc.process_events(); + }())); + + return 0; +} +``` + +## `ip_address`, `ipv4_address`, `ipv6_address` + +Helper classes for representing an IP address. + +API Synopsis: +```c++ +namespace cppcoro::net +{ + class ipv4_address + { + using bytes_t = std::uint8_t[4]; + public: + constexpr ipv4_address(); + explicit constexpr ipv4_address(std::uint32_t integer); + explicit constexpr ipv4_address(const std::uint8_t(&bytes)[4]); + explicit constexpr ipv4_address(std::uint8_t b0, + std::uint8_t b1, + std::uint8_t b2, + std::uint8_t b3); + + constexpr const bytes_t& bytes() const; + + constexpr std::uint32_t to_integer() const; + + static constexpr ipv4_address loopback(); + + constexpr bool is_loopback() const; + constexpr bool is_private_network() const; + + constexpr bool operator==(ipv4_address other) const; + constexpr bool operator!=(ipv4_address other) const; + constexpr bool operator<(ipv4_address other) const; + constexpr bool operator>(ipv4_address other) const; + constexpr bool operator<=(ipv4_address other) const; + constexpr bool operator>=(ipv4_address other) const; + + std::string to_string(); + + static std::optional from_string(std::string_view string) noexcept; + }; + + class ipv6_address + { + using bytes_t = std::uint8_t[16]; + public: + constexpr ipv6_address(); + + explicit constexpr ipv6_address( + std::uint64_t subnetPrefix, + std::uint64_t interfaceIdentifier); + + constexpr ipv6_address( + std::uint16_t part0, + std::uint16_t part1, + std::uint16_t part2, + std::uint16_t part3, + std::uint16_t part4, + std::uint16_t part5, + std::uint16_t part6, + std::uint16_t part7); + + explicit constexpr ipv6_address( + const std::uint16_t(&parts)[8]); + + explicit constexpr ipv6_address( + const std::uint8_t(bytes)[16]); + + constexpr const bytes_t& bytes() const; + + constexpr std::uint64_t subnet_prefix() const; + constexpr std::uint64_t interface_identifier() const; + + static constexpr ipv6_address unspecified(); + static constexpr ipv6_address loopback(); + + static std::optional from_string(std::string_view string) noexcept; + + std::string to_string() const; + + constexpr bool operator==(const ipv6_address& other) const; + constexpr bool operator!=(const ipv6_address& other) const; + constexpr bool operator<(const ipv6_address& other) const; + constexpr bool operator>(const ipv6_address& other) const; + constexpr bool operator<=(const ipv6_address& other) const; + constexpr bool operator>=(const ipv6_address& other) const; + + }; + + class ip_address + { + public: + + // Constructs to IPv4 address 0.0.0.0 + ip_address() noexcept; + + ip_address(ipv4_address address) noexcept; + ip_address(ipv6_address address) noexcept; + + bool is_ipv4() const noexcept; + bool is_ipv6() const noexcept; + + const ipv4_address& to_ipv4() const; + const ipv6_address& to_ipv6() const; + + const std::uint8_t* bytes() const noexcept; + + std::string to_string() const; + + static std::optional from_string(std::string_view string) noexcept; + + bool operator==(const ip_address& rhs) const noexcept; + bool operator!=(const ip_address& rhs) const noexcept; + + // ipv4_address sorts less than ipv6_address + bool operator<(const ip_address& rhs) const noexcept; + bool operator>(const ip_address& rhs) const noexcept; + bool operator<=(const ip_address& rhs) const noexcept; + bool operator>=(const ip_address& rhs) const noexcept; + + }; +} +``` + +## `ip_endpoint`, `ipv4_endpoint` `ipv6_endpoint` + +Helper classes for representing an IP address and port-number. + +API Synopsis: +```c++ +namespace cppcoro::net +{ + class ipv4_endpoint + { + public: + ipv4_endpoint() noexcept; + explicit ipv4_endpoint(ipv4_address address, std::uint16_t port = 0) noexcept; + + const ipv4_address& address() const noexcept; + std::uint16_t port() const noexcept; + + std::string to_string() const; + static std::optional from_string(std::string_view string) noexcept; + }; + + bool operator==(const ipv4_endpoint& a, const ipv4_endpoint& b); + bool operator!=(const ipv4_endpoint& a, const ipv4_endpoint& b); + bool operator<(const ipv4_endpoint& a, const ipv4_endpoint& b); + bool operator>(const ipv4_endpoint& a, const ipv4_endpoint& b); + bool operator<=(const ipv4_endpoint& a, const ipv4_endpoint& b); + bool operator>=(const ipv4_endpoint& a, const ipv4_endpoint& b); + + class ipv6_endpoint + { + public: + ipv6_endpoint() noexcept; + explicit ipv6_endpoint(ipv6_address address, std::uint16_t port = 0) noexcept; + + const ipv6_address& address() const noexcept; + std::uint16_t port() const noexcept; + + std::string to_string() const; + static std::optional from_string(std::string_view string) noexcept; + }; + + bool operator==(const ipv6_endpoint& a, const ipv6_endpoint& b); + bool operator!=(const ipv6_endpoint& a, const ipv6_endpoint& b); + bool operator<(const ipv6_endpoint& a, const ipv6_endpoint& b); + bool operator>(const ipv6_endpoint& a, const ipv6_endpoint& b); + bool operator<=(const ipv6_endpoint& a, const ipv6_endpoint& b); + bool operator>=(const ipv6_endpoint& a, const ipv6_endpoint& b); + + class ip_endpoint + { + public: + // Constructs to IPv4 end-point 0.0.0.0:0 + ip_endpoint() noexcept; + + ip_endpoint(ipv4_endpoint endpoint) noexcept; + ip_endpoint(ipv6_endpoint endpoint) noexcept; + + bool is_ipv4() const noexcept; + bool is_ipv6() const noexcept; + + const ipv4_endpoint& to_ipv4() const; + const ipv6_endpoint& to_ipv6() const; + + ip_address address() const noexcept; + std::uint16_t port() const noexcept; + + std::string to_string() const; + + static std::optional from_string(std::string_view string) noexcept; + + bool operator==(const ip_endpoint& rhs) const noexcept; + bool operator!=(const ip_endpoint& rhs) const noexcept; + + // ipv4_endpoint sorts less than ipv6_endpoint + bool operator<(const ip_endpoint& rhs) const noexcept; + bool operator>(const ip_endpoint& rhs) const noexcept; + bool operator<=(const ip_endpoint& rhs) const noexcept; + bool operator>=(const ip_endpoint& rhs) const noexcept; + }; +} +``` + +# Functions + +## `sync_wait()` + +The `sync_wait()` function can be used to synchronously wait until the specified `awaitable` +completes. + +The specified awaitable will be `co_await`ed on current thread inside a newly created coroutine. + +The `sync_wait()` call will block until the operation completes and will return the result of +the `co_await` expression or rethrow the exception if the `co_await` expression completed with +an unhandled exception. + +The `sync_wait()` function is mostly useful for starting a top-level task from within `main()` +and waiting until the task finishes, in practice it is the only way to start the first/top-level +`task`. + +API Summary: +```c++ +// +namespace cppcoro +{ + template + auto sync_wait(AWAITABLE&& awaitable) + -> typename awaitable_traits::await_result_t; +} +``` + +Examples: +```c++ +void example_task() +{ + auto makeTask = []() -> task + { + co_return "foo"; + }; + + auto task = makeTask(); + + // start the lazy task and wait until it completes + sync_wait(task); // -> "foo" + sync_wait(makeTask()); // -> "foo" +} + +void example_shared_task() +{ + auto makeTask = []() -> shared_task + { + co_return "foo"; + }; + + auto task = makeTask(); + // start the shared task and wait until it completes + sync_wait(task) == "foo"; + sync_wait(makeTask()) == "foo"; +} +``` + +## `when_all_ready()` + +The `when_all_ready()` function can be used to create a new awaitable that completes when +all of the input awaitables complete. + +Input tasks can be any type of awaitable. + +When the returned awaitable is `co_await`ed it will `co_await` each of the input awaitables +in turn on the awaiting thread in the order they are passed to the `when_all_ready()` +function. If these tasks to not complete synchronously then they will execute concurrently. + +Once all of the `co_await` expressions on input awaitables have run to completion the +returned awaitable will complete and resume the awaiting coroutine. The awaiting coroutine +will be resumed on the thread of the input awaitable that is last to complete. + +The returned awaitable is guaranteed not to throw an exception when `co_await`ed, +even if some of the input awaitables fail with an unhandled exception. + +Note, however, that the `when_all_ready()` call itself may throw `std::bad_alloc` if it +was unable to allocate memory for the coroutine frames required to await each of the +input awaitables. It may also throw an exception if any of the input awaitable objects +throw from their copy/move constructors. + +The result of `co_await`ing the returned awaitable is a `std::tuple` or `std::vector` +of `when_all_task` objects. These objects allow you to obtain the result (or exception) +of each input awaitable separately by calling the `when_all_task::result()` +method of the corresponding output task. +This allows the caller to concurrently await multiple awaitables and synchronize on +their completion while still retaining the ability to subsequently inspect the results of +each of the `co_await` operations for success/failure. + +This differs from `when_all()` where the failure of any individual `co_await` operation +causes the overall operation to fail with an exception. This means you cannot determine +which of the component `co_await` operations failed and also prevents you from obtaining +the results of the other `co_await` operations. + +API summary: +```c++ +// +namespace cppcoro +{ + // Concurrently await multiple awaitables. + // + // Returns an awaitable object that, when co_await'ed, will co_await each of the input + // awaitable objects and will resume the awaiting coroutine only when all of the + // component co_await operations complete. + // + // Result of co_await'ing the returned awaitable is a std::tuple of detail::when_all_task, + // one for each input awaitable and where T is the result-type of the co_await expression + // on the corresponding awaitable. + // + // AWAITABLES must be awaitable types and must be movable (if passed as rvalue) or copyable + // (if passed as lvalue). The co_await expression will be executed on an rvalue of the + // copied awaitable. + template + auto when_all_ready(AWAITABLES&&... awaitables) + -> Awaitable::await_result_t>...>>; + + // Concurrently await each awaitable in a vector of input awaitables. + template< + typename AWAITABLE, + typename RESULT = typename awaitable_traits::await_result_t> + auto when_all_ready(std::vector awaitables) + -> Awaitable>>; +} +``` + +Example usage: +```c++ +task get_record(int id); + +task<> example1() +{ + // Run 3 get_record() operations concurrently and wait until they're all ready. + // Returns a std::tuple of tasks that can be unpacked using structured bindings. + auto [task1, task2, task3] = co_await when_all_ready( + get_record(123), + get_record(456), + get_record(789)); + + // Unpack the result of each task + std::string& record1 = task1.result(); + std::string& record2 = task2.result(); + std::string& record3 = task3.result(); + + // Use records.... +} + +task<> example2() +{ + // Create the input tasks. They don't start executing yet. + std::vector> tasks; + for (int i = 0; i < 1000; ++i) + { + tasks.emplace_back(get_record(i)); + } + + // Execute all tasks concurrently. + std::vector> resultTasks = + co_await when_all_ready(std::move(tasks)); + + // Unpack and handle each result individually once they're all complete. + for (int i = 0; i < 1000; ++i) + { + try + { + std::string& record = tasks[i].result(); + std::cout << i << " = " << record << std::endl; + } + catch (const std::exception& ex) + { + std::cout << i << " : " << ex.what() << std::endl; + } + } +} +``` + +## `when_all()` + +The `when_all()` function can be used to create a new Awaitable that when `co_await`ed +will `co_await` each of the input awaitables concurrently and return an aggregate of +their individual results. + +When the returned awaitable is awaited, it will `co_await` each of the input awaitables +on the current thread. Once the first awaitable suspends, the second task will be started, +and so on. The operations execute concurrently until they have all run to completion. + +Once all component `co_await` operations have run to completion, an aggregate of the +results is constructed from each individual result. If an exception is thrown by any +of the input tasks or if the construction of the aggregate result throws an exception +then the exception will propagate out of the `co_await` of the returned awaitable. + +If multiple `co_await` operations fail with an exception then one of the exceptions +will propagate out of the `co_await when_all()` expression the other exceptions will be silently +ignored. It is not specified which operation's exception will be chosen. + +If it is important to know which component `co_await` operation failed or to retain +the ability to obtain results of other operations even if some of them fail then you +you should use `when_all_ready()` instead. + +API Summary: +```c++ +// +namespace cppcoro +{ + // Variadic version. + // + // Note that if the result of `co_await awaitable` yields a void-type + // for some awaitables then the corresponding component for that awaitable + // in the tuple will be an empty struct of type detail::void_value. + template + auto when_all(AWAITABLES&&... awaitables) + -> Awaitable::await_result_t...>>; + + // Overload for vector>. + template< + typename AWAITABLE, + typename RESULT = typename awaitable_traits::await_result_t, + std::enable_if_t, int> = 0> + auto when_all(std::vector awaitables) + -> Awaitable; + + // Overload for vector> that yield a value when awaited. + template< + typename AWAITABLE, + typename RESULT = typename awaitable_traits::await_result_t, + std::enable_if_t, int> = 0> + auto when_all(std::vector awaitables) + -> Awaitable, + std::reference_wrapper>, + std::remove_reference_t>>>; +} +``` + +Examples: +```c++ +task get_a(); +task get_b(); + +task<> example1() +{ + // Run get_a() and get_b() concurrently. + // Task yields a std::tuple which can be unpacked using structured bindings. + auto [a, b] = co_await when_all(get_a(), get_b()); + + // use a, b +} + +task get_record(int id); + +task<> example2() +{ + std::vector> tasks; + for (int i = 0; i < 1000; ++i) + { + tasks.emplace_back(get_record(i)); + } + + // Concurrently execute all get_record() tasks. + // If any of them fail with an exception then the exception will propagate + // out of the co_await expression once they have all completed. + std::vector records = co_await when_all(std::move(tasks)); + + // Process results + for (int i = 0; i < 1000; ++i) + { + std::cout << i << " = " << records[i] << std::endl; + } +} +``` + +## `fmap()` + +The `fmap()` function can be used to apply a callable function to the value(s) contained within +a container-type, returning a new container-type of the results of applying the function the +contained value(s). + +The `fmap()` function can apply a function to values of type `generator`, `recursive_generator` +and `async_generator` as well as any value that supports the `Awaitable` concept (eg. `task`). + +Each of these types provides an overload for `fmap()` that takes two arguments; a function to apply +and the container value. +See documentation for each type for the supported `fmap()` overloads. + +For example, the `fmap()` function can be used to apply a function to the eventual result of +a `task`, producing a new `task` that will complete with the return-value of the function. +```c++ +// Given a function you want to apply that converts +// a value of type A to value of type B. +B a_to_b(A value); + +// And a task that yields a value of type A +cppcoro::task get_an_a(); + +// We can apply the function to the result of the task using fmap() +// and obtain a new task yielding the result. +cppcoro::task bTask = fmap(a_to_b, get_an_a()); + +// An alternative syntax is to use the pipe notation. +cppcoro::task bTask = get_an_a() | cppcoro::fmap(a_to_b); +``` + +API Summary: +```c++ +// +namespace cppcoro +{ + template + struct fmap_transform + { + fmap_transform(FUNC&& func) noexcept(std::is_nothrow_move_constructible_v); + FUNC func; + }; + + // Type-deducing constructor for fmap_transform object that can be used + // in conjunction with operator|. + template + fmap_transform fmap(FUNC&& func); + + // operator| overloads for providing pipe-based syntactic sugar for fmap() + // such that the expression: + // | cppcoro::fmap() + // is equivalent to: + // fmap(, ) + + template + decltype(auto) operator|(T&& value, fmap_transform&& transform); + + template + decltype(auto) operator|(T&& value, fmap_transform& transform); + + template + decltype(auto) operator|(T&& value, const fmap_transform& transform); + + // Generic overload for all awaitable types. + // + // Returns an awaitable that when co_awaited, co_awaits the specified awaitable + // and applies the specified func to the result of the 'co_await awaitable' + // expression as if by 'std::invoke(func, co_await awaitable)'. + // + // If the type of 'co_await awaitable' expression is 'void' then co_awaiting the + // returned awaitable is equivalent to 'co_await awaitable, func()'. + template< + typename FUNC, + typename AWAITABLE, + std::enable_if_t, int> = 0> + auto fmap(FUNC&& func, AWAITABLE&& awaitable) + -> Awaitable::await_result_t>>; +} +``` + +The `fmap()` function is designed to look up the correct overload by argument-dependent +lookup (ADL) so it should generally be called without the `cppcoro::` prefix. + +## `resume_on()` + +The `resume_on()` function can be used to control the execution context that an awaitable +will resume the awaiting coroutine on when awaited. When applied to an `async_generator` +it controls which execution context the `co_await g.begin()` and `co_await ++it` operations +resume the awaiting coroutines on. + +Normally, the awaiting coroutine of an awaitable (eg. a `task`) or `async_generator` will +resume execution on whatever thread the operation completed on. In some cases this may not +be the thread that you want to continue executing on. In these cases you can use the +`resume_on()` function to create a new awaitable or generator that will resume execution +on a thread associated with a specified scheduler. + +The `resume_on()` function can be used either as a normal function returning a new awaitable/generator. +Or it can be used in a pipeline-syntax. + +Example: +```c++ +task load_record(int id); + +ui_thread_scheduler uiThreadScheduler; + +task<> example() +{ + // This will start load_record() on the current thread. + // Then when load_record() completes (probably on an I/O thread) + // it will reschedule execution onto thread pool and call to_json + // Once to_json completes it will transfer execution onto the + // ui thread before resuming this coroutine and returning the json text. + task jsonTask = + load_record(123) + | cppcoro::resume_on(threadpool::default()) + | cppcoro::fmap(to_json) + | cppcoro::resume_on(uiThreadScheduler); + + // At this point, all we've done is create a pipeline of tasks. + // The tasks haven't started executing yet. + + // Await the result. Starts the pipeline of tasks. + std::string jsonText = co_await jsonTask; + + // Guaranteed to be executing on ui thread here. + + someUiControl.set_text(jsonText); +} +``` + +API Summary: +```c++ +// +namespace cppcoro +{ + template + auto resume_on(SCHEDULER& scheduler, AWAITABLE awaitable) + -> Awaitable::await_traits_t>; + + template + async_generator resume_on(SCHEDULER& scheduler, async_generator source); + + template + struct resume_on_transform + { + explicit resume_on_transform(SCHEDULER& scheduler) noexcept; + SCHEDULER& scheduler; + }; + + // Construct a transform/operation that can be applied to a source object + // using "pipe" notation (ie. operator|). + template + resume_on_transform resume_on(SCHEDULER& scheduler) noexcept; + + // Equivalent to 'resume_on(transform.scheduler, std::forward(value))' + template + decltype(auto) operator|(T&& value, resume_on_transform transform) + { + return resume_on(transform.scheduler, std::forward(value)); + } +} +``` + +## `schedule_on()` + +The `schedule_on()` function can be used to change the execution context that a given +awaitable or `async_generator` starts executing on. + +When applied to an `async_generator` it also affects which execution context it resumes +on after `co_yield` statement. + +Note that the `schedule_on` transform does not specify the thread that the awaitable or +`async_generator` will complete or yield results on, that is up to the implementation of +the awaitable or generator. + +See the `resume_on()` operator for a transform that controls the thread the operation completes on. + +For example: +```c++ +task get_value(); +io_service ioSvc; + +task<> example() +{ + // Starts executing get_value() on the current thread. + int a = co_await get_value(); + + // Starts executing get_value() on a thread associated with ioSvc. + int b = co_await schedule_on(ioSvc, get_value()); +} +``` + +API Summary: +```c++ +// +namespace cppcoro +{ + // Return a task that yields the same result as 't' but that + // ensures that 't' is co_await'ed on a thread associated with + // the specified scheduler. Resulting task will complete on + // whatever thread 't' would normally complete on. + template + auto schedule_on(SCHEDULER& scheduler, AWAITABLE awaitable) + -> Awaitable::await_result_t>; + + // Return a generator that yields the same sequence of results as + // 'source' but that ensures that execution of the coroutine starts + // execution on a thread associated with 'scheduler' and resumes + // after a 'co_yield' on a thread associated with 'scheduler'. + template + async_generator schedule_on(SCHEDULER& scheduler, async_generator source); + + template + struct schedule_on_transform + { + explicit schedule_on_transform(SCHEDULER& scheduler) noexcept; + SCHEDULER& scheduler; + }; + + template + schedule_on_transform schedule_on(SCHEDULER& scheduler) noexcept; + + template + decltype(auto) operator|(T&& value, schedule_on_transform transform); +} +``` + +# Metafunctions + +## `awaitable_traits` + +This template metafunction can be used to determine what the resulting type of a `co_await` expression +will be if applied to an expression of type `T`. + +Note that this assumes the value of type `T` is being awaited in a context where it is unaffected by +any `await_transform` applied by the coroutine's promise object. The results may differ if a value +of type `T` is awaited in such a context. + +The `awaitable_traits` template metafunction does not define the `awaiter_t` or `await_result_t` +nested typedefs if type, `T`, is not awaitable. This allows its use in SFINAE contexts that disables +overloads when `T` is not awaitable. + +API Summary: +```c++ +// +namespace cppcoro +{ + template + struct awaitable_traits + { + // The type that results from applying `operator co_await()` to a value + // of type T, if T supports an `operator co_await()`, otherwise is type `T&&`. + typename awaiter_t = ; + + // The type of the result of co_await'ing a value of type T. + typename await_result_t = ; + }; +} +``` + +## `is_awaitable` + +The `is_awaitable` template metafunction allows you to query whether or not a given +type can be `co_await`ed or not from within a coroutine. + +API Summary: +```c++ +// +namespace cppcoro +{ + template + struct is_awaitable : std::bool_constant<...> + {}; + + template + constexpr bool is_awaitable_v = is_awaitable::value; +} +``` + +# Concepts + +## `Awaitable` concept + +An `Awaitable` is a concept that indicates that a type can be `co_await`ed in a coroutine context +that has no `await_transform` overloads and that the result of the `co_await` expression has type, `T`. + +For example, the type `task` implements the concept `Awaitable` whereas the type `task&` +implements the concept `Awaitable`. + +## `Awaiter` concept + +An `Awaiter` is a concept that indicates a type contains the `await_ready`, `await_suspend` and +`await_resume` methods required to implement the protocol for suspending/resuming an awaiting +coroutine. + +A type that satisfies `Awaiter` must have, for an instance of the type, `awaiter`: +- `awaiter.await_ready()` -> `bool` +- `awaiter.await_suspend(cppcoro::coroutine_handle{})` -> `void` or `bool` or `cppcoro::coroutine_handle

` for some `P`. +- `awaiter.await_resume()` -> `T` + +Any type that implements the `Awaiter` concept also implements the `Awaitable` concept. + +## `Scheduler` concept + +A `Scheduler` is a concept that allows scheduling execution of coroutines within some execution context. + +```c++ +concept Scheduler +{ + Awaitable schedule(); +} +``` + +Given a type, `S`, that implements the `Scheduler` concept, and an instance, `s`, of type `S`: +* The `s.schedule()` method returns an awaitable-type such that `co_await s.schedule()` + will unconditionally suspend the current coroutine and schedule it for resumption on the + execution context associated with the scheduler, `s`. +* The result of the `co_await s.schedule()` expression has type `void`. + +```c++ +cppcoro::task<> f(Scheduler& scheduler) +{ + // Execution of the coroutine is initially on the caller's execution context. + + // Suspends execution of the coroutine and schedules it for resumption on + // the scheduler's execution context. + co_await scheduler.schedule(); + + // At this point the coroutine is now executing on the scheduler's + // execution context. +} +``` + +## `DelayedScheduler` concept + +A `DelayedScheduler` is a concept that allows a coroutine to schedule itself for execution on +the scheduler's execution context after a specified duration of time has elapsed. + +```c++ +concept DelayedScheduler : Scheduler +{ + template + Awaitable schedule_after(std::chrono::duration delay); + + template + Awaitable schedule_after( + std::chrono::duration delay, + cppcoro::cancellation_token cancellationToken); +} +``` + +Given a type, `S`, that implements the `DelayedScheduler` and an instance, `s` of type `S`: +* The `s.schedule_after(delay)` method returns an object that can be awaited + such that `co_await s.schedule_after(delay)` suspends the current coroutine + for a duration of `delay` before scheduling the coroutine for resumption on + the execution context associated with the scheduler, `s`. +* The `co_await s.schedule_after(delay)` expression has type `void`. + +# Building + +andreasbuhr/cppcoro uses CMake as a build system. + +## Building on Windows + +This library currently requires Visual Studio 2017 or later and the Windows 10 SDK. + +Support for Linux ([#15](https://github.com/lewissbaker/cppcoro/issues/15)) is planned. + +### Prerequisites + +The CMakeLists requires version 3.13 or later. + +Ensure Python 2.7 interpreter is in your PATH and available as 'python'. + +Ensure Visual Studio 2017 Update 3 or later is installed. +Note that there are some known issues with coroutines in Update 2 or earlier that have been fixed in Update 3. + +You can also use an experimental version of the Visual Studio compiler by downloading a NuGet package from https://vcppdogfooding.azurewebsites.net/ and unzipping the .nuget file to a directory. + +Ensure that you have the Windows 10 SDK installed. +It will use the latest Windows 10 SDK and Universal C Runtime version by default. + +### Cloning the repository + +The cppcoro repository makes use of git submodules to pull in the source for the Cake build system. + +This means you need to pass the `--recursive` flag to the `git clone` command. eg. +``` +c:\Code> git clone --recursive https://github.com/lewissbaker/cppcoro.git +``` + +If you have already cloned cppcoro, then you should update the submodules after pulling changes. +``` +c:\Code\cppcoro> git submodule update --init --recursive +``` + +### Building from the command-line + +#### With CMake + +Cppcoro follows the usual CMake workflow with no custom options added. Notable [standard CMake options](https://cmake.org/cmake/help/latest/manual/cmake-variables.7.html): + +| Flag | Description | Default Value | +|----------------------|------------------------------|------------------------| +| BUILD_TESTING | Build the unit tests | ON | +| BUILD_SHARED_LIBS | Build as a shared library | OFF | +| CMAKE_BUILD_TYPE | Build as `Debug`/`Release` | | +| CMAKE_INSTALL_PREFIX | Where to install the library | `/usr/local` (on Unix) | + +CMake also respects the [conventional environment variables](https://cmake.org/cmake/help/latest/manual/cmake-env-variables.7.html): + +| Environment Variable | Description | +|----------------------|-------------------------------| +| CXX | Path to the C++ compiler | +| CXXFLAGS | C++ compiler flags to prepend | +| LDFLAGS | Linker flags to prepend | + +Example: + +```bash +cd +mkdir build +cd build +export CXX=clang++ +export CXXFLAGS="-stdlib=libc++ -march=native" +export LDFLAGS="-stdlib=libc++ -fuse-ld=lld -Wl,--gdb-index" +cmake .. [-GNinja] -DCMAKE_INSTALL_PREFIX=$HOME/.local -DBUILD_SHARED_LIBS=ON +ninja # or make -jN +ninja test # Run the tests +ninja install +``` + +The CMake build scripts will also install a `cppcoroConfig.cmake` file for consumers to use. +It will check at the consumer site that coroutines are indeed supported by the system and enable the appropriate compiler flag for Clang or MSVC, respectively. +Assuming cppcoro has been installed to `$HOME/.local` like in the example above it can be consumed like this: + +```cmake +find_package(cppcoro REQUIRED) +add_executable(app main.cpp) +target_link_libraries(app PRIVATE cppcoro::cppcoro) +``` + +```bash +$ cmake . -Dcppcoro_ROOT=$HOME/.local +# ... +-- Performing Test _CXX_COROUTINES_SUPPORTS_MS_FLAG +-- Performing Test _CXX_COROUTINES_SUPPORTS_MS_FLAG - Failed +-- Performing Test _CXX_COROUTINES_SUPPORTS_CORO_FLAG +-- Performing Test _CXX_COROUTINES_SUPPORTS_CORO_FLAG - Success +-- Looking for C++ include coroutine +-- Looking for C++ include coroutine - not found +-- Looking for C++ include experimental/coroutine +-- Looking for C++ include experimental/coroutine - found +-- Configuring done +-- Generating done +# ... +``` + +## Building on Linux + +The cppcoro project can also be built under Linux using Clang + libc++ 5.0 or later. + +Building cppcoro has been tested under Ubuntu 17.04. + +### Prerequisities + +Ensure you have the following packages installed: +* Python 2.7 +* Clang >= 5.0 +* LLD >= 5.0 +* libc++ >= 5.0 + + +### Building cppcoro + +This is assuming you have Clang and libc++ built and installed. + +If you don't have Clang configured yet, see the following sections +for details on setting up Clang for building with cppcoro. + +Checkout cppcoro and its submodules: +``` +git clone --recursive https://github.com/lewissbaker/cppcoro.git cppcoro +``` + +# Support + +GitHub issues are the primary mechanism for support, bug reports and feature requests. + +Contributions are welcome and pull-requests will be happily reviewed. +I only ask that you agree to license any contributions that you make under the MIT license. + +If you have general questions about C++ coroutines, you can generally find someone to help +in the `#coroutines` channel on [Cpplang Slack](https://cpplang.slack.com/) group. diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt new file mode 100644 index 0000000..e69de29 diff --git a/cmake/FindCoroutines.cmake b/cmake/FindCoroutines.cmake new file mode 100644 index 0000000..672c549 --- /dev/null +++ b/cmake/FindCoroutines.cmake @@ -0,0 +1,282 @@ +# Copyright (c) 2019-present, Facebook, Inc. +# +# This source code is licensed under the Apache License found in the +# LICENSE.txt file in the root directory of this source tree. + +#[=======================================================================[.rst: + +FindCoroutines +############## + +This module supports the C++ standard support for coroutines. Use +the :imp-target:`std::coroutines` imported target to + +Options +******* + +The ``COMPONENTS`` argument to this module supports the following values: + +.. find-component:: Experimental + :name: coro.Experimental + + Allows the module to find the "experimental" Coroutines TS + version of the coroutines library. This is the library that should be + used with the ``std::experimental`` namespace. + +.. find-component:: Final + :name: coro.Final + + Finds the final C++20 standard version of coroutines. + +If no components are provided, behaves as if the +:find-component:`coro.Final` component was specified. + +If both :find-component:`coro.Experimental` and :find-component:`coro.Final` are +provided, first looks for ``Final``, and falls back to ``Experimental`` in case +of failure. If ``Final`` is found, :imp-target:`std::coroutines` and all +:ref:`variables ` will refer to the ``Final`` version. + + +Imported Targets +**************** + +.. imp-target:: std::coroutines + + The ``std::coroutines`` imported target is defined when any requested + version of the C++ coroutines library has been found, whether it is + *Experimental* or *Final*. + + If no version of the coroutines library is available, this target will not + be defined. + + .. note:: + This target has ``cxx_std_17`` as an ``INTERFACE`` + :ref:`compile language standard feature `. Linking + to this target will automatically enable C++17 if no later standard + version is already required on the linking target. + + +.. _coro.variables: + +Variables +********* + +.. variable:: CXX_COROUTINES_HAVE_COROUTINES + + Set to ``TRUE`` when coroutines are supported in both the language and the + library. + +.. variable:: CXX_COROUTINES_HEADER + + Set to either ``coroutine`` or ``experimental/coroutine`` depending on + whether :find-component:`coro.Final` or :find-component:`coro.Experimental` was + found. + +.. variable:: CXX_COROUTINES_NAMESPACE + + Set to either ``std`` or ``std::experimental`` + depending on whether :find-component:`coro.Final` or + :find-component:`coro.Experimental` was found. + + +Examples +******** + +Using `find_package(Coroutines)` with no component arguments: + +.. code-block:: cmake + + find_package(Coroutines REQUIRED) + + add_executable(my-program main.cpp) + target_link_libraries(my-program PRIVATE std::coroutines) + + +#]=======================================================================] + + +if(TARGET std::coroutines) + # This module has already been processed. Don't do it again. + return() +endif() + +include(CheckCXXCompilerFlag) +include(CMakePushCheckState) +include(CheckIncludeFileCXX) +include(CheckCXXSourceCompiles) + +cmake_push_check_state() + +set(CMAKE_REQUIRED_QUIET ${Coroutines_FIND_QUIETLY}) + +check_cxx_compiler_flag(/await _CXX_COROUTINES_SUPPORTS_MS_FLAG) +check_cxx_compiler_flag(/await:heapelide _CXX_COROUTINES_SUPPORTS_MS_HEAPELIDE_FLAG) +check_cxx_compiler_flag(-fcoroutines-ts _CXX_COROUTINES_SUPPORTS_TS_FLAG) +check_cxx_compiler_flag(-fcoroutines _CXX_COROUTINES_SUPPORTS_CORO_FLAG) + +if(_CXX_COROUTINES_SUPPORTS_MS_FLAG) + set(_CXX_COROUTINES_EXTRA_FLAGS "/await") + if(_CXX_COROUTINES_SUPPORTS_MS_HEAPELIDE_FLAG AND CMAKE_SIZEOF_VOID_P GREATER_EQUAL 8) + list(APPEND _CXX_COROUTINES_EXTRA_FLAGS "/await:heapelide") + endif() +elseif(_CXX_COROUTINES_SUPPORTS_TS_FLAG) + set(_CXX_COROUTINES_EXTRA_FLAGS "-fcoroutines-ts") +elseif(_CXX_COROUTINES_SUPPORTS_CORO_FLAG) + set(_CXX_COROUTINES_EXTRA_FLAGS "-fcoroutines") +endif() + +# Normalize and check the component list we were given +set(want_components ${Coroutines_FIND_COMPONENTS}) +if(Coroutines_FIND_COMPONENTS STREQUAL "") + set(want_components Final) +endif() + +# Warn on any unrecognized components +set(extra_components ${want_components}) +list(REMOVE_ITEM extra_components Final Experimental) +foreach(component IN LISTS extra_components) + message(WARNING "Extraneous find_package component for Coroutines: ${component}") +endforeach() + +# Detect which of Experimental and Final we should look for +set(find_experimental TRUE) +set(find_final TRUE) +if(NOT "Final" IN_LIST want_components) + set(find_final FALSE) +endif() +if(NOT "Experimental" IN_LIST want_components) + set(find_experimental FALSE) +endif() + +if(find_final) + check_include_file_cxx("coroutine" _CXX_COROUTINES_HAVE_HEADER) + if(_CXX_COROUTINES_HAVE_HEADER) + check_cxx_source_compiles("#include \n typedef std::suspend_never blub; \nint main() {} " _CXX_COROUTINES_FINAL_HEADER_COMPILES) + set(_CXX_COROUTINES_HAVE_HEADER "${_CXX_COROUTINES_FINAL_HEADER_COMPILES}") + endif() + + if(NOT _CXX_COROUTINES_HAVE_HEADER) + cmake_push_check_state() + set(CMAKE_REQUIRED_FLAGS "${_CXX_COROUTINES_EXTRA_FLAGS}") + check_include_file_cxx("coroutine" _CXX_COROUTINES_HAVE_HEADER_WITH_FLAG) + if(_CXX_COROUTINES_HAVE_HEADER_WITH_FLAG) + check_cxx_source_compiles("#include \n typedef std::suspend_never blub; \nint main() {} " _CXX_COROUTINES_FINAL_HEADER_COMPILES_WITH_FLAG) + set(_CXX_COROUTINES_HAVE_HEADER_WITH_FLAG "${_CXX_COROUTINES_FINAL_HEADER_COMPILES_WITH_FLAG}") + endif() + set(_CXX_COROUTINES_HAVE_HEADER "${_CXX_COROUTINES_HAVE_HEADER_WITH_FLAG}") + cmake_pop_check_state() + endif() + mark_as_advanced(_CXX_COROUTINES_HAVE_HEADER) + if(_CXX_COROUTINES_HAVE_HEADER) + # We found the non-experimental header. Don't bother looking for the + # experimental one. + set(find_experimental FALSE) + endif() +else() + set(_CXX_COROUTINES_HAVE_HEADER FALSE) +endif() + +if(find_experimental) + check_include_file_cxx("experimental/coroutine" _CXX_COROUTINES_HAVE_EXPERIMENTAL_HEADER) + if(NOT _CXX_COROUTINES_HAVE_EXPERIMENTAL_HEADER) + cmake_push_check_state() + set(CMAKE_REQUIRED_FLAGS "${_CXX_COROUTINES_EXTRA_FLAGS}") + check_include_file_cxx("experimental/coroutine" _CXX_COROUTINES_HAVE_EXPERIMENTAL_HEADER_WITH_FLAG) + set(_CXX_COROUTINES_HAVE_EXPERIMENTAL_HEADER "${_CXX_COROUTINES_HAVE_EXPERIMENTAL_HEADER_WITH_FLAG}") + cmake_pop_check_state() + endif() + mark_as_advanced(_CXX_COROUTINES_HAVE_EXPERIMENTAL_HEADER) +else() + set(_CXX_COROUTINES_HAVE_EXPERIMENTAL_HEADER FALSE) +endif() + +if(_CXX_COROUTINES_HAVE_HEADER) + set(_have_coro TRUE) + set(_coro_header coroutine) + set(_coro_namespace std) +elseif(_CXX_COROUTINES_HAVE_EXPERIMENTAL_HEADER) + set(_have_coro TRUE) + set(_coro_header experimental/coroutine) + set(_coro_namespace std::experimental) +else() + set(_have_coro FALSE) +endif() + +set(CXX_COROUTINES_HAVE_COROUTINES ${_have_coro} CACHE BOOL "TRUE if we have the C++ coroutines feature") +set(CXX_COROUTINES_HEADER ${_coro_header} CACHE STRING "The header that should be included to obtain the coroutines APIs") +set(CXX_COROUTINES_NAMESPACE ${_coro_namespace} CACHE STRING "The C++ namespace that contains the coroutines APIs") + +set(_found FALSE) + +if(CXX_COROUTINES_HAVE_COROUTINES) + # We have some coroutines library available. Do link checks + string(CONFIGURE [[ + #include + #include <@CXX_COROUTINES_HEADER@> + + struct present { + struct promise_type { + int result; + present get_return_object() { return present{*this}; } + @CXX_COROUTINES_NAMESPACE@::suspend_never initial_suspend() { return {}; } + @CXX_COROUTINES_NAMESPACE@::suspend_always final_suspend() noexcept { return {}; } + void return_value(int i) { result = i; } + void unhandled_exception() {} + }; + friend struct promise_type; + present(present&& that) : coro_(std::exchange(that.coro_, {})) {} + ~present() { if(coro_) coro_.destroy(); } + bool await_ready() const { return true; } + void await_suspend(@CXX_COROUTINES_NAMESPACE@::coroutine_handle<>) const {} + int await_resume() const { return coro_.promise().result; } + private: + present(promise_type& promise) + : coro_(@CXX_COROUTINES_NAMESPACE@::coroutine_handle::from_promise(promise)) {} + @CXX_COROUTINES_NAMESPACE@::coroutine_handle coro_; + }; + + present f(int n) { + if (n < 2) + co_return 1; + else + co_return n * co_await f(n - 1); + } + + int main() { + return f(5).await_resume() != 120; + } + ]] code @ONLY) + + # Try to compile a simple coroutines program without any compiler flags + check_cxx_source_compiles("${code}" CXX_COROUTINES_NO_AWAIT_NEEDED) + + set(can_link ${CXX_COROUTINES_NO_AWAIT_NEEDED}) + + if(NOT CXX_COROUTINES_NO_AWAIT_NEEDED) + # Add the -fcoroutines-ts (or /await) flag + set(CMAKE_REQUIRED_FLAGS "${_CXX_COROUTINES_EXTRA_FLAGS}") + check_cxx_source_compiles("${code}" CXX_COROUTINES_AWAIT_NEEDED) + set(can_link "${CXX_COROUTINES_AWAIT_NEEDED}") + endif() + + if(can_link) + add_library(std::coroutines INTERFACE IMPORTED) + set(_found TRUE) + + if(CXX_COROUTINES_NO_AWAIT_NEEDED) + # Nothing to add... + elseif(CXX_COROUTINES_AWAIT_NEEDED) + target_compile_options(std::coroutines INTERFACE ${_CXX_COROUTINES_EXTRA_FLAGS}) + endif() + else() + set(CXX_COROUTINES_HAVE_COROUTINES FALSE) + endif() +endif() + +cmake_pop_check_state() + +set(Coroutines_FOUND ${_found} CACHE BOOL "TRUE if we can compile and link a program using std::coroutines" FORCE) + +if(Coroutines_FIND_REQUIRED AND NOT Coroutines_FOUND) + message(FATAL_ERROR "Cannot compile simple program using std::coroutines. Is C++17 or later activated?") +endif() diff --git a/cmake/cppcoroConfig.cmake b/cmake/cppcoroConfig.cmake new file mode 100644 index 0000000..0b9f9c0 --- /dev/null +++ b/cmake/cppcoroConfig.cmake @@ -0,0 +1,6 @@ +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) + +include(CMakeFindDependencyMacro) +find_dependency(Coroutines QUIET REQUIRED) + +include("${CMAKE_CURRENT_LIST_DIR}/cppcoroTargets.cmake") diff --git a/include/cppcoro/async_auto_reset_event.hpp b/include/cppcoro/async_auto_reset_event.hpp new file mode 100644 index 0000000..b74ae2b --- /dev/null +++ b/include/cppcoro/async_auto_reset_event.hpp @@ -0,0 +1,98 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_ASYNC_AUTO_RESET_EVENT_HPP_INCLUDED +#define CPPCORO_ASYNC_AUTO_RESET_EVENT_HPP_INCLUDED + +#include +#include +#include + +namespace cppcoro +{ + class async_auto_reset_event_operation; + + /// An async auto-reset event is a coroutine synchronisation abstraction + /// that allows one or more coroutines to wait until some thread calls + /// set() on the event. + /// + /// When a coroutine awaits a 'set' event the event is automatically + /// reset back to the 'not set' state, thus the name 'auto reset' event. + class async_auto_reset_event + { + public: + + /// Initialise the event to either 'set' or 'not set' state. + async_auto_reset_event(bool initiallySet = false) noexcept; + + ~async_auto_reset_event(); + + /// Wait for the event to enter the 'set' state. + /// + /// If the event is already 'set' then the event is set to the 'not set' + /// state and the awaiting coroutine continues without suspending. + /// Otherwise, the coroutine is suspended and later resumed when some + /// thread calls 'set()'. + /// + /// Note that the coroutine may be resumed inside a call to 'set()' + /// or inside another thread's call to 'operator co_await()'. + async_auto_reset_event_operation operator co_await() const noexcept; + + /// Set the state of the event to 'set'. + /// + /// If there are pending coroutines awaiting the event then one + /// pending coroutine is resumed and the state is immediately + /// set back to the 'not set' state. + /// + /// This operation is a no-op if the event was already 'set'. + void set() noexcept; + + /// Set the state of the event to 'not-set'. + /// + /// This is a no-op if the state was already 'not set'. + void reset() noexcept; + + private: + + friend class async_auto_reset_event_operation; + + void resume_waiters(std::uint64_t initialState) const noexcept; + + // Bits 0-31 - Set count + // Bits 32-63 - Waiter count + mutable std::atomic m_state; + + mutable std::atomic m_newWaiters; + + mutable async_auto_reset_event_operation* m_waiters; + + }; + + class async_auto_reset_event_operation + { + public: + + async_auto_reset_event_operation() noexcept; + + explicit async_auto_reset_event_operation(const async_auto_reset_event& event) noexcept; + + async_auto_reset_event_operation(const async_auto_reset_event_operation& other) noexcept; + + bool await_ready() const noexcept { return m_event == nullptr; } + bool await_suspend(cppcoro::coroutine_handle<> awaiter) noexcept; + void await_resume() const noexcept {} + + private: + + friend class async_auto_reset_event; + + const async_auto_reset_event* m_event; + async_auto_reset_event_operation* m_next; + cppcoro::coroutine_handle<> m_awaiter; + std::atomic m_refCount; + + }; +} + +#endif diff --git a/include/cppcoro/async_generator.hpp b/include/cppcoro/async_generator.hpp new file mode 100644 index 0000000..50403e7 --- /dev/null +++ b/include/cppcoro/async_generator.hpp @@ -0,0 +1,1088 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_ASYNC_GENERATOR_HPP_INCLUDED +#define CPPCORO_ASYNC_GENERATOR_HPP_INCLUDED + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace cppcoro +{ + template + class async_generator; + +#if CPPCORO_COMPILER_SUPPORTS_SYMMETRIC_TRANSFER + + namespace detail + { + template + class async_generator_iterator; + class async_generator_yield_operation; + class async_generator_advance_operation; + + class async_generator_promise_base + { + public: + + async_generator_promise_base() noexcept + : m_exception(nullptr) + { + // Other variables left intentionally uninitialised as they're + // only referenced in certain states by which time they should + // have been initialised. + } + + async_generator_promise_base(const async_generator_promise_base& other) = delete; + async_generator_promise_base& operator=(const async_generator_promise_base& other) = delete; + + cppcoro::suspend_always initial_suspend() const noexcept + { + return {}; + } + + async_generator_yield_operation final_suspend() noexcept; + + void unhandled_exception() noexcept + { + m_exception = std::current_exception(); + } + + void return_void() noexcept + { + } + + /// Query if the generator has reached the end of the sequence. + /// + /// Only valid to call after resuming from an awaited advance operation. + /// i.e. Either a begin() or iterator::operator++() operation. + bool finished() const noexcept + { + return m_currentValue == nullptr; + } + + void rethrow_if_unhandled_exception() + { + if (m_exception) + { + std::rethrow_exception(std::move(m_exception)); + } + } + + protected: + + async_generator_yield_operation internal_yield_value() noexcept; + + private: + + friend class async_generator_yield_operation; + friend class async_generator_advance_operation; + + std::exception_ptr m_exception; + + cppcoro::coroutine_handle<> m_consumerCoroutine; + + protected: + + void* m_currentValue; + }; + + class async_generator_yield_operation final + { + public: + + async_generator_yield_operation(cppcoro::coroutine_handle<> consumer) noexcept + : m_consumer(consumer) + {} + + bool await_ready() const noexcept + { + return false; + } + + cppcoro::coroutine_handle<> + await_suspend([[maybe_unused]] cppcoro::coroutine_handle<> producer) noexcept + { + return m_consumer; + } + + void await_resume() noexcept {} + + private: + + cppcoro::coroutine_handle<> m_consumer; + + }; + + inline async_generator_yield_operation async_generator_promise_base::final_suspend() noexcept + { + m_currentValue = nullptr; + return internal_yield_value(); + } + + inline async_generator_yield_operation async_generator_promise_base::internal_yield_value() noexcept + { + return async_generator_yield_operation{ m_consumerCoroutine }; + } + + class async_generator_advance_operation + { + protected: + + async_generator_advance_operation(std::nullptr_t) noexcept + : m_promise(nullptr) + , m_producerCoroutine(nullptr) + {} + + async_generator_advance_operation( + async_generator_promise_base& promise, + cppcoro::coroutine_handle<> producerCoroutine) noexcept + : m_promise(std::addressof(promise)) + , m_producerCoroutine(producerCoroutine) + { + } + + public: + + bool await_ready() const noexcept { return false; } + + cppcoro::coroutine_handle<> + await_suspend(cppcoro::coroutine_handle<> consumerCoroutine) noexcept + { + m_promise->m_consumerCoroutine = consumerCoroutine; + return m_producerCoroutine; + } + + protected: + + async_generator_promise_base* m_promise; + cppcoro::coroutine_handle<> m_producerCoroutine; + + }; + + template + class async_generator_promise final : public async_generator_promise_base + { + using value_type = std::remove_reference_t; + + public: + + async_generator_promise() noexcept = default; + + async_generator get_return_object() noexcept; + + async_generator_yield_operation yield_value(value_type& value) noexcept + { + m_currentValue = std::addressof(value); + return internal_yield_value(); + } + + async_generator_yield_operation yield_value(value_type&& value) noexcept + { + return yield_value(value); + } + + T& value() const noexcept + { + return *static_cast(m_currentValue); + } + + }; + + template + class async_generator_promise final : public async_generator_promise_base + { + public: + + async_generator_promise() noexcept = default; + + async_generator get_return_object() noexcept; + + async_generator_yield_operation yield_value(T&& value) noexcept + { + m_currentValue = std::addressof(value); + return internal_yield_value(); + } + + T&& value() const noexcept + { + return std::move(*static_cast(m_currentValue)); + } + + }; + + template + class async_generator_increment_operation final : public async_generator_advance_operation + { + public: + + async_generator_increment_operation(async_generator_iterator& iterator) noexcept + : async_generator_advance_operation(iterator.m_coroutine.promise(), iterator.m_coroutine) + , m_iterator(iterator) + {} + + async_generator_iterator& await_resume(); + + private: + + async_generator_iterator& m_iterator; + + }; + + template + class async_generator_iterator final + { + using promise_type = async_generator_promise; + using handle_type = cppcoro::coroutine_handle; + + public: + + using iterator_category = std::input_iterator_tag; + // Not sure what type should be used for difference_type as we don't + // allow calculating difference between two iterators. + using difference_type = std::ptrdiff_t; + using value_type = std::remove_reference_t; + using reference = std::add_lvalue_reference_t; + using pointer = std::add_pointer_t; + + async_generator_iterator(std::nullptr_t) noexcept + : m_coroutine(nullptr) + {} + + async_generator_iterator(handle_type coroutine) noexcept + : m_coroutine(coroutine) + {} + + async_generator_increment_operation operator++() noexcept + { + return async_generator_increment_operation{ *this }; + } + + reference operator*() const noexcept + { + return m_coroutine.promise().value(); + } + + bool operator==(const async_generator_iterator& other) const noexcept + { + return m_coroutine == other.m_coroutine; + } + + bool operator!=(const async_generator_iterator& other) const noexcept + { + return !(*this == other); + } + + private: + + friend class async_generator_increment_operation; + + handle_type m_coroutine; + + }; + + template + async_generator_iterator& async_generator_increment_operation::await_resume() + { + if (m_promise->finished()) + { + // Update iterator to end() + m_iterator = async_generator_iterator{ nullptr }; + m_promise->rethrow_if_unhandled_exception(); + } + + return m_iterator; + } + + template + class async_generator_begin_operation final : public async_generator_advance_operation + { + using promise_type = async_generator_promise; + using handle_type = cppcoro::coroutine_handle; + + public: + + async_generator_begin_operation(std::nullptr_t) noexcept + : async_generator_advance_operation(nullptr) + {} + + async_generator_begin_operation(handle_type producerCoroutine) noexcept + : async_generator_advance_operation(producerCoroutine.promise(), producerCoroutine) + {} + + bool await_ready() const noexcept + { + return m_promise == nullptr || async_generator_advance_operation::await_ready(); + } + + async_generator_iterator await_resume() + { + if (m_promise == nullptr) + { + // Called begin() on the empty generator. + return async_generator_iterator{ nullptr }; + } + else if (m_promise->finished()) + { + // Completed without yielding any values. + m_promise->rethrow_if_unhandled_exception(); + return async_generator_iterator{ nullptr }; + } + + return async_generator_iterator{ + handle_type::from_promise(*static_cast(m_promise)) + }; + } + }; + } + + template + class [[nodiscard]] async_generator + { + public: + + using promise_type = detail::async_generator_promise; + using iterator = detail::async_generator_iterator; + + async_generator() noexcept + : m_coroutine(nullptr) + {} + + explicit async_generator(promise_type& promise) noexcept + : m_coroutine(cppcoro::coroutine_handle::from_promise(promise)) + {} + + async_generator(async_generator&& other) noexcept + : m_coroutine(other.m_coroutine) + { + other.m_coroutine = nullptr; + } + + ~async_generator() + { + if (m_coroutine) + { + m_coroutine.destroy(); + } + } + + async_generator& operator=(async_generator&& other) noexcept + { + async_generator temp(std::move(other)); + swap(temp); + return *this; + } + + async_generator(const async_generator&) = delete; + async_generator& operator=(const async_generator&) = delete; + + auto begin() noexcept + { + if (!m_coroutine) + { + return detail::async_generator_begin_operation{ nullptr }; + } + + return detail::async_generator_begin_operation{ m_coroutine }; + } + + auto end() noexcept + { + return iterator{ nullptr }; + } + + void swap(async_generator& other) noexcept + { + using std::swap; + swap(m_coroutine, other.m_coroutine); + } + + private: + + cppcoro::coroutine_handle m_coroutine; + + }; + + template + void swap(async_generator& a, async_generator& b) noexcept + { + a.swap(b); + } + + namespace detail + { + template + async_generator async_generator_promise::get_return_object() noexcept + { + return async_generator{ *this }; + } + } +#else // !CPPCORO_COMPILER_SUPPORTS_SYMMETRIC_TRANSFER + + namespace detail + { + template + class async_generator_iterator; + class async_generator_yield_operation; + class async_generator_advance_operation; + + class async_generator_promise_base + { + public: + + async_generator_promise_base() noexcept + : m_state(state::value_ready_producer_suspended) + , m_exception(nullptr) + { + // Other variables left intentionally uninitialised as they're + // only referenced in certain states by which time they should + // have been initialised. + } + + async_generator_promise_base(const async_generator_promise_base& other) = delete; + async_generator_promise_base& operator=(const async_generator_promise_base& other) = delete; + + cppcoro::suspend_always initial_suspend() const noexcept + { + return {}; + } + + async_generator_yield_operation final_suspend() noexcept; + + void unhandled_exception() noexcept + { + // Don't bother capturing the exception if we have been cancelled + // as there is no consumer that will see it. + if (m_state.load(std::memory_order_relaxed) != state::cancelled) + { + m_exception = std::current_exception(); + } + } + + void return_void() noexcept + { + } + + /// Query if the generator has reached the end of the sequence. + /// + /// Only valid to call after resuming from an awaited advance operation. + /// i.e. Either a begin() or iterator::operator++() operation. + bool finished() const noexcept + { + return m_currentValue == nullptr; + } + + void rethrow_if_unhandled_exception() + { + if (m_exception) + { + std::rethrow_exception(std::move(m_exception)); + } + } + + /// Request that the generator cancel generation of new items. + /// + /// \return + /// Returns true if the request was completed synchronously and the associated + /// producer coroutine is now available to be destroyed. In which case the caller + /// is expected to call destroy() on the coroutine_handle. + /// Returns false if the producer coroutine was not at a suitable suspend-point. + /// The coroutine will be destroyed when it next reaches a co_yield or co_return + /// statement. + bool request_cancellation() noexcept + { + const auto previousState = m_state.exchange(state::cancelled, std::memory_order_acq_rel); + + // Not valid to destroy async_generator object if consumer coroutine still suspended + // in a co_await for next item. + assert(previousState != state::value_not_ready_consumer_suspended); + + // A coroutine should only ever be cancelled once, from the destructor of the + // owning async_generator object. + assert(previousState != state::cancelled); + + return previousState == state::value_ready_producer_suspended; + } + + protected: + + async_generator_yield_operation internal_yield_value() noexcept; + + private: + + friend class async_generator_yield_operation; + friend class async_generator_advance_operation; + + // State transition diagram + // VNRCA - value_not_ready_consumer_active + // VNRCS - value_not_ready_consumer_suspended + // VRPA - value_ready_producer_active + // VRPS - value_ready_producer_suspended + // + // A +--- VNRCA --[C]--> VNRCS yield_value() + // | | | A | A | . + // | [C] [P] | [P] | | . + // | | | [C] | [C] | . + // | | V | V | | . + // operator++/ | VRPS <--[P]--- VRPA V | + // begin() | | | | + // | [C] [C] | + // | +----+ +---+ | + // | | | | + // | V V V + // +--------> cancelled ~async_generator() + // + // [C] - Consumer performs this transition + // [P] - Producer performs this transition + enum class state + { + value_not_ready_consumer_active, + value_not_ready_consumer_suspended, + value_ready_producer_active, + value_ready_producer_suspended, + cancelled + }; + + std::atomic m_state; + + std::exception_ptr m_exception; + + cppcoro::coroutine_handle<> m_consumerCoroutine; + + protected: + + void* m_currentValue; + }; + + class async_generator_yield_operation final + { + using state = async_generator_promise_base::state; + + public: + + async_generator_yield_operation(async_generator_promise_base& promise, state initialState) noexcept + : m_promise(promise) + , m_initialState(initialState) + {} + + bool await_ready() const noexcept + { + return m_initialState == state::value_not_ready_consumer_suspended; + } + + bool await_suspend(cppcoro::coroutine_handle<> producer) noexcept; + + void await_resume() noexcept {} + + private: + async_generator_promise_base& m_promise; + state m_initialState; + }; + + inline async_generator_yield_operation async_generator_promise_base::final_suspend() noexcept + { + m_currentValue = nullptr; + return internal_yield_value(); + } + + inline async_generator_yield_operation async_generator_promise_base::internal_yield_value() noexcept + { + state currentState = m_state.load(std::memory_order_acquire); + assert(currentState != state::value_ready_producer_active); + assert(currentState != state::value_ready_producer_suspended); + + if (currentState == state::value_not_ready_consumer_suspended) + { + // Only need relaxed memory order since we're resuming the + // consumer on the same thread. + m_state.store(state::value_ready_producer_active, std::memory_order_relaxed); + + // Resume the consumer. + // It might ask for another value before returning, in which case it'll + // transition to value_not_ready_consumer_suspended and we can return from + // yield_value without suspending, otherwise we should try to suspend + // the producer in which case the consumer will wake us up again + // when it wants the next value. + m_consumerCoroutine.resume(); + + // Need to use acquire semantics here since it's possible that the + // consumer might have asked for the next value on a different thread + // which executed concurrently with the call to m_consumerCoro on the + // current thread above. + currentState = m_state.load(std::memory_order_acquire); + } + + return async_generator_yield_operation{ *this, currentState }; + } + + inline bool async_generator_yield_operation::await_suspend( + cppcoro::coroutine_handle<> producer) noexcept + { + state currentState = m_initialState; + if (currentState == state::value_not_ready_consumer_active) + { + bool producerSuspended = m_promise.m_state.compare_exchange_strong( + currentState, + state::value_ready_producer_suspended, + std::memory_order_release, + std::memory_order_acquire); + if (producerSuspended) + { + return true; + } + + if (currentState == state::value_not_ready_consumer_suspended) + { + // Can get away with using relaxed memory semantics here since we're + // resuming the consumer on the current thread. + m_promise.m_state.store(state::value_ready_producer_active, std::memory_order_relaxed); + + m_promise.m_consumerCoroutine.resume(); + + // The consumer might have asked for another value before returning, in which case + // it'll transition to value_not_ready_consumer_suspended and we can return without + // suspending, otherwise we should try to suspend the producer, in which case the + // consumer will wake us up again when it wants the next value. + // + // Need to use acquire semantics here since it's possible that the consumer might + // have asked for the next value on a different thread which executed concurrently + // with the call to m_consumerCoro.resume() above. + currentState = m_promise.m_state.load(std::memory_order_acquire); + if (currentState == state::value_not_ready_consumer_suspended) + { + return false; + } + } + } + + // By this point the consumer has been resumed if required and is now active. + + if (currentState == state::value_ready_producer_active) + { + // Try to suspend the producer. + // If we failed to suspend then it's either because the consumer destructed, transitioning + // the state to cancelled, or requested the next item, transitioning the state to value_not_ready_consumer_suspended. + const bool suspendedProducer = m_promise.m_state.compare_exchange_strong( + currentState, + state::value_ready_producer_suspended, + std::memory_order_release, + std::memory_order_acquire); + if (suspendedProducer) + { + return true; + } + + if (currentState == state::value_not_ready_consumer_suspended) + { + // Consumer has asked for the next value. + return false; + } + } + + assert(currentState == state::cancelled); + + // async_generator object has been destroyed and we're now at a + // co_yield/co_return suspension point so we can just destroy + // the coroutine. + producer.destroy(); + + return true; + } + + class async_generator_advance_operation + { + using state = async_generator_promise_base::state; + + protected: + + async_generator_advance_operation(std::nullptr_t) noexcept + : m_promise(nullptr) + , m_producerCoroutine(nullptr) + {} + + async_generator_advance_operation( + async_generator_promise_base& promise, + cppcoro::coroutine_handle<> producerCoroutine) noexcept + : m_promise(std::addressof(promise)) + , m_producerCoroutine(producerCoroutine) + { + state initialState = promise.m_state.load(std::memory_order_acquire); + if (initialState == state::value_ready_producer_suspended) + { + // Can use relaxed memory order here as we will be resuming the producer + // on the same thread. + promise.m_state.store(state::value_not_ready_consumer_active, std::memory_order_relaxed); + + producerCoroutine.resume(); + + // Need to use acquire memory order here since it's possible that the + // coroutine may have transferred execution to another thread and + // completed on that other thread before the call to resume() returns. + initialState = promise.m_state.load(std::memory_order_acquire); + } + + m_initialState = initialState; + } + + public: + + bool await_ready() const noexcept + { + return m_initialState == state::value_ready_producer_suspended; + } + + bool await_suspend(cppcoro::coroutine_handle<> consumerCoroutine) noexcept + { + m_promise->m_consumerCoroutine = consumerCoroutine; + + auto currentState = m_initialState; + if (currentState == state::value_ready_producer_active) + { + // A potential race between whether consumer or producer coroutine + // suspends first. Resolve the race using a compare-exchange. + if (m_promise->m_state.compare_exchange_strong( + currentState, + state::value_not_ready_consumer_suspended, + std::memory_order_release, + std::memory_order_acquire)) + { + return true; + } + + assert(currentState == state::value_ready_producer_suspended); + + m_promise->m_state.store(state::value_not_ready_consumer_active, std::memory_order_relaxed); + + m_producerCoroutine.resume(); + + currentState = m_promise->m_state.load(std::memory_order_acquire); + if (currentState == state::value_ready_producer_suspended) + { + // Producer coroutine produced a value synchronously. + return false; + } + } + + assert(currentState == state::value_not_ready_consumer_active); + + // Try to suspend consumer coroutine, transitioning to value_not_ready_consumer_suspended. + // This could be racing with producer making the next value available and suspending + // (transition to value_ready_producer_suspended) so we use compare_exchange to decide who + // wins the race. + // If compare_exchange succeeds then consumer suspended (and we return true). + // If it fails then producer yielded next value and suspended and we can return + // synchronously without suspended (ie. return false). + return m_promise->m_state.compare_exchange_strong( + currentState, + state::value_not_ready_consumer_suspended, + std::memory_order_release, + std::memory_order_acquire); + } + + protected: + + async_generator_promise_base* m_promise; + cppcoro::coroutine_handle<> m_producerCoroutine; + + private: + + state m_initialState; + + }; + + template + class async_generator_promise final : public async_generator_promise_base + { + using value_type = std::remove_reference_t; + + public: + + async_generator_promise() noexcept = default; + + async_generator get_return_object() noexcept; + + async_generator_yield_operation yield_value(value_type& value) noexcept + { + m_currentValue = std::addressof(value); + return internal_yield_value(); + } + + async_generator_yield_operation yield_value(value_type&& value) noexcept + { + return yield_value(value); + } + + T& value() const noexcept + { + return *static_cast(m_currentValue); + } + + }; + + template + class async_generator_promise final : public async_generator_promise_base + { + public: + + async_generator_promise() noexcept = default; + + async_generator get_return_object() noexcept; + + async_generator_yield_operation yield_value(T&& value) noexcept + { + m_currentValue = std::addressof(value); + return internal_yield_value(); + } + + T&& value() const noexcept + { + return std::move(*static_cast(m_currentValue)); + } + + }; + + template + class async_generator_increment_operation final : public async_generator_advance_operation + { + public: + + async_generator_increment_operation(async_generator_iterator& iterator) noexcept + : async_generator_advance_operation(iterator.m_coroutine.promise(), iterator.m_coroutine) + , m_iterator(iterator) + {} + + async_generator_iterator& await_resume(); + + private: + + async_generator_iterator& m_iterator; + + }; + + template + class async_generator_iterator final + { + using promise_type = async_generator_promise; + using handle_type = cppcoro::coroutine_handle; + + public: + + using iterator_category = std::input_iterator_tag; + // Not sure what type should be used for difference_type as we don't + // allow calculating difference between two iterators. + using difference_type = std::ptrdiff_t; + using value_type = std::remove_reference_t; + using reference = std::add_lvalue_reference_t; + using pointer = std::add_pointer_t; + + async_generator_iterator(std::nullptr_t) noexcept + : m_coroutine(nullptr) + {} + + async_generator_iterator(handle_type coroutine) noexcept + : m_coroutine(coroutine) + {} + + async_generator_increment_operation operator++() noexcept + { + return async_generator_increment_operation{ *this }; + } + + reference operator*() const noexcept + { + return m_coroutine.promise().value(); + } + + bool operator==(const async_generator_iterator& other) const noexcept + { + return m_coroutine == other.m_coroutine; + } + + bool operator!=(const async_generator_iterator& other) const noexcept + { + return !(*this == other); + } + + private: + + friend class async_generator_increment_operation; + + handle_type m_coroutine; + + }; + + template + async_generator_iterator& async_generator_increment_operation::await_resume() + { + if (m_promise->finished()) + { + // Update iterator to end() + m_iterator = async_generator_iterator{ nullptr }; + m_promise->rethrow_if_unhandled_exception(); + } + + return m_iterator; + } + + template + class async_generator_begin_operation final : public async_generator_advance_operation + { + using promise_type = async_generator_promise; + using handle_type = cppcoro::coroutine_handle; + + public: + + async_generator_begin_operation(std::nullptr_t) noexcept + : async_generator_advance_operation(nullptr) + {} + + async_generator_begin_operation(handle_type producerCoroutine) noexcept + : async_generator_advance_operation(producerCoroutine.promise(), producerCoroutine) + {} + + bool await_ready() const noexcept + { + return m_promise == nullptr || async_generator_advance_operation::await_ready(); + } + + async_generator_iterator await_resume() + { + if (m_promise == nullptr) + { + // Called begin() on the empty generator. + return async_generator_iterator{ nullptr }; + } + else if (m_promise->finished()) + { + // Completed without yielding any values. + m_promise->rethrow_if_unhandled_exception(); + return async_generator_iterator{ nullptr }; + } + + return async_generator_iterator{ + handle_type::from_promise(*static_cast(m_promise)) + }; + } + }; + } + + template + class async_generator + { + public: + + using promise_type = detail::async_generator_promise; + using iterator = detail::async_generator_iterator; + + async_generator() noexcept + : m_coroutine(nullptr) + {} + + explicit async_generator(promise_type& promise) noexcept + : m_coroutine(cppcoro::coroutine_handle::from_promise(promise)) + {} + + async_generator(async_generator&& other) noexcept + : m_coroutine(other.m_coroutine) + { + other.m_coroutine = nullptr; + } + + ~async_generator() + { + if (m_coroutine) + { + if (m_coroutine.promise().request_cancellation()) + { + m_coroutine.destroy(); + } + } + } + + async_generator& operator=(async_generator&& other) noexcept + { + async_generator temp(std::move(other)); + swap(temp); + return *this; + } + + async_generator(const async_generator&) = delete; + async_generator& operator=(const async_generator&) = delete; + + auto begin() noexcept + { + if (!m_coroutine) + { + return detail::async_generator_begin_operation{ nullptr }; + } + + return detail::async_generator_begin_operation{ m_coroutine }; + } + + auto end() noexcept + { + return iterator{ nullptr }; + } + + void swap(async_generator& other) noexcept + { + using std::swap; + swap(m_coroutine, other.m_coroutine); + } + + private: + + cppcoro::coroutine_handle m_coroutine; + + }; + + template + void swap(async_generator& a, async_generator& b) noexcept + { + a.swap(b); + } + + namespace detail + { + template + async_generator async_generator_promise::get_return_object() noexcept + { + return async_generator{ *this }; + } + } +#endif // !CPPCORO_COMPILER_SUPPORTS_SYMMETRIC_TRANSFER + + template + async_generator::iterator&>())>> fmap( + FUNC func, + async_generator source) + { + static_assert( + !std::is_reference_v, + "Passing by reference to async_generator coroutine is unsafe. " + "Use std::ref or std::cref to explicitly pass by reference."); + + // Explicitly hand-coding the loop here rather than using range-based + // for loop since it's difficult to std::forward the value of a + // range-based for-loop, preserving the value category of operator* + // return-value. + auto it = co_await source.begin(); + const auto itEnd = source.end(); + while (it != itEnd) + { + co_yield std::invoke(func, *it); + (void)co_await ++it; + } + } +} + +#endif diff --git a/include/cppcoro/async_latch.hpp b/include/cppcoro/async_latch.hpp new file mode 100644 index 0000000..9dfbb50 --- /dev/null +++ b/include/cppcoro/async_latch.hpp @@ -0,0 +1,75 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_ASYNC_LATCH_HPP_INCLUDED +#define CPPCORO_ASYNC_LATCH_HPP_INCLUDED + +#include + +#include +#include + +namespace cppcoro +{ + class async_latch + { + public: + + /// Construct the latch with the specified initial count. + /// + /// \param initialCount + /// The initial count of the latch. The latch will become signalled once + /// \c this->count_down() has been called \p initialCount times. + /// The latch will be immediately signalled on construction if this + /// parameter is zero or negative. + async_latch(std::ptrdiff_t initialCount) noexcept + : m_count(initialCount) + , m_event(initialCount <= 0) + {} + + /// Query if the latch has become signalled. + /// + /// The latch is marked as signalled once the count reaches zero. + bool is_ready() const noexcept { return m_event.is_set(); } + + /// Decrement the count by n. + /// + /// Any coroutines awaiting this latch will be resumed once the count + /// reaches zero. ie. when this method has been called at least 'initialCount' + /// times. + /// + /// Any awaiting coroutines that are currently suspended waiting for the + /// latch to become signalled will be resumed inside the last call to this + /// method (ie. the call that decrements the count to zero). + /// + /// \param n + /// The amount to decrement the count by. + void count_down(std::ptrdiff_t n = 1) noexcept + { + if (m_count.fetch_sub(n, std::memory_order_acq_rel) <= n) + { + m_event.set(); + } + } + + /// Allows the latch to be awaited within a coroutine. + /// + /// If the latch is already signalled (ie. the count has been decremented + /// to zero) then the awaiting coroutine will continue without suspending. + /// Otherwise, the coroutine will suspend and will later be resumed inside + /// a call to `count_down()`. + auto operator co_await() const noexcept + { + return m_event.operator co_await(); + } + + private: + + std::atomic m_count; + async_manual_reset_event m_event; + + }; +} + +#endif diff --git a/include/cppcoro/async_manual_reset_event.hpp b/include/cppcoro/async_manual_reset_event.hpp new file mode 100644 index 0000000..fd58282 --- /dev/null +++ b/include/cppcoro/async_manual_reset_event.hpp @@ -0,0 +1,104 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_ASYNC_MANUAL_RESET_EVENT_HPP_INCLUDED +#define CPPCORO_ASYNC_MANUAL_RESET_EVENT_HPP_INCLUDED + +#include +#include +#include + +namespace cppcoro +{ + class async_manual_reset_event_operation; + + /// An async manual-reset event is a coroutine synchronisation abstraction + /// that allows one or more coroutines to wait until some thread calls + /// set() on the event. + /// + /// When a coroutine awaits a 'set' event the coroutine continues without + /// suspending. Otherwise, if it awaits a 'not set' event the coroutine is + /// suspended and is later resumed inside the call to 'set()'. + /// + /// \seealso async_auto_reset_event + class async_manual_reset_event + { + public: + + /// Initialise the event to either 'set' or 'not set' state. + /// + /// \param initiallySet + /// If 'true' then initialises the event to the 'set' state, otherwise + /// initialises the event to the 'not set' state. + async_manual_reset_event(bool initiallySet = false) noexcept; + + ~async_manual_reset_event(); + + /// Wait for the event to enter the 'set' state. + /// + /// If the event is already 'set' then the coroutine continues without + /// suspending. + /// + /// Otherwise, the coroutine is suspended and later resumed when some + /// thread calls 'set()'. The coroutine will be resumed inside the next + /// call to 'set()'. + async_manual_reset_event_operation operator co_await() const noexcept; + + /// Query if the event is currently in the 'set' state. + bool is_set() const noexcept; + + /// Set the state of the event to 'set'. + /// + /// If there are pending coroutines awaiting the event then all + /// pending coroutines are resumed within this call. + /// Any coroutines that subsequently await the event will continue + /// without suspending. + /// + /// This operation is a no-op if the event was already 'set'. + void set() noexcept; + + /// Set the state of the event to 'not-set'. + /// + /// Any coroutines that subsequently await the event will suspend + /// until some thread calls 'set()'. + /// + /// This is a no-op if the state was already 'not set'. + void reset() noexcept; + + private: + + friend class async_manual_reset_event_operation; + + // This variable has 3 states: + // - this - The state is 'set'. + // - nullptr - The state is 'not set' with no waiters. + // - other - The state is 'not set'. + // Points to an 'async_manual_reset_event_operation' that is + // the head of a linked-list of waiters. + mutable std::atomic m_state; + + }; + + class async_manual_reset_event_operation + { + public: + + explicit async_manual_reset_event_operation(const async_manual_reset_event& event) noexcept; + + bool await_ready() const noexcept; + bool await_suspend(cppcoro::coroutine_handle<> awaiter) noexcept; + void await_resume() const noexcept {} + + private: + + friend class async_manual_reset_event; + + const async_manual_reset_event& m_event; + async_manual_reset_event_operation* m_next; + cppcoro::coroutine_handle<> m_awaiter; + + }; +} + +#endif diff --git a/include/cppcoro/async_mutex.hpp b/include/cppcoro/async_mutex.hpp new file mode 100644 index 0000000..2f4fd61 --- /dev/null +++ b/include/cppcoro/async_mutex.hpp @@ -0,0 +1,200 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_ASYNC_MUTEX_HPP_INCLUDED +#define CPPCORO_ASYNC_MUTEX_HPP_INCLUDED + +#include +#include +#include +#include // for std::adopt_lock_t + +namespace cppcoro +{ + class async_mutex_lock; + class async_mutex_lock_operation; + class async_mutex_scoped_lock_operation; + + /// \brief + /// A mutex that can be locked asynchronously using 'co_await'. + /// + /// Ownership of the mutex is not tied to any particular thread. + /// This allows the coroutine owning the lock to transition from + /// one thread to another while holding a lock. + /// + /// Implementation is lock-free, using only std::atomic values for + /// synchronisation. Awaiting coroutines are suspended without blocking + /// the current thread if the lock could not be acquired synchronously. + class async_mutex + { + public: + + /// \brief + /// Construct to a mutex that is not currently locked. + async_mutex() noexcept; + + /// Destroys the mutex. + /// + /// Behaviour is undefined if there are any outstanding coroutines + /// still waiting to acquire the lock. + ~async_mutex(); + + /// \brief + /// Attempt to acquire a lock on the mutex without blocking. + /// + /// \return + /// true if the lock was acquired, false if the mutex was already locked. + /// The caller is responsible for ensuring unlock() is called on the mutex + /// to release the lock if the lock was acquired by this call. + bool try_lock() noexcept; + + /// \brief + /// Acquire a lock on the mutex asynchronously. + /// + /// If the lock could not be acquired synchronously then the awaiting + /// coroutine will be suspended and later resumed when the lock becomes + /// available. If suspended, the coroutine will be resumed inside the + /// call to unlock() from the previous lock owner. + /// + /// \return + /// An operation object that must be 'co_await'ed to wait until the + /// lock is acquired. The result of the 'co_await m.lock_async()' + /// expression has type 'void'. + async_mutex_lock_operation lock_async() noexcept; + + /// \brief + /// Acquire a lock on the mutex asynchronously, returning an object that + /// will call unlock() automatically when it goes out of scope. + /// + /// If the lock could not be acquired synchronously then the awaiting + /// coroutine will be suspended and later resumed when the lock becomes + /// available. If suspended, the coroutine will be resumed inside the + /// call to unlock() from the previous lock owner. + /// + /// \return + /// An operation object that must be 'co_await'ed to wait until the + /// lock is acquired. The result of the 'co_await m.scoped_lock_async()' + /// expression returns an 'async_mutex_lock' object that will call + /// this->mutex() when it destructs. + async_mutex_scoped_lock_operation scoped_lock_async() noexcept; + + /// \brief + /// Unlock the mutex. + /// + /// Must only be called by the current lock-holder. + /// + /// If there are lock operations waiting to acquire the + /// mutex then the next lock operation in the queue will + /// be resumed inside this call. + void unlock(); + + private: + + friend class async_mutex_lock_operation; + + static constexpr std::uintptr_t not_locked = 1; + + // assume == reinterpret_cast(static_cast(nullptr)) + static constexpr std::uintptr_t locked_no_waiters = 0; + + // This field provides synchronisation for the mutex. + // + // It can have three kinds of values: + // - not_locked + // - locked_no_waiters + // - a pointer to the head of a singly linked list of recently + // queued async_mutex_lock_operation objects. This list is + // in most-recently-queued order as new items are pushed onto + // the front of the list. + std::atomic m_state; + + // Linked list of async lock operations that are waiting to acquire + // the mutex. These operations will acquire the lock in the order + // they appear in this list. Waiters in this list will acquire the + // mutex before waiters added to the m_newWaiters list. + async_mutex_lock_operation* m_waiters; + + }; + + /// \brief + /// An object that holds onto a mutex lock for its lifetime and + /// ensures that the mutex is unlocked when it is destructed. + /// + /// It is equivalent to a std::lock_guard object but requires + /// that the result of co_await async_mutex::lock_async() is + /// passed to the constructor rather than passing the async_mutex + /// object itself. + class async_mutex_lock + { + public: + + explicit async_mutex_lock(async_mutex& mutex, std::adopt_lock_t) noexcept + : m_mutex(&mutex) + {} + + async_mutex_lock(async_mutex_lock&& other) noexcept + : m_mutex(other.m_mutex) + { + other.m_mutex = nullptr; + } + + async_mutex_lock(const async_mutex_lock& other) = delete; + async_mutex_lock& operator=(const async_mutex_lock& other) = delete; + + // Releases the lock. + ~async_mutex_lock() + { + if (m_mutex != nullptr) + { + m_mutex->unlock(); + } + } + + private: + + async_mutex* m_mutex; + + }; + + class async_mutex_lock_operation + { + public: + + explicit async_mutex_lock_operation(async_mutex& mutex) noexcept + : m_mutex(mutex) + {} + + bool await_ready() const noexcept { return false; } + bool await_suspend(cppcoro::coroutine_handle<> awaiter) noexcept; + void await_resume() const noexcept {} + + protected: + + friend class async_mutex; + + async_mutex& m_mutex; + + private: + + async_mutex_lock_operation* m_next; + cppcoro::coroutine_handle<> m_awaiter; + + }; + + class async_mutex_scoped_lock_operation : public async_mutex_lock_operation + { + public: + + using async_mutex_lock_operation::async_mutex_lock_operation; + + [[nodiscard]] + async_mutex_lock await_resume() const noexcept + { + return async_mutex_lock{ m_mutex, std::adopt_lock }; + } + + }; +} + +#endif diff --git a/include/cppcoro/async_scope.hpp b/include/cppcoro/async_scope.hpp new file mode 100644 index 0000000..9b65e1b --- /dev/null +++ b/include/cppcoro/async_scope.hpp @@ -0,0 +1,102 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_ASYNC_SCOPE_HPP_INCLUDED +#define CPPCORO_ASYNC_SCOPE_HPP_INCLUDED + +#include + +#include +#include +#include +#include + +namespace cppcoro +{ + class async_scope + { + public: + + async_scope() noexcept + : m_count(1u) + {} + + ~async_scope() + { + // scope must be co_awaited before it destructs. + assert(m_continuation); + } + + template + void spawn(AWAITABLE&& awaitable) + { + [](async_scope* scope, std::decay_t awaitable) -> oneway_task + { + scope->on_work_started(); + auto decrementOnCompletion = on_scope_exit([scope] { scope->on_work_finished(); }); + co_await std::move(awaitable); + }(this, std::forward(awaitable)); + } + + [[nodiscard]] auto join() noexcept + { + class awaiter + { + async_scope* m_scope; + public: + awaiter(async_scope* scope) noexcept : m_scope(scope) {} + + bool await_ready() noexcept + { + return m_scope->m_count.load(std::memory_order_acquire) == 0; + } + + bool await_suspend(cppcoro::coroutine_handle<> continuation) noexcept + { + m_scope->m_continuation = continuation; + return m_scope->m_count.fetch_sub(1u, std::memory_order_acq_rel) > 1u; + } + + void await_resume() noexcept + {} + }; + + return awaiter{ this }; + } + + private: + + void on_work_finished() noexcept + { + if (m_count.fetch_sub(1u, std::memory_order_acq_rel) == 1) + { + m_continuation.resume(); + } + } + + void on_work_started() noexcept + { + assert(m_count.load(std::memory_order_relaxed) != 0); + m_count.fetch_add(1, std::memory_order_relaxed); + } + + struct oneway_task + { + struct promise_type + { + cppcoro::suspend_never initial_suspend() noexcept { return {}; } + cppcoro::suspend_never final_suspend() noexcept { return {}; } + void unhandled_exception() { std::terminate(); } + oneway_task get_return_object() { return {}; } + void return_void() {} + }; + }; + + std::atomic m_count; + cppcoro::coroutine_handle<> m_continuation; + + }; +} + +#endif diff --git a/include/cppcoro/awaitable_traits.hpp b/include/cppcoro/awaitable_traits.hpp new file mode 100644 index 0000000..5a7465d --- /dev/null +++ b/include/cppcoro/awaitable_traits.hpp @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_AWAITABLE_TRAITS_HPP_INCLUDED +#define CPPCORO_AWAITABLE_TRAITS_HPP_INCLUDED + +#include + +#include + +namespace cppcoro +{ + template + struct awaitable_traits + {}; + + template + struct awaitable_traits()))>> + { + using awaiter_t = decltype(cppcoro::detail::get_awaiter(std::declval())); + + using await_result_t = decltype(std::declval().await_resume()); + }; +} + +#endif diff --git a/include/cppcoro/broken_promise.hpp b/include/cppcoro/broken_promise.hpp new file mode 100644 index 0000000..55462fc --- /dev/null +++ b/include/cppcoro/broken_promise.hpp @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_BROKEN_PROMISE_HPP_INCLUDED +#define CPPCORO_BROKEN_PROMISE_HPP_INCLUDED + +#include + +namespace cppcoro +{ + /// \brief + /// Exception thrown when you attempt to retrieve the result of + /// a task that has been detached from its promise/coroutine. + class broken_promise : public std::logic_error + { + public: + broken_promise() + : std::logic_error("broken promise") + {} + }; +} + +#endif diff --git a/include/cppcoro/cancellation_registration.hpp b/include/cppcoro/cancellation_registration.hpp new file mode 100644 index 0000000..64d267b --- /dev/null +++ b/include/cppcoro/cancellation_registration.hpp @@ -0,0 +1,87 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_CANCELLATION_REGISTRATION_HPP_INCLUDED +#define CPPCORO_CANCELLATION_REGISTRATION_HPP_INCLUDED + +#include + +#include +#include +#include +#include +#include + +namespace cppcoro +{ + namespace detail + { + class cancellation_state; + struct cancellation_registration_list_chunk; + struct cancellation_registration_state; + } + + class cancellation_registration + { + public: + + /// Registers the callback to be executed when cancellation is requested + /// on the cancellation_token. + /// + /// The callback will be executed if cancellation is requested for the + /// specified cancellation token. If cancellation has already been requested + /// then the callback will be executed immediately, before the constructor + /// returns. If cancellation has not yet been requested then the callback + /// will be executed on the first thread to request cancellation inside + /// the call to cancellation_source::request_cancellation(). + /// + /// \param token + /// The cancellation token to register the callback with. + /// + /// \param callback + /// The callback to be executed when cancellation is requested on the + /// the cancellation_token. Note that callback must not throw an exception + /// if called when cancellation is requested otherwise std::terminate() + /// will be called. + /// + /// \throw std::bad_alloc + /// If registration failed due to insufficient memory available. + template< + typename FUNC, + typename = std::enable_if_t, FUNC&&>>> + cancellation_registration(cancellation_token token, FUNC&& callback) + : m_callback(std::forward(callback)) + { + register_callback(std::move(token)); + } + + cancellation_registration(const cancellation_registration& other) = delete; + cancellation_registration& operator=(const cancellation_registration& other) = delete; + + /// Deregisters the callback. + /// + /// After the destructor returns it is guaranteed that the callback + /// will not be subsequently called during a call to request_cancellation() + /// on the cancellation_source. + /// + /// This may block if cancellation has been requested on another thread + /// is it will need to wait until this callback has finished executing + /// before the callback can be destroyed. + ~cancellation_registration(); + + private: + + friend class detail::cancellation_state; + friend struct detail::cancellation_registration_state; + + void register_callback(cancellation_token&& token); + + detail::cancellation_state* m_state; + std::function m_callback; + detail::cancellation_registration_list_chunk* m_chunk; + std::uint32_t m_entryIndex; + }; +} + +#endif diff --git a/include/cppcoro/cancellation_source.hpp b/include/cppcoro/cancellation_source.hpp new file mode 100644 index 0000000..e0f100e --- /dev/null +++ b/include/cppcoro/cancellation_source.hpp @@ -0,0 +1,71 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_CANCELLATION_SOURCE_HPP_INCLUDED +#define CPPCORO_CANCELLATION_SOURCE_HPP_INCLUDED + +namespace cppcoro +{ + class cancellation_token; + + namespace detail + { + class cancellation_state; + } + + class cancellation_source + { + public: + + /// Construct to a new cancellation source. + cancellation_source(); + + /// Create a new reference to the same underlying cancellation + /// source as \p other. + cancellation_source(const cancellation_source& other) noexcept; + + cancellation_source(cancellation_source&& other) noexcept; + + ~cancellation_source(); + + cancellation_source& operator=(const cancellation_source& other) noexcept; + + cancellation_source& operator=(cancellation_source&& other) noexcept; + + /// Query if this cancellation source can be cancelled. + /// + /// A cancellation source object will not be cancellable if it has + /// previously been moved into another cancellation_source instance + /// or was copied from a cancellation_source that was not cancellable. + bool can_be_cancelled() const noexcept; + + /// Obtain a cancellation token that can be used to query if + /// cancellation has been requested on this source. + /// + /// The cancellation token can be passed into functions that you + /// may want to later be able to request cancellation. + cancellation_token token() const noexcept; + + /// Request cancellation of operations that were passed an associated + /// cancellation token. + /// + /// Any cancellation callback registered via a cancellation_registration + /// object will be called inside this function by the first thread to + /// call this method. + /// + /// This operation is a no-op if can_be_cancelled() returns false. + void request_cancellation(); + + /// Query if some thread has called 'request_cancellation()' on this + /// cancellation_source. + bool is_cancellation_requested() const noexcept; + + private: + + detail::cancellation_state* m_state; + + }; +} + +#endif diff --git a/include/cppcoro/cancellation_token.hpp b/include/cppcoro/cancellation_token.hpp new file mode 100644 index 0000000..49e8f82 --- /dev/null +++ b/include/cppcoro/cancellation_token.hpp @@ -0,0 +1,72 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_CANCELLATION_TOKEN_HPP_INCLUDED +#define CPPCORO_CANCELLATION_TOKEN_HPP_INCLUDED + +namespace cppcoro +{ + class cancellation_source; + class cancellation_registration; + + namespace detail + { + class cancellation_state; + } + + class cancellation_token + { + public: + + /// Construct to a cancellation token that can't be cancelled. + cancellation_token() noexcept; + + /// Copy another cancellation token. + /// + /// New token will refer to the same underlying state. + cancellation_token(const cancellation_token& other) noexcept; + + cancellation_token(cancellation_token&& other) noexcept; + + ~cancellation_token(); + + cancellation_token& operator=(const cancellation_token& other) noexcept; + + cancellation_token& operator=(cancellation_token&& other) noexcept; + + void swap(cancellation_token& other) noexcept; + + /// Query if it is possible that this operation will be cancelled + /// or not. + /// + /// Cancellable operations may be able to take more efficient code-paths + /// if they don't need to handle cancellation requests. + bool can_be_cancelled() const noexcept; + + /// Query if some thread has requested cancellation on an associated + /// cancellation_source object. + bool is_cancellation_requested() const noexcept; + + /// Throws cppcoro::operation_cancelled exception if cancellation + /// has been requested for the associated operation. + void throw_if_cancellation_requested() const; + + private: + + friend class cancellation_source; + friend class cancellation_registration; + + cancellation_token(detail::cancellation_state* state) noexcept; + + detail::cancellation_state* m_state; + + }; + + inline void swap(cancellation_token& a, cancellation_token& b) noexcept + { + a.swap(b); + } +} + +#endif diff --git a/include/cppcoro/config.hpp b/include/cppcoro/config.hpp new file mode 100644 index 0000000..526bb7f --- /dev/null +++ b/include/cppcoro/config.hpp @@ -0,0 +1,166 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_CONFIG_HPP_INCLUDED +#define CPPCORO_CONFIG_HPP_INCLUDED + +///////////////////////////////////////////////////////////////////////////// +// Compiler Detection + +#if defined(_MSC_VER) +# define CPPCORO_COMPILER_MSVC _MSC_FULL_VER +#else +# define CPPCORO_COMPILER_MSVC 0 +#endif + +#if defined(__clang__) +# define CPPCORO_COMPILER_CLANG (__clang_major__ * 10000 + \ + __clang_minor__ * 100 + \ + __clang_patchlevel__) +#else +# define CPPCORO_COMPILER_CLANG 0 +#endif + +#if defined(__GNUC__) +# define CPPCORO_COMPILER_GCC (__GNUC__ * 10000 + \ + __GNUC_MINOR__ * 100 + \ + __GNUC_PATCHLEVEL__) +#else +# define CPPCORO_COMPILER_GCC 0 +#endif + +/// \def CPPCORO_COMPILER_SUPPORTS_SYMMETRIC_TRANSFER +/// Defined to 1 if the compiler supports returning a coroutine_handle from +/// the await_suspend() method as a way of transferring execution +/// to another coroutine with a guaranteed tail-call. +#if CPPCORO_COMPILER_CLANG +# if __clang_major__ >= 7 +# define CPPCORO_COMPILER_SUPPORTS_SYMMETRIC_TRANSFER 1 +# endif +#endif +#ifndef CPPCORO_COMPILER_SUPPORTS_SYMMETRIC_TRANSFER +# define CPPCORO_COMPILER_SUPPORTS_SYMMETRIC_TRANSFER 0 +#endif + +#if CPPCORO_COMPILER_MSVC +# define CPPCORO_ASSUME(X) __assume(X) +#else +# define CPPCORO_ASSUME(X) +#endif + +#if CPPCORO_COMPILER_MSVC +# define CPPCORO_NOINLINE __declspec(noinline) +#elif CPPCORO_COMPILER_CLANG || CPPCORO_COMPILER_GCC +# define CPPCORO_NOINLINE __attribute__((noinline)) +#else +# define CPPCORO_NOINLINE +#endif + +#if CPPCORO_COMPILER_MSVC +# define CPPCORO_FORCE_INLINE __forceinline +#elif CPPCORO_COMPILER_CLANG +# define CPPCORO_FORCE_INLINE __attribute__((always_inline)) +#else +# define CPPCORO_FORCE_INLINE inline +#endif + +///////////////////////////////////////////////////////////////////////////// +// OS Detection + +/// \def CPPCORO_OS_WINNT +/// Defined to non-zero if the target platform is a WindowsNT variant. +/// 0x0500 - Windows 2000 +/// 0x0501 - Windows XP/Server 2003 +/// 0x0502 - Windows XP SP2/Server 2003 SP1 +/// 0x0600 - Windows Vista/Server 2008 +/// 0x0601 - Windows 7 +/// 0x0602 - Windows 8 +/// 0x0603 - Windows 8.1 +/// 0x0A00 - Windows 10 +#if defined(_WIN32_WINNT) || defined(_WIN32) +# if !defined(_WIN32_WINNT) +// Default to targeting Windows 10 if not defined. +# define _WIN32_WINNT 0x0A00 +# endif +# define CPPCORO_OS_WINNT _WIN32_WINNT +#else +# define CPPCORO_OS_WINNT 0 +#endif + +#if defined(__linux__) +# define CPPCORO_OS_LINUX 1 +#else +# define CPPCORO_OS_LINUX 0 +#endif + +///////////////////////////////////////////////////////////////////////////// +// CPU Detection + +/// \def CPPCORO_CPU_X86 +/// Defined to 1 if target CPU is of x86 family. +#if CPPCORO_COMPILER_MSVC +# if defined(_M_IX86) +# define CPPCORO_CPU_X86 1 +# endif +#elif CPPCORO_COMPILER_GCC || CPPCORO_COMPILER_CLANG +# if defined(__i386__) +# define CPPCORO_CPU_X86 1 +# endif +#endif +#if !defined(CPPCORO_CPU_X86) +# define CPPCORO_CPU_X86 0 +#endif + +/// \def CPPCORO_CPU_X64 +/// Defined to 1 if the target CPU is x64 family. +#if CPPCORO_COMPILER_MSVC +# if defined(_M_X64) +# define CPPCORO_CPU_X64 1 +# endif +#elif CPPCORO_COMPILER_GCC || CPPCORO_COMPILER_CLANG +# if defined(__x86_64__) +# define CPPCORO_CPU_X64 1 +# endif +#endif +#if !defined(CPPCORO_CPU_X64) +# define CPPCORO_CPU_X64 0 +#endif + +/// \def CPPCORO_CPU_32BIT +/// Defined if compiling for a 32-bit CPU architecture. +#if CPPCORO_CPU_X86 +# define CPPCORO_CPU_32BIT 1 +#else +# define CPPCORO_CPU_32BIT 0 +#endif + +/// \def CPPCORO_CPU_64BIT +/// Defined if compiling for a 64-bit CPU architecture. +#if CPPCORO_CPU_X64 +# define CPPCORO_CPU_64BIT 1 +#else +# define CPPCORO_CPU_64BIT 0 +#endif + +#if CPPCORO_COMPILER_MSVC +# define CPPCORO_CPU_CACHE_LINE std::hardware_destructive_interference_size +#else +// On most architectures we can assume a 64-byte cache line. +# define CPPCORO_CPU_CACHE_LINE 64 +#endif + +#if CPPCORO_COMPILER_MSVC + #if __has_include() + #include + #ifdef __cpp_lib_coroutine + #define CPPCORO_COROHEADER_FOUND_AND_USABLE + #endif + #endif +#else + #if __has_include() + #define CPPCORO_COROHEADER_FOUND_AND_USABLE + #endif +#endif + +#endif diff --git a/include/cppcoro/coroutine.hpp b/include/cppcoro/coroutine.hpp new file mode 100644 index 0000000..cd8632a --- /dev/null +++ b/include/cppcoro/coroutine.hpp @@ -0,0 +1,35 @@ +#ifndef CPPCORO_COROUTINE_HPP_INCLUDED +#define CPPCORO_COROUTINE_HPP_INCLUDED + +#include + +#ifdef CPPCORO_COROHEADER_FOUND_AND_USABLE + +#include + +namespace cppcoro { + using std::coroutine_handle; + using std::suspend_always; + using std::noop_coroutine; + using std::suspend_never; +} + +#elif __has_include() + +#include + +namespace cppcoro { + using std::experimental::coroutine_handle; + using std::experimental::suspend_always; + using std::experimental::suspend_never; + +#if CPPCORO_COMPILER_SUPPORTS_SYMMETRIC_TRANSFER + using std::experimental::noop_coroutine; +#endif +} + +#else +#error Cppcoro requires a C++20 compiler with coroutine support +#endif + +#endif diff --git a/include/cppcoro/detail/any.hpp b/include/cppcoro/detail/any.hpp new file mode 100644 index 0000000..b1ec9cb --- /dev/null +++ b/include/cppcoro/detail/any.hpp @@ -0,0 +1,22 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_DETAIL_ANY_HPP_INCLUDED +#define CPPCORO_DETAIL_ANY_HPP_INCLUDED + +namespace cppcoro +{ + namespace detail + { + // Helper type that can be cast-to from any type. + struct any + { + template + any(T&&) noexcept + {} + }; + } +} + +#endif diff --git a/include/cppcoro/detail/get_awaiter.hpp b/include/cppcoro/detail/get_awaiter.hpp new file mode 100644 index 0000000..57417dc --- /dev/null +++ b/include/cppcoro/detail/get_awaiter.hpp @@ -0,0 +1,49 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_DETAIL_GET_AWAITER_HPP_INCLUDED +#define CPPCORO_DETAIL_GET_AWAITER_HPP_INCLUDED + +#include +#include + +namespace cppcoro +{ + namespace detail + { + template + auto get_awaiter_impl(T&& value, int) + noexcept(noexcept(static_cast(value).operator co_await())) + -> decltype(static_cast(value).operator co_await()) + { + return static_cast(value).operator co_await(); + } + + template + auto get_awaiter_impl(T&& value, long) + noexcept(noexcept(operator co_await(static_cast(value)))) + -> decltype(operator co_await(static_cast(value))) + { + return operator co_await(static_cast(value)); + } + + template< + typename T, + std::enable_if_t::value, int> = 0> + T&& get_awaiter_impl(T&& value, cppcoro::detail::any) noexcept + { + return static_cast(value); + } + + template + auto get_awaiter(T&& value) + noexcept(noexcept(detail::get_awaiter_impl(static_cast(value), 123))) + -> decltype(detail::get_awaiter_impl(static_cast(value), 123)) + { + return detail::get_awaiter_impl(static_cast(value), 123); + } + } +} + +#endif diff --git a/include/cppcoro/detail/is_awaiter.hpp b/include/cppcoro/detail/is_awaiter.hpp new file mode 100644 index 0000000..c5781ce --- /dev/null +++ b/include/cppcoro/detail/is_awaiter.hpp @@ -0,0 +1,55 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_DETAIL_IS_AWAITER_HPP_INCLUDED +#define CPPCORO_DETAIL_IS_AWAITER_HPP_INCLUDED + +#include +#include + +namespace cppcoro +{ + namespace detail + { + template + struct is_coroutine_handle + : std::false_type + {}; + + template + struct is_coroutine_handle> + : std::true_type + {}; + + // NOTE: We're accepting a return value of coroutine_handle

here + // which is an extension supported by Clang which is not yet part of + // the C++ coroutines TS. + template + struct is_valid_await_suspend_return_value : std::disjunction< + std::is_void, + std::is_same, + is_coroutine_handle> + {}; + + template> + struct is_awaiter : std::false_type {}; + + // NOTE: We're testing whether await_suspend() will be callable using an + // arbitrary coroutine_handle here by checking if it supports being passed + // a coroutine_handle. This may result in a false-result for some + // types which are only awaitable within a certain context. + template + struct is_awaiter().await_ready()), + decltype(std::declval().await_suspend(std::declval>())), + decltype(std::declval().await_resume())>> : + std::conjunction< + std::is_constructible().await_ready())>, + detail::is_valid_await_suspend_return_value< + decltype(std::declval().await_suspend(std::declval>()))>> + {}; + } +} + +#endif diff --git a/include/cppcoro/detail/lightweight_manual_reset_event.hpp b/include/cppcoro/detail/lightweight_manual_reset_event.hpp new file mode 100644 index 0000000..fb5b53f --- /dev/null +++ b/include/cppcoro/detail/lightweight_manual_reset_event.hpp @@ -0,0 +1,65 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_DETAIL_LIGHTWEIGHT_MANUAL_RESET_EVENT_HPP_INCLUDED +#define CPPCORO_DETAIL_LIGHTWEIGHT_MANUAL_RESET_EVENT_HPP_INCLUDED + +#include +#include +#include + +#if CPPCORO_OS_LINUX || (CPPCORO_OS_WINNT >= 0x0602) +# include +# include +#elif CPPCORO_OS_WINNT +# include +#else +# include +# include +#endif + +namespace cppcoro +{ + class io_service; + + namespace detail + { + class lightweight_manual_reset_event + { + public: + + lightweight_manual_reset_event(bool initiallySet = false); + + ~lightweight_manual_reset_event(); + + void set() noexcept; + + void reset() noexcept; + + void wait() noexcept; + void wait(std::span srvs, std::chrono::system_clock::duration step) noexcept; + + private: +#if CPPCORO_OS_LINUX + std::atomic m_value; +#elif CPPCORO_OS_WINNT >= 0x0602 + // Windows 8 or newer we can use WaitOnAddress() + std::atomic m_value; +#elif CPPCORO_OS_WINNT + // Before Windows 8 we need to use a WIN32 manual reset event. + cppcoro::detail::win32::handle_t m_eventHandle; +#else + // For other platforms that don't have a native futex + // or manual reset event we can just use a std::mutex + // and std::condition_variable to perform the wait. + // Not so lightweight, but should be portable to all platforms. + std::mutex m_mutex; + std::condition_variable m_cv; + bool m_isSet; +#endif + }; + } +} + +#endif diff --git a/include/cppcoro/detail/manual_lifetime.hpp b/include/cppcoro/detail/manual_lifetime.hpp new file mode 100644 index 0000000..01bb10c --- /dev/null +++ b/include/cppcoro/detail/manual_lifetime.hpp @@ -0,0 +1,120 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_DETAIL_MANUAL_LIFETIME_HPP_INCLUDED +#define CPPCORO_DETAIL_MANUAL_LIFETIME_HPP_INCLUDED + +#include +#include + +namespace cppcoro::detail +{ + template + struct manual_lifetime + { + public: + manual_lifetime() noexcept {} + ~manual_lifetime() noexcept {} + + manual_lifetime(const manual_lifetime&) = delete; + manual_lifetime(manual_lifetime&&) = delete; + manual_lifetime& operator=(const manual_lifetime&) = delete; + manual_lifetime& operator=(manual_lifetime&&) = delete; + + template + std::enable_if_t> construct(Args&&... args) + noexcept(std::is_nothrow_constructible_v) + { + ::new (static_cast(std::addressof(m_value))) T(static_cast(args)...); + } + + void destruct() noexcept(std::is_nothrow_destructible_v) + { + m_value.~T(); + } + + std::add_pointer_t operator->() noexcept { return std::addressof(**this); } + std::add_pointer_t operator->() const noexcept { return std::addressof(**this); } + + T& operator*() & noexcept { return m_value; } + const T& operator*() const & noexcept { return m_value; } + T&& operator*() && noexcept { return static_cast(m_value); } + const T&& operator*() const && noexcept { return static_cast(m_value); } + + private: + union { + T m_value; + }; + }; + + template + struct manual_lifetime + { + public: + manual_lifetime() noexcept {} + ~manual_lifetime() noexcept {} + + manual_lifetime(const manual_lifetime&) = delete; + manual_lifetime(manual_lifetime&&) = delete; + manual_lifetime& operator=(const manual_lifetime&) = delete; + manual_lifetime& operator=(manual_lifetime&&) = delete; + + void construct(T& value) noexcept + { + m_value = std::addressof(value); + } + + void destruct() noexcept {} + + T* operator->() noexcept { return m_value; } + const T* operator->() const noexcept { return m_value; } + + T& operator*() noexcept { return *m_value; } + const T& operator*() const noexcept { return *m_value; } + + private: + T* m_value; + }; + + template + struct manual_lifetime + { + public: + manual_lifetime() noexcept {} + ~manual_lifetime() noexcept {} + + manual_lifetime(const manual_lifetime&) = delete; + manual_lifetime(manual_lifetime&&) = delete; + manual_lifetime& operator=(const manual_lifetime&) = delete; + manual_lifetime& operator=(manual_lifetime&&) = delete; + + void construct(T&& value) noexcept + { + m_value = std::addressof(value); + } + + void destruct() noexcept {} + + T* operator->() noexcept { return m_value; } + const T* operator->() const noexcept { return m_value; } + + T& operator*() & noexcept { return *m_value; } + const T& operator*() const & noexcept { return *m_value; } + T&& operator*() && noexcept { return static_cast(*m_value); } + const T&& operator*() const && noexcept { return static_cast(*m_value); } + + private: + T* m_value; + }; + + template<> + struct manual_lifetime + { + void construct() noexcept {} + void destruct() noexcept {} + void operator*() const noexcept {} + }; +} + +#endif diff --git a/include/cppcoro/detail/remove_rvalue_reference.hpp b/include/cppcoro/detail/remove_rvalue_reference.hpp new file mode 100644 index 0000000..300bca1 --- /dev/null +++ b/include/cppcoro/detail/remove_rvalue_reference.hpp @@ -0,0 +1,29 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_DETAIL_REMOVE_RVALUE_REFERENCE_HPP_INCLUDED +#define CPPCORO_DETAIL_REMOVE_RVALUE_REFERENCE_HPP_INCLUDED + +namespace cppcoro +{ + namespace detail + { + template + struct remove_rvalue_reference + { + using type = T; + }; + + template + struct remove_rvalue_reference + { + using type = T; + }; + + template + using remove_rvalue_reference_t = typename remove_rvalue_reference::type; + } +} + +#endif diff --git a/include/cppcoro/detail/sync_wait_task.hpp b/include/cppcoro/detail/sync_wait_task.hpp new file mode 100644 index 0000000..9f95330 --- /dev/null +++ b/include/cppcoro/detail/sync_wait_task.hpp @@ -0,0 +1,300 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_DETAIL_SYNC_WAIT_TASK_HPP_INCLUDED +#define CPPCORO_DETAIL_SYNC_WAIT_TASK_HPP_INCLUDED + +#include +#include +#include + +#include +#include +#include +#include + +namespace cppcoro +{ + namespace detail + { + template + class sync_wait_task; + + template + class sync_wait_task_promise final + { + using coroutine_handle_t = cppcoro::coroutine_handle>; + + public: + + using reference = RESULT&&; + + sync_wait_task_promise() noexcept + {} + + void start(detail::lightweight_manual_reset_event& event) + { + m_event = &event; + coroutine_handle_t::from_promise(*this).resume(); + } + + auto get_return_object() noexcept + { + return coroutine_handle_t::from_promise(*this); + } + + cppcoro::suspend_always initial_suspend() noexcept + { + return{}; + } + + auto final_suspend() noexcept + { + class completion_notifier + { + public: + + bool await_ready() const noexcept { return false; } + + void await_suspend(coroutine_handle_t coroutine) const noexcept + { + coroutine.promise().m_event->set(); + } + + void await_resume() noexcept {} + }; + + return completion_notifier{}; + } + +#if CPPCORO_COMPILER_MSVC && CPPCORO_COMPILER_MSVC < 19'20'00000 + // HACK: This is needed to work around a bug in MSVC 2017.7/2017.8. + // See comment in make_sync_wait_task below. + template + Awaitable&& await_transform(Awaitable&& awaitable) + { + return static_cast(awaitable); + } + + struct get_promise_t {}; + static constexpr get_promise_t get_promise = {}; + + auto await_transform(get_promise_t) + { + class awaiter + { + public: + awaiter(sync_wait_task_promise* promise) noexcept : m_promise(promise) {} + bool await_ready() noexcept { + return true; + } + void await_suspend(cppcoro::coroutine_handle<>) noexcept {} + sync_wait_task_promise& await_resume() noexcept + { + return *m_promise; + } + private: + sync_wait_task_promise* m_promise; + }; + return awaiter{ this }; + } +#endif + + auto yield_value(reference result) noexcept + { + m_result = std::addressof(result); + return final_suspend(); + } + + void return_void() noexcept + { + // The coroutine should have either yielded a value or thrown + // an exception in which case it should have bypassed return_void(). + assert(false); + } + + void unhandled_exception() + { + m_exception = std::current_exception(); + } + + reference result() + { + if (m_exception) + { + std::rethrow_exception(m_exception); + } + + return static_cast(*m_result); + } + + private: + + detail::lightweight_manual_reset_event* m_event; + std::remove_reference_t* m_result; + std::exception_ptr m_exception; + + }; + + template<> + class sync_wait_task_promise + { + using coroutine_handle_t = cppcoro::coroutine_handle>; + + public: + + sync_wait_task_promise() noexcept + {} + + void start(detail::lightweight_manual_reset_event& event) + { + m_event = &event; + coroutine_handle_t::from_promise(*this).resume(); + } + + auto get_return_object() noexcept + { + return coroutine_handle_t::from_promise(*this); + } + + cppcoro::suspend_always initial_suspend() noexcept + { + return{}; + } + + auto final_suspend() noexcept + { + class completion_notifier + { + public: + + bool await_ready() const noexcept { return false; } + + void await_suspend(coroutine_handle_t coroutine) const noexcept + { + coroutine.promise().m_event->set(); + } + + void await_resume() noexcept {} + }; + + return completion_notifier{}; + } + + void return_void() {} + + void unhandled_exception() + { + m_exception = std::current_exception(); + } + + void result() + { + if (m_exception) + { + std::rethrow_exception(m_exception); + } + } + + private: + + detail::lightweight_manual_reset_event* m_event; + std::exception_ptr m_exception; + + }; + + template + class sync_wait_task final + { + public: + + using promise_type = sync_wait_task_promise; + + using coroutine_handle_t = cppcoro::coroutine_handle; + + sync_wait_task(coroutine_handle_t coroutine) noexcept + : m_coroutine(coroutine) + {} + + sync_wait_task(sync_wait_task&& other) noexcept + : m_coroutine(std::exchange(other.m_coroutine, coroutine_handle_t{})) + {} + + ~sync_wait_task() + { + if (m_coroutine) m_coroutine.destroy(); + } + + sync_wait_task(const sync_wait_task&) = delete; + sync_wait_task& operator=(const sync_wait_task&) = delete; + + void start(lightweight_manual_reset_event& event) noexcept + { + m_coroutine.promise().start(event); + } + + decltype(auto) result() + { + return m_coroutine.promise().result(); + } + + private: + + coroutine_handle_t m_coroutine; + + }; + +#if CPPCORO_COMPILER_MSVC && CPPCORO_COMPILER_MSVC < 19'20'00000 + // HACK: Work around bug in MSVC where passing a parameter by universal reference + // results in an error when passed a move-only type, complaining that the copy-constructor + // has been deleted. The parameter should be passed by reference and the compiler should + // notcalling the copy-constructor for the argument + template< + typename AWAITABLE, + typename RESULT = typename cppcoro::awaitable_traits::await_result_t, + std::enable_if_t, int> = 0> + sync_wait_task make_sync_wait_task(AWAITABLE& awaitable) + { + // HACK: Workaround another bug in MSVC where the expression 'co_yield co_await x' seems + // to completely ignore the co_yield an never calls promise.yield_value(). + // The coroutine seems to be resuming the 'co_await' after the 'co_yield' + // rather than before the 'co_yield'. + // This bug is present in VS 2017.7 and VS 2017.8. + auto& promise = co_await sync_wait_task_promise::get_promise; + co_await promise.yield_value(co_await std::forward(awaitable)); + + //co_yield co_await std::forward(awaitable); + } + + template< + typename AWAITABLE, + typename RESULT = typename cppcoro::awaitable_traits::await_result_t, + std::enable_if_t, int> = 0> + sync_wait_task make_sync_wait_task(AWAITABLE& awaitable) + { + co_await static_cast(awaitable); + } +#else + template< + typename AWAITABLE, + typename RESULT = typename cppcoro::awaitable_traits::await_result_t, + std::enable_if_t, int> = 0> + sync_wait_task make_sync_wait_task(AWAITABLE&& awaitable) + { + co_yield co_await std::forward(awaitable); + } + + template< + typename AWAITABLE, + typename RESULT = typename cppcoro::awaitable_traits::await_result_t, + std::enable_if_t, int> = 0> + sync_wait_task make_sync_wait_task(AWAITABLE&& awaitable) + { + co_await std::forward(awaitable); + } +#endif + } +} + +#endif diff --git a/include/cppcoro/detail/unwrap_reference.hpp b/include/cppcoro/detail/unwrap_reference.hpp new file mode 100644 index 0000000..08a2159 --- /dev/null +++ b/include/cppcoro/detail/unwrap_reference.hpp @@ -0,0 +1,31 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_DETAIL_UNWRAP_REFERENCE_HPP_INCLUDED +#define CPPCORO_DETAIL_UNWRAP_REFERENCE_HPP_INCLUDED + +#include + +namespace cppcoro +{ + namespace detail + { + template + struct unwrap_reference + { + using type = T; + }; + + template + struct unwrap_reference> + { + using type = T; + }; + + template + using unwrap_reference_t = typename unwrap_reference::type; + } +} + +#endif diff --git a/include/cppcoro/detail/void_value.hpp b/include/cppcoro/detail/void_value.hpp new file mode 100644 index 0000000..420cad6 --- /dev/null +++ b/include/cppcoro/detail/void_value.hpp @@ -0,0 +1,16 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_DETAIL_VOID_VALUE_HPP_INCLUDED +#define CPPCORO_DETAIL_VOID_VALUE_HPP_INCLUDED + +namespace cppcoro +{ + namespace detail + { + struct void_value {}; + } +} + +#endif diff --git a/include/cppcoro/detail/when_all_counter.hpp b/include/cppcoro/detail/when_all_counter.hpp new file mode 100644 index 0000000..0a38e42 --- /dev/null +++ b/include/cppcoro/detail/when_all_counter.hpp @@ -0,0 +1,55 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_DETAIL_WHEN_ALL_COUNTER_HPP_INCLUDED +#define CPPCORO_DETAIL_WHEN_ALL_COUNTER_HPP_INCLUDED + +#include +#include +#include + +namespace cppcoro +{ + namespace detail + { + class when_all_counter + { + public: + + when_all_counter(std::size_t count) noexcept + : m_count(count + 1) + , m_awaitingCoroutine(nullptr) + {} + + bool is_ready() const noexcept + { + // We consider this complete if we're asking whether it's ready + // after a coroutine has already been registered. + return static_cast(m_awaitingCoroutine); + } + + bool try_await(cppcoro::coroutine_handle<> awaitingCoroutine) noexcept + { + m_awaitingCoroutine = awaitingCoroutine; + return m_count.fetch_sub(1, std::memory_order_acq_rel) > 1; + } + + void notify_awaitable_completed() noexcept + { + if (m_count.fetch_sub(1, std::memory_order_acq_rel) == 1) + { + m_awaitingCoroutine.resume(); + } + } + + protected: + + std::atomic m_count; + cppcoro::coroutine_handle<> m_awaitingCoroutine; + + }; + } +} + +#endif diff --git a/include/cppcoro/detail/when_all_ready_awaitable.hpp b/include/cppcoro/detail/when_all_ready_awaitable.hpp new file mode 100644 index 0000000..54a5263 --- /dev/null +++ b/include/cppcoro/detail/when_all_ready_awaitable.hpp @@ -0,0 +1,258 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_DETAIL_WHEN_ALL_READY_AWAITABLE_HPP_INCLUDED +#define CPPCORO_DETAIL_WHEN_ALL_READY_AWAITABLE_HPP_INCLUDED + +#include + +#include +#include + +namespace cppcoro +{ + namespace detail + { + template + class when_all_ready_awaitable; + + template<> + class when_all_ready_awaitable> + { + public: + + constexpr when_all_ready_awaitable() noexcept {} + explicit constexpr when_all_ready_awaitable(std::tuple<>) noexcept {} + + constexpr bool await_ready() const noexcept { return true; } + void await_suspend(cppcoro::coroutine_handle<>) noexcept {} + std::tuple<> await_resume() const noexcept { return {}; } + + }; + + template + class when_all_ready_awaitable> + { + public: + + explicit when_all_ready_awaitable(TASKS&&... tasks) + noexcept(std::conjunction_v...>) + : m_counter(sizeof...(TASKS)) + , m_tasks(std::move(tasks)...) + {} + + explicit when_all_ready_awaitable(std::tuple&& tasks) + noexcept(std::is_nothrow_move_constructible_v>) + : m_counter(sizeof...(TASKS)) + , m_tasks(std::move(tasks)) + {} + + when_all_ready_awaitable(when_all_ready_awaitable&& other) noexcept + : m_counter(sizeof...(TASKS)) + , m_tasks(std::move(other.m_tasks)) + {} + + auto operator co_await() & noexcept + { + struct awaiter + { + awaiter(when_all_ready_awaitable& awaitable) noexcept + : m_awaitable(awaitable) + {} + + bool await_ready() const noexcept + { + return m_awaitable.is_ready(); + } + + bool await_suspend(cppcoro::coroutine_handle<> awaitingCoroutine) noexcept + { + return m_awaitable.try_await(awaitingCoroutine); + } + + std::tuple& await_resume() noexcept + { + return m_awaitable.m_tasks; + } + + private: + + when_all_ready_awaitable& m_awaitable; + + }; + + return awaiter{ *this }; + } + + auto operator co_await() && noexcept + { + struct awaiter + { + awaiter(when_all_ready_awaitable& awaitable) noexcept + : m_awaitable(awaitable) + {} + + bool await_ready() const noexcept + { + return m_awaitable.is_ready(); + } + + bool await_suspend(cppcoro::coroutine_handle<> awaitingCoroutine) noexcept + { + return m_awaitable.try_await(awaitingCoroutine); + } + + std::tuple&& await_resume() noexcept + { + return std::move(m_awaitable.m_tasks); + } + + private: + + when_all_ready_awaitable& m_awaitable; + + }; + + return awaiter{ *this }; + } + + private: + + bool is_ready() const noexcept + { + return m_counter.is_ready(); + } + + bool try_await(cppcoro::coroutine_handle<> awaitingCoroutine) noexcept + { + start_tasks(std::make_integer_sequence{}); + return m_counter.try_await(awaitingCoroutine); + } + + template + void start_tasks(std::integer_sequence) noexcept + { + (void)std::initializer_list{ + (std::get(m_tasks).start(m_counter), 0)... + }; + } + + when_all_counter m_counter; + std::tuple m_tasks; + + }; + + template + class when_all_ready_awaitable + { + public: + + explicit when_all_ready_awaitable(TASK_CONTAINER&& tasks) noexcept + : m_counter(tasks.size()) + , m_tasks(std::forward(tasks)) + {} + + when_all_ready_awaitable(when_all_ready_awaitable&& other) + noexcept(std::is_nothrow_move_constructible_v) + : m_counter(other.m_tasks.size()) + , m_tasks(std::move(other.m_tasks)) + {} + + when_all_ready_awaitable(const when_all_ready_awaitable&) = delete; + when_all_ready_awaitable& operator=(const when_all_ready_awaitable&) = delete; + + auto operator co_await() & noexcept + { + class awaiter + { + public: + + awaiter(when_all_ready_awaitable& awaitable) + : m_awaitable(awaitable) + {} + + bool await_ready() const noexcept + { + return m_awaitable.is_ready(); + } + + bool await_suspend(cppcoro::coroutine_handle<> awaitingCoroutine) noexcept + { + return m_awaitable.try_await(awaitingCoroutine); + } + + TASK_CONTAINER& await_resume() noexcept + { + return m_awaitable.m_tasks; + } + + private: + + when_all_ready_awaitable& m_awaitable; + + }; + + return awaiter{ *this }; + } + + + auto operator co_await() && noexcept + { + class awaiter + { + public: + + awaiter(when_all_ready_awaitable& awaitable) + : m_awaitable(awaitable) + {} + + bool await_ready() const noexcept + { + return m_awaitable.is_ready(); + } + + bool await_suspend(cppcoro::coroutine_handle<> awaitingCoroutine) noexcept + { + return m_awaitable.try_await(awaitingCoroutine); + } + + TASK_CONTAINER&& await_resume() noexcept + { + return std::move(m_awaitable.m_tasks); + } + + private: + + when_all_ready_awaitable& m_awaitable; + + }; + + return awaiter{ *this }; + } + + private: + + bool is_ready() const noexcept + { + return m_counter.is_ready(); + } + + bool try_await(cppcoro::coroutine_handle<> awaitingCoroutine) noexcept + { + for (auto&& task : m_tasks) + { + task.start(m_counter); + } + + return m_counter.try_await(awaitingCoroutine); + } + + when_all_counter m_counter; + TASK_CONTAINER m_tasks; + + }; + } +} + +#endif diff --git a/include/cppcoro/detail/when_all_task.hpp b/include/cppcoro/detail/when_all_task.hpp new file mode 100644 index 0000000..5787e00 --- /dev/null +++ b/include/cppcoro/detail/when_all_task.hpp @@ -0,0 +1,357 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_DETAIL_WHEN_ALL_TASK_HPP_INCLUDED +#define CPPCORO_DETAIL_WHEN_ALL_TASK_HPP_INCLUDED + +#include + +#include +#include + +#include +#include +#include + +namespace cppcoro +{ + namespace detail + { + template + class when_all_ready_awaitable; + + template + class when_all_task; + + template + class when_all_task_promise final + { + public: + + using coroutine_handle_t = cppcoro::coroutine_handle>; + + when_all_task_promise() noexcept + {} + + auto get_return_object() noexcept + { + return coroutine_handle_t::from_promise(*this); + } + + cppcoro::suspend_always initial_suspend() noexcept + { + return{}; + } + + auto final_suspend() noexcept + { + class completion_notifier + { + public: + + bool await_ready() const noexcept { return false; } + + void await_suspend(coroutine_handle_t coro) const noexcept + { + coro.promise().m_counter->notify_awaitable_completed(); + } + + void await_resume() const noexcept {} + + }; + + return completion_notifier{}; + } + + void unhandled_exception() noexcept + { + m_exception = std::current_exception(); + } + + void return_void() noexcept + { + // We should have either suspended at co_yield point or + // an exception was thrown before running off the end of + // the coroutine. + assert(false); + } + +#if CPPCORO_COMPILER_MSVC && CPPCORO_COMPILER_MSVC < 19'20'00000 + // HACK: This is needed to work around a bug in MSVC 2017.7/2017.8. + // See comment in make_when_all_task below. + template + Awaitable&& await_transform(Awaitable&& awaitable) + { + return static_cast(awaitable); + } + + struct get_promise_t {}; + static constexpr get_promise_t get_promise = {}; + + auto await_transform(get_promise_t) + { + class awaiter + { + public: + awaiter(when_all_task_promise* promise) noexcept : m_promise(promise) {} + bool await_ready() noexcept { + return true; + } + void await_suspend(cppcoro::coroutine_handle<>) noexcept {} + when_all_task_promise& await_resume() noexcept + { + return *m_promise; + } + private: + when_all_task_promise* m_promise; + }; + return awaiter{ this }; + } +#endif + + + auto yield_value(RESULT&& result) noexcept + { + m_result = std::addressof(result); + return final_suspend(); + } + + void start(when_all_counter& counter) noexcept + { + m_counter = &counter; + coroutine_handle_t::from_promise(*this).resume(); + } + + RESULT& result() & + { + rethrow_if_exception(); + return *m_result; + } + + RESULT&& result() && + { + rethrow_if_exception(); + return std::forward(*m_result); + } + + private: + + void rethrow_if_exception() + { + if (m_exception) + { + std::rethrow_exception(m_exception); + } + } + + when_all_counter* m_counter; + std::exception_ptr m_exception; + std::add_pointer_t m_result; + + }; + + template<> + class when_all_task_promise final + { + public: + + using coroutine_handle_t = cppcoro::coroutine_handle>; + + when_all_task_promise() noexcept + {} + + auto get_return_object() noexcept + { + return coroutine_handle_t::from_promise(*this); + } + + cppcoro::suspend_always initial_suspend() noexcept + { + return{}; + } + + auto final_suspend() noexcept + { + class completion_notifier + { + public: + + bool await_ready() const noexcept { return false; } + + void await_suspend(coroutine_handle_t coro) const noexcept + { + coro.promise().m_counter->notify_awaitable_completed(); + } + + void await_resume() const noexcept {} + + }; + + return completion_notifier{}; + } + + void unhandled_exception() noexcept + { + m_exception = std::current_exception(); + } + + void return_void() noexcept + { + } + + void start(when_all_counter& counter) noexcept + { + m_counter = &counter; + coroutine_handle_t::from_promise(*this).resume(); + } + + void result() + { + if (m_exception) + { + std::rethrow_exception(m_exception); + } + } + + private: + + when_all_counter* m_counter; + std::exception_ptr m_exception; + + }; + + template + class when_all_task final + { + public: + + using promise_type = when_all_task_promise; + + using coroutine_handle_t = typename promise_type::coroutine_handle_t; + + when_all_task(coroutine_handle_t coroutine) noexcept + : m_coroutine(coroutine) + {} + + when_all_task(when_all_task&& other) noexcept + : m_coroutine(std::exchange(other.m_coroutine, coroutine_handle_t{})) + {} + + ~when_all_task() + { + if (m_coroutine) m_coroutine.destroy(); + } + + when_all_task(const when_all_task&) = delete; + when_all_task& operator=(const when_all_task&) = delete; + + decltype(auto) result() & + { + return m_coroutine.promise().result(); + } + + decltype(auto) result() && + { + return std::move(m_coroutine.promise()).result(); + } + + decltype(auto) non_void_result() & + { + if constexpr (std::is_void_vresult())>) + { + this->result(); + return void_value{}; + } + else + { + return this->result(); + } + } + + decltype(auto) non_void_result() && + { + if constexpr (std::is_void_vresult())>) + { + std::move(*this).result(); + return void_value{}; + } + else + { + return std::move(*this).result(); + } + } + + private: + + template + friend class when_all_ready_awaitable; + + void start(when_all_counter& counter) noexcept + { + m_coroutine.promise().start(counter); + } + + coroutine_handle_t m_coroutine; + + }; + + template< + typename AWAITABLE, + typename RESULT = typename cppcoro::awaitable_traits::await_result_t, + std::enable_if_t, int> = 0> + when_all_task make_when_all_task(AWAITABLE awaitable) + { +#if CPPCORO_COMPILER_MSVC && CPPCORO_COMPILER_MSVC < 19'20'00000 + // HACK: Workaround another bug in MSVC where the expression 'co_yield co_await x' seems + // to completely ignore the co_yield an never calls promise.yield_value(). + // The coroutine seems to be resuming the 'co_await' after the 'co_yield' + // rather than before the 'co_yield'. + // This bug is present in VS 2017.7 and VS 2017.8. + auto& promise = co_await when_all_task_promise::get_promise; + co_await promise.yield_value(co_await std::forward(awaitable)); +#else + co_yield co_await static_cast(awaitable); +#endif + } + + template< + typename AWAITABLE, + typename RESULT = typename cppcoro::awaitable_traits::await_result_t, + std::enable_if_t, int> = 0> + when_all_task make_when_all_task(AWAITABLE awaitable) + { + co_await static_cast(awaitable); + } + + template< + typename AWAITABLE, + typename RESULT = typename cppcoro::awaitable_traits::await_result_t, + std::enable_if_t, int> = 0> + when_all_task make_when_all_task(std::reference_wrapper awaitable) + { +#if CPPCORO_COMPILER_MSVC && CPPCORO_COMPILER_MSVC < 19'20'00000 + // HACK: Workaround another bug in MSVC where the expression 'co_yield co_await x' seems + // to completely ignore the co_yield and never calls promise.yield_value(). + // The coroutine seems to be resuming the 'co_await' after the 'co_yield' + // rather than before the 'co_yield'. + // This bug is present in VS 2017.7 and VS 2017.8. + auto& promise = co_await when_all_task_promise::get_promise; + co_await promise.yield_value(co_await awaitable.get()); +#else + co_yield co_await awaitable.get(); +#endif + } + + template< + typename AWAITABLE, + typename RESULT = typename cppcoro::awaitable_traits::await_result_t, + std::enable_if_t, int> = 0> + when_all_task make_when_all_task(std::reference_wrapper awaitable) + { + co_await awaitable.get(); + } + } +} + +#endif diff --git a/include/cppcoro/detail/win32.hpp b/include/cppcoro/detail/win32.hpp new file mode 100644 index 0000000..a1e68e3 --- /dev/null +++ b/include/cppcoro/detail/win32.hpp @@ -0,0 +1,179 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_DETAIL_WIN32_HPP_INCLUDED +#define CPPCORO_DETAIL_WIN32_HPP_INCLUDED + +#include + +#if !CPPCORO_OS_WINNT +# error is only supported on the Windows platform. +#endif + +#include +#include + +struct _OVERLAPPED; + +namespace cppcoro +{ + namespace detail + { + namespace win32 + { + using handle_t = void*; + using ulongptr_t = std::uintptr_t; + using longptr_t = std::intptr_t; + using dword_t = unsigned long; + using socket_t = std::uintptr_t; + using ulong_t = unsigned long; + +#if CPPCORO_COMPILER_MSVC +# pragma warning(push) +# pragma warning(disable : 4201) // Non-standard anonymous struct/union +#endif + + /// Structure needs to correspond exactly to the builtin + /// _OVERLAPPED structure from Windows.h. + struct overlapped + { + ulongptr_t Internal; + ulongptr_t InternalHigh; + union + { + struct + { + dword_t Offset; + dword_t OffsetHigh; + }; + void* Pointer; + }; + handle_t hEvent; + }; + +#if CPPCORO_COMPILER_MSVC +# pragma warning(pop) +#endif + + struct wsabuf + { + constexpr wsabuf() noexcept + : len(0) + , buf(nullptr) + {} + + constexpr wsabuf(void* ptr, std::size_t size) + : len(size <= ulong_t(-1) ? ulong_t(size) : ulong_t(-1)) + , buf(static_cast(ptr)) + {} + + ulong_t len; + char* buf; + }; + + struct io_state : win32::overlapped + { + using callback_type = void( + io_state* state, + win32::dword_t errorCode, + win32::dword_t numberOfBytesTransferred, + win32::ulongptr_t completionKey); + + io_state(callback_type* callback = nullptr) noexcept + : io_state(std::uint64_t(0), callback) + {} + + io_state(void* pointer, callback_type* callback) noexcept + : m_callback(callback) + { + this->Internal = 0; + this->InternalHigh = 0; + this->Pointer = pointer; + this->hEvent = nullptr; + } + + io_state(std::uint64_t offset, callback_type* callback) noexcept + : m_callback(callback) + { + this->Internal = 0; + this->InternalHigh = 0; + this->Offset = static_cast(offset); + this->OffsetHigh = static_cast(offset >> 32); + this->hEvent = nullptr; + } + + callback_type* m_callback; + }; + + class safe_handle + { + public: + + safe_handle() + : m_handle(nullptr) + {} + + explicit safe_handle(handle_t handle) + : m_handle(handle) + {} + + safe_handle(const safe_handle& other) = delete; + + safe_handle(safe_handle&& other) noexcept + : m_handle(other.m_handle) + { + other.m_handle = nullptr; + } + + ~safe_handle() + { + close(); + } + + safe_handle& operator=(safe_handle handle) noexcept + { + swap(handle); + return *this; + } + + constexpr handle_t handle() const { return m_handle; } + + /// Calls CloseHandle() and sets the handle to NULL. + void close() noexcept; + + void swap(safe_handle& other) noexcept + { + std::swap(m_handle, other.m_handle); + } + + bool operator==(const safe_handle& other) const + { + return m_handle == other.m_handle; + } + + bool operator!=(const safe_handle& other) const + { + return m_handle != other.m_handle; + } + + bool operator==(handle_t handle) const + { + return m_handle == handle; + } + + bool operator!=(handle_t handle) const + { + return m_handle != handle; + } + + private: + + handle_t m_handle; + + }; + } + } +} + +#endif diff --git a/include/cppcoro/detail/win32_overlapped_operation.hpp b/include/cppcoro/detail/win32_overlapped_operation.hpp new file mode 100644 index 0000000..82cc04c --- /dev/null +++ b/include/cppcoro/detail/win32_overlapped_operation.hpp @@ -0,0 +1,376 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_DETAIL_WIN32_OVERLAPPED_OPERATION_HPP_INCLUDED +#define CPPCORO_DETAIL_WIN32_OVERLAPPED_OPERATION_HPP_INCLUDED + +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace cppcoro +{ + namespace detail + { + class win32_overlapped_operation_base + : protected detail::win32::io_state + { + public: + + win32_overlapped_operation_base( + detail::win32::io_state::callback_type* callback) noexcept + : detail::win32::io_state(callback) + , m_errorCode(0) + , m_numberOfBytesTransferred(0) + {} + + win32_overlapped_operation_base( + void* pointer, + detail::win32::io_state::callback_type* callback) noexcept + : detail::win32::io_state(pointer, callback) + , m_errorCode(0) + , m_numberOfBytesTransferred(0) + {} + + win32_overlapped_operation_base( + std::uint64_t offset, + detail::win32::io_state::callback_type* callback) noexcept + : detail::win32::io_state(offset, callback) + , m_errorCode(0) + , m_numberOfBytesTransferred(0) + {} + + _OVERLAPPED* get_overlapped() noexcept + { + return reinterpret_cast<_OVERLAPPED*>( + static_cast(this)); + } + + std::size_t get_result() + { + if (m_errorCode != 0) + { + throw std::system_error{ + static_cast(m_errorCode), + std::system_category() + }; + } + + return m_numberOfBytesTransferred; + } + + detail::win32::dword_t m_errorCode; + detail::win32::dword_t m_numberOfBytesTransferred; + + }; + + template + class win32_overlapped_operation + : protected win32_overlapped_operation_base + { + protected: + + win32_overlapped_operation() noexcept + : win32_overlapped_operation_base( + &win32_overlapped_operation::on_operation_completed) + {} + + win32_overlapped_operation(void* pointer) noexcept + : win32_overlapped_operation_base( + pointer, + &win32_overlapped_operation::on_operation_completed) + {} + + win32_overlapped_operation(std::uint64_t offset) noexcept + : win32_overlapped_operation_base( + offset, + &win32_overlapped_operation::on_operation_completed) + {} + + public: + + bool await_ready() const noexcept { return false; } + + CPPCORO_NOINLINE + bool await_suspend(cppcoro::coroutine_handle<> awaitingCoroutine) + { + static_assert(std::is_base_of_v); + + m_awaitingCoroutine = awaitingCoroutine; + return static_cast(this)->try_start(); + } + + decltype(auto) await_resume() + { + return static_cast(this)->get_result(); + } + + private: + + static void on_operation_completed( + detail::win32::io_state* ioState, + detail::win32::dword_t errorCode, + detail::win32::dword_t numberOfBytesTransferred, + [[maybe_unused]] detail::win32::ulongptr_t completionKey) noexcept + { + auto* operation = static_cast(ioState); + operation->m_errorCode = errorCode; + operation->m_numberOfBytesTransferred = numberOfBytesTransferred; + operation->m_awaitingCoroutine.resume(); + } + + cppcoro::coroutine_handle<> m_awaitingCoroutine; + + }; + + template + class win32_overlapped_operation_cancellable + : protected win32_overlapped_operation_base + { + // ERROR_OPERATION_ABORTED value from + static constexpr detail::win32::dword_t error_operation_aborted = 995L; + + protected: + + win32_overlapped_operation_cancellable(cancellation_token&& ct) noexcept + : win32_overlapped_operation_base(&win32_overlapped_operation_cancellable::on_operation_completed) + , m_state(ct.is_cancellation_requested() ? state::completed : state::not_started) + , m_cancellationToken(std::move(ct)) + { + m_errorCode = error_operation_aborted; + } + + win32_overlapped_operation_cancellable( + void* pointer, + cancellation_token&& ct) noexcept + : win32_overlapped_operation_base(pointer, &win32_overlapped_operation_cancellable::on_operation_completed) + , m_state(ct.is_cancellation_requested() ? state::completed : state::not_started) + , m_cancellationToken(std::move(ct)) + { + m_errorCode = error_operation_aborted; + } + + win32_overlapped_operation_cancellable( + std::uint64_t offset, + cancellation_token&& ct) noexcept + : win32_overlapped_operation_base(offset, &win32_overlapped_operation_cancellable::on_operation_completed) + , m_state(ct.is_cancellation_requested() ? state::completed : state::not_started) + , m_cancellationToken(std::move(ct)) + { + m_errorCode = error_operation_aborted; + } + + win32_overlapped_operation_cancellable( + win32_overlapped_operation_cancellable&& other) noexcept + : win32_overlapped_operation_base(std::move(other)) + , m_state(other.m_state.load(std::memory_order_relaxed)) + , m_cancellationToken(std::move(other.m_cancellationToken)) + { + assert(m_errorCode == other.m_errorCode); + assert(m_numberOfBytesTransferred == other.m_numberOfBytesTransferred); + } + + public: + + bool await_ready() const noexcept + { + return m_state.load(std::memory_order_relaxed) == state::completed; + } + + CPPCORO_NOINLINE + bool await_suspend(cppcoro::coroutine_handle<> awaitingCoroutine) + { + static_assert(std::is_base_of_v); + + m_awaitingCoroutine = awaitingCoroutine; + + // TRICKY: Register cancellation callback before starting the operation + // in case the callback registration throws due to insufficient + // memory. We need to make sure that the logic that occurs after + // starting the operation is noexcept, otherwise we run into the + // problem of not being able to cancel the started operation and + // the dilemma of what to do with the exception. + // + // However, doing this means that the cancellation callback may run + // prior to returning below so in the case that cancellation may + // occur we defer setting the state to 'started' until after + // the operation has finished starting. The cancellation callback + // will only attempt to request cancellation of the operation with + // CancelIoEx() once the state has been set to 'started'. + const bool canBeCancelled = m_cancellationToken.can_be_cancelled(); + if (canBeCancelled) + { + m_cancellationCallback.emplace( + std::move(m_cancellationToken), + [this] { this->on_cancellation_requested(); }); + } + else + { + m_state.store(state::started, std::memory_order_relaxed); + } + + // Now start the operation. + const bool willCompleteAsynchronously = static_cast(this)->try_start(); + if (!willCompleteAsynchronously) + { + // Operation completed synchronously, resume awaiting coroutine immediately. + return false; + } + + if (canBeCancelled) + { + // Need to flag that the operation has finished starting now. + + // However, the operation may have completed concurrently on + // another thread, transitioning directly from not_started -> complete. + // Or it may have had the cancellation callback execute and transition + // from not_started -> cancellation_requested. We use a compare-exchange + // to determine a winner between these potential racing cases. + state oldState = state::not_started; + if (!m_state.compare_exchange_strong( + oldState, + state::started, + std::memory_order_release, + std::memory_order_acquire)) + { + if (oldState == state::cancellation_requested) + { + // Request the operation be cancelled. + // Note that it may have already completed on a background + // thread by now so this request for cancellation may end up + // being ignored. + static_cast(this)->cancel(); + + if (!m_state.compare_exchange_strong( + oldState, + state::started, + std::memory_order_release, + std::memory_order_acquire)) + { + assert(oldState == state::completed); + return false; + } + } + else + { + assert(oldState == state::completed); + return false; + } + } + } + + return true; + } + + decltype(auto) await_resume() + { + // Free memory used by the cancellation callback now that the operation + // has completed rather than waiting until the operation object destructs. + // eg. If the operation is passed to when_all() then the operation object + // may not be destructed until all of the operations complete. + m_cancellationCallback.reset(); + + if (m_errorCode == error_operation_aborted) + { + throw operation_cancelled{}; + } + + return static_cast(this)->get_result(); + } + + private: + + enum class state + { + not_started, + started, + cancellation_requested, + completed + }; + + void on_cancellation_requested() noexcept + { + auto oldState = m_state.load(std::memory_order_acquire); + if (oldState == state::not_started) + { + // This callback is running concurrently with await_suspend(). + // The call to start the operation may not have returned yet so + // we can't safely request cancellation of it. Instead we try to + // notify the await_suspend() thread by transitioning the state + // to state::cancellation_requested so that the await_suspend() + // thread can request cancellation after it has finished starting + // the operation. + const bool transferredCancelResponsibility = + m_state.compare_exchange_strong( + oldState, + state::cancellation_requested, + std::memory_order_release, + std::memory_order_acquire); + if (transferredCancelResponsibility) + { + return; + } + } + + // No point requesting cancellation if the operation has already completed. + if (oldState != state::completed) + { + static_cast(this)->cancel(); + } + } + + static void on_operation_completed( + detail::win32::io_state* ioState, + detail::win32::dword_t errorCode, + detail::win32::dword_t numberOfBytesTransferred, + [[maybe_unused]] detail::win32::ulongptr_t completionKey) noexcept + { + auto* operation = static_cast(ioState); + + operation->m_errorCode = errorCode; + operation->m_numberOfBytesTransferred = numberOfBytesTransferred; + + auto state = operation->m_state.load(std::memory_order_acquire); + if (state == state::started) + { + operation->m_state.store(state::completed, std::memory_order_relaxed); + operation->m_awaitingCoroutine.resume(); + } + else + { + // We are racing with await_suspend() call suspending. + // Try to mark it as completed using an atomic exchange and look + // at the previous value to determine whether the coroutine suspended + // first (in which case we resume it now) or we marked it as completed + // first (in which case await_suspend() will return false and immediately + // resume the coroutine). + state = operation->m_state.exchange( + state::completed, + std::memory_order_acq_rel); + if (state == state::started) + { + // The await_suspend() method returned (or will return) 'true' and so + // we need to resume the coroutine. + operation->m_awaitingCoroutine.resume(); + } + } + } + + std::atomic m_state; + cppcoro::cancellation_token m_cancellationToken; + std::optional m_cancellationCallback; + cppcoro::coroutine_handle<> m_awaitingCoroutine; + + }; + } +} + +#endif diff --git a/include/cppcoro/file.hpp b/include/cppcoro/file.hpp new file mode 100644 index 0000000..1366af8 --- /dev/null +++ b/include/cppcoro/file.hpp @@ -0,0 +1,54 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_FILE_HPP_INCLUDED +#define CPPCORO_FILE_HPP_INCLUDED + +#include + +#include +#include +#include + +#if CPPCORO_OS_WINNT +# include +#endif + +#include + +namespace cppcoro +{ + class io_service; + + class file + { + public: + + file(file&& other) noexcept = default; + + virtual ~file(); + + /// Get the size of the file in bytes. + std::uint64_t size() const; + + protected: + +#if CPPCORO_OS_WINNT + file(detail::win32::safe_handle&& fileHandle) noexcept; + + static detail::win32::safe_handle open( + detail::win32::dword_t fileAccess, + io_service& ioService, + const cppcoro::filesystem::path& path, + file_open_mode openMode, + file_share_mode shareMode, + file_buffering_mode bufferingMode); + + detail::win32::safe_handle m_fileHandle; +#endif + + }; +} + +#endif diff --git a/include/cppcoro/file_buffering_mode.hpp b/include/cppcoro/file_buffering_mode.hpp new file mode 100644 index 0000000..40ddc3f --- /dev/null +++ b/include/cppcoro/file_buffering_mode.hpp @@ -0,0 +1,32 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_FILE_BUFFERING_MODE_HPP_INCLUDED +#define CPPCORO_FILE_BUFFERING_MODE_HPP_INCLUDED + +namespace cppcoro +{ + enum class file_buffering_mode + { + default_ = 0, + sequential = 1, + random_access = 2, + unbuffered = 4, + write_through = 8, + temporary = 16 + }; + + constexpr file_buffering_mode operator&(file_buffering_mode a, file_buffering_mode b) + { + return static_cast( + static_cast(a) & static_cast(b)); + } + + constexpr file_buffering_mode operator|(file_buffering_mode a, file_buffering_mode b) + { + return static_cast(static_cast(a) | static_cast(b)); + } +} + +#endif diff --git a/include/cppcoro/file_open_mode.hpp b/include/cppcoro/file_open_mode.hpp new file mode 100644 index 0000000..e76f699 --- /dev/null +++ b/include/cppcoro/file_open_mode.hpp @@ -0,0 +1,40 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_FILE_OPEN_MODE_HPP_INCLUDED +#define CPPCORO_FILE_OPEN_MODE_HPP_INCLUDED + +namespace cppcoro +{ + enum class file_open_mode + { + /// Open an existing file. + /// + /// If file does not already exist when opening the file then raises + /// an exception. + open_existing, + + /// Create a new file, overwriting an existing file if one exists. + /// + /// If a file exists at the path then it is overwitten with a new file. + /// If no file exists at the path then a new one is created. + create_always, + + /// Create a new file. + /// + /// If the file already exists then raises an exception. + create_new, + + /// Open the existing file if one exists, otherwise create a new empty + /// file. + create_or_open, + + /// Open the existing file, truncating the file size to zero. + /// + /// If the file does not exist then raises an exception. + truncate_existing + }; +} + +#endif diff --git a/include/cppcoro/file_read_operation.hpp b/include/cppcoro/file_read_operation.hpp new file mode 100644 index 0000000..4116c2f --- /dev/null +++ b/include/cppcoro/file_read_operation.hpp @@ -0,0 +1,99 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_FILE_READ_OPERATION_HPP_INCLUDED +#define CPPCORO_FILE_READ_OPERATION_HPP_INCLUDED + +#include +#include +#include + +#include +#include + +#if CPPCORO_OS_WINNT +# include +# include + +namespace cppcoro +{ + class file_read_operation_impl + { + public: + + file_read_operation_impl( + detail::win32::handle_t fileHandle, + void* buffer, + std::size_t byteCount) noexcept + : m_fileHandle(fileHandle) + , m_buffer(buffer) + , m_byteCount(byteCount) + {} + + bool try_start(cppcoro::detail::win32_overlapped_operation_base& operation) noexcept; + void cancel(cppcoro::detail::win32_overlapped_operation_base& operation) noexcept; + + private: + + detail::win32::handle_t m_fileHandle; + void* m_buffer; + std::size_t m_byteCount; + + }; + + class file_read_operation + : public cppcoro::detail::win32_overlapped_operation + { + public: + + file_read_operation( + detail::win32::handle_t fileHandle, + std::uint64_t fileOffset, + void* buffer, + std::size_t byteCount) noexcept + : cppcoro::detail::win32_overlapped_operation(fileOffset) + , m_impl(fileHandle, buffer, byteCount) + {} + + private: + + friend class cppcoro::detail::win32_overlapped_operation; + + bool try_start() noexcept { return m_impl.try_start(*this); } + + file_read_operation_impl m_impl; + + }; + + class file_read_operation_cancellable + : public cppcoro::detail::win32_overlapped_operation_cancellable + { + public: + + file_read_operation_cancellable( + detail::win32::handle_t fileHandle, + std::uint64_t fileOffset, + void* buffer, + std::size_t byteCount, + cancellation_token&& cancellationToken) noexcept + : cppcoro::detail::win32_overlapped_operation_cancellable( + fileOffset, std::move(cancellationToken)) + , m_impl(fileHandle, buffer, byteCount) + {} + + private: + + friend class cppcoro::detail::win32_overlapped_operation_cancellable; + + bool try_start() noexcept { return m_impl.try_start(*this); } + void cancel() noexcept { m_impl.cancel(*this); } + + file_read_operation_impl m_impl; + + }; + +#endif +} + +#endif diff --git a/include/cppcoro/file_share_mode.hpp b/include/cppcoro/file_share_mode.hpp new file mode 100644 index 0000000..d7679a5 --- /dev/null +++ b/include/cppcoro/file_share_mode.hpp @@ -0,0 +1,45 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_FILE_SHARE_MODE_HPP_INCLUDED +#define CPPCORO_FILE_SHARE_MODE_HPP_INCLUDED + +namespace cppcoro +{ + enum class file_share_mode + { + /// Don't allow any other processes to open the file concurrently. + none = 0, + + /// Allow other processes to open the file in read-only mode + /// concurrently with this process opening the file. + read = 1, + + /// Allow other processes to open the file in write-only mode + /// concurrently with this process opening the file. + write = 2, + + /// Allow other processes to open the file in read and/or write mode + /// concurrently with this process opening the file. + read_write = read | write, + + /// Allow other processes to delete the file while this process + /// has the file open. + delete_ = 4 + }; + + constexpr file_share_mode operator|(file_share_mode a, file_share_mode b) + { + return static_cast( + static_cast(a) | static_cast(b)); + } + + constexpr file_share_mode operator&(file_share_mode a, file_share_mode b) + { + return static_cast( + static_cast(a) & static_cast(b)); + } +} + +#endif diff --git a/include/cppcoro/file_write_operation.hpp b/include/cppcoro/file_write_operation.hpp new file mode 100644 index 0000000..40f6854 --- /dev/null +++ b/include/cppcoro/file_write_operation.hpp @@ -0,0 +1,98 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_FILE_WRITE_OPERATION_HPP_INCLUDED +#define CPPCORO_FILE_WRITE_OPERATION_HPP_INCLUDED + +#include +#include +#include + +#include +#include + +#if CPPCORO_OS_WINNT +# include +# include + +namespace cppcoro +{ + class file_write_operation_impl + { + public: + + file_write_operation_impl( + detail::win32::handle_t fileHandle, + const void* buffer, + std::size_t byteCount) noexcept + : m_fileHandle(fileHandle) + , m_buffer(buffer) + , m_byteCount(byteCount) + {} + + bool try_start(cppcoro::detail::win32_overlapped_operation_base& operation) noexcept; + void cancel(cppcoro::detail::win32_overlapped_operation_base& operation) noexcept; + + private: + + detail::win32::handle_t m_fileHandle; + const void* m_buffer; + std::size_t m_byteCount; + + }; + + class file_write_operation + : public cppcoro::detail::win32_overlapped_operation + { + public: + + file_write_operation( + detail::win32::handle_t fileHandle, + std::uint64_t fileOffset, + const void* buffer, + std::size_t byteCount) noexcept + : cppcoro::detail::win32_overlapped_operation(fileOffset) + , m_impl(fileHandle, buffer, byteCount) + {} + + private: + + friend class cppcoro::detail::win32_overlapped_operation; + + bool try_start() noexcept { return m_impl.try_start(*this); } + + file_write_operation_impl m_impl; + + }; + + class file_write_operation_cancellable + : public cppcoro::detail::win32_overlapped_operation_cancellable + { + public: + + file_write_operation_cancellable( + detail::win32::handle_t fileHandle, + std::uint64_t fileOffset, + const void* buffer, + std::size_t byteCount, + cancellation_token&& ct) noexcept + : cppcoro::detail::win32_overlapped_operation_cancellable(fileOffset, std::move(ct)) + , m_impl(fileHandle, buffer, byteCount) + {} + + private: + + friend class cppcoro::detail::win32_overlapped_operation_cancellable; + + bool try_start() noexcept { return m_impl.try_start(*this); } + void cancel() noexcept { m_impl.cancel(*this); } + + file_write_operation_impl m_impl; + + }; +} + +#endif // CPPCORO_OS_WINNT + +#endif diff --git a/include/cppcoro/filesystem.hpp b/include/cppcoro/filesystem.hpp new file mode 100644 index 0000000..798b8f7 --- /dev/null +++ b/include/cppcoro/filesystem.hpp @@ -0,0 +1,24 @@ +#ifndef CPPCORO_FILESYSTEM_HPP_INCLUDED +#define CPPCORO_FILESYSTEM_HPP_INCLUDED + +#if __has_include() + +#include + +namespace cppcoro { + namespace filesystem = std::filesystem; +} + +#elif __has_include() + +#include + +namespace cppcoro { + namespace filesystem = std::experimental::filesystem; +} + +#else +#error Cppcoro requires a C++20 compiler with filesystem support +#endif + +#endif diff --git a/include/cppcoro/fmap.hpp b/include/cppcoro/fmap.hpp new file mode 100644 index 0000000..6c4e802 --- /dev/null +++ b/include/cppcoro/fmap.hpp @@ -0,0 +1,169 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_FMAP_HPP_INCLUDED +#define CPPCORO_FMAP_HPP_INCLUDED + +#include +#include + +#include +#include +#include + +namespace cppcoro +{ + namespace detail + { + template + class fmap_awaiter + { + using awaiter_t = typename awaitable_traits::awaiter_t; + FUNC&& m_func; + awaiter_t m_awaiter; + + public: + + fmap_awaiter(FUNC&& func, AWAITABLE&& awaitable) + noexcept( + std::is_nothrow_move_constructible_v && + noexcept(detail::get_awaiter(static_cast(awaitable)))) + : m_func(static_cast(func)) + , m_awaiter(detail::get_awaiter(static_cast(awaitable))) + {} + + decltype(auto) await_ready() + noexcept(noexcept(static_cast(m_awaiter).await_ready())) + { + return static_cast(m_awaiter).await_ready(); + } + + template + decltype(auto) await_suspend(cppcoro::coroutine_handle coro) + noexcept(noexcept(static_cast(m_awaiter).await_suspend(std::move(coro)))) + { + return static_cast(m_awaiter).await_suspend(std::move(coro)); + } + + template< + typename AWAIT_RESULT = decltype(std::declval().await_resume()), + std::enable_if_t, int> = 0> + decltype(auto) await_resume() + noexcept(noexcept(std::invoke(static_cast(m_func)))) + { + static_cast(m_awaiter).await_resume(); + return std::invoke(static_cast(m_func)); + } + + template< + typename AWAIT_RESULT = decltype(std::declval().await_resume()), + std::enable_if_t, int> = 0> + decltype(auto) await_resume() + noexcept(noexcept(std::invoke(static_cast(m_func), static_cast(m_awaiter).await_resume()))) + { + return std::invoke( + static_cast(m_func), + static_cast(m_awaiter).await_resume()); + } + }; + + template + class fmap_awaitable + { + static_assert(!std::is_lvalue_reference_v); + static_assert(!std::is_lvalue_reference_v); + public: + + template< + typename FUNC_ARG, + typename AWAITABLE_ARG, + std::enable_if_t< + std::is_constructible_v && + std::is_constructible_v, int> = 0> + explicit fmap_awaitable(FUNC_ARG&& func, AWAITABLE_ARG&& awaitable) + noexcept( + std::is_nothrow_constructible_v && + std::is_nothrow_constructible_v) + : m_func(static_cast(func)) + , m_awaitable(static_cast(awaitable)) + {} + + auto operator co_await() const & + { + return fmap_awaiter(m_func, m_awaitable); + } + + auto operator co_await() & + { + return fmap_awaiter(m_func, m_awaitable); + } + + auto operator co_await() && + { + return fmap_awaiter( + static_cast(m_func), + static_cast(m_awaitable)); + } + + private: + + FUNC m_func; + AWAITABLE m_awaitable; + + }; + } + + template + struct fmap_transform + { + explicit fmap_transform(FUNC&& f) + noexcept(std::is_nothrow_move_constructible_v) + : func(std::forward(f)) + {} + + FUNC func; + }; + + template< + typename FUNC, + typename AWAITABLE, + std::enable_if_t, int> = 0> + auto fmap(FUNC&& func, AWAITABLE&& awaitable) + { + return detail::fmap_awaitable< + std::remove_cv_t>, + std::remove_cv_t>>( + std::forward(func), + std::forward(awaitable)); + } + + template + auto fmap(FUNC&& func) + { + return fmap_transform{ std::forward(func) }; + } + + template + decltype(auto) operator|(T&& value, fmap_transform&& transform) + { + // Use ADL for finding fmap() overload. + return fmap(std::forward(transform.func), std::forward(value)); + } + + template + decltype(auto) operator|(T&& value, const fmap_transform& transform) + { + // Use ADL for finding fmap() overload. + return fmap(transform.func, std::forward(value)); + } + + template + decltype(auto) operator|(T&& value, fmap_transform& transform) + { + // Use ADL for finding fmap() overload. + return fmap(transform.func, std::forward(value)); + } +} + +#endif diff --git a/include/cppcoro/generator.hpp b/include/cppcoro/generator.hpp new file mode 100644 index 0000000..7b5df49 --- /dev/null +++ b/include/cppcoro/generator.hpp @@ -0,0 +1,260 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_GENERATOR_HPP_INCLUDED +#define CPPCORO_GENERATOR_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include + +namespace cppcoro +{ + template + class generator; + + namespace detail + { + template + class generator_promise + { + public: + + using value_type = std::remove_reference_t; + using reference_type = std::conditional_t, T, T&>; + using pointer_type = value_type*; + + generator_promise() = default; + + generator get_return_object() noexcept; + + constexpr cppcoro::suspend_always initial_suspend() const noexcept { return {}; } + constexpr cppcoro::suspend_always final_suspend() const noexcept { return {}; } + + template< + typename U = T, + std::enable_if_t::value, int> = 0> + cppcoro::suspend_always yield_value(std::remove_reference_t& value) noexcept + { + m_value = std::addressof(value); + return {}; + } + + cppcoro::suspend_always yield_value(std::remove_reference_t&& value) noexcept + { + m_value = std::addressof(value); + return {}; + } + + void unhandled_exception() + { + m_exception = std::current_exception(); + } + + void return_void() + { + } + + reference_type value() const noexcept + { + return static_cast(*m_value); + } + + // Don't allow any use of 'co_await' inside the generator coroutine. + template + cppcoro::suspend_never await_transform(U&& value) = delete; + + void rethrow_if_exception() + { + if (m_exception) + { + std::rethrow_exception(m_exception); + } + } + + private: + + pointer_type m_value; + std::exception_ptr m_exception; + + }; + + struct generator_sentinel {}; + + template + class generator_iterator + { + using coroutine_handle = cppcoro::coroutine_handle>; + + public: + + using iterator_category = std::input_iterator_tag; + // What type should we use for counting elements of a potentially infinite sequence? + using difference_type = std::ptrdiff_t; + using value_type = typename generator_promise::value_type; + using reference = typename generator_promise::reference_type; + using pointer = typename generator_promise::pointer_type; + + // Iterator needs to be default-constructible to satisfy the Range concept. + generator_iterator() noexcept + : m_coroutine(nullptr) + {} + + explicit generator_iterator(coroutine_handle coroutine) noexcept + : m_coroutine(coroutine) + {} + + friend bool operator==(const generator_iterator& it, generator_sentinel) noexcept + { + return !it.m_coroutine || it.m_coroutine.done(); + } + + friend bool operator!=(const generator_iterator& it, generator_sentinel s) noexcept + { + return !(it == s); + } + + friend bool operator==(generator_sentinel s, const generator_iterator& it) noexcept + { + return (it == s); + } + + friend bool operator!=(generator_sentinel s, const generator_iterator& it) noexcept + { + return it != s; + } + + generator_iterator& operator++() + { + m_coroutine.resume(); + if (m_coroutine.done()) + { + m_coroutine.promise().rethrow_if_exception(); + } + + return *this; + } + + // Need to provide post-increment operator to implement the 'Range' concept. + void operator++(int) + { + (void)operator++(); + } + + reference operator*() const noexcept + { + return m_coroutine.promise().value(); + } + + pointer operator->() const noexcept + { + return std::addressof(operator*()); + } + + private: + + coroutine_handle m_coroutine; + }; + } + + template + class [[nodiscard]] generator + { + public: + + using promise_type = detail::generator_promise; + using iterator = detail::generator_iterator; + + generator() noexcept + : m_coroutine(nullptr) + {} + + generator(generator&& other) noexcept + : m_coroutine(other.m_coroutine) + { + other.m_coroutine = nullptr; + } + + generator(const generator& other) = delete; + + ~generator() + { + if (m_coroutine) + { + m_coroutine.destroy(); + } + } + + generator& operator=(generator other) noexcept + { + swap(other); + return *this; + } + + iterator begin() + { + if (m_coroutine) + { + m_coroutine.resume(); + if (m_coroutine.done()) + { + m_coroutine.promise().rethrow_if_exception(); + } + } + + return iterator{ m_coroutine }; + } + + detail::generator_sentinel end() noexcept + { + return detail::generator_sentinel{}; + } + + void swap(generator& other) noexcept + { + std::swap(m_coroutine, other.m_coroutine); + } + + private: + + friend class detail::generator_promise; + + explicit generator(cppcoro::coroutine_handle coroutine) noexcept + : m_coroutine(coroutine) + {} + + cppcoro::coroutine_handle m_coroutine; + + }; + + template + void swap(generator& a, generator& b) + { + a.swap(b); + } + + namespace detail + { + template + generator generator_promise::get_return_object() noexcept + { + using coroutine_handle = cppcoro::coroutine_handle>; + return generator{ coroutine_handle::from_promise(*this) }; + } + } + + template + generator::iterator::reference>> fmap(FUNC func, generator source) + { + for (auto&& value : source) + { + co_yield std::invoke(func, static_cast(value)); + } + } +} + +#endif diff --git a/include/cppcoro/inline_scheduler.hpp b/include/cppcoro/inline_scheduler.hpp new file mode 100644 index 0000000..a0862a0 --- /dev/null +++ b/include/cppcoro/inline_scheduler.hpp @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_INLINE_SCHEDULER_HPP_INCLUDED +#define CPPCORO_INLINE_SCHEDULER_HPP_INCLUDED + +#include + +namespace cppcoro +{ + class inline_scheduler + { + public: + + inline_scheduler() noexcept = default; + + cppcoro::suspend_never schedule() const noexcept + { + return {}; + } + }; +} + +#endif diff --git a/include/cppcoro/io_service.hpp b/include/cppcoro/io_service.hpp new file mode 100644 index 0000000..b6b4dbd --- /dev/null +++ b/include/cppcoro/io_service.hpp @@ -0,0 +1,321 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_IO_SERVICE_HPP_INCLUDED +#define CPPCORO_IO_SERVICE_HPP_INCLUDED + +#include +#include +#include + +#if CPPCORO_OS_WINNT +# include +#endif + +#include +#include +#include +#include +#include +#include +#include + +namespace cppcoro +{ + class io_service + { + public: + + class schedule_operation; + class timed_schedule_operation; + + /// Initialises the io_service. + /// + /// Does not set a concurrency hint. All threads that enter the + /// event loop will actively process events. + io_service(); + + /// Initialise the io_service with a concurrency hint. + /// + /// \param concurrencyHint + /// Specifies the target maximum number of I/O threads to be + /// actively processing events. + /// Note that the number of active threads may temporarily go + /// above this number. + io_service(std::uint32_t concurrencyHint); + + ~io_service(); + + io_service(io_service&& other) = delete; + io_service(const io_service& other) = delete; + io_service& operator=(io_service&& other) = delete; + io_service& operator=(const io_service& other) = delete; + + /// Returns an operation that when awaited suspends the awaiting + /// coroutine and reschedules it for resumption on an I/O thread + /// associated with this io_service. + [[nodiscard]] + schedule_operation schedule() noexcept; + + /// Returns an operation that when awaited will suspend the + /// awaiting coroutine for the specified delay. Once the delay + /// has elapsed, the coroutine will resume execution on an + /// I/O thread associated with this io_service. + /// + /// \param delay + /// The amount of time to delay scheduling resumption of the coroutine + /// on an I/O thread. There is no guarantee that the coroutine will + /// be resumed exactly after this delay. + /// + /// \param cancellationToken [optional] + /// A cancellation token that can be used to communicate a request to + /// cancel the delayed schedule operation and schedule it for resumption + /// immediately. + /// The co_await operation will throw cppcoro::operation_cancelled if + /// cancellation was requested before the coroutine could be resumed. + template + [[nodiscard]] + timed_schedule_operation schedule_after( + const std::chrono::duration& delay, + cancellation_token cancellationToken = {}) noexcept; + + /// Process events until the io_service is stopped. + /// + /// \return + /// The number of events processed during this call. + std::uint64_t process_events(); + + /// Process events until either the io_service is stopped or + /// there are no more pending events in the queue. + /// + /// \return + /// The number of events processed during this call. + std::uint64_t process_pending_events(); + + /// Block until either one event is processed or the io_service is stopped. + /// + /// \return + /// The number of events processed during this call. + /// This will either be 0 or 1. + std::uint64_t process_one_event(); + + /// Process one event if there are any events pending, otherwise if there + /// are no events pending or the io_service is stopped then return immediately. + /// + /// \return + /// The number of events processed during this call. + /// This will either be 0 or 1. + std::uint64_t process_one_pending_event(); + + /// Shut down the io_service. + /// + /// This will cause any threads currently in a call to one of the process_xxx() methods + /// to return from that call once they finish processing the current event. + /// + /// This call does not wait until all threads have exited the event loop so you + /// must use other synchronisation mechanisms to wait for those threads. + void stop() noexcept; + + /// Reset an io_service to prepare it for resuming processing of events. + /// + /// Call this after a call to stop() to allow calls to process_xxx() methods + /// to process events. + /// + /// After calling stop() you should ensure that all threads have returned from + /// calls to process_xxx() methods before calling reset(). + void reset(); + + bool is_stop_requested() const noexcept; + + void notify_work_started() noexcept; + + void notify_work_finished() noexcept; + +#if CPPCORO_OS_WINNT + detail::win32::handle_t native_iocp_handle() noexcept; + void ensure_winsock_initialised(); +#endif + + private: + + class timer_thread_state; + class timer_queue; + + friend class schedule_operation; + friend class timed_schedule_operation; + + void schedule_impl(schedule_operation* operation) noexcept; + + void try_reschedule_overflow_operations() noexcept; + + bool try_enter_event_loop() noexcept; + void exit_event_loop() noexcept; + + bool try_process_one_event(bool waitForEvent); + + void post_wake_up_event() noexcept; + + timer_thread_state* ensure_timer_thread_started(); + + static constexpr std::uint32_t stop_requested_flag = 1; + static constexpr std::uint32_t active_thread_count_increment = 2; + + // Bit 0: stop_requested_flag + // Bit 1-31: count of active threads currently running the event loop + std::atomic m_threadState; + + std::atomic m_workCount; + +#if CPPCORO_OS_WINNT + detail::win32::safe_handle m_iocpHandle; + + std::atomic m_winsockInitialised; + std::mutex m_winsockInitialisationMutex; +#endif + + // Head of a linked-list of schedule operations that are + // ready to run but that failed to be queued to the I/O + // completion port (eg. due to low memory). + std::atomic m_scheduleOperations; + + std::atomic m_timerState; + + }; + + class io_service::schedule_operation + { + public: + + schedule_operation(io_service& service) noexcept + : m_service(service) + {} + + bool await_ready() const noexcept { return false; } + void await_suspend(cppcoro::coroutine_handle<> awaiter) noexcept; + void await_resume() const noexcept {} + + private: + + friend class io_service; + friend class io_service::timed_schedule_operation; + + io_service& m_service; + cppcoro::coroutine_handle<> m_awaiter; + schedule_operation* m_next; + + }; + + class io_service::timed_schedule_operation + { + public: + + timed_schedule_operation( + io_service& service, + std::chrono::high_resolution_clock::time_point resumeTime, + cppcoro::cancellation_token cancellationToken) noexcept; + + timed_schedule_operation(timed_schedule_operation&& other) noexcept; + + ~timed_schedule_operation(); + + timed_schedule_operation& operator=(timed_schedule_operation&& other) = delete; + timed_schedule_operation(const timed_schedule_operation& other) = delete; + timed_schedule_operation& operator=(const timed_schedule_operation& other) = delete; + + bool await_ready() const noexcept; + void await_suspend(cppcoro::coroutine_handle<> awaiter); + void await_resume(); + + private: + + friend class io_service::timer_queue; + friend class io_service::timer_thread_state; + + io_service::schedule_operation m_scheduleOperation; + std::chrono::high_resolution_clock::time_point m_resumeTime; + + cppcoro::cancellation_token m_cancellationToken; + std::optional m_cancellationRegistration; + + timed_schedule_operation* m_next; + + std::atomic m_refCount; + + }; + + class io_work_scope + { + public: + + explicit io_work_scope(io_service& service) noexcept + : m_service(&service) + { + service.notify_work_started(); + } + + io_work_scope(const io_work_scope& other) noexcept + : m_service(other.m_service) + { + if (m_service != nullptr) + { + m_service->notify_work_started(); + } + } + + io_work_scope(io_work_scope&& other) noexcept + : m_service(other.m_service) + { + other.m_service = nullptr; + } + + ~io_work_scope() + { + if (m_service != nullptr) + { + m_service->notify_work_finished(); + } + } + + void swap(io_work_scope& other) noexcept + { + std::swap(m_service, other.m_service); + } + + io_work_scope& operator=(io_work_scope other) noexcept + { + swap(other); + return *this; + } + + io_service& service() noexcept + { + return *m_service; + } + + private: + + io_service* m_service; + + }; + + inline void swap(io_work_scope& a, io_work_scope& b) + { + a.swap(b); + } +} + +template +cppcoro::io_service::timed_schedule_operation +cppcoro::io_service::schedule_after( + const std::chrono::duration& duration, + cppcoro::cancellation_token cancellationToken) noexcept +{ + return timed_schedule_operation{ + *this, + std::chrono::high_resolution_clock::now() + duration, + std::move(cancellationToken) + }; +} + +#endif diff --git a/include/cppcoro/is_awaitable.hpp b/include/cppcoro/is_awaitable.hpp new file mode 100644 index 0000000..ea9bf21 --- /dev/null +++ b/include/cppcoro/is_awaitable.hpp @@ -0,0 +1,26 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_IS_AWAITABLE_HPP_INCLUDED +#define CPPCORO_IS_AWAITABLE_HPP_INCLUDED + +#include + +#include + +namespace cppcoro +{ + template> + struct is_awaitable : std::false_type {}; + + template + struct is_awaitable()))>> + : std::true_type + {}; + + template + constexpr bool is_awaitable_v = is_awaitable::value; +} + +#endif diff --git a/include/cppcoro/multi_producer_sequencer.hpp b/include/cppcoro/multi_producer_sequencer.hpp new file mode 100644 index 0000000..c656594 --- /dev/null +++ b/include/cppcoro/multi_producer_sequencer.hpp @@ -0,0 +1,829 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_MULTI_PRODUCER_SEQUENCER_HPP_INCLUDED +#define CPPCORO_MULTI_PRODUCER_SEQUENCER_HPP_INCLUDED + +#include +#include +#include +#include + +#include + +#include +#include +#include + +namespace cppcoro +{ + template + class multi_producer_sequencer_claim_one_operation; + + template + class multi_producer_sequencer_claim_operation; + + template + class multi_producer_sequencer_wait_operation_base; + + template + class multi_producer_sequencer_wait_operation; + + /// A multi-producer sequencer is a thread-synchronisation primitive that can be + /// used to synchronise access to a ring-buffer of power-of-two size where you + /// have multiple producers concurrently claiming slots in the ring-buffer and + /// publishing items. + /// + /// When a writer wants to write to a slot in the buffer it first atomically + /// increments a counter by the number of slots it wishes to allocate. + /// It then waits until all of those slots have become available and then + /// returns the range of sequence numbers allocated back to the caller. + /// The caller then writes to those slots and when done publishes them by + /// writing the sequence numbers published to each of the slots to the + /// corresponding element of an array of equal size to the ring buffer. + /// When a reader wants to check if the next sequence number is available + /// it then simply needs to read from the corresponding slot in this array + /// to check if the value stored there is equal to the sequence number it + /// is wanting to read. + /// + /// This means concurrent writers are wait-free when there is space available + /// in the ring buffer, requiring a single atomic fetch-add operation as the + /// only contended write operation. All other writes are to memory locations + /// owned by a particular writer. Concurrent writers can publish items out of + /// order so that one writer does not hold up other writers until the ring + /// buffer fills up. + template< + typename SEQUENCE = std::size_t, + typename TRAITS = sequence_traits> + class multi_producer_sequencer + { + public: + + multi_producer_sequencer( + const sequence_barrier& consumerBarrier, + std::size_t bufferSize, + SEQUENCE initialSequence = TRAITS::initial_sequence); + + /// The size of the circular buffer. This will be a power-of-two. + std::size_t buffer_size() const noexcept { return m_sequenceMask + 1; } + + /// Lookup the last-known-published sequence number after the specified + /// sequence number. + SEQUENCE last_published_after(SEQUENCE lastKnownPublished) const noexcept; + + /// Wait until the specified target sequence number has been published. + /// + /// Returns an awaitable type that when co_awaited will suspend the awaiting + /// coroutine until the specified 'targetSequence' number and all prior sequence + /// numbers have been published. + template + multi_producer_sequencer_wait_operation wait_until_published( + SEQUENCE targetSequence, + SEQUENCE lastKnownPublished, + SCHEDULER& scheduler) const noexcept; + + /// Query if there are currently any slots available for claiming. + /// + /// Note that this return-value is only approximate if you have multiple producers + /// since immediately after returning true another thread may have claimed the + /// last available slot. + bool any_available() const noexcept; + + /// Claim a single slot in the buffer and wait until that slot becomes available. + /// + /// Returns an Awaitable type that yields the sequence number of the slot that + /// was claimed. + /// + /// Once the producer has claimed a slot then they are free to write to that + /// slot within the ring buffer. Once the value has been initialised the item + /// must be published by calling the .publish() method, passing the sequence + /// number. + template + multi_producer_sequencer_claim_one_operation + claim_one(SCHEDULER& scheduler) noexcept; + + /// Claim a contiguous range of sequence numbers corresponding to slots within + /// a ring-buffer. + /// + /// This will claim at most the specified count of sequence numbers but may claim + /// fewer if there are only fewer entries available in the buffer. But will claim + /// at least one sequence number. + /// + /// Returns an awaitable that will yield a sequence_range object containing the + /// sequence numbers that were claimed. + /// + /// The caller is responsible for ensuring that they publish every element of the + /// returned sequence range by calling .publish(). + template + multi_producer_sequencer_claim_operation + claim_up_to(std::size_t count, SCHEDULER& scheduler) noexcept; + + /// Publish the element with the specified sequence number, making it available + /// to consumers. + /// + /// Note that different sequence numbers may be published by different producer + /// threads out of order. A sequence number will not become available to consumers + /// until all preceding sequence numbers have also been published. + /// + /// \param sequence + /// The sequence number of the elemnt to publish + /// This sequence number must have been previously acquired via a call to 'claim_one()' + /// or 'claim_up_to()'. + void publish(SEQUENCE sequence) noexcept; + + /// Publish a contiguous range of sequence numbers, making each of them available + /// to consumers. + /// + /// This is equivalent to calling publish(seq) for each sequence number, seq, in + /// the specified range, but is more efficient since it only checks to see if + /// there are coroutines that need to be woken up once. + void publish(const sequence_range& range) noexcept; + + private: + + template + friend class multi_producer_sequencer_wait_operation_base; + + template + friend class multi_producer_sequencer_claim_operation; + + template + friend class multi_producer_sequencer_claim_one_operation; + + void resume_ready_awaiters() noexcept; + void add_awaiter(multi_producer_sequencer_wait_operation_base* awaiter) const noexcept; + +#if CPPCORO_COMPILER_MSVC +# pragma warning(push) +# pragma warning(disable : 4324) // C4324: structure was padded due to alignment specifier +#endif + + const sequence_barrier& m_consumerBarrier; + const std::size_t m_sequenceMask; + const std::unique_ptr[]> m_published; + + alignas(CPPCORO_CPU_CACHE_LINE) + std::atomic m_nextToClaim; + + alignas(CPPCORO_CPU_CACHE_LINE) + mutable std::atomic*> m_awaiters; + +#if CPPCORO_COMPILER_MSVC +# pragma warning(pop) +#endif + + }; + + template + class multi_producer_sequencer_claim_awaiter + { + public: + + multi_producer_sequencer_claim_awaiter( + const sequence_barrier& consumerBarrier, + std::size_t bufferSize, + const sequence_range& claimedRange, + SCHEDULER& scheduler) noexcept + : m_barrierWait(consumerBarrier, claimedRange.back() - bufferSize, scheduler) + , m_claimedRange(claimedRange) + {} + + bool await_ready() const noexcept + { + return m_barrierWait.await_ready(); + } + + auto await_suspend(cppcoro::coroutine_handle<> awaitingCoroutine) noexcept + { + return m_barrierWait.await_suspend(awaitingCoroutine); + } + + sequence_range await_resume() noexcept + { + return m_claimedRange; + } + + private: + + sequence_barrier_wait_operation m_barrierWait; + sequence_range m_claimedRange; + + }; + + template + class multi_producer_sequencer_claim_operation + { + public: + + multi_producer_sequencer_claim_operation( + multi_producer_sequencer& sequencer, + std::size_t count, + SCHEDULER& scheduler) noexcept + : m_sequencer(sequencer) + , m_count(count < sequencer.buffer_size() ? count : sequencer.buffer_size()) + , m_scheduler(scheduler) + { + } + + multi_producer_sequencer_claim_awaiter operator co_await() noexcept + { + // We wait until the awaitable is actually co_await'ed before we claim the + // range of elements. If we claimed them earlier, then it may be possible for + // the caller to fail to co_await the result eg. due to an exception, which + // would leave the sequence numbers unable to be published and would eventually + // deadlock consumers that waited on them. + // + // TODO: We could try and acquire only as many as are available if fewer than + // m_count elements are available. This would complicate the logic here somewhat + // as we'd need to use a compare-exchange instead. + const SEQUENCE first = m_sequencer.m_nextToClaim.fetch_add(m_count, std::memory_order_relaxed); + return multi_producer_sequencer_claim_awaiter{ + m_sequencer.m_consumerBarrier, + m_sequencer.buffer_size(), + sequence_range{ first, first + m_count }, + m_scheduler + }; + } + + private: + + multi_producer_sequencer& m_sequencer; + std::size_t m_count; + SCHEDULER& m_scheduler; + + }; + + template + class multi_producer_sequencer_claim_one_awaiter + { + public: + + multi_producer_sequencer_claim_one_awaiter( + const sequence_barrier& consumerBarrier, + std::size_t bufferSize, + SEQUENCE claimedSequence, + SCHEDULER& scheduler) noexcept + : m_waitOp(consumerBarrier, claimedSequence - bufferSize, scheduler) + , m_claimedSequence(claimedSequence) + {} + + bool await_ready() const noexcept + { + return m_waitOp.await_ready(); + } + + auto await_suspend(cppcoro::coroutine_handle<> awaitingCoroutine) noexcept + { + return m_waitOp.await_suspend(awaitingCoroutine); + } + + SEQUENCE await_resume() noexcept + { + return m_claimedSequence; + } + + private: + + sequence_barrier_wait_operation m_waitOp; + SEQUENCE m_claimedSequence; + + }; + + template + class multi_producer_sequencer_claim_one_operation + { + public: + + multi_producer_sequencer_claim_one_operation( + multi_producer_sequencer& sequencer, + SCHEDULER& scheduler) noexcept + : m_sequencer(sequencer) + , m_scheduler(scheduler) + {} + + multi_producer_sequencer_claim_one_awaiter operator co_await() noexcept + { + return multi_producer_sequencer_claim_one_awaiter{ + m_sequencer.m_consumerBarrier, + m_sequencer.buffer_size(), + m_sequencer.m_nextToClaim.fetch_add(1, std::memory_order_relaxed), + m_scheduler + }; + } + + private: + + multi_producer_sequencer& m_sequencer; + SCHEDULER& m_scheduler; + + }; + + template + class multi_producer_sequencer_wait_operation_base + { + public: + + multi_producer_sequencer_wait_operation_base( + const multi_producer_sequencer& sequencer, + SEQUENCE targetSequence, + SEQUENCE lastKnownPublished) noexcept + : m_sequencer(sequencer) + , m_targetSequence(targetSequence) + , m_lastKnownPublished(lastKnownPublished) + , m_readyToResume(false) + {} + + multi_producer_sequencer_wait_operation_base( + const multi_producer_sequencer_wait_operation_base& other) noexcept + : m_sequencer(other.m_sequencer) + , m_targetSequence(other.m_targetSequence) + , m_lastKnownPublished(other.m_lastKnownPublished) + , m_readyToResume(false) + {} + + bool await_ready() const noexcept + { + return !TRAITS::precedes(m_lastKnownPublished, m_targetSequence); + } + + bool await_suspend(cppcoro::coroutine_handle<> awaitingCoroutine) noexcept + { + m_awaitingCoroutine = awaitingCoroutine; + + m_sequencer.add_awaiter(this); + + // Mark the waiter as ready to resume. + // If it was already marked as ready-to-resume within the call to add_awaiter() or + // on another thread then this exchange() will return true. In this case we want to + // resume immediately and continue execution by returning false. + return !m_readyToResume.exchange(true, std::memory_order_acquire); + } + + SEQUENCE await_resume() noexcept + { + return m_lastKnownPublished; + } + + protected: + + friend class multi_producer_sequencer; + + void resume(SEQUENCE lastKnownPublished) noexcept + { + m_lastKnownPublished = lastKnownPublished; + if (m_readyToResume.exchange(true, std::memory_order_release)) + { + resume_impl(); + } + } + + virtual void resume_impl() noexcept = 0; + + const multi_producer_sequencer& m_sequencer; + SEQUENCE m_targetSequence; + SEQUENCE m_lastKnownPublished; + multi_producer_sequencer_wait_operation_base* m_next; + cppcoro::coroutine_handle<> m_awaitingCoroutine; + std::atomic m_readyToResume; + }; + + template + class multi_producer_sequencer_wait_operation : + public multi_producer_sequencer_wait_operation_base + { + using schedule_operation = decltype(std::declval().schedule()); + + public: + + multi_producer_sequencer_wait_operation( + const multi_producer_sequencer& sequencer, + SEQUENCE targetSequence, + SEQUENCE lastKnownPublished, + SCHEDULER& scheduler) noexcept + : multi_producer_sequencer_wait_operation_base(sequencer, targetSequence, lastKnownPublished) + , m_scheduler(scheduler) + {} + + multi_producer_sequencer_wait_operation( + const multi_producer_sequencer_wait_operation& other) noexcept + : multi_producer_sequencer_wait_operation_base(other) + , m_scheduler(other.m_scheduler) + {} + + ~multi_producer_sequencer_wait_operation() + { + if (m_isScheduleAwaiterCreated) + { + m_scheduleAwaiter.destruct(); + } + if (m_isScheduleOperationCreated) + { + m_scheduleOperation.destruct(); + } + } + + SEQUENCE await_resume() noexcept(noexcept(m_scheduleOperation->await_resume())) + { + if (m_isScheduleOperationCreated) + { + m_scheduleOperation->await_resume(); + } + + return multi_producer_sequencer_wait_operation_base::await_resume(); + } + + private: + + void resume_impl() noexcept override + { + try + { + m_scheduleOperation.construct(m_scheduler.schedule()); + m_isScheduleOperationCreated = true; + + m_scheduleAwaiter.construct(detail::get_awaiter( + static_cast(*m_scheduleOperation))); + m_isScheduleAwaiterCreated = true; + + if (!m_scheduleAwaiter->await_ready()) + { + using await_suspend_result_t = decltype(m_scheduleAwaiter->await_suspend(this->m_awaitingCoroutine)); + if constexpr (std::is_void_v) + { + m_scheduleAwaiter->await_suspend(this->m_awaitingCoroutine); + return; + } + else if constexpr (std::is_same_v) + { + if (m_scheduleAwaiter->await_suspend(this->m_awaitingCoroutine)) + { + return; + } + } + else + { + // Assume it returns a coroutine_handle. + m_scheduleAwaiter->await_suspend(this->m_awaitingCoroutine).resume(); + return; + } + } + } + catch (...) + { + // Ignore failure to reschedule and resume inline? + // Should we catch the exception and rethrow from await_resume()? + // Or should we require that 'co_await scheduler.schedule()' is noexcept? + } + + // Resume outside the catch-block. + this->m_awaitingCoroutine.resume(); + } + + SCHEDULER& m_scheduler; + // Can't use std::optional here since T could be a reference. + detail::manual_lifetime m_scheduleOperation; + detail::manual_lifetime::awaiter_t> m_scheduleAwaiter; + bool m_isScheduleOperationCreated = false; + bool m_isScheduleAwaiterCreated = false; + + }; + + template + multi_producer_sequencer::multi_producer_sequencer( + const sequence_barrier& consumerBarrier, + std::size_t bufferSize, + SEQUENCE initialSequence) + : m_consumerBarrier(consumerBarrier) + , m_sequenceMask(bufferSize - 1) + , m_published(std::make_unique[]>(bufferSize)) + , m_nextToClaim(initialSequence + 1) + , m_awaiters(nullptr) + { + // bufferSize must be a positive power-of-two + assert(bufferSize > 0 && (bufferSize & (bufferSize - 1)) == 0); + // but must be no larger than the max diff value. + using diff_t = typename TRAITS::difference_type; + using unsigned_diff_t = std::make_unsigned_t; + constexpr unsigned_diff_t maxSize = static_cast(std::numeric_limits::max()); + assert(bufferSize <= maxSize); + + SEQUENCE seq = initialSequence - (bufferSize - 1); + do + { +#ifdef __cpp_lib_atomic_value_initialization + m_published[seq & m_sequenceMask].store(seq, std::memory_order_relaxed); +#else // ^^^ __cpp_lib_atomic_value_initialization // !__cpp_lib_atomic_value_initialization vvv + std::atomic_init(&m_published[seq & m_sequenceMask], seq); +#endif // !__cpp_lib_atomic_value_initialization + } while (seq++ != initialSequence); + } + + template + SEQUENCE multi_producer_sequencer::last_published_after( + SEQUENCE lastKnownPublished) const noexcept + { + const auto mask = m_sequenceMask; + SEQUENCE seq = lastKnownPublished + 1; + while (m_published[seq & mask].load(std::memory_order_acquire) == seq) + { + lastKnownPublished = seq++; + } + return lastKnownPublished; + } + + template + template + multi_producer_sequencer_wait_operation + multi_producer_sequencer::wait_until_published( + SEQUENCE targetSequence, + SEQUENCE lastKnownPublished, + SCHEDULER& scheduler) const noexcept + { + return multi_producer_sequencer_wait_operation{ + *this, targetSequence, lastKnownPublished, scheduler + }; + } + + template + bool multi_producer_sequencer::any_available() const noexcept + { + return TRAITS::precedes( + m_nextToClaim.load(std::memory_order_relaxed), + m_consumerBarrier.last_published() + buffer_size()); + } + + template + template + multi_producer_sequencer_claim_one_operation + multi_producer_sequencer::claim_one(SCHEDULER& scheduler) noexcept + { + return multi_producer_sequencer_claim_one_operation{ *this, scheduler }; + } + + template + template + multi_producer_sequencer_claim_operation + multi_producer_sequencer::claim_up_to(std::size_t count, SCHEDULER& scheduler) noexcept + { + return multi_producer_sequencer_claim_operation{ *this, count, scheduler }; + } + + template + void multi_producer_sequencer::publish(SEQUENCE sequence) noexcept + { + m_published[sequence & m_sequenceMask].store(sequence, std::memory_order_seq_cst); + + // Resume any waiters that might have been satisfied by this publish operation. + resume_ready_awaiters(); + } + + template + void multi_producer_sequencer::publish(const sequence_range& range) noexcept + { + if (range.empty()) + { + return; + } + + // Publish all but the first sequence number using relaxed atomics. + // No consumer should be reading those subsequent sequence numbers until they've seen + // that the first sequence number in the range is published. + for (SEQUENCE seq : range.skip(1)) + { + m_published[seq & m_sequenceMask].store(seq, std::memory_order_relaxed); + } + + // Now publish the first sequence number with seq_cst semantics. + m_published[range.front() & m_sequenceMask].store(range.front(), std::memory_order_seq_cst); + + // Resume any waiters that might have been satisfied by this publish operation. + resume_ready_awaiters(); + } + + template + void multi_producer_sequencer::resume_ready_awaiters() noexcept + { + using awaiter_t = multi_producer_sequencer_wait_operation_base; + + awaiter_t* awaiters = m_awaiters.load(std::memory_order_seq_cst); + if (awaiters == nullptr) + { + // No awaiters + return; + } + + // There were some awaiters. Try to acquire the list of waiters with an + // atomic exchange as we might be racing with other consumers/producers. + awaiters = m_awaiters.exchange(nullptr, std::memory_order_seq_cst); + if (awaiters == nullptr) + { + // Didn't acquire the list + // Some other thread is now responsible for resuming them. Our job is done. + return; + } + + SEQUENCE lastKnownPublished; + + awaiter_t* awaitersToResume; + awaiter_t** awaitersToResumeTail = &awaitersToResume; + + awaiter_t* awaitersToRequeue; + awaiter_t** awaitersToRequeueTail = &awaitersToRequeue; + + do + { + using diff_t = typename TRAITS::difference_type; + + lastKnownPublished = last_published_after(awaiters->m_lastKnownPublished); + + // First scan the list of awaiters and split them into 'requeue' and 'resume' lists. + auto minDiff = std::numeric_limits::max(); + do + { + auto diff = TRAITS::difference(awaiters->m_targetSequence, lastKnownPublished); + if (diff > 0) + { + // Not ready yet. + minDiff = diff < minDiff ? diff : minDiff; + *awaitersToRequeueTail = awaiters; + awaitersToRequeueTail = &awaiters->m_next; + } + else + { + *awaitersToResumeTail = awaiters; + awaitersToResumeTail = &awaiters->m_next; + } + awaiters->m_lastKnownPublished = lastKnownPublished; + awaiters = awaiters->m_next; + } while (awaiters != nullptr); + + // Null-terinate the requeue list + *awaitersToRequeueTail = nullptr; + + if (awaitersToRequeue != nullptr) + { + // Requeue the waiters that are not ready yet. + awaiter_t* oldHead = nullptr; + while (!m_awaiters.compare_exchange_weak(oldHead, awaitersToRequeue, std::memory_order_seq_cst, std::memory_order_relaxed)) + { + *awaitersToRequeueTail = oldHead; + } + + // Reset the awaitersToRequeue list + awaitersToRequeueTail = &awaitersToRequeue; + + const SEQUENCE earliestTargetSequence = lastKnownPublished + minDiff; + + // Now we need to check again to see if any of the waiters we just enqueued + // is now satisfied by a concurrent call to publish(). + // + // We need to be a bit more careful here since we are no longer holding any + // awaiters and so producers/consumers may advance the sequence number arbitrarily + // far. If the sequence number advances more than buffer_size() ahead of the + // earliestTargetSequence then the m_published[] array may have sequence numbers + // that have advanced beyond earliestTargetSequence, potentially even wrapping + // sequence numbers around to then be preceding where they were before. If this + // happens then we don't need to worry about resuming any awaiters that were waiting + // for 'earliestTargetSequence' since some other thread has already resumed them. + // So the only case we need to worry about here is when all m_published entries for + // sequence numbers in range [lastKnownPublished + 1, earliestTargetSequence] have + // published sequence numbers that match the range. + const auto sequenceMask = m_sequenceMask; + SEQUENCE seq = lastKnownPublished + 1; + while (m_published[seq & sequenceMask].load(std::memory_order_seq_cst) == seq) + { + lastKnownPublished = seq; + if (seq == earliestTargetSequence) + { + // At least one of the awaiters we just published is now satisfied. + // Reacquire the list of awaiters and continue around the outer loop. + awaiters = m_awaiters.exchange(nullptr, std::memory_order_acquire); + break; + } + ++seq; + } + } + } while (awaiters != nullptr); + + // Null-terminate list of awaiters to resume. + *awaitersToResumeTail = nullptr; + + while (awaitersToResume != nullptr) + { + awaiter_t* next = awaitersToResume->m_next; + awaitersToResume->resume(lastKnownPublished); + awaitersToResume = next; + } + } + + template + void multi_producer_sequencer::add_awaiter( + multi_producer_sequencer_wait_operation_base* awaiter) const noexcept + { + using awaiter_t = multi_producer_sequencer_wait_operation_base; + + SEQUENCE targetSequence = awaiter->m_targetSequence; + SEQUENCE lastKnownPublished = awaiter->m_lastKnownPublished; + + awaiter_t* awaitersToEnqueue = awaiter; + awaiter_t** awaitersToEnqueueTail = &awaiter->m_next; + + awaiter_t* awaitersToResume; + awaiter_t** awaitersToResumeTail = &awaitersToResume; + + const SEQUENCE sequenceMask = m_sequenceMask; + + do + { + // Enqueue the awaiters. + { + awaiter_t* oldHead = m_awaiters.load(std::memory_order_relaxed); + do + { + *awaitersToEnqueueTail = oldHead; + } while (!m_awaiters.compare_exchange_weak( + oldHead, + awaitersToEnqueue, + std::memory_order_seq_cst, + std::memory_order_relaxed)); + } + + // Reset list of waiters + awaitersToEnqueueTail = &awaitersToEnqueue; + + // Check to see if the last-known published sequence number has advanced + // while we were enqueuing the awaiters. Need to use seq_cst memory order + // here to ensure that if there are concurrent calls to publish() that would + // wake up any of the awaiters we just enqueued that either we will see their + // write to m_published slots or they will see our write to m_awaiters. + // + // Note also, that we are assuming that the last-known published sequence is + // not going to advance more than buffer_size() ahead of targetSequence since + // there is at least one consumer that won't be resumed and so thus can't + // publish the sequence number it's waiting for to its sequence_barrier and so + // producers won't be able to claim its slot in the buffer. + // + // TODO: Check whether we can weaken the memory order here to just use 'seq_cst' on the + // first .load() and then use 'acquire' on subsequent .load(). + while (m_published[(lastKnownPublished + 1) & sequenceMask].load(std::memory_order_seq_cst) == (lastKnownPublished + 1)) + { + ++lastKnownPublished; + } + + if (!TRAITS::precedes(lastKnownPublished, targetSequence)) + { + // At least one awaiter we just enqueued has now been satisified. + // To ensure it is woken up we need to reacquire the list of awaiters and resume + awaiter_t* awaiters = m_awaiters.exchange(nullptr, std::memory_order_acquire); + + using diff_t = typename TRAITS::difference_type; + + diff_t minDiff = std::numeric_limits::max(); + + while (awaiters != nullptr) + { + diff_t diff = TRAITS::difference(targetSequence, lastKnownPublished); + if (diff > 0) + { + // Not yet ready. + minDiff = diff < minDiff ? diff : minDiff; + *awaitersToEnqueueTail = awaiters; + awaitersToEnqueueTail = &awaiters->m_next; + awaiters->m_lastKnownPublished = lastKnownPublished; + } + else + { + // Now ready. + *awaitersToResumeTail = awaiters; + awaitersToResumeTail = &awaiters->m_next; + } + awaiters = awaiters->m_next; + } + + // Calculate the earliest sequence number that any awaiters in the + // awaitersToEnqueue list are waiting for. We'll use this next time + // around the loop. + targetSequence = static_cast(lastKnownPublished + minDiff); + } + + // Null-terminate list of awaiters to enqueue. + *awaitersToEnqueueTail = nullptr; + + } while (awaitersToEnqueue != nullptr); + + // Null-terminate awaiters to resume. + *awaitersToResumeTail = nullptr; + + // Finally, resume any awaiters we've found that are ready to go. + while (awaitersToResume != nullptr) + { + // Read m_next before calling .resume() as resuming could destroy the awaiter. + awaiter_t* next = awaitersToResume->m_next; + awaitersToResume->resume(lastKnownPublished); + awaitersToResume = next; + } + } +} + +#endif diff --git a/include/cppcoro/net/ip_address.hpp b/include/cppcoro/net/ip_address.hpp new file mode 100644 index 0000000..f1d847f --- /dev/null +++ b/include/cppcoro/net/ip_address.hpp @@ -0,0 +1,147 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_NET_IP_ADDRESS_HPP_INCLUDED +#define CPPCORO_NET_IP_ADDRESS_HPP_INCLUDED + +#include +#include + +#include +#include +#include + +namespace cppcoro +{ + namespace net + { + class ip_address + { + public: + + // Constructs to IPv4 address 0.0.0.0 + ip_address() noexcept; + + ip_address(ipv4_address address) noexcept; + ip_address(ipv6_address address) noexcept; + + bool is_ipv4() const noexcept { return m_family == family::ipv4; } + bool is_ipv6() const noexcept { return m_family == family::ipv6; } + + const ipv4_address& to_ipv4() const; + const ipv6_address& to_ipv6() const; + + const std::uint8_t* bytes() const noexcept; + + std::string to_string() const; + + static std::optional from_string(std::string_view string) noexcept; + + bool operator==(const ip_address& rhs) const noexcept; + bool operator!=(const ip_address& rhs) const noexcept; + + // ipv4_address sorts less than ipv6_address + bool operator<(const ip_address& rhs) const noexcept; + bool operator>(const ip_address& rhs) const noexcept; + bool operator<=(const ip_address& rhs) const noexcept; + bool operator>=(const ip_address& rhs) const noexcept; + + private: + + enum class family + { + ipv4, + ipv6 + }; + + family m_family; + + union + { + ipv4_address m_ipv4; + ipv6_address m_ipv6; + }; + + }; + + inline ip_address::ip_address() noexcept + : m_family(family::ipv4) + , m_ipv4() + {} + + inline ip_address::ip_address(ipv4_address address) noexcept + : m_family(family::ipv4) + , m_ipv4(address) + {} + + inline ip_address::ip_address(ipv6_address address) noexcept + : m_family(family::ipv6) + , m_ipv6(address) + { + } + + inline const ipv4_address& ip_address::to_ipv4() const + { + assert(is_ipv4()); + return m_ipv4; + } + + inline const ipv6_address& ip_address::to_ipv6() const + { + assert(is_ipv6()); + return m_ipv6; + } + + inline const std::uint8_t* ip_address::bytes() const noexcept + { + return is_ipv4() ? m_ipv4.bytes() : m_ipv6.bytes(); + } + + inline bool ip_address::operator==(const ip_address& rhs) const noexcept + { + if (is_ipv4()) + { + return rhs.is_ipv4() && m_ipv4 == rhs.m_ipv4; + } + else + { + return rhs.is_ipv6() && m_ipv6 == rhs.m_ipv6; + } + } + + inline bool ip_address::operator!=(const ip_address& rhs) const noexcept + { + return !(*this == rhs); + } + + inline bool ip_address::operator<(const ip_address& rhs) const noexcept + { + if (is_ipv4()) + { + return !rhs.is_ipv4() || m_ipv4 < rhs.m_ipv4; + } + else + { + return rhs.is_ipv6() && m_ipv6 < rhs.m_ipv6; + } + } + + inline bool ip_address::operator>(const ip_address& rhs) const noexcept + { + return rhs < *this; + } + + inline bool ip_address::operator<=(const ip_address& rhs) const noexcept + { + return !(rhs < *this); + } + + inline bool ip_address::operator>=(const ip_address& rhs) const noexcept + { + return !(*this < rhs); + } + } +} + +#endif diff --git a/include/cppcoro/net/ip_endpoint.hpp b/include/cppcoro/net/ip_endpoint.hpp new file mode 100644 index 0000000..d15422d --- /dev/null +++ b/include/cppcoro/net/ip_endpoint.hpp @@ -0,0 +1,161 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_NET_IP_ENDPOINT_HPP_INCLUDED +#define CPPCORO_NET_IP_ENDPOINT_HPP_INCLUDED + +#include +#include +#include + +#include +#include +#include + +namespace cppcoro +{ + namespace net + { + class ip_endpoint + { + public: + + // Constructs to IPv4 end-point 0.0.0.0:0 + ip_endpoint() noexcept; + + ip_endpoint(ipv4_endpoint endpoint) noexcept; + ip_endpoint(ipv6_endpoint endpoint) noexcept; + + bool is_ipv4() const noexcept { return m_family == family::ipv4; } + bool is_ipv6() const noexcept { return m_family == family::ipv6; } + + const ipv4_endpoint& to_ipv4() const; + const ipv6_endpoint& to_ipv6() const; + + ip_address address() const noexcept; + std::uint16_t port() const noexcept; + + std::string to_string() const; + + static std::optional from_string(std::string_view string) noexcept; + + bool operator==(const ip_endpoint& rhs) const noexcept; + bool operator!=(const ip_endpoint& rhs) const noexcept; + + // ipv4_endpoint sorts less than ipv6_endpoint + bool operator<(const ip_endpoint& rhs) const noexcept; + bool operator>(const ip_endpoint& rhs) const noexcept; + bool operator<=(const ip_endpoint& rhs) const noexcept; + bool operator>=(const ip_endpoint& rhs) const noexcept; + + private: + + enum class family + { + ipv4, + ipv6 + }; + + family m_family; + + union + { + ipv4_endpoint m_ipv4; + ipv6_endpoint m_ipv6; + }; + + }; + + inline ip_endpoint::ip_endpoint() noexcept + : m_family(family::ipv4) + , m_ipv4() + {} + + inline ip_endpoint::ip_endpoint(ipv4_endpoint endpoint) noexcept + : m_family(family::ipv4) + , m_ipv4(endpoint) + {} + + inline ip_endpoint::ip_endpoint(ipv6_endpoint endpoint) noexcept + : m_family(family::ipv6) + , m_ipv6(endpoint) + { + } + + inline const ipv4_endpoint& ip_endpoint::to_ipv4() const + { + assert(is_ipv4()); + return m_ipv4; + } + + inline const ipv6_endpoint& ip_endpoint::to_ipv6() const + { + assert(is_ipv6()); + return m_ipv6; + } + + inline ip_address ip_endpoint::address() const noexcept + { + if (is_ipv4()) + { + return m_ipv4.address(); + } + else + { + return m_ipv6.address(); + } + } + + inline std::uint16_t ip_endpoint::port() const noexcept + { + return is_ipv4() ? m_ipv4.port() : m_ipv6.port(); + } + + inline bool ip_endpoint::operator==(const ip_endpoint& rhs) const noexcept + { + if (is_ipv4()) + { + return rhs.is_ipv4() && m_ipv4 == rhs.m_ipv4; + } + else + { + return rhs.is_ipv6() && m_ipv6 == rhs.m_ipv6; + } + } + + inline bool ip_endpoint::operator!=(const ip_endpoint& rhs) const noexcept + { + return !(*this == rhs); + } + + inline bool ip_endpoint::operator<(const ip_endpoint& rhs) const noexcept + { + if (is_ipv4()) + { + return !rhs.is_ipv4() || m_ipv4 < rhs.m_ipv4; + } + else + { + return rhs.is_ipv6() && m_ipv6 < rhs.m_ipv6; + } + } + + inline bool ip_endpoint::operator>(const ip_endpoint& rhs) const noexcept + { + return rhs < *this; + } + + inline bool ip_endpoint::operator<=(const ip_endpoint& rhs) const noexcept + { + return !(rhs < *this); + } + + inline bool ip_endpoint::operator>=(const ip_endpoint& rhs) const noexcept + { + return !(*this < rhs); + } + } +} + +#endif diff --git a/include/cppcoro/net/ipv4_address.hpp b/include/cppcoro/net/ipv4_address.hpp new file mode 100644 index 0000000..7a5dd43 --- /dev/null +++ b/include/cppcoro/net/ipv4_address.hpp @@ -0,0 +1,134 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_NET_IPV4_ADDRESS_HPP_INCLUDED +#define CPPCORO_NET_IPV4_ADDRESS_HPP_INCLUDED + +#include +#include +#include +#include + +namespace cppcoro::net +{ + class ipv4_address + { + using bytes_t = std::uint8_t[4]; + + public: + + constexpr ipv4_address() + : m_bytes{ 0, 0, 0, 0 } + {} + + explicit constexpr ipv4_address(std::uint32_t integer) + : m_bytes{ + static_cast(integer >> 24), + static_cast(integer >> 16), + static_cast(integer >> 8), + static_cast(integer) } + {} + + explicit constexpr ipv4_address(const std::uint8_t(&bytes)[4]) + : m_bytes{ bytes[0], bytes[1], bytes[2], bytes[3] } + {} + + explicit constexpr ipv4_address( + std::uint8_t b0, + std::uint8_t b1, + std::uint8_t b2, + std::uint8_t b3) + : m_bytes{ b0, b1, b2, b3 } + {} + + constexpr const bytes_t& bytes() const { return m_bytes; } + + constexpr std::uint32_t to_integer() const + { + return + std::uint32_t(m_bytes[0]) << 24 | + std::uint32_t(m_bytes[1]) << 16 | + std::uint32_t(m_bytes[2]) << 8 | + std::uint32_t(m_bytes[3]); + } + + static constexpr ipv4_address loopback() + { + return ipv4_address(127, 0, 0, 1); + } + + constexpr bool is_loopback() const + { + return m_bytes[0] == 127; + } + + constexpr bool is_private_network() const + { + return m_bytes[0] == 10 || + (m_bytes[0] == 172 && (m_bytes[1] & 0xF0) == 0x10) || + (m_bytes[0] == 192 && m_bytes[2] == 168); + } + + constexpr bool operator==(ipv4_address other) const + { + return + m_bytes[0] == other.m_bytes[0] && + m_bytes[1] == other.m_bytes[1] && + m_bytes[2] == other.m_bytes[2] && + m_bytes[3] == other.m_bytes[3]; + } + + constexpr bool operator!=(ipv4_address other) const + { + return !(*this == other); + } + + constexpr bool operator<(ipv4_address other) const + { + return to_integer() < other.to_integer(); + } + + constexpr bool operator>(ipv4_address other) const + { + return other < *this; + } + + constexpr bool operator<=(ipv4_address other) const + { + return !(other < *this); + } + + constexpr bool operator>=(ipv4_address other) const + { + return !(*this < other); + } + + /// Parse a string representation of an IP address. + /// + /// Parses strings of the form: + /// - "num.num.num.num" where num is an integer in range [0, 255]. + /// - A single integer value in range [0, 2^32). + /// + /// \param string + /// The string to parse. + /// Must be in ASCII, UTF-8 or Latin-1 encoding. + /// + /// \return + /// The IP address if successful, otherwise std::nullopt if the string + /// could not be parsed as an IPv4 address. + static std::optional from_string(std::string_view string) noexcept; + + /// Convert the IP address to dotted decimal notation. + /// + /// eg. "12.67.190.23" + std::string to_string() const; + + private: + + alignas(std::uint32_t) std::uint8_t m_bytes[4]; + + }; +} + +#endif diff --git a/include/cppcoro/net/ipv4_endpoint.hpp b/include/cppcoro/net/ipv4_endpoint.hpp new file mode 100644 index 0000000..11ee72e --- /dev/null +++ b/include/cppcoro/net/ipv4_endpoint.hpp @@ -0,0 +1,82 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_NET_IPV4_ENDPOINT_HPP_INCLUDED +#define CPPCORO_NET_IPV4_ENDPOINT_HPP_INCLUDED + +#include + +#include +#include +#include + +namespace cppcoro +{ + namespace net + { + class ipv4_endpoint + { + public: + + // Construct to 0.0.0.0:0 + ipv4_endpoint() noexcept + : m_address() + , m_port(0) + {} + + explicit ipv4_endpoint(ipv4_address address, std::uint16_t port = 0) noexcept + : m_address(address) + , m_port(port) + {} + + const ipv4_address& address() const noexcept { return m_address; } + + std::uint16_t port() const noexcept { return m_port; } + + std::string to_string() const; + + static std::optional from_string(std::string_view string) noexcept; + + private: + + ipv4_address m_address; + std::uint16_t m_port; + + }; + + inline bool operator==(const ipv4_endpoint& a, const ipv4_endpoint& b) + { + return a.address() == b.address() && + a.port() == b.port(); + } + + inline bool operator!=(const ipv4_endpoint& a, const ipv4_endpoint& b) + { + return !(a == b); + } + + inline bool operator<(const ipv4_endpoint& a, const ipv4_endpoint& b) + { + return a.address() < b.address() || + (a.address() == b.address() && a.port() < b.port()); + } + + inline bool operator>(const ipv4_endpoint& a, const ipv4_endpoint& b) + { + return b < a; + } + + inline bool operator<=(const ipv4_endpoint& a, const ipv4_endpoint& b) + { + return !(b < a); + } + + inline bool operator>=(const ipv4_endpoint& a, const ipv4_endpoint& b) + { + return !(a < b); + } + } +} + +#endif diff --git a/include/cppcoro/net/ipv6_address.hpp b/include/cppcoro/net/ipv6_address.hpp new file mode 100644 index 0000000..46a92d7 --- /dev/null +++ b/include/cppcoro/net/ipv6_address.hpp @@ -0,0 +1,245 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_NET_IPV6_ADDRESS_HPP_INCLUDED +#define CPPCORO_NET_IPV6_ADDRESS_HPP_INCLUDED + +#include +#include +#include +#include + +namespace cppcoro::net +{ + class ipv4_address; + + class ipv6_address + { + using bytes_t = std::uint8_t[16]; + + public: + + constexpr ipv6_address(); + + explicit constexpr ipv6_address( + std::uint64_t subnetPrefix, + std::uint64_t interfaceIdentifier); + + constexpr ipv6_address( + std::uint16_t part0, + std::uint16_t part1, + std::uint16_t part2, + std::uint16_t part3, + std::uint16_t part4, + std::uint16_t part5, + std::uint16_t part6, + std::uint16_t part7); + + explicit constexpr ipv6_address( + const std::uint16_t(&parts)[8]); + + explicit constexpr ipv6_address( + const std::uint8_t(&bytes)[16]); + + constexpr const bytes_t& bytes() const { return m_bytes; } + + constexpr std::uint64_t subnet_prefix() const; + + constexpr std::uint64_t interface_identifier() const; + + /// Get the IPv6 unspedified address :: (all zeroes). + static constexpr ipv6_address unspecified(); + + /// Get the IPv6 loopback address ::1. + static constexpr ipv6_address loopback(); + + /// Parse a string representation of an IPv6 address. + /// + /// \param string + /// The string to parse. + /// Must be in ASCII, UTF-8 or Latin-1 encoding. + /// + /// \return + /// The IP address if successful, otherwise std::nullopt if the string + /// could not be parsed as an IPv4 address. + static std::optional from_string(std::string_view string) noexcept; + + /// Convert the IP address to contracted string form. + /// + /// Address is broken up into 16-bit parts, with each part represended in 1-4 + /// lower-case hexadecimal with leading zeroes omitted. Parts are separated + /// by separated by a ':'. The longest contiguous run of zero parts is contracted + /// to "::". + /// + /// For example: + /// ipv6_address::unspecified() -> "::" + /// ipv6_address::loopback() -> "::1" + /// ipv6_address(0x0011223344556677, 0x8899aabbccddeeff) -> + /// "11:2233:4455:6677:8899:aabb:ccdd:eeff" + /// ipv6_address(0x0102030400000000, 0x003fc447ab991011) -> + /// "102:304::3f:c447:ab99:1011" + std::string to_string() const; + + constexpr bool operator==(const ipv6_address& other) const; + constexpr bool operator!=(const ipv6_address& other) const; + constexpr bool operator<(const ipv6_address& other) const; + constexpr bool operator>(const ipv6_address& other) const; + constexpr bool operator<=(const ipv6_address& other) const; + constexpr bool operator>=(const ipv6_address& other) const; + + private: + + alignas(std::uint64_t) std::uint8_t m_bytes[16]; + + }; + + constexpr ipv6_address::ipv6_address() + : m_bytes{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 } + {} + + constexpr ipv6_address::ipv6_address( + std::uint64_t subnetPrefix, + std::uint64_t interfaceIdentifier) + : m_bytes{ + static_cast(subnetPrefix >> 56), + static_cast(subnetPrefix >> 48), + static_cast(subnetPrefix >> 40), + static_cast(subnetPrefix >> 32), + static_cast(subnetPrefix >> 24), + static_cast(subnetPrefix >> 16), + static_cast(subnetPrefix >> 8), + static_cast(subnetPrefix), + static_cast(interfaceIdentifier >> 56), + static_cast(interfaceIdentifier >> 48), + static_cast(interfaceIdentifier >> 40), + static_cast(interfaceIdentifier >> 32), + static_cast(interfaceIdentifier >> 24), + static_cast(interfaceIdentifier >> 16), + static_cast(interfaceIdentifier >> 8), + static_cast(interfaceIdentifier) } + {} + + constexpr ipv6_address::ipv6_address( + std::uint16_t part0, + std::uint16_t part1, + std::uint16_t part2, + std::uint16_t part3, + std::uint16_t part4, + std::uint16_t part5, + std::uint16_t part6, + std::uint16_t part7) + : m_bytes{ + static_cast(part0 >> 8), + static_cast(part0), + static_cast(part1 >> 8), + static_cast(part1), + static_cast(part2 >> 8), + static_cast(part2), + static_cast(part3 >> 8), + static_cast(part3), + static_cast(part4 >> 8), + static_cast(part4), + static_cast(part5 >> 8), + static_cast(part5), + static_cast(part6 >> 8), + static_cast(part6), + static_cast(part7 >> 8), + static_cast(part7) } + {} + + constexpr ipv6_address::ipv6_address( + const std::uint16_t(&parts)[8]) + : ipv6_address( + parts[0], parts[1], parts[2], parts[3], + parts[4], parts[5], parts[6], parts[7]) + {} + + constexpr ipv6_address::ipv6_address(const std::uint8_t(&bytes)[16]) + : m_bytes{ + bytes[0], bytes[1], bytes[2], bytes[3], + bytes[4], bytes[5], bytes[6], bytes[7], + bytes[8], bytes[9], bytes[10], bytes[11], + bytes[12], bytes[13], bytes[14], bytes[15] } + {} + + constexpr std::uint64_t ipv6_address::subnet_prefix() const + { + return + static_cast(m_bytes[0]) << 56 | + static_cast(m_bytes[1]) << 48 | + static_cast(m_bytes[2]) << 40 | + static_cast(m_bytes[3]) << 32 | + static_cast(m_bytes[4]) << 24 | + static_cast(m_bytes[5]) << 16 | + static_cast(m_bytes[6]) << 8 | + static_cast(m_bytes[7]); + } + + constexpr std::uint64_t ipv6_address::interface_identifier() const + { + return + static_cast(m_bytes[8]) << 56 | + static_cast(m_bytes[9]) << 48 | + static_cast(m_bytes[10]) << 40 | + static_cast(m_bytes[11]) << 32 | + static_cast(m_bytes[12]) << 24 | + static_cast(m_bytes[13]) << 16 | + static_cast(m_bytes[14]) << 8 | + static_cast(m_bytes[15]); + } + + constexpr ipv6_address ipv6_address::unspecified() + { + return ipv6_address{}; + } + + constexpr ipv6_address ipv6_address::loopback() + { + return ipv6_address{ 0, 0, 0, 0, 0, 0, 0, 1 }; + } + + constexpr bool ipv6_address::operator==(const ipv6_address& other) const + { + for (int i = 0; i < 16; ++i) + { + if (m_bytes[i] != other.m_bytes[i]) return false; + } + return true; + } + + constexpr bool ipv6_address::operator!=(const ipv6_address& other) const + { + return !(*this == other); + } + + constexpr bool ipv6_address::operator<(const ipv6_address& other) const + { + for (int i = 0; i < 16; ++i) + { + if (m_bytes[i] != other.m_bytes[i]) + return m_bytes[i] < other.m_bytes[i]; + } + + return false; + } + + constexpr bool ipv6_address::operator>(const ipv6_address& other) const + { + return (other < *this); + } + + constexpr bool ipv6_address::operator<=(const ipv6_address& other) const + { + return !(other < *this); + } + + constexpr bool ipv6_address::operator>=(const ipv6_address& other) const + { + return !(*this < other); + } +} + +#endif diff --git a/include/cppcoro/net/ipv6_endpoint.hpp b/include/cppcoro/net/ipv6_endpoint.hpp new file mode 100644 index 0000000..d0e50bb --- /dev/null +++ b/include/cppcoro/net/ipv6_endpoint.hpp @@ -0,0 +1,82 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_NET_IPV6_ENDPOINT_HPP_INCLUDED +#define CPPCORO_NET_IPV6_ENDPOINT_HPP_INCLUDED + +#include + +#include +#include +#include + +namespace cppcoro +{ + namespace net + { + class ipv6_endpoint + { + public: + + // Construct to [::]:0 + ipv6_endpoint() noexcept + : m_address() + , m_port(0) + {} + + explicit ipv6_endpoint(ipv6_address address, std::uint16_t port = 0) noexcept + : m_address(address) + , m_port(port) + {} + + const ipv6_address& address() const noexcept { return m_address; } + + std::uint16_t port() const noexcept { return m_port; } + + std::string to_string() const; + + static std::optional from_string(std::string_view string) noexcept; + + private: + + ipv6_address m_address; + std::uint16_t m_port; + + }; + + inline bool operator==(const ipv6_endpoint& a, const ipv6_endpoint& b) + { + return a.address() == b.address() && + a.port() == b.port(); + } + + inline bool operator!=(const ipv6_endpoint& a, const ipv6_endpoint& b) + { + return !(a == b); + } + + inline bool operator<(const ipv6_endpoint& a, const ipv6_endpoint& b) + { + return a.address() < b.address() || + (a.address() == b.address() && a.port() < b.port()); + } + + inline bool operator>(const ipv6_endpoint& a, const ipv6_endpoint& b) + { + return b < a; + } + + inline bool operator<=(const ipv6_endpoint& a, const ipv6_endpoint& b) + { + return !(b < a); + } + + inline bool operator>=(const ipv6_endpoint& a, const ipv6_endpoint& b) + { + return !(a < b); + } + } +} + +#endif diff --git a/include/cppcoro/net/socket.hpp b/include/cppcoro/net/socket.hpp new file mode 100644 index 0000000..a61eac6 --- /dev/null +++ b/include/cppcoro/net/socket.hpp @@ -0,0 +1,268 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_NET_SOCKET_HPP_INCLUDED +#define CPPCORO_NET_SOCKET_HPP_INCLUDED + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if CPPCORO_OS_WINNT +# include +#endif + +namespace cppcoro +{ + class io_service; + + namespace net + { + class socket + { + public: + + /// Create a socket that can be used to communicate using TCP/IPv4 protocol. + /// + /// \param ioSvc + /// The I/O service the socket will use for dispatching I/O completion events. + /// + /// \return + /// The newly created socket. + /// + /// \throws std::system_error + /// If the socket could not be created for some reason. + static socket create_tcpv4(io_service& ioSvc); + + /// Create a socket that can be used to communicate using TCP/IPv6 protocol. + /// + /// \param ioSvc + /// The I/O service the socket will use for dispatching I/O completion events. + /// + /// \return + /// The newly created socket. + /// + /// \throws std::system_error + /// If the socket could not be created for some reason. + static socket create_tcpv6(io_service& ioSvc); + + /// Create a socket that can be used to communicate using UDP/IPv4 protocol. + /// + /// \param ioSvc + /// The I/O service the socket will use for dispatching I/O completion events. + /// + /// \return + /// The newly created socket. + /// + /// \throws std::system_error + /// If the socket could not be created for some reason. + static socket create_udpv4(io_service& ioSvc); + + /// Create a socket that can be used to communicate using UDP/IPv6 protocol. + /// + /// \param ioSvc + /// The I/O service the socket will use for dispatching I/O completion events. + /// + /// \return + /// The newly created socket. + /// + /// \throws std::system_error + /// If the socket could not be created for some reason. + static socket create_udpv6(io_service& ioSvc); + + socket(socket&& other) noexcept; + + /// Closes the socket, releasing any associated resources. + /// + /// If the socket still has an open connection then the connection will be + /// reset. The destructor will not block waiting for queueud data to be sent. + /// If you need to ensure that queued data is delivered then you must call + /// disconnect() and wait until the disconnect operation completes. + ~socket(); + + socket& operator=(socket&& other) noexcept; + +#if CPPCORO_OS_WINNT + /// Get the Win32 socket handle assocaited with this socket. + cppcoro::detail::win32::socket_t native_handle() noexcept { return m_handle; } + + /// Query whether I/O operations that complete synchronously will skip posting + /// an I/O completion event to the I/O completion port. + /// + /// The operation class implementations can use this to determine whether or not + /// it should immediately resume the coroutine on the current thread upon an + /// operation completing synchronously or whether it should suspend the coroutine + /// and wait until the I/O completion event is dispatched to an I/O thread. + bool skip_completion_on_success() noexcept { return m_skipCompletionOnSuccess; } +#endif + + /// Get the address and port of the local end-point. + /// + /// If the socket is not bound then this will be the unspecified end-point + /// of the socket's associated address-family. + const ip_endpoint& local_endpoint() const noexcept { return m_localEndPoint; } + + /// Get the address and port of the remote end-point. + /// + /// If the socket is not in the connected state then this will be the unspecified + /// end-point of the socket's associated address-family. + const ip_endpoint& remote_endpoint() const noexcept { return m_remoteEndPoint; } + + /// Bind the local end of this socket to the specified local end-point. + /// + /// \param localEndPoint + /// The end-point to bind to. + /// This can be either an unspecified address (in which case it binds to all available + /// interfaces) and/or an unspecified port (in which case a random port is allocated). + /// + /// \throws std::system_error + /// If the socket could not be bound for some reason. + void bind(const ip_endpoint& localEndPoint); + + /// Put the socket into a passive listening state that will start acknowledging + /// and queueing up new connections ready to be accepted by a call to 'accept()'. + /// + /// The backlog of connections ready to be accepted will be set to some default + /// suitable large value, depending on the network provider. If you need more + /// control over the size of the queue then use the overload of listen() + /// that accepts a 'backlog' parameter. + /// + /// \throws std::system_error + /// If the socket could not be placed into a listening mode. + void listen(); + + /// Put the socket into a passive listening state that will start acknowledging + /// and queueing up new connections ready to be accepted by a call to 'accept()'. + /// + /// \param backlog + /// The maximum number of pending connections to allow in the queue of ready-to-accept + /// connections. + /// + /// \throws std::system_error + /// If the socket could not be placed into a listening mode. + void listen(std::uint32_t backlog); + + /// Connect the socket to the specified remote end-point. + /// + /// The socket must be in a bound but unconnected state prior to this call. + /// + /// \param remoteEndPoint + /// The IP address and port-number to connect to. + /// + /// \return + /// An awaitable object that must be co_await'ed to perform the async connect + /// operation. The result of the co_await expression is type void. + [[nodiscard]] + socket_connect_operation connect(const ip_endpoint& remoteEndPoint) noexcept; + + /// Connect to the specified remote end-point. + /// + /// \param remoteEndPoint + /// The IP address and port of the remote end-point to connect to. + /// + /// \param ct + /// A cancellation token that can be used to communicate a request to + /// later cancel the operation. If the operation is successfully + /// cancelled then it will complete by throwing a cppcoro::operation_cancelled + /// exception. + /// + /// \return + /// An awaitable object that will start the connect operation when co_await'ed + /// and will suspend the coroutine, resuming it when the operation completes. + /// The result of the co_await expression has type 'void'. + [[nodiscard]] + socket_connect_operation_cancellable connect( + const ip_endpoint& remoteEndPoint, + cancellation_token ct) noexcept; + + [[nodiscard]] + socket_accept_operation accept(socket& acceptingSocket) noexcept; + [[nodiscard]] + socket_accept_operation_cancellable accept( + socket& acceptingSocket, + cancellation_token ct) noexcept; + + [[nodiscard]] + socket_disconnect_operation disconnect() noexcept; + [[nodiscard]] + socket_disconnect_operation_cancellable disconnect(cancellation_token ct) noexcept; + + [[nodiscard]] + socket_send_operation send( + const void* buffer, + std::size_t size) noexcept; + [[nodiscard]] + socket_send_operation_cancellable send( + const void* buffer, + std::size_t size, + cancellation_token ct) noexcept; + + [[nodiscard]] + socket_recv_operation recv( + void* buffer, + std::size_t size) noexcept; + [[nodiscard]] + socket_recv_operation_cancellable recv( + void* buffer, + std::size_t size, + cancellation_token ct) noexcept; + + [[nodiscard]] + socket_recv_from_operation recv_from( + void* buffer, + std::size_t size) noexcept; + [[nodiscard]] + socket_recv_from_operation_cancellable recv_from( + void* buffer, + std::size_t size, + cancellation_token ct) noexcept; + + [[nodiscard]] + socket_send_to_operation send_to( + const ip_endpoint& destination, + const void* buffer, + std::size_t size) noexcept; + [[nodiscard]] + socket_send_to_operation_cancellable send_to( + const ip_endpoint& destination, + const void* buffer, + std::size_t size, + cancellation_token ct) noexcept; + + void close_send(); + void close_recv(); + + private: + + friend class socket_accept_operation_impl; + friend class socket_connect_operation_impl; + +#if CPPCORO_OS_WINNT + explicit socket( + cppcoro::detail::win32::socket_t handle, + bool skipCompletionOnSuccess) noexcept; +#endif + +#if CPPCORO_OS_WINNT + cppcoro::detail::win32::socket_t m_handle; + bool m_skipCompletionOnSuccess; +#endif + + ip_endpoint m_localEndPoint; + ip_endpoint m_remoteEndPoint; + + }; + } +} + +#endif diff --git a/include/cppcoro/net/socket_accept_operation.hpp b/include/cppcoro/net/socket_accept_operation.hpp new file mode 100644 index 0000000..ae966f0 --- /dev/null +++ b/include/cppcoro/net/socket_accept_operation.hpp @@ -0,0 +1,108 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_NET_SOCKET_ACCEPT_OPERATION_HPP_INCLUDED +#define CPPCORO_NET_SOCKET_ACCEPT_OPERATION_HPP_INCLUDED + +#include +#include +#include + +#if CPPCORO_OS_WINNT +# include +# include + +# include +# include + +namespace cppcoro +{ + namespace net + { + class socket; + + class socket_accept_operation_impl + { + public: + + socket_accept_operation_impl( + socket& listeningSocket, + socket& acceptingSocket) noexcept + : m_listeningSocket(listeningSocket) + , m_acceptingSocket(acceptingSocket) + {} + + bool try_start(cppcoro::detail::win32_overlapped_operation_base& operation) noexcept; + void cancel(cppcoro::detail::win32_overlapped_operation_base& operation) noexcept; + void get_result(cppcoro::detail::win32_overlapped_operation_base& operation); + + private: + +#if CPPCORO_COMPILER_MSVC +# pragma warning(push) +# pragma warning(disable : 4324) // Structure padded due to alignment +#endif + + socket& m_listeningSocket; + socket& m_acceptingSocket; + alignas(8) std::uint8_t m_addressBuffer[88]; + +#if CPPCORO_COMPILER_MSVC +# pragma warning(pop) +#endif + + }; + + class socket_accept_operation + : public cppcoro::detail::win32_overlapped_operation + { + public: + + socket_accept_operation( + socket& listeningSocket, + socket& acceptingSocket) noexcept + : m_impl(listeningSocket, acceptingSocket) + {} + + private: + + friend class cppcoro::detail::win32_overlapped_operation; + + bool try_start() noexcept { return m_impl.try_start(*this); } + void get_result() { m_impl.get_result(*this); } + + socket_accept_operation_impl m_impl; + + }; + + class socket_accept_operation_cancellable + : public cppcoro::detail::win32_overlapped_operation_cancellable + { + public: + + socket_accept_operation_cancellable( + socket& listeningSocket, + socket& acceptingSocket, + cancellation_token&& ct) noexcept + : cppcoro::detail::win32_overlapped_operation_cancellable(std::move(ct)) + , m_impl(listeningSocket, acceptingSocket) + {} + + private: + + friend class cppcoro::detail::win32_overlapped_operation_cancellable; + + bool try_start() noexcept { return m_impl.try_start(*this); } + void cancel() noexcept { m_impl.cancel(*this); } + void get_result() { m_impl.get_result(*this); } + + socket_accept_operation_impl m_impl; + + }; + } +} + +#endif // CPPCORO_OS_WINNT + +#endif diff --git a/include/cppcoro/net/socket_connect_operation.hpp b/include/cppcoro/net/socket_connect_operation.hpp new file mode 100644 index 0000000..b7eedd3 --- /dev/null +++ b/include/cppcoro/net/socket_connect_operation.hpp @@ -0,0 +1,95 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_NET_SOCKET_CONNECT_OPERATION_HPP_INCLUDED +#define CPPCORO_NET_SOCKET_CONNECT_OPERATION_HPP_INCLUDED + +#include +#include +#include + +#if CPPCORO_OS_WINNT +# include +# include + +namespace cppcoro +{ + namespace net + { + class socket; + + class socket_connect_operation_impl + { + public: + + socket_connect_operation_impl( + socket& socket, + const ip_endpoint& remoteEndPoint) noexcept + : m_socket(socket) + , m_remoteEndPoint(remoteEndPoint) + {} + + bool try_start(cppcoro::detail::win32_overlapped_operation_base& operation) noexcept; + void cancel(cppcoro::detail::win32_overlapped_operation_base& operation) noexcept; + void get_result(cppcoro::detail::win32_overlapped_operation_base& operation); + + private: + + socket& m_socket; + ip_endpoint m_remoteEndPoint; + + }; + + class socket_connect_operation + : public cppcoro::detail::win32_overlapped_operation + { + public: + + socket_connect_operation( + socket& socket, + const ip_endpoint& remoteEndPoint) noexcept + : m_impl(socket, remoteEndPoint) + {} + + private: + + friend class cppcoro::detail::win32_overlapped_operation; + + bool try_start() noexcept { return m_impl.try_start(*this); } + decltype(auto) get_result() { return m_impl.get_result(*this); } + + socket_connect_operation_impl m_impl; + + }; + + class socket_connect_operation_cancellable + : public cppcoro::detail::win32_overlapped_operation_cancellable + { + public: + + socket_connect_operation_cancellable( + socket& socket, + const ip_endpoint& remoteEndPoint, + cancellation_token&& ct) noexcept + : cppcoro::detail::win32_overlapped_operation_cancellable(std::move(ct)) + , m_impl(socket, remoteEndPoint) + {} + + private: + + friend class cppcoro::detail::win32_overlapped_operation_cancellable; + + bool try_start() noexcept { return m_impl.try_start(*this); } + void cancel() noexcept { m_impl.cancel(*this); } + void get_result() { m_impl.get_result(*this); } + + socket_connect_operation_impl m_impl; + + }; + } +} + +#endif // CPPCORO_OS_WINNT + +#endif diff --git a/include/cppcoro/net/socket_disconnect_operation.hpp b/include/cppcoro/net/socket_disconnect_operation.hpp new file mode 100644 index 0000000..7bdcc03 --- /dev/null +++ b/include/cppcoro/net/socket_disconnect_operation.hpp @@ -0,0 +1,85 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_NET_SOCKET_DISCONNECT_OPERATION_HPP_INCLUDED +#define CPPCORO_NET_SOCKET_DISCONNECT_OPERATION_HPP_INCLUDED + +#include +#include + +#if CPPCORO_OS_WINNT +# include +# include + +namespace cppcoro +{ + namespace net + { + class socket; + + class socket_disconnect_operation_impl + { + public: + + socket_disconnect_operation_impl(socket& socket) noexcept + : m_socket(socket) + {} + + bool try_start(cppcoro::detail::win32_overlapped_operation_base& operation) noexcept; + void cancel(cppcoro::detail::win32_overlapped_operation_base& operation) noexcept; + void get_result(cppcoro::detail::win32_overlapped_operation_base& operation); + + private: + + socket& m_socket; + + }; + + class socket_disconnect_operation + : public cppcoro::detail::win32_overlapped_operation + { + public: + + socket_disconnect_operation(socket& socket) noexcept + : m_impl(socket) + {} + + private: + + friend class cppcoro::detail::win32_overlapped_operation; + + bool try_start() noexcept { return m_impl.try_start(*this); } + void get_result() { m_impl.get_result(*this); } + + socket_disconnect_operation_impl m_impl; + + }; + + class socket_disconnect_operation_cancellable + : public cppcoro::detail::win32_overlapped_operation_cancellable + { + public: + + socket_disconnect_operation_cancellable(socket& socket, cancellation_token&& ct) noexcept + : cppcoro::detail::win32_overlapped_operation_cancellable(std::move(ct)) + , m_impl(socket) + {} + + private: + + friend class cppcoro::detail::win32_overlapped_operation_cancellable; + + bool try_start() noexcept { return m_impl.try_start(*this); } + void cancel() noexcept { m_impl.cancel(*this); } + void get_result() { m_impl.get_result(*this); } + + socket_disconnect_operation_impl m_impl; + + }; + } +} + +#endif // CPPCORO_OS_WINNT + +#endif diff --git a/include/cppcoro/net/socket_recv_from_operation.hpp b/include/cppcoro/net/socket_recv_from_operation.hpp new file mode 100644 index 0000000..37f2d01 --- /dev/null +++ b/include/cppcoro/net/socket_recv_from_operation.hpp @@ -0,0 +1,106 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_NET_SOCKET_RECV_FROM_OPERATION_HPP_INCLUDED +#define CPPCORO_NET_SOCKET_RECV_FROM_OPERATION_HPP_INCLUDED + +#include +#include +#include + +#include +#include + +#if CPPCORO_OS_WINNT +# include +# include + +namespace cppcoro::net +{ + class socket; + + class socket_recv_from_operation_impl + { + public: + + socket_recv_from_operation_impl( + socket& socket, + void* buffer, + std::size_t byteCount) noexcept + : m_socket(socket) + , m_buffer(buffer, byteCount) + {} + + bool try_start(cppcoro::detail::win32_overlapped_operation_base& operation) noexcept; + void cancel(cppcoro::detail::win32_overlapped_operation_base& operation) noexcept; + std::tuple get_result( + cppcoro::detail::win32_overlapped_operation_base& operation); + + private: + + socket& m_socket; + cppcoro::detail::win32::wsabuf m_buffer; + + static constexpr std::size_t sockaddrStorageAlignment = 4; + + // Storage suitable for either SOCKADDR_IN or SOCKADDR_IN6 + alignas(sockaddrStorageAlignment) std::uint8_t m_sourceSockaddrStorage[28]; + int m_sourceSockaddrLength; + + }; + + class socket_recv_from_operation + : public cppcoro::detail::win32_overlapped_operation + { + public: + + socket_recv_from_operation( + socket& socket, + void* buffer, + std::size_t byteCount) noexcept + : m_impl(socket, buffer, byteCount) + {} + + private: + + friend class cppcoro::detail::win32_overlapped_operation; + + bool try_start() noexcept { return m_impl.try_start(*this); } + decltype(auto) get_result() { return m_impl.get_result(*this); } + + socket_recv_from_operation_impl m_impl; + + }; + + class socket_recv_from_operation_cancellable + : public cppcoro::detail::win32_overlapped_operation_cancellable + { + public: + + socket_recv_from_operation_cancellable( + socket& socket, + void* buffer, + std::size_t byteCount, + cancellation_token&& ct) noexcept + : cppcoro::detail::win32_overlapped_operation_cancellable(std::move(ct)) + , m_impl(socket, buffer, byteCount) + {} + + private: + + friend class cppcoro::detail::win32_overlapped_operation_cancellable; + + bool try_start() noexcept { return m_impl.try_start(*this); } + void cancel() noexcept { m_impl.cancel(*this); } + decltype(auto) get_result() { return m_impl.get_result(*this); } + + socket_recv_from_operation_impl m_impl; + + }; + +} + +#endif // CPPCORO_OS_WINNT + +#endif diff --git a/include/cppcoro/net/socket_recv_operation.hpp b/include/cppcoro/net/socket_recv_operation.hpp new file mode 100644 index 0000000..c9dca8b --- /dev/null +++ b/include/cppcoro/net/socket_recv_operation.hpp @@ -0,0 +1,94 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_NET_SOCKET_RECV_OPERATION_HPP_INCLUDED +#define CPPCORO_NET_SOCKET_RECV_OPERATION_HPP_INCLUDED + +#include +#include + +#include + +#if CPPCORO_OS_WINNT +# include +# include + +namespace cppcoro::net +{ + class socket; + + class socket_recv_operation_impl + { + public: + + socket_recv_operation_impl( + socket& s, + void* buffer, + std::size_t byteCount) noexcept + : m_socket(s) + , m_buffer(buffer, byteCount) + {} + + bool try_start(cppcoro::detail::win32_overlapped_operation_base& operation) noexcept; + void cancel(cppcoro::detail::win32_overlapped_operation_base& operation) noexcept; + + private: + + socket& m_socket; + cppcoro::detail::win32::wsabuf m_buffer; + + }; + + class socket_recv_operation + : public cppcoro::detail::win32_overlapped_operation + { + public: + + socket_recv_operation( + socket& s, + void* buffer, + std::size_t byteCount) noexcept + : m_impl(s, buffer, byteCount) + {} + + private: + + friend class cppcoro::detail::win32_overlapped_operation; + + bool try_start() noexcept { return m_impl.try_start(*this); } + + socket_recv_operation_impl m_impl; + + }; + + class socket_recv_operation_cancellable + : public cppcoro::detail::win32_overlapped_operation_cancellable + { + public: + + socket_recv_operation_cancellable( + socket& s, + void* buffer, + std::size_t byteCount, + cancellation_token&& ct) noexcept + : cppcoro::detail::win32_overlapped_operation_cancellable(std::move(ct)) + , m_impl(s, buffer, byteCount) + {} + + private: + + friend class cppcoro::detail::win32_overlapped_operation_cancellable; + + bool try_start() noexcept { return m_impl.try_start(*this); } + void cancel() noexcept { m_impl.cancel(*this); } + + socket_recv_operation_impl m_impl; + + }; + +} + +#endif // CPPCORO_OS_WINNT + +#endif diff --git a/include/cppcoro/net/socket_send_operation.hpp b/include/cppcoro/net/socket_send_operation.hpp new file mode 100644 index 0000000..702d2ab --- /dev/null +++ b/include/cppcoro/net/socket_send_operation.hpp @@ -0,0 +1,94 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_NET_SOCKET_SEND_OPERATION_HPP_INCLUDED +#define CPPCORO_NET_SOCKET_SEND_OPERATION_HPP_INCLUDED + +#include +#include + +#include + +#if CPPCORO_OS_WINNT +# include +# include + +namespace cppcoro::net +{ + class socket; + + class socket_send_operation_impl + { + public: + + socket_send_operation_impl( + socket& s, + const void* buffer, + std::size_t byteCount) noexcept + : m_socket(s) + , m_buffer(const_cast(buffer), byteCount) + {} + + bool try_start(cppcoro::detail::win32_overlapped_operation_base& operation) noexcept; + void cancel(cppcoro::detail::win32_overlapped_operation_base& operation) noexcept; + + private: + + socket& m_socket; + cppcoro::detail::win32::wsabuf m_buffer; + + }; + + class socket_send_operation + : public cppcoro::detail::win32_overlapped_operation + { + public: + + socket_send_operation( + socket& s, + const void* buffer, + std::size_t byteCount) noexcept + : m_impl(s, buffer, byteCount) + {} + + private: + + friend class cppcoro::detail::win32_overlapped_operation; + + bool try_start() noexcept { return m_impl.try_start(*this); } + + socket_send_operation_impl m_impl; + + }; + + class socket_send_operation_cancellable + : public cppcoro::detail::win32_overlapped_operation_cancellable + { + public: + + socket_send_operation_cancellable( + socket& s, + const void* buffer, + std::size_t byteCount, + cancellation_token&& ct) noexcept + : cppcoro::detail::win32_overlapped_operation_cancellable(std::move(ct)) + , m_impl(s, buffer, byteCount) + {} + + private: + + friend class cppcoro::detail::win32_overlapped_operation_cancellable; + + bool try_start() noexcept { return m_impl.try_start(*this); } + void cancel() noexcept { return m_impl.cancel(*this); } + + socket_send_operation_impl m_impl; + + }; + +} + +#endif // CPPCORO_OS_WINNT + +#endif diff --git a/include/cppcoro/net/socket_send_to_operation.hpp b/include/cppcoro/net/socket_send_to_operation.hpp new file mode 100644 index 0000000..60d51b2 --- /dev/null +++ b/include/cppcoro/net/socket_send_to_operation.hpp @@ -0,0 +1,100 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_NET_SOCKET_SEND_TO_OPERATION_HPP_INCLUDED +#define CPPCORO_NET_SOCKET_SEND_TO_OPERATION_HPP_INCLUDED + +#include +#include +#include + +#include + +#if CPPCORO_OS_WINNT +# include +# include + +namespace cppcoro::net +{ + class socket; + + class socket_send_to_operation_impl + { + public: + + socket_send_to_operation_impl( + socket& s, + const ip_endpoint& destination, + const void* buffer, + std::size_t byteCount) noexcept + : m_socket(s) + , m_destination(destination) + , m_buffer(const_cast(buffer), byteCount) + {} + + bool try_start(cppcoro::detail::win32_overlapped_operation_base& operation) noexcept; + void cancel(cppcoro::detail::win32_overlapped_operation_base& operation) noexcept; + + private: + + socket& m_socket; + ip_endpoint m_destination; + cppcoro::detail::win32::wsabuf m_buffer; + + }; + + class socket_send_to_operation + : public cppcoro::detail::win32_overlapped_operation + { + public: + + socket_send_to_operation( + socket& s, + const ip_endpoint& destination, + const void* buffer, + std::size_t byteCount) noexcept + : m_impl(s, destination, buffer, byteCount) + {} + + private: + + friend class cppcoro::detail::win32_overlapped_operation; + + bool try_start() noexcept { return m_impl.try_start(*this); } + + socket_send_to_operation_impl m_impl; + + }; + + class socket_send_to_operation_cancellable + : public cppcoro::detail::win32_overlapped_operation_cancellable + { + public: + + socket_send_to_operation_cancellable( + socket& s, + const ip_endpoint& destination, + const void* buffer, + std::size_t byteCount, + cancellation_token&& ct) noexcept + : cppcoro::detail::win32_overlapped_operation_cancellable(std::move(ct)) + , m_impl(s, destination, buffer, byteCount) + {} + + private: + + friend class cppcoro::detail::win32_overlapped_operation_cancellable; + + bool try_start() noexcept { return m_impl.try_start(*this); } + void cancel() noexcept { return m_impl.cancel(*this); } + + socket_send_to_operation_impl m_impl; + + }; + +} + +#endif // CPPCORO_OS_WINNT + +#endif diff --git a/include/cppcoro/on_scope_exit.hpp b/include/cppcoro/on_scope_exit.hpp new file mode 100644 index 0000000..8e2920d --- /dev/null +++ b/include/cppcoro/on_scope_exit.hpp @@ -0,0 +1,147 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_ON_SCOPE_EXIT_HPP_INCLUDED +#define CPPCORO_ON_SCOPE_EXIT_HPP_INCLUDED + +#include +#include + +namespace cppcoro +{ + template + class scoped_lambda + { + public: + + scoped_lambda(FUNC&& func) + : m_func(std::forward(func)) + , m_cancelled(false) + {} + + scoped_lambda(const scoped_lambda& other) = delete; + + scoped_lambda(scoped_lambda&& other) + : m_func(std::forward(other.m_func)) + , m_cancelled(other.m_cancelled) + { + other.cancel(); + } + + ~scoped_lambda() + { + if (!m_cancelled) + { + m_func(); + } + } + + void cancel() + { + m_cancelled = true; + } + + void call_now() + { + m_cancelled = true; + m_func(); + } + + private: + + FUNC m_func; + bool m_cancelled; + + }; + + /// A scoped lambda that executes the lambda when the object destructs + /// but only if exiting due to an exception (CALL_ON_FAILURE = true) or + /// only if not exiting due to an exception (CALL_ON_FAILURE = false). + template + class conditional_scoped_lambda + { + public: + + conditional_scoped_lambda(FUNC&& func) + : m_func(std::forward(func)) + , m_uncaughtExceptionCount(std::uncaught_exceptions()) + , m_cancelled(false) + {} + + conditional_scoped_lambda(const conditional_scoped_lambda& other) = delete; + + conditional_scoped_lambda(conditional_scoped_lambda&& other) + noexcept(std::is_nothrow_move_constructible::value) + : m_func(std::forward(other.m_func)) + , m_uncaughtExceptionCount(other.m_uncaughtExceptionCount) + , m_cancelled(other.m_cancelled) + { + other.cancel(); + } + + ~conditional_scoped_lambda() noexcept(CALL_ON_FAILURE || noexcept(std::declval()())) + { + if (!m_cancelled && (is_unwinding_due_to_exception() == CALL_ON_FAILURE)) + { + m_func(); + } + } + + void cancel() noexcept + { + m_cancelled = true; + } + + private: + + bool is_unwinding_due_to_exception() const noexcept + { + return std::uncaught_exceptions() > m_uncaughtExceptionCount; + } + + FUNC m_func; + int m_uncaughtExceptionCount; + bool m_cancelled; + + }; + + /// Returns an object that calls the provided function when it goes out + /// of scope either normally or due to an uncaught exception unwinding + /// the stack. + /// + /// \param func + /// The function to call when the scope exits. + /// The function must be noexcept. + template + auto on_scope_exit(FUNC&& func) + { + return scoped_lambda{ std::forward(func) }; + } + + /// Returns an object that calls the provided function when it goes out + /// of scope due to an uncaught exception unwinding the stack. + /// + /// \param func + /// The function to be called if unwinding due to an exception. + /// The function must be noexcept. + template + auto on_scope_failure(FUNC&& func) + { + return conditional_scoped_lambda{ std::forward(func) }; + } + + /// Returns an object that calls the provided function when it goes out + /// of scope via normal execution (ie. not unwinding due to an exception). + /// + /// \param func + /// The function to call if the scope exits normally. + /// The function does not necessarily need to be noexcept. + template + auto on_scope_success(FUNC&& func) + { + return conditional_scoped_lambda{ std::forward(func) }; + } +} + +#endif diff --git a/include/cppcoro/operation_cancelled.hpp b/include/cppcoro/operation_cancelled.hpp new file mode 100644 index 0000000..2746ae0 --- /dev/null +++ b/include/cppcoro/operation_cancelled.hpp @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_OPERATION_CANCELLED_HPP_INCLUDED +#define CPPCORO_OPERATION_CANCELLED_HPP_INCLUDED + +#include + +namespace cppcoro +{ + class operation_cancelled : public std::exception + { + public: + + operation_cancelled() noexcept + : std::exception() + {} + + const char* what() const noexcept override { return "operation cancelled"; } + }; +} + +#endif diff --git a/include/cppcoro/read_only_file.hpp b/include/cppcoro/read_only_file.hpp new file mode 100644 index 0000000..2527142 --- /dev/null +++ b/include/cppcoro/read_only_file.hpp @@ -0,0 +1,59 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_READ_ONLY_FILE_HPP_INCLUDED +#define CPPCORO_READ_ONLY_FILE_HPP_INCLUDED + +#include +#include +#include + +#include + +namespace cppcoro +{ + class read_only_file : public readable_file + { + public: + + /// Open a file for read-only access. + /// + /// \param ioContext + /// The I/O context to use when dispatching I/O completion events. + /// When asynchronous read operations on this file complete the + /// completion events will be dispatched to an I/O thread associated + /// with the I/O context. + /// + /// \param path + /// Path of the file to open. + /// + /// \param shareMode + /// Specifies the access to be allowed on the file concurrently with this file access. + /// + /// \param bufferingMode + /// Specifies the modes/hints to provide to the OS that affects the behaviour + /// of its file buffering. + /// + /// \return + /// An object that can be used to read from the file. + /// + /// \throw std::system_error + /// If the file could not be opened for read. + [[nodiscard]] + static read_only_file open( + io_service& ioService, + const cppcoro::filesystem::path& path, + file_share_mode shareMode = file_share_mode::read, + file_buffering_mode bufferingMode = file_buffering_mode::default_); + + protected: + +#if CPPCORO_OS_WINNT + read_only_file(detail::win32::safe_handle&& fileHandle) noexcept; +#endif + + }; +} + +#endif diff --git a/include/cppcoro/read_write_file.hpp b/include/cppcoro/read_write_file.hpp new file mode 100644 index 0000000..de9e537 --- /dev/null +++ b/include/cppcoro/read_write_file.hpp @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_READ_WRITE_FILE_HPP_INCLUDED +#define CPPCORO_READ_WRITE_FILE_HPP_INCLUDED + +#include +#include +#include +#include +#include + +#include + +namespace cppcoro +{ + class read_write_file : public readable_file, public writable_file + { + public: + + /// Open a file for read-write access. + /// + /// \param ioContext + /// The I/O context to use when dispatching I/O completion events. + /// When asynchronous write operations on this file complete the + /// completion events will be dispatched to an I/O thread associated + /// with the I/O context. + /// + /// \param pathMode + /// Path of the file to open. + /// + /// \param openMode + /// Specifies how the file should be opened and how to handle cases + /// when the file exists or doesn't exist. + /// + /// \param shareMode + /// Specifies the access to be allowed on the file concurrently with this file access. + /// + /// \param bufferingMode + /// Specifies the modes/hints to provide to the OS that affects the behaviour + /// of its file buffering. + /// + /// \return + /// An object that can be used to write to the file. + /// + /// \throw std::system_error + /// If the file could not be opened for write. + [[nodiscard]] + static read_write_file open( + io_service& ioService, + const cppcoro::filesystem::path& path, + file_open_mode openMode = file_open_mode::create_or_open, + file_share_mode shareMode = file_share_mode::none, + file_buffering_mode bufferingMode = file_buffering_mode::default_); + + protected: + +#if CPPCORO_OS_WINNT + read_write_file(detail::win32::safe_handle&& fileHandle) noexcept; +#endif + + }; +} + +#endif diff --git a/include/cppcoro/readable_file.hpp b/include/cppcoro/readable_file.hpp new file mode 100644 index 0000000..01159df --- /dev/null +++ b/include/cppcoro/readable_file.hpp @@ -0,0 +1,65 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_READABLE_FILE_HPP_INCLUDED +#define CPPCORO_READABLE_FILE_HPP_INCLUDED + +#include +#include +#include + +namespace cppcoro +{ + class readable_file : virtual public file + { + public: + + /// Read some data from the file. + /// + /// Reads \a byteCount bytes from the file starting at \a offset + /// into the specified \a buffer. + /// + /// \param offset + /// The offset within the file to start reading from. + /// If the file has been opened using file_buffering_mode::unbuffered + /// then the offset must be a multiple of the file-system's sector size. + /// + /// \param buffer + /// The buffer to read the file contents into. + /// If the file has been opened using file_buffering_mode::unbuffered + /// then the address of the start of the buffer must be a multiple of + /// the file-system's sector size. + /// + /// \param byteCount + /// The number of bytes to read from the file. + /// If the file has been opeend using file_buffering_mode::unbuffered + /// then the byteCount must be a multiple of the file-system's sector size. + /// + /// \param ct + /// An optional cancellation_token that can be used to cancel the + /// read operation before it completes. + /// + /// \return + /// An object that represents the read-operation. + /// This object must be co_await'ed to start the read operation. + [[nodiscard]] + file_read_operation read( + std::uint64_t offset, + void* buffer, + std::size_t byteCount) const noexcept; + [[nodiscard]] + file_read_operation_cancellable read( + std::uint64_t offset, + void* buffer, + std::size_t byteCount, + cancellation_token ct) const noexcept; + + protected: + + using file::file; + + }; +} + +#endif diff --git a/include/cppcoro/recursive_generator.hpp b/include/cppcoro/recursive_generator.hpp new file mode 100644 index 0000000..65af46c --- /dev/null +++ b/include/cppcoro/recursive_generator.hpp @@ -0,0 +1,345 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_RECURSIVE_GENERATOR_HPP_INCLUDED +#define CPPCORO_RECURSIVE_GENERATOR_HPP_INCLUDED + +#include + +#include +#include +#include +#include +#include + +namespace cppcoro +{ + template + class [[nodiscard]] recursive_generator + { + public: + + class promise_type final + { + public: + + promise_type() noexcept + : m_value(nullptr) + , m_exception(nullptr) + , m_root(this) + , m_parentOrLeaf(this) + {} + + promise_type(const promise_type&) = delete; + promise_type(promise_type&&) = delete; + + auto get_return_object() noexcept + { + return recursive_generator{ *this }; + } + + cppcoro::suspend_always initial_suspend() noexcept + { + return {}; + } + + cppcoro::suspend_always final_suspend() noexcept + { + return {}; + } + + void unhandled_exception() noexcept + { + m_exception = std::current_exception(); + } + + void return_void() noexcept {} + + cppcoro::suspend_always yield_value(T& value) noexcept + { + m_value = std::addressof(value); + return {}; + } + + cppcoro::suspend_always yield_value(T&& value) noexcept + { + m_value = std::addressof(value); + return {}; + } + + auto yield_value(recursive_generator&& generator) noexcept + { + return yield_value(generator); + } + + auto yield_value(recursive_generator& generator) noexcept + { + struct awaitable + { + + awaitable(promise_type* childPromise) + : m_childPromise(childPromise) + {} + + bool await_ready() noexcept + { + return this->m_childPromise == nullptr; + } + + void await_suspend(cppcoro::coroutine_handle) noexcept + {} + + void await_resume() + { + if (this->m_childPromise != nullptr) + { + this->m_childPromise->throw_if_exception(); + } + } + + private: + promise_type* m_childPromise; + }; + + if (generator.m_promise != nullptr) + { + m_root->m_parentOrLeaf = generator.m_promise; + generator.m_promise->m_root = m_root; + generator.m_promise->m_parentOrLeaf = this; + generator.m_promise->resume(); + + if (!generator.m_promise->is_complete()) + { + return awaitable{ generator.m_promise }; + } + + m_root->m_parentOrLeaf = this; + } + + return awaitable{ nullptr }; + } + + // Don't allow any use of 'co_await' inside the recursive_generator coroutine. + template + cppcoro::suspend_never await_transform(U&& value) = delete; + + void destroy() noexcept + { + cppcoro::coroutine_handle::from_promise(*this).destroy(); + } + + void throw_if_exception() + { + if (m_exception != nullptr) + { + std::rethrow_exception(std::move(m_exception)); + } + } + + bool is_complete() noexcept + { + return cppcoro::coroutine_handle::from_promise(*this).done(); + } + + T& value() noexcept + { + assert(this == m_root); + assert(!is_complete()); + return *(m_parentOrLeaf->m_value); + } + + void pull() noexcept + { + assert(this == m_root); + assert(!m_parentOrLeaf->is_complete()); + + m_parentOrLeaf->resume(); + + while (m_parentOrLeaf != this && m_parentOrLeaf->is_complete()) + { + m_parentOrLeaf = m_parentOrLeaf->m_parentOrLeaf; + m_parentOrLeaf->resume(); + } + } + + private: + + void resume() noexcept + { + cppcoro::coroutine_handle::from_promise(*this).resume(); + } + + std::add_pointer_t m_value; + std::exception_ptr m_exception; + + promise_type* m_root; + + // If this is the promise of the root generator then this field + // is a pointer to the leaf promise. + // For non-root generators this is a pointer to the parent promise. + promise_type* m_parentOrLeaf; + + }; + + recursive_generator() noexcept + : m_promise(nullptr) + {} + + recursive_generator(promise_type& promise) noexcept + : m_promise(&promise) + {} + + recursive_generator(recursive_generator&& other) noexcept + : m_promise(other.m_promise) + { + other.m_promise = nullptr; + } + + recursive_generator(const recursive_generator& other) = delete; + recursive_generator& operator=(const recursive_generator& other) = delete; + + ~recursive_generator() + { + if (m_promise != nullptr) + { + m_promise->destroy(); + } + } + + recursive_generator& operator=(recursive_generator&& other) noexcept + { + if (this != &other) + { + if (m_promise != nullptr) + { + m_promise->destroy(); + } + + m_promise = other.m_promise; + other.m_promise = nullptr; + } + + return *this; + } + + class iterator + { + public: + + using iterator_category = std::input_iterator_tag; + // What type should we use for counting elements of a potentially infinite sequence? + using difference_type = std::ptrdiff_t; + using value_type = std::remove_reference_t; + using reference = std::conditional_t, T, T&>; + using pointer = std::add_pointer_t; + + iterator() noexcept + : m_promise(nullptr) + {} + + explicit iterator(promise_type* promise) noexcept + : m_promise(promise) + {} + + bool operator==(const iterator& other) const noexcept + { + return m_promise == other.m_promise; + } + + bool operator!=(const iterator& other) const noexcept + { + return m_promise != other.m_promise; + } + + iterator& operator++() + { + assert(m_promise != nullptr); + assert(!m_promise->is_complete()); + + m_promise->pull(); + if (m_promise->is_complete()) + { + auto* temp = m_promise; + m_promise = nullptr; + temp->throw_if_exception(); + } + + return *this; + } + + void operator++(int) + { + (void)operator++(); + } + + reference operator*() const noexcept + { + assert(m_promise != nullptr); + return static_cast(m_promise->value()); + } + + pointer operator->() const noexcept + { + return std::addressof(operator*()); + } + + private: + + promise_type* m_promise; + + }; + + iterator begin() + { + if (m_promise != nullptr) + { + m_promise->pull(); + if (!m_promise->is_complete()) + { + return iterator(m_promise); + } + + m_promise->throw_if_exception(); + } + + return iterator(nullptr); + } + + iterator end() noexcept + { + return iterator(nullptr); + } + + void swap(recursive_generator& other) noexcept + { + std::swap(m_promise, other.m_promise); + } + + private: + + friend class promise_type; + + promise_type* m_promise; + + }; + + template + void swap(recursive_generator& a, recursive_generator& b) noexcept + { + a.swap(b); + } + + // Note: When applying fmap operator to a recursive_generator we just yield a non-recursive + // generator since we generally won't be using the result in a recursive context. + template + generator::iterator::reference>> fmap(FUNC func, recursive_generator source) + { + for (auto&& value : source) + { + co_yield std::invoke(func, static_cast(value)); + } + } +} + +#endif diff --git a/include/cppcoro/resume_on.hpp b/include/cppcoro/resume_on.hpp new file mode 100644 index 0000000..b26188b --- /dev/null +++ b/include/cppcoro/resume_on.hpp @@ -0,0 +1,129 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_RESUME_ON_HPP_INCLUDED +#define CPPCORO_RESUME_ON_HPP_INCLUDED + +#include +#include +#include +#include + +#include +#include + +namespace cppcoro +{ + template + struct resume_on_transform + { + explicit resume_on_transform(SCHEDULER& s) noexcept + : scheduler(s) + {} + + SCHEDULER& scheduler; + }; + + template + resume_on_transform resume_on(SCHEDULER& scheduler) noexcept + { + return resume_on_transform(scheduler); + } + + template + decltype(auto) operator|(T&& value, resume_on_transform transform) + { + return resume_on(transform.scheduler, std::forward(value)); + } + + template< + typename SCHEDULER, + typename AWAITABLE, + typename AWAIT_RESULT = detail::remove_rvalue_reference_t::await_result_t>, + std::enable_if_t, int> = 0> + auto resume_on(SCHEDULER& scheduler, AWAITABLE awaitable) + -> task + { + bool rescheduled = false; + std::exception_ptr ex; + try + { + // We manually get the awaiter here so that we can keep + // it alive across the call to `scheduler.schedule()` + // just in case the result is a reference to a value + // in the awaiter that would otherwise be a temporary + // and destructed before the value could be returned. + + auto&& awaiter = detail::get_awaiter(static_cast(awaitable)); + + auto&& result = co_await static_cast(awaiter); + + // Flag as rescheduled before scheduling in case it is the + // schedule() operation that throws an exception as we don't + // want to attempt to schedule twice if scheduling fails. + rescheduled = true; + + co_await scheduler.schedule(); + + co_return static_cast(result); + } + catch (...) + { + ex = std::current_exception(); + } + + // We still want to resume on the scheduler even in the presence + // of an exception. + if (!rescheduled) + { + co_await scheduler.schedule(); + } + + std::rethrow_exception(ex); + } + + template< + typename SCHEDULER, + typename AWAITABLE, + typename AWAIT_RESULT = detail::remove_rvalue_reference_t::await_result_t>, + std::enable_if_t, int> = 0> + auto resume_on(SCHEDULER& scheduler, AWAITABLE awaitable) + -> task<> + { + std::exception_ptr ex; + try + { + co_await static_cast(awaitable); + } + catch (...) + { + ex = std::current_exception(); + } + + // NOTE: We're assuming that `schedule()` operation is noexcept + // here. If it were to throw what would we do if 'ex' was non-null? + // Presumably we'd treat it the same as throwing an exception while + // unwinding and call std::terminate()? + + co_await scheduler.schedule(); + + if (ex) + { + std::rethrow_exception(ex); + } + } + + template + async_generator resume_on(SCHEDULER& scheduler, async_generator source) + { + for (auto iter = co_await source.begin(); iter != source.end(); co_await ++iter) + { + auto& value = *iter; + co_await scheduler.schedule(); + co_yield value; + } + } +} + +#endif diff --git a/include/cppcoro/round_robin_scheduler.hpp b/include/cppcoro/round_robin_scheduler.hpp new file mode 100644 index 0000000..cd15405 --- /dev/null +++ b/include/cppcoro/round_robin_scheduler.hpp @@ -0,0 +1,124 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_ROUND_ROBIN_SCHEDULER_HPP_INCLUDED +#define CPPCORO_ROUND_ROBIN_SCHEDULER_HPP_INCLUDED + +#include + +#include +#include +#include +#include +#include + +namespace cppcoro +{ +#if CPPCORO_COMPILER_SUPPORTS_SYMMETRIC_TRANSFER + /// This is a scheduler class that schedules coroutines in a round-robin + /// fashion once N coroutines have been scheduled to it. + /// + /// Only supports access from a single thread at a time so + /// + /// This implementation was inspired by Gor Nishanov's CppCon 2018 talk + /// about nano-coroutines. + /// + /// The implementation relies on symmetric transfer and noop_coroutine() + /// and so only works with a relatively recent version of Clang and does + /// not yet work with MSVC. + template + class round_robin_scheduler + { + static_assert( + N >= 2, + "Round robin scheduler must be configured to support at least two coroutines"); + + class schedule_operation + { + public: + explicit schedule_operation(round_robin_scheduler& s) noexcept : m_scheduler(s) {} + + bool await_ready() noexcept + { + return false; + } + + cppcoro::coroutine_handle<> await_suspend( + cppcoro::coroutine_handle<> awaitingCoroutine) noexcept + { + return m_scheduler.exchange_next(awaitingCoroutine); + } + + void await_resume() noexcept {} + + private: + round_robin_scheduler& m_scheduler; + }; + + friend class schedule_operation; + + public: + round_robin_scheduler() noexcept + : m_index(0) + , m_noop(cppcoro::noop_coroutine()) + { + for (size_t i = 0; i < N - 1; ++i) + { + m_coroutines[i] = m_noop(); + } + } + + ~round_robin_scheduler() + { + // All tasks should have been joined before calling destructor. + assert(std::all_of( + m_coroutines.begin(), + m_coroutines.end(), + [&](auto h) { return h == m_noop; })); + } + + schedule_operation schedule() noexcept + { + return schedule_operation{ *this }; + } + + /// Resume any queued coroutines until there are no more coroutines. + void drain() noexcept + { + size_t countRemaining = N - 1; + do + { + auto nextToResume = exchange_next(m_noop); + if (nextToResume != m_noop) + { + nextToResume.resume(); + countRemaining = N - 1; + } + else + { + --countRemaining; + } + } while (countRemaining > 0); + } + + private: + + cppcoro::coroutine_handle exchange_next( + cppcoro::coroutine_handle<> coroutine) noexcept + { + auto coroutineToResume = std::exchange( + m_scheduler.m_coroutines[m_scheduler.m_index], + awaitingCoroutine); + m_scheduler.m_index = m_scheduler.m_index < (N - 2) ? m_scheduler.m_index + 1 : 0; + return coroutineToResume; + } + + size_t m_index; + const cppcoro::coroutine_handle<> m_noop; + std::array, N - 1> m_coroutines; + }; +#endif +} + +#endif diff --git a/include/cppcoro/schedule_on.hpp b/include/cppcoro/schedule_on.hpp new file mode 100644 index 0000000..98ecf42 --- /dev/null +++ b/include/cppcoro/schedule_on.hpp @@ -0,0 +1,69 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_SCHEDULE_ON_HPP_INCLUDED +#define CPPCORO_SCHEDULE_ON_HPP_INCLUDED + +#include +#include +#include +#include + +#include + +namespace cppcoro +{ + template + struct schedule_on_transform + { + explicit schedule_on_transform(SCHEDULER& scheduler) noexcept + : scheduler(scheduler) + {} + + SCHEDULER& scheduler; + }; + + template + schedule_on_transform schedule_on(SCHEDULER& scheduler) + { + return schedule_on_transform{ scheduler }; + } + + template + decltype(auto) operator|(T&& value, schedule_on_transform transform) + { + return schedule_on(transform.scheduler, std::forward(value)); + } + + template + auto schedule_on(SCHEDULER& scheduler, AWAITABLE awaitable) + -> task::await_result_t>> + { + co_await scheduler.schedule(); + co_return co_await std::move(awaitable); + } + + template + async_generator schedule_on(SCHEDULER& scheduler, async_generator source) + { + // Transfer exection to the scheduler before the implicit calls to + // 'co_await begin()' or subsequent calls to `co_await iterator::operator++()` + // below. This ensures that all calls to the generator's coroutine_handle<>::resume() + // are executed on the execution context of the scheduler. + co_await scheduler.schedule(); + + const auto itEnd = source.end(); + auto it = co_await source.begin(); + while (it != itEnd) + { + co_yield *it; + + co_await scheduler.schedule(); + + (void)co_await ++it; + } + } +} + +#endif diff --git a/include/cppcoro/sequence_barrier.hpp b/include/cppcoro/sequence_barrier.hpp new file mode 100644 index 0000000..e1f0eb8 --- /dev/null +++ b/include/cppcoro/sequence_barrier.hpp @@ -0,0 +1,470 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_SEQUENCE_BARRIER_HPP_INCLUDED +#define CPPCORO_SEQUENCE_BARRIER_HPP_INCLUDED + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace cppcoro +{ + template + class sequence_barrier_wait_operation_base; + + template + class sequence_barrier_wait_operation; + + /// A sequence barrier is a synchronisation primitive that allows a single-producer + /// and multiple-consumers to coordinate with respect to a monotonically increasing + /// sequence number. + /// + /// A single producer advances the sequence number by publishing new sequence numbers in a + /// monotonically increasing order. One or more consumers can query the last-published + /// sequence number and can wait until a particular sequence number has been published. + /// + /// A sequence barrier can be used to represent a cursor into a thread-safe producer/consumer + /// ring-buffer. + /// + /// See the LMAX Disruptor pattern for more background: + /// https://lmax-exchange.github.io/disruptor/files/Disruptor-1.0.pdf + template< + typename SEQUENCE = std::size_t, + typename TRAITS = sequence_traits> + class sequence_barrier + { + static_assert( + std::is_integral_v, + "sequence_barrier requires an integral sequence type"); + + using awaiter_t = sequence_barrier_wait_operation_base; + + public: + + /// Construct a sequence barrier with the specified initial sequence number + /// as the initial value 'last_published()'. + sequence_barrier(SEQUENCE initialSequence = TRAITS::initial_sequence) noexcept + : m_lastPublished(initialSequence) + , m_awaiters(nullptr) + {} + + ~sequence_barrier() + { + // Shouldn't be destructing a sequence barrier if there are still waiters. + assert(m_awaiters.load(std::memory_order_relaxed) == nullptr); + } + + /// Query the sequence number that was most recently published by the producer. + /// + /// You can assume that all sequence numbers prior to the returned sequence number + /// have also been published. This means you can safely access all elements with + /// sequence numbers up to and including the returned sequence number without any + /// further synchronisation. + SEQUENCE last_published() const noexcept + { + return m_lastPublished.load(std::memory_order_acquire); + } + + /// Wait until a particular sequence number has been published. + /// + /// If the specified sequence number is not yet published then the awaiting coroutine + /// will be suspended and later resumed inside the call to publish() that publishes + /// the specified sequence number. + /// + /// \param targetSequence + /// The sequence number to wait for. + /// + /// \return + /// An awaitable that when co_await'ed will suspend the awaiting coroutine until + /// the specified target sequence number has been published. + /// The result of the co_await expression will be the last-known published sequence + /// number. This is guaranteed not to precede \p targetSequence but may be a sequence + /// number after \p targetSequence, which indicates that more elements have been + /// published than you were waiting for. + template + [[nodiscard]] + sequence_barrier_wait_operation wait_until_published( + SEQUENCE targetSequence, + SCHEDULER& scheduler) const noexcept; + + /// Publish the specified sequence number to consumers. + /// + /// This publishes all sequence numbers up to and including the specified sequence + /// number. This will resume any coroutine that was suspended waiting for a sequence + /// number that was published by this operation. + /// + /// \param sequence + /// The sequence number to publish. This number must not precede the current + /// last_published() value. ie. the published sequence numbers must be monotonically + /// increasing. + void publish(SEQUENCE sequence) noexcept; + + private: + + friend class sequence_barrier_wait_operation_base; + + void add_awaiter(awaiter_t* awaiter) const noexcept; + +#if CPPCORO_COMPILER_MSVC +# pragma warning(push) +# pragma warning(disable : 4324) // C4324: structure was padded due to alignment specifier +#endif + + // First cache-line is written to by the producer only + alignas(CPPCORO_CPU_CACHE_LINE) + std::atomic m_lastPublished; + + // Second cache-line is written to by both the producer and consumers + alignas(CPPCORO_CPU_CACHE_LINE) + mutable std::atomic m_awaiters; + +#if CPPCORO_COMPILER_MSVC +# pragma warning(pop) +#endif + + }; + + template + class sequence_barrier_wait_operation_base + { + public: + + explicit sequence_barrier_wait_operation_base( + const sequence_barrier& barrier, + SEQUENCE targetSequence) noexcept + : m_barrier(barrier) + , m_targetSequence(targetSequence) + , m_lastKnownPublished(barrier.last_published()) + , m_readyToResume(false) + {} + + sequence_barrier_wait_operation_base( + const sequence_barrier_wait_operation_base& other) noexcept + : m_barrier(other.m_barrier) + , m_targetSequence(other.m_targetSequence) + , m_lastKnownPublished(other.m_lastKnownPublished) + , m_readyToResume(false) + {} + + bool await_ready() const noexcept + { + return !TRAITS::precedes(m_lastKnownPublished, m_targetSequence); + } + + bool await_suspend(cppcoro::coroutine_handle<> awaitingCoroutine) noexcept + { + m_awaitingCoroutine = awaitingCoroutine; + m_barrier.add_awaiter(this); + return !m_readyToResume.exchange(true, std::memory_order_acquire); + } + + SEQUENCE await_resume() noexcept + { + return m_lastKnownPublished; + } + + protected: + + friend class sequence_barrier; + + void resume() noexcept + { + // This synchronises with the exchange(true, std::memory_order_acquire) in await_suspend(). + if (m_readyToResume.exchange(true, std::memory_order_release)) + { + resume_impl(); + } + } + + virtual void resume_impl() noexcept = 0; + + const sequence_barrier& m_barrier; + const SEQUENCE m_targetSequence; + SEQUENCE m_lastKnownPublished; + sequence_barrier_wait_operation_base* m_next; + cppcoro::coroutine_handle<> m_awaitingCoroutine; + std::atomic m_readyToResume; + + }; + + template + class sequence_barrier_wait_operation : public sequence_barrier_wait_operation_base + { + using schedule_operation = decltype(std::declval().schedule()); + + public: + sequence_barrier_wait_operation( + const sequence_barrier& barrier, + SEQUENCE targetSequence, + SCHEDULER& scheduler) noexcept + : sequence_barrier_wait_operation_base(barrier, targetSequence) + , m_scheduler(scheduler) + {} + + sequence_barrier_wait_operation( + const sequence_barrier_wait_operation& other) noexcept + : sequence_barrier_wait_operation_base(other) + , m_scheduler(other.m_scheduler) + {} + + ~sequence_barrier_wait_operation() + { + if (m_isScheduleAwaiterCreated) + { + m_scheduleAwaiter.destruct(); + } + if (m_isScheduleOperationCreated) + { + m_scheduleOperation.destruct(); + } + } + + decltype(auto) await_resume() noexcept(noexcept(m_scheduleAwaiter->await_resume())) + { + if (m_isScheduleAwaiterCreated) + { + m_scheduleAwaiter->await_resume(); + } + + return sequence_barrier_wait_operation_base::await_resume(); + } + + private: + + void resume_impl() noexcept override + { + try + { + m_scheduleOperation.construct(m_scheduler.schedule()); + m_isScheduleOperationCreated = true; + + m_scheduleAwaiter.construct(detail::get_awaiter( + static_cast(*m_scheduleOperation))); + m_isScheduleAwaiterCreated = true; + + if (!m_scheduleAwaiter->await_ready()) + { + using await_suspend_result_t = decltype(m_scheduleAwaiter->await_suspend(this->m_awaitingCoroutine)); + if constexpr (std::is_void_v) + { + m_scheduleAwaiter->await_suspend(this->m_awaitingCoroutine); + return; + } + else if constexpr (std::is_same_v) + { + if (m_scheduleAwaiter->await_suspend(this->m_awaitingCoroutine)) + { + return; + } + } + else + { + // Assume it returns a coroutine_handle. + m_scheduleAwaiter->await_suspend(this->m_awaitingCoroutine).resume(); + return; + } + } + } + catch (...) + { + // Ignore failure to reschedule and resume inline? + // Should we catch the exception and rethrow from await_resume()? + // Or should we require that 'co_await scheduler.schedule()' is noexcept? + } + + // Resume outside the catch-block. + this->m_awaitingCoroutine.resume(); + } + + SCHEDULER& m_scheduler; + // Can't use std::optional here since T could be a reference. + detail::manual_lifetime m_scheduleOperation; + detail::manual_lifetime::awaiter_t> m_scheduleAwaiter; + bool m_isScheduleOperationCreated = false; + bool m_isScheduleAwaiterCreated = false; + }; + + template + template + [[nodiscard]] + sequence_barrier_wait_operation sequence_barrier::wait_until_published( + SEQUENCE targetSequence, + SCHEDULER& scheduler) const noexcept + { + return sequence_barrier_wait_operation(*this, targetSequence, scheduler); + } + + template + void sequence_barrier::publish(SEQUENCE sequence) noexcept + { + m_lastPublished.store(sequence, std::memory_order_seq_cst); + + // Cheaper check to see if there are any awaiting coroutines. + auto* awaiters = m_awaiters.load(std::memory_order_seq_cst); + if (awaiters == nullptr) + { + return; + } + + // Acquire the list of awaiters. + // Note we may be racing with add_awaiter() which could also acquire the list of waiters + // so we need to check again whether we won the race and acquired the list. + awaiters = m_awaiters.exchange(nullptr, std::memory_order_acquire); + if (awaiters == nullptr) + { + return; + } + + // Check the list of awaiters for ones that are now satisfied by the sequence number + // we just published. Awaiters are added to either the 'awaitersToResume' list or to + // the 'awaitersToRequeue' list. + awaiter_t* awaitersToResume; + awaiter_t** awaitersToResumeTail = &awaitersToResume; + + awaiter_t* awaitersToRequeue; + awaiter_t** awaitersToRequeueTail = &awaitersToRequeue; + + do + { + if (TRAITS::precedes(sequence, awaiters->m_targetSequence)) + { + // Target sequence not reached. Append to 'requeue' list. + *awaitersToRequeueTail = awaiters; + awaitersToRequeueTail = &awaiters->m_next; + } + else + { + // Target sequence reached. Append to 'resume' list. + *awaitersToResumeTail = awaiters; + awaitersToResumeTail = &awaiters->m_next; + } + awaiters = awaiters->m_next; + } while (awaiters != nullptr); + + // Null-terminate the two lists. + *awaitersToRequeueTail = nullptr; + *awaitersToResumeTail = nullptr; + + if (awaitersToRequeue != nullptr) + { + awaiter_t* oldHead = nullptr; + while (!m_awaiters.compare_exchange_weak( + oldHead, + awaitersToRequeue, + std::memory_order_release, + std::memory_order_relaxed)) + { + *awaitersToRequeueTail = oldHead; + } + } + + while (awaitersToResume != nullptr) + { + auto* next = awaitersToResume->m_next; + awaitersToResume->m_lastKnownPublished = sequence; + awaitersToResume->resume(); + awaitersToResume = next; + } + } + + template + void sequence_barrier::add_awaiter(awaiter_t* awaiter) const noexcept + { + SEQUENCE targetSequence = awaiter->m_targetSequence; + awaiter_t* awaitersToRequeue = awaiter; + awaiter_t** awaitersToRequeueTail = &awaiter->m_next; + + SEQUENCE lastKnownPublished; + awaiter_t* awaitersToResume; + awaiter_t** awaitersToResumeTail = &awaitersToResume; + + do + { + // Enqueue the awaiter(s) + { + auto* oldHead = m_awaiters.load(std::memory_order_relaxed); + do + { + *awaitersToRequeueTail = oldHead; + } while (!m_awaiters.compare_exchange_weak( + oldHead, + awaitersToRequeue, + std::memory_order_seq_cst, + std::memory_order_relaxed)); + } + + // Check that the sequence we were waiting for wasn't published while + // we were enqueueing the waiter. + // This needs to be seq_cst memory order to ensure that in the case that the producer + // publishes a new sequence number concurrently with this call that we either see + // their write to m_lastPublished after enqueueing our awaiter, or they see our + // write to m_awaiters after their write to m_lastPublished. + lastKnownPublished = m_lastPublished.load(std::memory_order_seq_cst); + if (TRAITS::precedes(lastKnownPublished, targetSequence)) + { + // None of the the awaiters we enqueued have been satisfied yet. + break; + } + + // Reset the requeue list to empty + awaitersToRequeueTail = &awaitersToRequeue; + + // At least one of the awaiters we just enqueued is now satisfied by a concurrently + // published sequence number. The producer thread may not have seen our write to m_awaiters + // so we need to try to re-acquire the list of awaiters to ensure that the waiters that + // are now satisfied are woken up. + auto* awaiters = m_awaiters.exchange(nullptr, std::memory_order_acquire); + + auto minDiff = std::numeric_limits::max(); + + while (awaiters != nullptr) + { + const auto diff = TRAITS::difference(awaiters->m_targetSequence, lastKnownPublished); + if (diff > 0) + { + *awaitersToRequeueTail = awaiters; + awaitersToRequeueTail = &awaiters->m_next; + minDiff = diff < minDiff ? diff : minDiff; + } + else + { + *awaitersToResumeTail = awaiters; + awaitersToResumeTail = &awaiters->m_next; + } + + awaiters = awaiters->m_next; + } + + // Null-terminate the list of awaiters to requeue. + *awaitersToRequeueTail = nullptr; + + // Calculate the earliest target sequence required by any of the awaiters to requeue. + targetSequence = static_cast(lastKnownPublished + minDiff); + + } while (awaitersToRequeue != nullptr); + + // Null-terminate the list of awaiters to resume + *awaitersToResumeTail = nullptr; + + // Resume the awaiters that are ready + while (awaitersToResume != nullptr) + { + auto* next = awaitersToResume->m_next; + awaitersToResume->m_lastKnownPublished = lastKnownPublished; + awaitersToResume->resume(); + awaitersToResume = next; + } + } +} + +#endif diff --git a/include/cppcoro/sequence_range.hpp b/include/cppcoro/sequence_range.hpp new file mode 100644 index 0000000..fcc8145 --- /dev/null +++ b/include/cppcoro/sequence_range.hpp @@ -0,0 +1,107 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_SEQUENCE_RANGE_HPP_INCLUDED +#define CPPCORO_SEQUENCE_RANGE_HPP_INCLUDED + +#include + +#include +#include + +namespace cppcoro +{ + template> + class sequence_range + { + public: + + using value_type = SEQUENCE; + using difference_type = typename TRAITS::difference_type; + using size_type = typename TRAITS::size_type; + + class const_iterator + { + public: + + using iterator_category = std::random_access_iterator_tag; + using value_type = SEQUENCE; + using difference_type = typename TRAITS::difference_type; + using reference = const SEQUENCE&; + using pointer = const SEQUENCE*; + + explicit constexpr const_iterator(SEQUENCE value) noexcept : m_value(value) {} + + const SEQUENCE& operator*() const noexcept { return m_value; } + const SEQUENCE* operator->() const noexcept { return std::addressof(m_value); } + + const_iterator& operator++() noexcept { ++m_value; return *this; } + const_iterator& operator--() noexcept { --m_value; return *this; } + + const_iterator operator++(int) noexcept { return const_iterator(m_value++); } + const_iterator operator--(int) noexcept { return const_iterator(m_value--); } + + constexpr difference_type operator-(const_iterator other) const noexcept { return TRAITS::difference(m_value, other.m_value); } + constexpr const_iterator operator-(difference_type delta) const noexcept { return const_iterator{ static_cast(m_value - delta) }; } + constexpr const_iterator operator+(difference_type delta) const noexcept { return const_iterator{ static_cast(m_value + delta) }; } + + constexpr bool operator==(const_iterator other) const noexcept { return m_value == other.m_value; } + constexpr bool operator!=(const_iterator other) const noexcept { return m_value != other.m_value; } + + private: + + SEQUENCE m_value; + + }; + + constexpr sequence_range() noexcept + : m_begin() + , m_end() + {} + + constexpr sequence_range(SEQUENCE begin, SEQUENCE end) noexcept + : m_begin(begin) + , m_end(end) + {} + + constexpr const_iterator begin() const noexcept { return const_iterator(m_begin); } + constexpr const_iterator end() const noexcept { return const_iterator(m_end); } + + constexpr SEQUENCE front() const noexcept { return m_begin; } + constexpr SEQUENCE back() const noexcept { return m_end - 1; } + + constexpr size_type size() const noexcept + { + return static_cast(TRAITS::difference(m_end, m_begin)); + } + + constexpr bool empty() const noexcept + { + return m_begin == m_end; + } + + constexpr SEQUENCE operator[](size_type index) const noexcept + { + return m_begin + index; + } + + constexpr sequence_range first(size_type count) const noexcept + { + return sequence_range{ m_begin, static_cast(m_begin + std::min(size(), count)) }; + } + + constexpr sequence_range skip(size_type count) const noexcept + { + return sequence_range{ m_begin + std::min(size(), count), m_end }; + } + + private: + + SEQUENCE m_begin; + SEQUENCE m_end; + + }; +} + +#endif diff --git a/include/cppcoro/sequence_traits.hpp b/include/cppcoro/sequence_traits.hpp new file mode 100644 index 0000000..e06744e --- /dev/null +++ b/include/cppcoro/sequence_traits.hpp @@ -0,0 +1,33 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_SEQUENCE_TRAITS_HPP_INCLUDED +#define CPPCORO_SEQUENCE_TRAITS_HPP_INCLUDED + +#include + +namespace cppcoro +{ + template + struct sequence_traits + { + using value_type = SEQUENCE; + using difference_type = std::make_signed_t; + using size_type = std::make_unsigned_t; + + static constexpr value_type initial_sequence = static_cast(-1); + + static constexpr difference_type difference(value_type a, value_type b) + { + return static_cast(a - b); + } + + static constexpr bool precedes(value_type a, value_type b) + { + return difference(a, b) < 0; + } + }; +} + +#endif diff --git a/include/cppcoro/shared_task.hpp b/include/cppcoro/shared_task.hpp new file mode 100644 index 0000000..f447829 --- /dev/null +++ b/include/cppcoro/shared_task.hpp @@ -0,0 +1,511 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_SHARED_LAZY_TASK_HPP_INCLUDED +#define CPPCORO_SHARED_LAZY_TASK_HPP_INCLUDED + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +namespace cppcoro +{ + template + class shared_task; + + namespace detail + { + struct shared_task_waiter + { + cppcoro::coroutine_handle<> m_continuation; + shared_task_waiter* m_next; + }; + + class shared_task_promise_base + { + friend struct final_awaiter; + + struct final_awaiter + { + bool await_ready() const noexcept { return false; } + + template + void await_suspend(cppcoro::coroutine_handle h) noexcept + { + shared_task_promise_base& promise = h.promise(); + + // Exchange operation needs to be 'release' so that subsequent awaiters have + // visibility of the result. Also needs to be 'acquire' so we have visibility + // of writes to the waiters list. + void* const valueReadyValue = &promise; + void* waiters = promise.m_waiters.exchange(valueReadyValue, std::memory_order_acq_rel); + if (waiters != nullptr) + { + shared_task_waiter* waiter = static_cast(waiters); + while (waiter->m_next != nullptr) + { + // Read the m_next pointer before resuming the coroutine + // since resuming the coroutine may destroy the shared_task_waiter value. + auto* next = waiter->m_next; + waiter->m_continuation.resume(); + waiter = next; + } + + // Resume last waiter in tail position to allow it to potentially + // be compiled as a tail-call. + waiter->m_continuation.resume(); + } + } + + void await_resume() noexcept {} + }; + + public: + + shared_task_promise_base() noexcept + : m_refCount(1) + , m_waiters(&this->m_waiters) + , m_exception(nullptr) + {} + + cppcoro::suspend_always initial_suspend() noexcept { return {}; } + final_awaiter final_suspend() noexcept { return {}; } + + void unhandled_exception() noexcept + { + m_exception = std::current_exception(); + } + + bool is_ready() const noexcept + { + const void* const valueReadyValue = this; + return m_waiters.load(std::memory_order_acquire) == valueReadyValue; + } + + void add_ref() noexcept + { + m_refCount.fetch_add(1, std::memory_order_relaxed); + } + + /// Decrement the reference count. + /// + /// \return + /// true if successfully detached, false if this was the last + /// reference to the coroutine, in which case the caller must + /// call destroy() on the coroutine handle. + bool try_detach() noexcept + { + return m_refCount.fetch_sub(1, std::memory_order_acq_rel) != 1; + } + + /// Try to enqueue a waiter to the list of waiters. + /// + /// \param waiter + /// Pointer to the state from the waiter object. + /// Must have waiter->m_coroutine member populated with the coroutine + /// handle of the awaiting coroutine. + /// + /// \param coroutine + /// Coroutine handle for this promise object. + /// + /// \return + /// true if the waiter was successfully queued, in which case + /// waiter->m_coroutine will be resumed when the task completes. + /// false if the coroutine was already completed and the awaiting + /// coroutine can continue without suspending. + bool try_await(shared_task_waiter* waiter, cppcoro::coroutine_handle<> coroutine) + { + void* const valueReadyValue = this; + void* const notStartedValue = &this->m_waiters; + constexpr void* startedNoWaitersValue = static_cast(nullptr); + + // NOTE: If the coroutine is not yet started then the first waiter + // will start the coroutine before enqueuing itself up to the list + // of suspended waiters waiting for completion. We split this into + // two steps to allow the first awaiter to return without suspending. + // This avoids recursively resuming the first waiter inside the call to + // coroutine.resume() in the case that the coroutine completes + // synchronously, which could otherwise lead to stack-overflow if + // the awaiting coroutine awaited many synchronously-completing + // tasks in a row. + + // Start the coroutine if not already started. + void* oldWaiters = m_waiters.load(std::memory_order_acquire); + if (oldWaiters == notStartedValue && + m_waiters.compare_exchange_strong( + oldWaiters, + startedNoWaitersValue, + std::memory_order_relaxed)) + { + // Start the task executing. + coroutine.resume(); + oldWaiters = m_waiters.load(std::memory_order_acquire); + } + + // Enqueue the waiter into the list of waiting coroutines. + do + { + if (oldWaiters == valueReadyValue) + { + // Coroutine already completed, don't suspend. + return false; + } + + waiter->m_next = static_cast(oldWaiters); + } while (!m_waiters.compare_exchange_weak( + oldWaiters, + static_cast(waiter), + std::memory_order_release, + std::memory_order_acquire)); + + return true; + } + + protected: + + bool completed_with_unhandled_exception() + { + return m_exception != nullptr; + } + + void rethrow_if_unhandled_exception() + { + if (m_exception != nullptr) + { + std::rethrow_exception(m_exception); + } + } + + private: + + std::atomic m_refCount; + + // Value is either + // - nullptr - indicates started, no waiters + // - this - indicates value is ready + // - &this->m_waiters - indicates coroutine not started + // - other - pointer to head item in linked-list of waiters. + // values are of type 'cppcoro::shared_task_waiter'. + // indicates that the coroutine has been started. + std::atomic m_waiters; + + std::exception_ptr m_exception; + + }; + + template + class shared_task_promise : public shared_task_promise_base + { + public: + + shared_task_promise() noexcept = default; + + ~shared_task_promise() + { + if (this->is_ready() && !this->completed_with_unhandled_exception()) + { + reinterpret_cast(&m_valueStorage)->~T(); + } + } + + shared_task get_return_object() noexcept; + + template< + typename VALUE, + typename = std::enable_if_t>> + void return_value(VALUE&& value) + noexcept(std::is_nothrow_constructible_v) + { + new (&m_valueStorage) T(std::forward(value)); + } + + T& result() + { + this->rethrow_if_unhandled_exception(); + return *reinterpret_cast(&m_valueStorage); + } + + private: + + // Not using std::aligned_storage here due to bug in MSVC 2015 Update 2 + // that means it doesn't work for types with alignof(T) > 8. + // See MS-Connect bug #2658635. + alignas(T) char m_valueStorage[sizeof(T)]; + + }; + + template<> + class shared_task_promise : public shared_task_promise_base + { + public: + + shared_task_promise() noexcept = default; + + shared_task get_return_object() noexcept; + + void return_void() noexcept + {} + + void result() + { + this->rethrow_if_unhandled_exception(); + } + + }; + + template + class shared_task_promise : public shared_task_promise_base + { + public: + + shared_task_promise() noexcept = default; + + shared_task get_return_object() noexcept; + + void return_value(T& value) noexcept + { + m_value = std::addressof(value); + } + + T& result() + { + this->rethrow_if_unhandled_exception(); + return *m_value; + } + + private: + + T* m_value; + + }; + } + + template + class [[nodiscard]] shared_task + { + public: + + using promise_type = detail::shared_task_promise; + + using value_type = T; + + private: + + struct awaitable_base + { + cppcoro::coroutine_handle m_coroutine; + detail::shared_task_waiter m_waiter; + + awaitable_base(cppcoro::coroutine_handle coroutine) noexcept + : m_coroutine(coroutine) + {} + + bool await_ready() const noexcept + { + return !m_coroutine || m_coroutine.promise().is_ready(); + } + + bool await_suspend(cppcoro::coroutine_handle<> awaiter) noexcept + { + m_waiter.m_continuation = awaiter; + return m_coroutine.promise().try_await(&m_waiter, m_coroutine); + } + }; + + public: + + shared_task() noexcept + : m_coroutine(nullptr) + {} + + explicit shared_task(cppcoro::coroutine_handle coroutine) + : m_coroutine(coroutine) + { + // Don't increment the ref-count here since it has already been + // initialised to 2 (one for shared_task and one for coroutine) + // in the shared_task_promise constructor. + } + + shared_task(shared_task&& other) noexcept + : m_coroutine(other.m_coroutine) + { + other.m_coroutine = nullptr; + } + + shared_task(const shared_task& other) noexcept + : m_coroutine(other.m_coroutine) + { + if (m_coroutine) + { + m_coroutine.promise().add_ref(); + } + } + + ~shared_task() + { + destroy(); + } + + shared_task& operator=(shared_task&& other) noexcept + { + if (&other != this) + { + destroy(); + + m_coroutine = other.m_coroutine; + other.m_coroutine = nullptr; + } + + return *this; + } + + shared_task& operator=(const shared_task& other) noexcept + { + if (m_coroutine != other.m_coroutine) + { + destroy(); + + m_coroutine = other.m_coroutine; + + if (m_coroutine) + { + m_coroutine.promise().add_ref(); + } + } + + return *this; + } + + void swap(shared_task& other) noexcept + { + std::swap(m_coroutine, other.m_coroutine); + } + + /// \brief + /// Query if the task result is complete. + /// + /// Awaiting a task that is ready will not block. + bool is_ready() const noexcept + { + return !m_coroutine || m_coroutine.promise().is_ready(); + } + + auto operator co_await() const noexcept + { + struct awaitable : awaitable_base + { + using awaitable_base::awaitable_base; + + decltype(auto) await_resume() + { + if (!this->m_coroutine) + { + throw broken_promise{}; + } + + return this->m_coroutine.promise().result(); + } + }; + + return awaitable{ m_coroutine }; + } + + /// \brief + /// Returns an awaitable that will await completion of the task without + /// attempting to retrieve the result. + auto when_ready() const noexcept + { + struct awaitable : awaitable_base + { + using awaitable_base::awaitable_base; + + void await_resume() const noexcept {} + }; + + return awaitable{ m_coroutine }; + } + + private: + + template + friend bool operator==(const shared_task&, const shared_task&) noexcept; + + void destroy() noexcept + { + if (m_coroutine) + { + if (!m_coroutine.promise().try_detach()) + { + m_coroutine.destroy(); + } + } + } + + cppcoro::coroutine_handle m_coroutine; + + }; + + template + bool operator==(const shared_task& lhs, const shared_task& rhs) noexcept + { + return lhs.m_coroutine == rhs.m_coroutine; + } + + template + bool operator!=(const shared_task& lhs, const shared_task& rhs) noexcept + { + return !(lhs == rhs); + } + + template + void swap(shared_task& a, shared_task& b) noexcept + { + a.swap(b); + } + + namespace detail + { + template + shared_task shared_task_promise::get_return_object() noexcept + { + return shared_task{ + cppcoro::coroutine_handle::from_promise(*this) + }; + } + + template + shared_task shared_task_promise::get_return_object() noexcept + { + return shared_task{ + cppcoro::coroutine_handle::from_promise(*this) + }; + } + + inline shared_task shared_task_promise::get_return_object() noexcept + { + return shared_task{ + cppcoro::coroutine_handle::from_promise(*this) + }; + } + } + + template + auto make_shared_task(AWAITABLE awaitable) + -> shared_task::await_result_t>> + { + co_return co_await static_cast(awaitable); + } +} + +#endif diff --git a/include/cppcoro/single_consumer_async_auto_reset_event.hpp b/include/cppcoro/single_consumer_async_auto_reset_event.hpp new file mode 100644 index 0000000..56d8a9e --- /dev/null +++ b/include/cppcoro/single_consumer_async_auto_reset_event.hpp @@ -0,0 +1,101 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_SINGLE_CONSUMER_ASYNC_AUTO_RESET_EVENT_HPP_INCLUDED +#define CPPCORO_SINGLE_CONSUMER_ASYNC_AUTO_RESET_EVENT_HPP_INCLUDED + +#include +#include +#include +#include + +namespace cppcoro +{ + class single_consumer_async_auto_reset_event + { + public: + + single_consumer_async_auto_reset_event(bool initiallySet = false) noexcept + : m_state(initiallySet ? this : nullptr) + {} + + void set() noexcept + { + void* oldValue = m_state.exchange(this, std::memory_order_release); + if (oldValue != nullptr && oldValue != this) + { + // There was a waiting coroutine that we now need to resume. + auto handle = *static_cast*>(oldValue); + + // We also need to transition the state back to 'not set' before + // resuming the coroutine. This operation needs to be 'acquire' + // so that it synchronises with other calls to .set() that execute + // concurrently with this call and execute the above m_state.exchange(this) + // operation with 'release' semantics. + // This needs to be an exchange() instead of a store() so that it can have + // 'acquire' semantics. + (void)m_state.exchange(nullptr, std::memory_order_acquire); + + // Finally, resume the waiting coroutine. + handle.resume(); + } + } + + auto operator co_await() const noexcept + { + class awaiter + { + public: + + awaiter(const single_consumer_async_auto_reset_event& event) noexcept + : m_event(event) + {} + + bool await_ready() const noexcept { return false; } + + bool await_suspend(cppcoro::coroutine_handle<> awaitingCoroutine) noexcept + { + m_awaitingCoroutine = awaitingCoroutine; + + void* oldValue = nullptr; + if (!m_event.m_state.compare_exchange_strong( + oldValue, + &m_awaitingCoroutine, + std::memory_order_release, + std::memory_order_relaxed)) + { + // This will only fail if the event was already 'set' + // In which case we can just reset back to 'not set' + // Need to use exchange() rather than store() here so we can make this + // operation an 'acquire' operation so that we get visibility of all + // writes prior to all preceding calls to .set(). + assert(oldValue == &m_event); + (void)m_event.m_state.exchange(nullptr, std::memory_order_acquire); + return false; + } + + return true; + } + + void await_resume() noexcept {} + + private: + const single_consumer_async_auto_reset_event& m_event; + cppcoro::coroutine_handle<> m_awaitingCoroutine; + }; + + return awaiter{ *this }; + } + + private: + + // nullptr - not set, no waiter + // this - set + // other - not set, pointer is address of a coroutine_handle<> to resume. + mutable std::atomic m_state; + + }; +} + +#endif diff --git a/include/cppcoro/single_consumer_event.hpp b/include/cppcoro/single_consumer_event.hpp new file mode 100644 index 0000000..983c5ea --- /dev/null +++ b/include/cppcoro/single_consumer_event.hpp @@ -0,0 +1,128 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_SINGLE_CONSUMER_EVENT_HPP_INCLUDED +#define CPPCORO_SINGLE_CONSUMER_EVENT_HPP_INCLUDED + +#include +#include + +namespace cppcoro +{ + /// \brief + /// A manual-reset event that supports only a single awaiting + /// coroutine at a time. + /// + /// You can co_await the event to suspend the current coroutine until + /// some thread calls set(). If the event is already set then the + /// coroutine will not be suspended and will continue execution. + /// If the event was not yet set then the coroutine will be resumed + /// on the thread that calls set() within the call to set(). + /// + /// Callers must ensure that only one coroutine is executing a + /// co_await statement at any point in time. + class single_consumer_event + { + public: + + /// \brief + /// Construct a new event, initialising to either 'set' or 'not set' state. + /// + /// \param initiallySet + /// If true then initialises the event to the 'set' state. + /// Otherwise, initialised the event to the 'not set' state. + single_consumer_event(bool initiallySet = false) noexcept + : m_state(initiallySet ? state::set : state::not_set) + {} + + /// Query if this event has been set. + bool is_set() const noexcept + { + return m_state.load(std::memory_order_acquire) == state::set; + } + + /// \brief + /// Transition this event to the 'set' state if it is not already set. + /// + /// If there was a coroutine awaiting the event then it will be resumed + /// inside this call. + void set() + { + const state oldState = m_state.exchange(state::set, std::memory_order_acq_rel); + if (oldState == state::not_set_consumer_waiting) + { + m_awaiter.resume(); + } + } + + /// \brief + /// Transition this event to the 'non set' state if it was in the set state. + void reset() noexcept + { + state oldState = state::set; + m_state.compare_exchange_strong(oldState, state::not_set, std::memory_order_relaxed); + } + + /// \brief + /// Wait until the event becomes set. + /// + /// If the event is already set then the awaiting coroutine will not be suspended + /// and will continue execution. If the event was not yet set then the coroutine + /// will be suspended and will be later resumed inside a subsequent call to set() + /// on the thread that calls set(). + auto operator co_await() noexcept + { + class awaiter + { + public: + + awaiter(single_consumer_event& event) : m_event(event) {} + + bool await_ready() const noexcept + { + return m_event.is_set(); + } + + bool await_suspend(cppcoro::coroutine_handle<> awaiter) + { + m_event.m_awaiter = awaiter; + + state oldState = state::not_set; + return m_event.m_state.compare_exchange_strong( + oldState, + state::not_set_consumer_waiting, + std::memory_order_release, + std::memory_order_acquire); + } + + void await_resume() noexcept {} + + private: + + single_consumer_event& m_event; + + }; + + return awaiter{ *this }; + } + + private: + + enum class state + { + not_set, + not_set_consumer_waiting, + set + }; + + // TODO: Merge these two fields into a single std::atomic + // by encoding 'not_set' as 0 (nullptr), 'set' as 1 and + // 'not_set_consumer_waiting' as a coroutine handle pointer. + std::atomic m_state; + cppcoro::coroutine_handle<> m_awaiter; + + }; +} + +#endif diff --git a/include/cppcoro/single_producer_sequencer.hpp b/include/cppcoro/single_producer_sequencer.hpp new file mode 100644 index 0000000..77e8d58 --- /dev/null +++ b/include/cppcoro/single_producer_sequencer.hpp @@ -0,0 +1,246 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_SINGLE_PRODUCER_SEQUENCER_HPP_INCLUDED +#define CPPCORO_SINGLE_PRODUCER_SEQUENCER_HPP_INCLUDED + +#include +#include +#include + +namespace cppcoro +{ + template + class single_producer_sequencer_claim_one_operation; + + template + class single_producer_sequencer_claim_operation; + + template< + typename SEQUENCE = std::size_t, + typename TRAITS = sequence_traits> + class single_producer_sequencer + { + public: + + using size_type = typename sequence_range::size_type; + + single_producer_sequencer( + const sequence_barrier& consumerBarrier, + std::size_t bufferSize, + SEQUENCE initialSequence = TRAITS::initial_sequence) noexcept + : m_consumerBarrier(consumerBarrier) + , m_bufferSize(bufferSize) + , m_nextToClaim(initialSequence + 1) + , m_producerBarrier(initialSequence) + {} + + /// Claim a slot in the ring buffer asynchronously. + /// + /// \return + /// Returns an operation that when awaited will suspend the coroutine until + /// a slot is available for writing in the ring buffer. The result of the + /// co_await expression will be the sequence number of the slot. + /// The caller must publish() the claimed sequence number once they have written to + /// the ring-buffer. + template + [[nodiscard]] + single_producer_sequencer_claim_one_operation + claim_one(SCHEDULER& scheduler) noexcept; + + /// Claim one or more contiguous slots in the ring-buffer. + /// + /// Use this method over many calls to claim_one() when you have multiple elements to + /// enqueue. This will claim as many slots as are available up to the specified count + /// but may claim as few as one slot if only one slot is available. + /// + /// \param count + /// The maximum number of slots to claim. + /// + /// \return + /// Returns an awaitable object that when awaited returns a sequence_range that contains + /// the range of sequence numbers that were claimed. Once you have written element values + /// to all of the claimed slots you must publish() the sequence range in order to make + /// the elements available to consumers. + template + [[nodiscard]] + single_producer_sequencer_claim_operation claim_up_to( + std::size_t count, SCHEDULER& scheduler) noexcept; + + /// Publish the specified sequence number. + /// + /// This also implies that all prior sequence numbers have already been published. + void publish(SEQUENCE sequence) noexcept + { + m_producerBarrier.publish(sequence); + } + + /// Publish a contiguous range of sequence numbers. + /// + /// You must have already published all prior sequence numbers. + /// + /// This is equivalent to just publishing the last sequence number in the range. + void publish(const sequence_range& sequences) noexcept + { + m_producerBarrier.publish(sequences.back()); + } + + /// Query what the last-published sequence number is. + /// + /// You can assume that all prior sequence numbers are also published. + SEQUENCE last_published() const noexcept + { + return m_producerBarrier.last_published(); + } + + /// Asynchronously wait until the specified sequence number is published. + /// + /// \param targetSequence + /// The sequence number to wait for. + /// + /// \return + /// Returns an Awaitable type that, when awaited, will suspend the awaiting coroutine until the + /// specified sequence number has been published. + /// + /// The result of the 'co_await barrier.wait_until_published(seq)' expression will be the + /// last-published sequence number, which is guaranteed to be at least 'seq' but may be some + /// subsequent sequence number if additional items were published while waiting for the + /// the requested sequence number to be published. + template + [[nodiscard]] + auto wait_until_published(SEQUENCE targetSequence, SCHEDULER& scheduler) const noexcept + { + return m_producerBarrier.wait_until_published(targetSequence, scheduler); + } + + private: + + template + friend class single_producer_sequencer_claim_operation; + + template + friend class single_producer_sequencer_claim_one_operation; + +#if CPPCORO_COMPILER_MSVC +# pragma warning(push) +# pragma warning(disable : 4324) // C4324: structure was padded due to alignment specifier +#endif + + const sequence_barrier& m_consumerBarrier; + const std::size_t m_bufferSize; + + alignas(CPPCORO_CPU_CACHE_LINE) + SEQUENCE m_nextToClaim; + + sequence_barrier m_producerBarrier; + +#if CPPCORO_COMPILER_MSVC +# pragma warning(pop) +#endif + }; + + template + class single_producer_sequencer_claim_one_operation + { + public: + + single_producer_sequencer_claim_one_operation( + single_producer_sequencer& sequencer, + SCHEDULER& scheduler) noexcept + : m_consumerWaitOperation( + sequencer.m_consumerBarrier, + static_cast(sequencer.m_nextToClaim - sequencer.m_bufferSize), + scheduler) + , m_sequencer(sequencer) + {} + + bool await_ready() const noexcept + { + return m_consumerWaitOperation.await_ready(); + } + + auto await_suspend(cppcoro::coroutine_handle<> awaitingCoroutine) noexcept + { + return m_consumerWaitOperation.await_suspend(awaitingCoroutine); + } + + SEQUENCE await_resume() const noexcept + { + return m_sequencer.m_nextToClaim++; + } + + private: + + sequence_barrier_wait_operation m_consumerWaitOperation; + single_producer_sequencer& m_sequencer; + + }; + + template + class single_producer_sequencer_claim_operation + { + public: + + explicit single_producer_sequencer_claim_operation( + single_producer_sequencer& sequencer, + std::size_t count, + SCHEDULER& scheduler) noexcept + : m_consumerWaitOperation( + sequencer.m_consumerBarrier, + static_cast(sequencer.m_nextToClaim - sequencer.m_bufferSize), + scheduler) + , m_sequencer(sequencer) + , m_count(count) + {} + + bool await_ready() const noexcept + { + return m_consumerWaitOperation.await_ready(); + } + + auto await_suspend(cppcoro::coroutine_handle<> awaitingCoroutine) noexcept + { + return m_consumerWaitOperation.await_suspend(awaitingCoroutine); + } + + sequence_range await_resume() noexcept + { + const SEQUENCE lastAvailableSequence = + static_cast(m_consumerWaitOperation.await_resume() + m_sequencer.m_bufferSize); + const SEQUENCE begin = m_sequencer.m_nextToClaim; + const std::size_t availableCount = static_cast(lastAvailableSequence - begin) + 1; + const std::size_t countToClaim = std::min(m_count, availableCount); + const SEQUENCE end = static_cast(begin + countToClaim); + m_sequencer.m_nextToClaim = end; + return sequence_range(begin, end); + } + + private: + + sequence_barrier_wait_operation m_consumerWaitOperation; + single_producer_sequencer& m_sequencer; + std::size_t m_count; + + }; + + template + template + [[nodiscard]] + single_producer_sequencer_claim_one_operation + single_producer_sequencer::claim_one(SCHEDULER& scheduler) noexcept + { + return single_producer_sequencer_claim_one_operation{ *this, scheduler }; + } + + template + template + [[nodiscard]] + single_producer_sequencer_claim_operation + single_producer_sequencer::claim_up_to(std::size_t count, SCHEDULER& scheduler) noexcept + { + return single_producer_sequencer_claim_operation(*this, count, scheduler); + } +} + +#endif diff --git a/include/cppcoro/static_thread_pool.hpp b/include/cppcoro/static_thread_pool.hpp new file mode 100644 index 0000000..07a2078 --- /dev/null +++ b/include/cppcoro/static_thread_pool.hpp @@ -0,0 +1,116 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_STATIC_THREAD_POOL_HPP_INCLUDED +#define CPPCORO_STATIC_THREAD_POOL_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include +#include + +namespace cppcoro +{ + class static_thread_pool + { + public: + + /// Initialise to a number of threads equal to the number of cores + /// on the current machine. + static_thread_pool(); + + /// Construct a thread pool with the specified number of threads. + /// + /// \param threadCount + /// The number of threads in the pool that will be used to execute work. + explicit static_thread_pool(std::uint32_t threadCount); + + ~static_thread_pool(); + + class schedule_operation + { + public: + + schedule_operation(static_thread_pool* tp) noexcept : m_threadPool(tp) {} + + bool await_ready() noexcept { return false; } + void await_suspend(cppcoro::coroutine_handle<> awaitingCoroutine) noexcept; + void await_resume() noexcept {} + + private: + + friend class static_thread_pool; + + static_thread_pool* m_threadPool; + cppcoro::coroutine_handle<> m_awaitingCoroutine; + schedule_operation* m_next; + + }; + + std::uint32_t thread_count() const noexcept { return m_threadCount; } + + [[nodiscard]] + schedule_operation schedule() noexcept { return schedule_operation{ this }; } + + private: + + friend class schedule_operation; + + void run_worker_thread(std::uint32_t threadIndex) noexcept; + + void shutdown(); + + void schedule_impl(schedule_operation* operation) noexcept; + + void remote_enqueue(schedule_operation* operation) noexcept; + + bool has_any_queued_work_for(std::uint32_t threadIndex) noexcept; + + bool approx_has_any_queued_work_for(std::uint32_t threadIndex) const noexcept; + + bool is_shutdown_requested() const noexcept; + + void notify_intent_to_sleep(std::uint32_t threadIndex) noexcept; + void try_clear_intent_to_sleep(std::uint32_t threadIndex) noexcept; + + schedule_operation* try_global_dequeue() noexcept; + + /// Try to steal a task from another thread. + /// + /// \return + /// A pointer to the operation that was stolen if one could be stolen + /// from another thread. Otherwise returns nullptr if none of the other + /// threads had any tasks that could be stolen. + schedule_operation* try_steal_from_other_thread(std::uint32_t thisThreadIndex) noexcept; + + void wake_one_thread() noexcept; + + class thread_state; + + static thread_local thread_state* s_currentState; + static thread_local static_thread_pool* s_currentThreadPool; + + const std::uint32_t m_threadCount; + const std::unique_ptr m_threadStates; + + std::vector m_threads; + + std::atomic m_stopRequested; + + std::mutex m_globalQueueMutex; + std::atomic m_globalQueueHead; + + //alignas(std::hardware_destructive_interference_size) + std::atomic m_globalQueueTail; + + //alignas(std::hardware_destructive_interference_size) + std::atomic m_sleepingThreadCount; + + }; +} + +#endif diff --git a/include/cppcoro/sync_wait.hpp b/include/cppcoro/sync_wait.hpp new file mode 100644 index 0000000..c59bcda --- /dev/null +++ b/include/cppcoro/sync_wait.hpp @@ -0,0 +1,50 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_SYNC_WAIT_HPP_INCLUDED +#define CPPCORO_SYNC_WAIT_HPP_INCLUDED + +#include +#include +#include + +#include +#include +#include + +namespace cppcoro +{ + template + auto sync_wait(AWAITABLE&& awaitable) + -> typename cppcoro::awaitable_traits::await_result_t + { + auto task = detail::make_sync_wait_task(std::forward(awaitable)); + detail::lightweight_manual_reset_event event; + task.start(event); + event.wait(); + return task.result(); + } + template + auto sync_wait(AWAITABLE&& awaitable, io_service& srv, std::chrono::system_clock::duration step) + -> typename cppcoro::awaitable_traits::await_result_t + { + auto task = detail::make_sync_wait_task(std::forward(awaitable)); + detail::lightweight_manual_reset_event event; + task.start(event); + event.wait({ &srv, 1 }, step); + return task.result(); + } + template + auto sync_wait(AWAITABLE&& awaitable, std::span srvs, std::chrono::system_clock::duration step) + -> typename cppcoro::awaitable_traits::await_result_t + { + auto task = detail::make_sync_wait_task(std::forward(awaitable)); + detail::lightweight_manual_reset_event event; + task.start(event); + event.wait(srvs, step); + return task.result(); + } +} + +#endif diff --git a/include/cppcoro/task.hpp b/include/cppcoro/task.hpp new file mode 100644 index 0000000..dd261cb --- /dev/null +++ b/include/cppcoro/task.hpp @@ -0,0 +1,481 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_TASK_HPP_INCLUDED +#define CPPCORO_TASK_HPP_INCLUDED + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace cppcoro +{ + template class task; + + namespace detail + { + class task_promise_base + { + friend struct final_awaitable; + + struct final_awaitable + { + bool await_ready() const noexcept { return false; } + +#if CPPCORO_COMPILER_SUPPORTS_SYMMETRIC_TRANSFER + template + cppcoro::coroutine_handle<> await_suspend( + cppcoro::coroutine_handle coro) noexcept + { + return coro.promise().m_continuation; + } +#else + // HACK: Need to add CPPCORO_NOINLINE to await_suspend() method + // to avoid MSVC 2017.8 from spilling some local variables in + // await_suspend() onto the coroutine frame in some cases. + // Without this, some tests in async_auto_reset_event_tests.cpp + // were crashing under x86 optimised builds. + template + CPPCORO_NOINLINE + void await_suspend(cppcoro::coroutine_handle coroutine) noexcept + { + task_promise_base& promise = coroutine.promise(); + + // Use 'release' memory semantics in case we finish before the + // awaiter can suspend so that the awaiting thread sees our + // writes to the resulting value. + // Use 'acquire' memory semantics in case the caller registered + // the continuation before we finished. Ensure we see their write + // to m_continuation. + if (promise.m_state.exchange(true, std::memory_order_acq_rel)) + { + promise.m_continuation.resume(); + } + } +#endif + + void await_resume() noexcept {} + }; + + public: + + task_promise_base() noexcept +#if !CPPCORO_COMPILER_SUPPORTS_SYMMETRIC_TRANSFER + : m_state(false) +#endif + {} + + auto initial_suspend() noexcept + { + return cppcoro::suspend_always{}; + } + + auto final_suspend() noexcept + { + return final_awaitable{}; + } + +#if CPPCORO_COMPILER_SUPPORTS_SYMMETRIC_TRANSFER + void set_continuation(cppcoro::coroutine_handle<> continuation) noexcept + { + m_continuation = continuation; + } +#else + bool try_set_continuation(cppcoro::coroutine_handle<> continuation) + { + m_continuation = continuation; + return !m_state.exchange(true, std::memory_order_acq_rel); + } +#endif + + private: + + cppcoro::coroutine_handle<> m_continuation; + +#if !CPPCORO_COMPILER_SUPPORTS_SYMMETRIC_TRANSFER + // Initially false. Set to true when either a continuation is registered + // or when the coroutine has run to completion. Whichever operation + // successfully transitions from false->true got there first. + std::atomic m_state; +#endif + + }; + + template + class task_promise final : public task_promise_base + { + public: + + task_promise() noexcept {} + + ~task_promise() + { + switch (m_resultType) + { + case result_type::value: + m_value.~T(); + break; + case result_type::exception: + m_exception.~exception_ptr(); + break; + default: + break; + } + } + + task get_return_object() noexcept; + + void unhandled_exception() noexcept + { + ::new (static_cast(std::addressof(m_exception))) std::exception_ptr( + std::current_exception()); + m_resultType = result_type::exception; + } + + template< + typename VALUE, + typename = std::enable_if_t>> + void return_value(VALUE&& value) + noexcept(std::is_nothrow_constructible_v) + { + ::new (static_cast(std::addressof(m_value))) T(std::forward(value)); + m_resultType = result_type::value; + } + + T& result() & + { + if (m_resultType == result_type::exception) + { + std::rethrow_exception(m_exception); + } + + assert(m_resultType == result_type::value); + + return m_value; + } + + // HACK: Need to have co_await of task return prvalue rather than + // rvalue-reference to work around an issue with MSVC where returning + // rvalue reference of a fundamental type from await_resume() will + // cause the value to be copied to a temporary. This breaks the + // sync_wait() implementation. + // See https://github.com/lewissbaker/cppcoro/issues/40#issuecomment-326864107 + using rvalue_type = std::conditional_t< + std::is_arithmetic_v || std::is_pointer_v, + T, + T&&>; + + rvalue_type result() && + { + if (m_resultType == result_type::exception) + { + std::rethrow_exception(m_exception); + } + + assert(m_resultType == result_type::value); + + return std::move(m_value); + } + + private: + + enum class result_type { empty, value, exception }; + + result_type m_resultType = result_type::empty; + + union + { + T m_value; + std::exception_ptr m_exception; + }; + + }; + + template<> + class task_promise : public task_promise_base + { + public: + + task_promise() noexcept = default; + + task get_return_object() noexcept; + + void return_void() noexcept + {} + + void unhandled_exception() noexcept + { + m_exception = std::current_exception(); + } + + void result() + { + if (m_exception) + { + std::rethrow_exception(m_exception); + } + } + + private: + + std::exception_ptr m_exception; + + }; + + template + class task_promise : public task_promise_base + { + public: + + task_promise() noexcept = default; + + task get_return_object() noexcept; + + void unhandled_exception() noexcept + { + m_exception = std::current_exception(); + } + + void return_value(T& value) noexcept + { + m_value = std::addressof(value); + } + + T& result() + { + if (m_exception) + { + std::rethrow_exception(m_exception); + } + + return *m_value; + } + + private: + + T* m_value = nullptr; + std::exception_ptr m_exception; + + }; + } + + /// \brief + /// A task represents an operation that produces a result both lazily + /// and asynchronously. + /// + /// When you call a coroutine that returns a task, the coroutine + /// simply captures any passed parameters and returns exeuction to the + /// caller. Execution of the coroutine body does not start until the + /// coroutine is first co_await'ed. + template + class [[nodiscard]] task + { + public: + + using promise_type = detail::task_promise; + + using value_type = T; + + private: + + struct awaitable_base + { + cppcoro::coroutine_handle m_coroutine; + + awaitable_base(cppcoro::coroutine_handle coroutine) noexcept + : m_coroutine(coroutine) + {} + + bool await_ready() const noexcept + { + return !m_coroutine || m_coroutine.done(); + } + +#if CPPCORO_COMPILER_SUPPORTS_SYMMETRIC_TRANSFER + cppcoro::coroutine_handle<> await_suspend( + cppcoro::coroutine_handle<> awaitingCoroutine) noexcept + { + m_coroutine.promise().set_continuation(awaitingCoroutine); + return m_coroutine; + } +#else + bool await_suspend(cppcoro::coroutine_handle<> awaitingCoroutine) noexcept + { + // NOTE: We are using the bool-returning version of await_suspend() here + // to work around a potential stack-overflow issue if a coroutine + // awaits many synchronously-completing tasks in a loop. + // + // We first start the task by calling resume() and then conditionally + // attach the continuation if it has not already completed. This allows us + // to immediately resume the awaiting coroutine without increasing + // the stack depth, avoiding the stack-overflow problem. However, it has + // the down-side of requiring a std::atomic to arbitrate the race between + // the coroutine potentially completing on another thread concurrently + // with registering the continuation on this thread. + // + // We can eliminate the use of the std::atomic once we have access to + // coroutine_handle-returning await_suspend() on both MSVC and Clang + // as this will provide ability to suspend the awaiting coroutine and + // resume another coroutine with a guaranteed tail-call to resume(). + m_coroutine.resume(); + return m_coroutine.promise().try_set_continuation(awaitingCoroutine); + } +#endif + }; + + public: + + task() noexcept + : m_coroutine(nullptr) + {} + + explicit task(cppcoro::coroutine_handle coroutine) + : m_coroutine(coroutine) + {} + + task(task&& t) noexcept + : m_coroutine(t.m_coroutine) + { + t.m_coroutine = nullptr; + } + + /// Disable copy construction/assignment. + task(const task&) = delete; + task& operator=(const task&) = delete; + + /// Frees resources used by this task. + ~task() + { + if (m_coroutine) + { + m_coroutine.destroy(); + } + } + + task& operator=(task&& other) noexcept + { + if (std::addressof(other) != this) + { + if (m_coroutine) + { + m_coroutine.destroy(); + } + + m_coroutine = other.m_coroutine; + other.m_coroutine = nullptr; + } + + return *this; + } + + /// \brief + /// Query if the task result is complete. + /// + /// Awaiting a task that is ready is guaranteed not to block/suspend. + bool is_ready() const noexcept + { + return !m_coroutine || m_coroutine.done(); + } + + auto operator co_await() const & noexcept + { + struct awaitable : awaitable_base + { + using awaitable_base::awaitable_base; + + decltype(auto) await_resume() + { + if (!this->m_coroutine) + { + throw broken_promise{}; + } + + return this->m_coroutine.promise().result(); + } + }; + + return awaitable{ m_coroutine }; + } + + auto operator co_await() const && noexcept + { + struct awaitable : awaitable_base + { + using awaitable_base::awaitable_base; + + decltype(auto) await_resume() + { + if (!this->m_coroutine) + { + throw broken_promise{}; + } + + return std::move(this->m_coroutine.promise()).result(); + } + }; + + return awaitable{ m_coroutine }; + } + + /// \brief + /// Returns an awaitable that will await completion of the task without + /// attempting to retrieve the result. + auto when_ready() const noexcept + { + struct awaitable : awaitable_base + { + using awaitable_base::awaitable_base; + + void await_resume() const noexcept {} + }; + + return awaitable{ m_coroutine }; + } + + private: + + cppcoro::coroutine_handle m_coroutine; + + }; + + namespace detail + { + template + task task_promise::get_return_object() noexcept + { + return task{ cppcoro::coroutine_handle::from_promise(*this) }; + } + + inline task task_promise::get_return_object() noexcept + { + return task{ cppcoro::coroutine_handle::from_promise(*this) }; + } + + template + task task_promise::get_return_object() noexcept + { + return task{ cppcoro::coroutine_handle::from_promise(*this) }; + } + } + + template + auto make_task(AWAITABLE awaitable) + -> task::await_result_t>> + { + co_return co_await static_cast(awaitable); + } +} + +#endif diff --git a/include/cppcoro/when_all.hpp b/include/cppcoro/when_all.hpp new file mode 100644 index 0000000..f0c1be8 --- /dev/null +++ b/include/cppcoro/when_all.hpp @@ -0,0 +1,91 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_WHEN_ALL_HPP_INCLUDED +#define CPPCORO_WHEN_ALL_HPP_INCLUDED + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +namespace cppcoro +{ + ////////// + // Variadic when_all() + + template< + typename... AWAITABLES, + std::enable_if_t< + std::conjunction_v>>...>, + int> = 0> + [[nodiscard]] auto when_all(AWAITABLES&&... awaitables) + { + return fmap([](auto&& taskTuple) + { + return std::apply([](auto&&... tasks) { + return std::make_tuple(static_cast(tasks).non_void_result()...); + }, static_cast(taskTuple)); + }, when_all_ready(std::forward(awaitables)...)); + } + + ////////// + // when_all() with vector of awaitable + + template< + typename AWAITABLE, + typename RESULT = typename awaitable_traits>::await_result_t, + std::enable_if_t, int> = 0> + [[nodiscard]] + auto when_all(std::vector awaitables) + { + return fmap([](auto&& taskVector) { + for (auto& task : taskVector) + { + task.result(); + } + }, when_all_ready(std::move(awaitables))); + } + + template< + typename AWAITABLE, + typename RESULT = typename awaitable_traits>::await_result_t, + std::enable_if_t, int> = 0> + [[nodiscard]] + auto when_all(std::vector awaitables) + { + using result_t = std::conditional_t< + std::is_lvalue_reference_v, + std::reference_wrapper>, + std::remove_reference_t>; + + return fmap([](auto&& taskVector) { + std::vector results; + results.reserve(taskVector.size()); + for (auto& task : taskVector) + { + if constexpr (std::is_rvalue_reference_v) + { + results.emplace_back(std::move(task).result()); + } + else + { + results.emplace_back(task.result()); + } + } + return results; + }, when_all_ready(std::move(awaitables))); + } +} + +#endif diff --git a/include/cppcoro/when_all_ready.hpp b/include/cppcoro/when_all_ready.hpp new file mode 100644 index 0000000..dccc80f --- /dev/null +++ b/include/cppcoro/when_all_ready.hpp @@ -0,0 +1,56 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_WHEN_ALL_READY_HPP_INCLUDED +#define CPPCORO_WHEN_ALL_READY_HPP_INCLUDED + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +namespace cppcoro +{ + template< + typename... AWAITABLES, + std::enable_if_t>>...>, int> = 0> + [[nodiscard]] + CPPCORO_FORCE_INLINE auto when_all_ready(AWAITABLES&&... awaitables) + { + return detail::when_all_ready_awaitable>>::await_result_t>...>>( + std::make_tuple(detail::make_when_all_task(std::forward(awaitables))...)); + } + + // TODO: Generalise this from vector to arbitrary sequence of awaitable. + + template< + typename AWAITABLE, + typename RESULT = typename awaitable_traits>::await_result_t> + [[nodiscard]] auto when_all_ready(std::vector awaitables) + { + std::vector> tasks; + + tasks.reserve(awaitables.size()); + + for (auto& awaitable : awaitables) + { + tasks.emplace_back(detail::make_when_all_task(std::move(awaitable))); + } + + return detail::when_all_ready_awaitable>>( + std::move(tasks)); + } +} + +#endif diff --git a/include/cppcoro/writable_file.hpp b/include/cppcoro/writable_file.hpp new file mode 100644 index 0000000..40ef7fe --- /dev/null +++ b/include/cppcoro/writable_file.hpp @@ -0,0 +1,71 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_WRITABLE_FILE_HPP_INCLUDED +#define CPPCORO_WRITABLE_FILE_HPP_INCLUDED + +#include +#include +#include + +namespace cppcoro +{ + class writable_file : virtual public file + { + public: + + /// Set the size of the file. + /// + /// \param fileSize + /// The new size of the file in bytes. + void set_size(std::uint64_t fileSize); + + /// Write some data to the file. + /// + /// Writes \a byteCount bytes from the file starting at \a offset + /// into the specified \a buffer. + /// + /// \param offset + /// The offset within the file to start writing from. + /// If the file has been opened using file_buffering_mode::unbuffered + /// then the offset must be a multiple of the file-system's sector size. + /// + /// \param buffer + /// The buffer containing the data to be written to the file. + /// If the file has been opened using file_buffering_mode::unbuffered + /// then the address of the start of the buffer must be a multiple of + /// the file-system's sector size. + /// + /// \param byteCount + /// The number of bytes to write to the file. + /// If the file has been opeend using file_buffering_mode::unbuffered + /// then the byteCount must be a multiple of the file-system's sector size. + /// + /// \param ct + /// An optional cancellation_token that can be used to cancel the + /// write operation before it completes. + /// + /// \return + /// An object that represents the write operation. + /// This object must be co_await'ed to start the write operation. + [[nodiscard]] + file_write_operation write( + std::uint64_t offset, + const void* buffer, + std::size_t byteCount) noexcept; + [[nodiscard]] + file_write_operation_cancellable write( + std::uint64_t offset, + const void* buffer, + std::size_t byteCount, + cancellation_token ct) noexcept; + + protected: + + using file::file; + + }; +} + +#endif diff --git a/include/cppcoro/write_only_file.hpp b/include/cppcoro/write_only_file.hpp new file mode 100644 index 0000000..1af6657 --- /dev/null +++ b/include/cppcoro/write_only_file.hpp @@ -0,0 +1,65 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_WRITE_ONLY_FILE_HPP_INCLUDED +#define CPPCORO_WRITE_ONLY_FILE_HPP_INCLUDED + +#include +#include +#include +#include + +#include + +namespace cppcoro +{ + class write_only_file : public writable_file + { + public: + + /// Open a file for write-only access. + /// + /// \param ioContext + /// The I/O context to use when dispatching I/O completion events. + /// When asynchronous write operations on this file complete the + /// completion events will be dispatched to an I/O thread associated + /// with the I/O context. + /// + /// \param pathMode + /// Path of the file to open. + /// + /// \param openMode + /// Specifies how the file should be opened and how to handle cases + /// when the file exists or doesn't exist. + /// + /// \param shareMode + /// Specifies the access to be allowed on the file concurrently with this file access. + /// + /// \param bufferingMode + /// Specifies the modes/hints to provide to the OS that affects the behaviour + /// of its file buffering. + /// + /// \return + /// An object that can be used to write to the file. + /// + /// \throw std::system_error + /// If the file could not be opened for write. + [[nodiscard]] + static write_only_file open( + io_service& ioService, + const cppcoro::filesystem::path& path, + file_open_mode openMode = file_open_mode::create_or_open, + file_share_mode shareMode = file_share_mode::none, + file_buffering_mode bufferingMode = file_buffering_mode::default_); + + protected: + +#if CPPCORO_OS_WINNT + write_only_file(detail::win32::safe_handle&& fileHandle) noexcept; +#endif + + }; +} + +#endif diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 0000000..3ea6a31 --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,178 @@ +set(includes + awaitable_traits.hpp + is_awaitable.hpp + async_auto_reset_event.hpp + async_manual_reset_event.hpp + async_generator.hpp + async_mutex.hpp + async_latch.hpp + async_scope.hpp + broken_promise.hpp + cancellation_registration.hpp + cancellation_source.hpp + cancellation_token.hpp + task.hpp + sequence_barrier.hpp + sequence_traits.hpp + single_producer_sequencer.hpp + multi_producer_sequencer.hpp + shared_task.hpp + shared_task.hpp + single_consumer_event.hpp + single_consumer_async_auto_reset_event.hpp + sync_wait.hpp + task.hpp + io_service.hpp + config.hpp + on_scope_exit.hpp + file_share_mode.hpp + file_open_mode.hpp + file_buffering_mode.hpp + file.hpp + fmap.hpp + when_all.hpp + when_all_ready.hpp + resume_on.hpp + schedule_on.hpp + generator.hpp + readable_file.hpp + recursive_generator.hpp + writable_file.hpp + read_only_file.hpp + write_only_file.hpp + read_write_file.hpp + file_read_operation.hpp + file_write_operation.hpp + static_thread_pool.hpp +) +list(TRANSFORM includes PREPEND "${PROJECT_SOURCE_DIR}/include/cppcoro/") + +set(netIncludes + ip_address.hpp + ip_endpoint.hpp + ipv4_address.hpp + ipv4_endpoint.hpp + ipv6_address.hpp + ipv6_endpoint.hpp + socket.hpp +) +list(TRANSFORM netIncludes PREPEND "${PROJECT_SOURCE_DIR}/include/cppcoro/net/") + +set(detailIncludes + void_value.hpp + when_all_ready_awaitable.hpp + when_all_counter.hpp + when_all_task.hpp + get_awaiter.hpp + is_awaiter.hpp + any.hpp + sync_wait_task.hpp + unwrap_reference.hpp + lightweight_manual_reset_event.hpp +) +list(TRANSFORM detailIncludes PREPEND "${PROJECT_SOURCE_DIR}/include/cppcoro/detail/") + +set(privateHeaders + cancellation_state.hpp + socket_helpers.hpp + auto_reset_event.hpp + spin_wait.hpp + spin_mutex.hpp +) + +set(sources + async_auto_reset_event.cpp + async_manual_reset_event.cpp + async_mutex.cpp + cancellation_state.cpp + cancellation_token.cpp + cancellation_source.cpp + cancellation_registration.cpp + lightweight_manual_reset_event.cpp + ip_address.cpp + ip_endpoint.cpp + ipv4_address.cpp + ipv4_endpoint.cpp + ipv6_address.cpp + ipv6_endpoint.cpp + static_thread_pool.cpp + auto_reset_event.cpp + spin_wait.cpp + spin_mutex.cpp +) + +if(WIN32) + set(win32DetailIncludes + win32.hpp + win32_overlapped_operation.hpp + ) + list(TRANSFORM win32DetailIncludes PREPEND "${PROJECT_SOURCE_DIR}/include/cppcoro/detail/") + list(APPEND detailIncludes ${win32DetailIncludes}) + + set(win32NetIncludes + socket.hpp + socket_accept_operation.hpp + socket_connect_operation.hpp + socket_disconnect_operation.hpp + socket_recv_operation.hpp + socket_recv_from_operation.hpp + socket_send_operation.hpp + socket_send_to_operation.hpp + ) + list(TRANSFORM win32NetIncludes PREPEND "${PROJECT_SOURCE_DIR}/include/cppcoro/net/") + list(APPEND netIncludes ${win32NetIncludes}) + + set(win32Sources + win32.cpp + io_service.cpp + file.cpp + readable_file.cpp + writable_file.cpp + read_only_file.cpp + write_only_file.cpp + read_write_file.cpp + file_read_operation.cpp + file_write_operation.cpp + socket_helpers.cpp + socket.cpp + socket_accept_operation.cpp + socket_connect_operation.cpp + socket_disconnect_operation.cpp + socket_send_operation.cpp + socket_send_to_operation.cpp + socket_recv_operation.cpp + socket_recv_from_operation.cpp + ) + list(APPEND sources ${win32Sources}) + + list(APPEND libraries Ws2_32 Mswsock Synchronization) + list(APPEND compile_options /EHsc) + + if("${MSVC_VERSION}" VERSION_GREATER_EQUAL 1900) + # TODO remove this when experimental/non-experimental include are fixed + list(APPEND compile_definition _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING=1) + endif() +endif() + +add_library(cppcoro + ${includes} + ${netIncludes} + ${detailIncludes} + ${privateHeaders} + ${sources} +) + +target_include_directories(cppcoro PUBLIC + $ + $) + +target_compile_definitions(cppcoro PUBLIC ${compile_definition}) +target_compile_options(cppcoro PUBLIC ${compile_options}) + +#find_package(Coroutines COMPONENTS Experimental Final REQUIRED) +#target_link_libraries(cppcoro PUBLIC std::coroutines ${libraries}) + +install(TARGETS cppcoro EXPORT cppcoroTargets + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + RUNTIME DESTINATION bin) diff --git a/lib/async_auto_reset_event.cpp b/lib/async_auto_reset_event.cpp new file mode 100644 index 0000000..fa0bb73 --- /dev/null +++ b/lib/async_auto_reset_event.cpp @@ -0,0 +1,285 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include + +#include + +#include +#include + +namespace +{ + namespace local + { + // Some helpers for manipulating the 'm_state' value. + + constexpr std::uint64_t set_increment = 1; + constexpr std::uint64_t waiter_increment = std::uint64_t(1) << 32; + + constexpr std::uint32_t get_set_count(std::uint64_t state) + { + return static_cast(state); + } + + constexpr std::uint32_t get_waiter_count(std::uint64_t state) + { + return static_cast(state >> 32); + } + + constexpr std::uint32_t get_resumable_waiter_count(std::uint64_t state) + { + return std::min(get_set_count(state), get_waiter_count(state)); + } + } +} + +cppcoro::async_auto_reset_event::async_auto_reset_event(bool initiallySet) noexcept + : m_state(initiallySet ? local::set_increment : 0) + , m_newWaiters(nullptr) + , m_waiters(nullptr) +{ +} + +cppcoro::async_auto_reset_event::~async_auto_reset_event() +{ + assert(m_newWaiters.load(std::memory_order_relaxed) == nullptr); + assert(m_waiters == nullptr); +} + +cppcoro::async_auto_reset_event_operation +cppcoro::async_auto_reset_event::operator co_await() const noexcept +{ + std::uint64_t oldState = m_state.load(std::memory_order_relaxed); + if (local::get_set_count(oldState) > local::get_waiter_count(oldState)) + { + // Try to synchronously acquire the event. + if (m_state.compare_exchange_strong( + oldState, + oldState - local::set_increment, + std::memory_order_acquire, + std::memory_order_relaxed)) + { + // Acquired the event, return an operation object that + // won't suspend. + return async_auto_reset_event_operation{}; + } + } + + return async_auto_reset_event_operation{ *this }; +} + +void cppcoro::async_auto_reset_event::set() noexcept +{ + std::uint64_t oldState = m_state.load(std::memory_order_relaxed); + do + { + if (local::get_set_count(oldState) > local::get_waiter_count(oldState)) + { + // Already set. + return; + } + + // Increment the set-count + } while (!m_state.compare_exchange_weak( + oldState, + oldState + local::set_increment, + std::memory_order_acq_rel, + std::memory_order_acquire)); + + // Did we transition from non-zero waiters and zero set-count + // to non-zero set-count? + // If so then we acquired the lock and are responsible for resuming waiters. + if (oldState != 0 && local::get_set_count(oldState) == 0) + { + // We acquired the lock. + resume_waiters(oldState + local::set_increment); + } +} + +void cppcoro::async_auto_reset_event::reset() noexcept +{ + std::uint64_t oldState = m_state.load(std::memory_order_relaxed); + while (local::get_set_count(oldState) > local::get_waiter_count(oldState)) + { + if (m_state.compare_exchange_weak( + oldState, + oldState - local::set_increment, + std::memory_order_relaxed)) + { + // Successfully reset. + return; + } + } + + // Not set. Nothing to do. +} + +void cppcoro::async_auto_reset_event::resume_waiters( + std::uint64_t initialState) const noexcept +{ + async_auto_reset_event_operation* waitersToResumeList = nullptr; + async_auto_reset_event_operation** waitersToResumeListEnd = &waitersToResumeList; + + std::uint32_t waiterCountToResume = local::get_resumable_waiter_count(initialState); + + assert(waiterCountToResume > 0); + + do + { + // Dequeue 'waiterCountToResume' from m_waiters/m_newWaiters and + // push them onto 'waitersToResumeList'. + for (std::uint32_t i = 0; i < waiterCountToResume; ++i) + { + if (m_waiters == nullptr) + { + // We've run out of of waiters that we can consume without synchronisation + // Dequeue the list of new waiters atomically. + auto* newWaiters = m_newWaiters.exchange(nullptr, std::memory_order_acquire); + + // There should always be enough waiters in the list as + // the waiters are queued before the waiter-count is incremented. + assert(newWaiters != nullptr); + CPPCORO_ASSUME(newWaiters != nullptr); + + // Reverse order of new waiters so they are resumed in FIFO. + // This ensures fairness. + // + // The alternative would be to not reverse the list and instead + // resume waiters in the reverse order they were queued in. + // This might result in better cache locality (most recently + // suspended coroutine might still be in cache). + // It should still provide a bounded wait time as well since we + // are guaranteed to process all waiters in this list before + // looking at any waiters newly queued after this point. + // Something to consider. + do + { + auto* next = newWaiters->m_next; + newWaiters->m_next = m_waiters; + m_waiters = newWaiters; + newWaiters = next; + } while (newWaiters != nullptr); + } + + assert(m_waiters != nullptr); + + // Pop the next waiter off the list + auto* waiterToResume = m_waiters; + m_waiters = m_waiters->m_next; + + // Push it onto the end of the list of waiters to resume + waiterToResume->m_next = nullptr; + *waitersToResumeListEnd = waiterToResume; + waitersToResumeListEnd = &waiterToResume->m_next; + } + + // We've now removed 'waiterCountToResume' waiters from the list + // so we can now decrement both the waiter and set count. + // + // However, there might have been more waiters or more calls to + // set() since we last checked so we need to go around again if + // there are still waiters that are ready to resume after decrementing + // both the 'waiter count' and 'set count' by 'waiterCountToResume'. + const std::uint64_t delta = + std::uint64_t(waiterCountToResume) | + std::uint64_t(waiterCountToResume) << 32; + + // Needs to be 'release' as we're releasing the lock and anyone that + // subsequently acquires the lock needs to see our prior writes to + // m_waiters. + // Needs to be 'acquire' in the case that new waiters were added so + // that we see their prior writes to 'm_newWaiters'. + const std::uint64_t newState = + m_state.fetch_sub(delta, std::memory_order_acq_rel) - delta; + + waiterCountToResume = local::get_resumable_waiter_count(newState); + } while (waiterCountToResume > 0); + + // Now resume all of the waiters we've dequeued. + // There should be at least one. + assert(waitersToResumeList != nullptr); + CPPCORO_ASSUME(waitersToResumeList != nullptr); + + do + { + auto* const waiter = waitersToResumeList; + + // Read 'next' before resuming since resuming the waiter is + // likely to destroy the waiter object. + auto* const next = waitersToResumeList->m_next; + + // Decrement reference count and see if we decremented the last + // reference and if so then we are responsible for resuming. + // If not, then await_suspend() is responsible for resuming by + // returning 'false' and not suspending. + if (waiter->m_refCount.fetch_sub(1, std::memory_order_release) == 1) + { + waiter->m_awaiter.resume(); + } + + waitersToResumeList = next; + } while (waitersToResumeList != nullptr); +} + +cppcoro::async_auto_reset_event_operation::async_auto_reset_event_operation() noexcept + : m_event(nullptr) +{} + +cppcoro::async_auto_reset_event_operation::async_auto_reset_event_operation( + const async_auto_reset_event& event) noexcept + : m_event(&event) + , m_refCount(2) +{} + +cppcoro::async_auto_reset_event_operation::async_auto_reset_event_operation( + const async_auto_reset_event_operation& other) noexcept + : m_event(other.m_event) + , m_refCount(2) +{} + +bool cppcoro::async_auto_reset_event_operation::await_suspend( + cppcoro::coroutine_handle<> awaiter) noexcept +{ + m_awaiter = awaiter; + + // Queue the waiter to the m_newWaiters list. + async_auto_reset_event_operation* head = m_event->m_newWaiters.load(std::memory_order_relaxed); + do + { + m_next = head; + } while (!m_event->m_newWaiters.compare_exchange_weak( + head, + this, + std::memory_order_release, + std::memory_order_relaxed)); + + // Increment the waiter count. + // Needs to be 'release' so that our prior write to m_newWaiters is + // visible to anyone that acquires the lock. + // Needs to be 'acquire' in case we acquired the lock so we can see + // others' writes to m_newWaiters and writes prior to set() calls. + const std::uint64_t oldState = + m_event->m_state.fetch_add(local::waiter_increment, std::memory_order_acq_rel); + + if (oldState != 0 && local::get_waiter_count(oldState) == 0) + { + // We transitioned from non-zero set and zero waiters to + // non-zero set and non-zero waiters, so we acquired the lock + // and thus responsibility for resuming waiters. + m_event->resume_waiters(oldState + local::waiter_increment); + } + + // Decrement the ref-count to indicate that this waiter is now safe + // to resume. We don't want it to resume while we're still accessing the + // m_event object as resuming it might cause the event object to be + // destructed. + // + // Need 'acquire' semantics here in the case that another thread has + // concurrently dequeued us and scheduled us for resumption by decrementing + // the ref-count with 'release' semantics so that we see the writes prior + // to the 'set()' call that released this waiter. + return m_refCount.fetch_sub(1, std::memory_order_acquire) != 1; +} diff --git a/lib/async_manual_reset_event.cpp b/lib/async_manual_reset_event.cpp new file mode 100644 index 0000000..f663b00 --- /dev/null +++ b/lib/async_manual_reset_event.cpp @@ -0,0 +1,99 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include + +#include + +#include + +cppcoro::async_manual_reset_event::async_manual_reset_event(bool initiallySet) noexcept + : m_state(initiallySet ? static_cast(this) : nullptr) +{} + +cppcoro::async_manual_reset_event::~async_manual_reset_event() +{ + // There should be no coroutines still awaiting the event. + assert( + m_state.load(std::memory_order_relaxed) == nullptr || + m_state.load(std::memory_order_relaxed) == static_cast(this)); +} + +bool cppcoro::async_manual_reset_event::is_set() const noexcept +{ + return m_state.load(std::memory_order_acquire) == static_cast(this); +} + +cppcoro::async_manual_reset_event_operation +cppcoro::async_manual_reset_event::operator co_await() const noexcept +{ + return async_manual_reset_event_operation{ *this }; +} + +void cppcoro::async_manual_reset_event::set() noexcept +{ + void* const setState = static_cast(this); + + // Needs 'release' semantics so that prior writes are visible to event awaiters + // that synchronise either via 'is_set()' or 'operator co_await()'. + // Needs 'acquire' semantics in case there are any waiters so that we see + // prior writes to the waiting coroutine's state and to the contents of + // the queued async_manual_reset_event_operation objects. + void* oldState = m_state.exchange(setState, std::memory_order_acq_rel); + if (oldState != setState) + { + auto* current = static_cast(oldState); + while (current != nullptr) + { + auto* next = current->m_next; + current->m_awaiter.resume(); + current = next; + } + } +} + +void cppcoro::async_manual_reset_event::reset() noexcept +{ + void* oldState = static_cast(this); + m_state.compare_exchange_strong(oldState, nullptr, std::memory_order_relaxed); +} + +cppcoro::async_manual_reset_event_operation::async_manual_reset_event_operation( + const async_manual_reset_event& event) noexcept + : m_event(event) +{ +} + +bool cppcoro::async_manual_reset_event_operation::await_ready() const noexcept +{ + return m_event.is_set(); +} + +bool cppcoro::async_manual_reset_event_operation::await_suspend( + cppcoro::coroutine_handle<> awaiter) noexcept +{ + m_awaiter = awaiter; + + const void* const setState = static_cast(&m_event); + + void* oldState = m_event.m_state.load(std::memory_order_acquire); + do + { + if (oldState == setState) + { + // State is now 'set' no need to suspend. + return false; + } + + m_next = static_cast(oldState); + } while (!m_event.m_state.compare_exchange_weak( + oldState, + static_cast(this), + std::memory_order_release, + std::memory_order_acquire)); + + // Successfully queued this waiter to the list. + return true; +} diff --git a/lib/async_mutex.cpp b/lib/async_mutex.cpp new file mode 100644 index 0000000..f713c93 --- /dev/null +++ b/lib/async_mutex.cpp @@ -0,0 +1,122 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include + +#include + +cppcoro::async_mutex::async_mutex() noexcept + : m_state(not_locked) + , m_waiters(nullptr) +{} + +cppcoro::async_mutex::~async_mutex() +{ + [[maybe_unused]] auto state = m_state.load(std::memory_order_relaxed); + assert(state == not_locked || state == locked_no_waiters); + assert(m_waiters == nullptr); +} + +bool cppcoro::async_mutex::try_lock() noexcept +{ + // Try to atomically transition from nullptr (not-locked) -> this (locked-no-waiters). + auto oldState = not_locked; + return m_state.compare_exchange_strong( + oldState, + locked_no_waiters, + std::memory_order_acquire, + std::memory_order_relaxed); +} + +cppcoro::async_mutex_lock_operation cppcoro::async_mutex::lock_async() noexcept +{ + return async_mutex_lock_operation{ *this }; +} + +cppcoro::async_mutex_scoped_lock_operation cppcoro::async_mutex::scoped_lock_async() noexcept +{ + return async_mutex_scoped_lock_operation{ *this }; +} + +void cppcoro::async_mutex::unlock() +{ + assert(m_state.load(std::memory_order_relaxed) != not_locked); + + async_mutex_lock_operation* waitersHead = m_waiters; + if (waitersHead == nullptr) + { + auto oldState = locked_no_waiters; + const bool releasedLock = m_state.compare_exchange_strong( + oldState, + not_locked, + std::memory_order_release, + std::memory_order_relaxed); + if (releasedLock) + { + return; + } + + // At least one new waiter. + // Acquire the list of new waiter operations atomically. + oldState = m_state.exchange(locked_no_waiters, std::memory_order_acquire); + + assert(oldState != locked_no_waiters && oldState != not_locked); + + // Transfer the list to m_waiters, reversing the list in the process so + // that the head of the list is the first to be resumed. + auto* next = reinterpret_cast(oldState); + do + { + auto* temp = next->m_next; + next->m_next = waitersHead; + waitersHead = next; + next = temp; + } while (next != nullptr); + } + + assert(waitersHead != nullptr); + + m_waiters = waitersHead->m_next; + + // Resume the waiter. + // This will pass the ownership of the lock on to that operation/coroutine. + waitersHead->m_awaiter.resume(); +} + +bool cppcoro::async_mutex_lock_operation::await_suspend(cppcoro::coroutine_handle<> awaiter) noexcept +{ + m_awaiter = awaiter; + + std::uintptr_t oldState = m_mutex.m_state.load(std::memory_order_acquire); + while (true) + { + if (oldState == async_mutex::not_locked) + { + if (m_mutex.m_state.compare_exchange_weak( + oldState, + async_mutex::locked_no_waiters, + std::memory_order_acquire, + std::memory_order_relaxed)) + { + // Acquired lock, don't suspend. + return false; + } + } + else + { + // Try to push this operation onto the head of the waiter stack. + m_next = reinterpret_cast(oldState); + if (m_mutex.m_state.compare_exchange_weak( + oldState, + reinterpret_cast(this), + std::memory_order_release, + std::memory_order_relaxed)) + { + // Queued operation to waiters list, suspend now. + return true; + } + } + } +} diff --git a/lib/auto_reset_event.cpp b/lib/auto_reset_event.cpp new file mode 100644 index 0000000..25e0f3e --- /dev/null +++ b/lib/auto_reset_event.cpp @@ -0,0 +1,97 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include "auto_reset_event.hpp" + +#if CPPCORO_OS_WINNT +# define WIN32_LEAN_AND_MEAN +# include +# include +#endif + +namespace cppcoro +{ +#if CPPCORO_OS_WINNT + + auto_reset_event::auto_reset_event(bool initiallySet) + : m_event(::CreateEventW(NULL, FALSE, initiallySet ? TRUE : FALSE, NULL)) + { + if (m_event.handle() == NULL) + { + DWORD errorCode = ::GetLastError(); + throw std::system_error + { + static_cast(errorCode), + std::system_category(), + "auto_reset_event: CreateEvent failed" + }; + } + } + + auto_reset_event::~auto_reset_event() + { + } + + void auto_reset_event::set() + { + BOOL ok =::SetEvent(m_event.handle()); + if (!ok) + { + DWORD errorCode = ::GetLastError(); + throw std::system_error + { + static_cast(errorCode), + std::system_category(), + "auto_reset_event: SetEvent failed" + }; + } + } + + void auto_reset_event::wait() + { + DWORD result = ::WaitForSingleObjectEx(m_event.handle(), INFINITE, FALSE); + if (result != WAIT_OBJECT_0) + { + DWORD errorCode = ::GetLastError(); + throw std::system_error + { + static_cast(errorCode), + std::system_category(), + "auto_reset_event: WaitForSingleObjectEx failed" + }; + } + } + +#else + + auto_reset_event::auto_reset_event(bool initiallySet) + : m_isSet(initiallySet) + {} + + auto_reset_event::~auto_reset_event() + {} + + void auto_reset_event::set() + { + std::unique_lock lock{ m_mutex }; + if (!m_isSet) + { + m_isSet = true; + m_cv.notify_one(); + } + } + + void auto_reset_event::wait() + { + std::unique_lock lock{ m_mutex }; + while (!m_isSet) + { + m_cv.wait(lock); + } + m_isSet = false; + } + +#endif +} diff --git a/lib/auto_reset_event.hpp b/lib/auto_reset_event.hpp new file mode 100644 index 0000000..480f2d2 --- /dev/null +++ b/lib/auto_reset_event.hpp @@ -0,0 +1,44 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_AUTO_RESET_EVENT_HPP_INCLUDED +#define CPPCORO_AUTO_RESET_EVENT_HPP_INCLUDED + +#include + +#if CPPCORO_OS_WINNT +# include +#else +# include +# include +#endif + +namespace cppcoro +{ + class auto_reset_event + { + public: + + auto_reset_event(bool initiallySet = false); + + ~auto_reset_event(); + + void set(); + + void wait(); + + private: + +#if CPPCORO_OS_WINNT + cppcoro::detail::win32::safe_handle m_event; +#else + std::mutex m_mutex; + std::condition_variable m_cv; + bool m_isSet; +#endif + + }; +} + +#endif diff --git a/lib/build.cake b/lib/build.cake new file mode 100644 index 0000000..a32e1c4 --- /dev/null +++ b/lib/build.cake @@ -0,0 +1,182 @@ +############################################################################### +# Copyright Lewis Baker +# Licenced under MIT license. See LICENSE.txt for details. +############################################################################### + +import cake.path + +from cake.tools import compiler, script, env, project, variant + +includes = cake.path.join(env.expand('${CPPCORO}'), 'include', 'cppcoro', [ + 'awaitable_traits.hpp', + 'is_awaitable.hpp', + 'async_auto_reset_event.hpp', + 'async_manual_reset_event.hpp', + 'async_generator.hpp', + 'async_mutex.hpp', + 'async_latch.hpp', + 'async_scope.hpp', + 'broken_promise.hpp', + 'cancellation_registration.hpp', + 'cancellation_source.hpp', + 'cancellation_token.hpp', + 'task.hpp', + 'sequence_barrier.hpp', + 'sequence_traits.hpp', + 'single_producer_sequencer.hpp', + 'multi_producer_sequencer.hpp', + 'shared_task.hpp', + 'single_consumer_event.hpp', + 'single_consumer_async_auto_reset_event.hpp', + 'sync_wait.hpp', + 'task.hpp', + 'io_service.hpp', + 'config.hpp', + 'on_scope_exit.hpp', + 'file_share_mode.hpp', + 'file_open_mode.hpp', + 'file_buffering_mode.hpp', + 'file.hpp', + 'fmap.hpp', + 'when_all.hpp', + 'when_all_ready.hpp', + 'resume_on.hpp', + 'schedule_on.hpp', + 'generator.hpp', + 'readable_file.hpp', + 'recursive_generator.hpp', + 'writable_file.hpp', + 'read_only_file.hpp', + 'write_only_file.hpp', + 'read_write_file.hpp', + 'file_read_operation.hpp', + 'file_write_operation.hpp', + 'static_thread_pool.hpp', + ]) + +netIncludes = cake.path.join(env.expand('${CPPCORO}'), 'include', 'cppcoro', 'net', [ + 'ip_address.hpp', + 'ip_endpoint.hpp', + 'ipv4_address.hpp', + 'ipv4_endpoint.hpp', + 'ipv6_address.hpp', + 'ipv6_endpoint.hpp', + 'socket.hpp', +]) + +detailIncludes = cake.path.join(env.expand('${CPPCORO}'), 'include', 'cppcoro', 'detail', [ + 'void_value.hpp', + 'when_all_ready_awaitable.hpp', + 'when_all_counter.hpp', + 'when_all_task.hpp', + 'get_awaiter.hpp', + 'is_awaiter.hpp', + 'any.hpp', + 'sync_wait_task.hpp', + 'unwrap_reference.hpp', + 'lightweight_manual_reset_event.hpp', + ]) + +privateHeaders = script.cwd([ + 'cancellation_state.hpp', + 'socket_helpers.hpp', + 'auto_reset_event.hpp', + 'spin_wait.hpp', + 'spin_mutex.hpp', + ]) + +sources = script.cwd([ + 'async_auto_reset_event.cpp', + 'async_manual_reset_event.cpp', + 'async_mutex.cpp', + 'cancellation_state.cpp', + 'cancellation_token.cpp', + 'cancellation_source.cpp', + 'cancellation_registration.cpp', + 'lightweight_manual_reset_event.cpp', + 'ip_address.cpp', + 'ip_endpoint.cpp', + 'ipv4_address.cpp', + 'ipv4_endpoint.cpp', + 'ipv6_address.cpp', + 'ipv6_endpoint.cpp', + 'static_thread_pool.cpp', + 'auto_reset_event.cpp', + 'spin_wait.cpp', + 'spin_mutex.cpp', + ]) + +extras = script.cwd([ + 'build.cake', + 'use.cake', + ]) + +if variant.platform == "windows": + detailIncludes.extend(cake.path.join(env.expand('${CPPCORO}'), 'include', 'cppcoro', 'detail', [ + 'win32.hpp', + 'win32_overlapped_operation.hpp', + ])) + netIncludes.extend(cake.path.join(env.expand('${CPPCORO}'), 'include', 'cppcoro', 'net', [ + 'socket.hpp', + 'socket_accept_operation.hpp', + 'socket_connect_operation.hpp', + 'socket_disconnect_operation.hpp', + 'socket_recv_operation.hpp', + 'socket_recv_from_operation.hpp', + 'socket_send_operation.hpp', + 'socket_send_to_operation.hpp', + ])) + sources.extend(script.cwd([ + 'win32.cpp', + 'io_service.cpp', + 'file.cpp', + 'readable_file.cpp', + 'writable_file.cpp', + 'read_only_file.cpp', + 'write_only_file.cpp', + 'read_write_file.cpp', + 'file_read_operation.cpp', + 'file_write_operation.cpp', + 'socket_helpers.cpp', + 'socket.cpp', + 'socket_accept_operation.cpp', + 'socket_connect_operation.cpp', + 'socket_disconnect_operation.cpp', + 'socket_send_operation.cpp', + 'socket_send_to_operation.cpp', + 'socket_recv_operation.cpp', + 'socket_recv_from_operation.cpp', + ])) + +buildDir = env.expand('${CPPCORO_BUILD}') + +compiler.addIncludePath(env.expand('${CPPCORO}/include')) + +objects = compiler.objects( + targetDir=env.expand('${CPPCORO_BUILD}/obj'), + sources=sources, + ) + +lib = compiler.library( + target=env.expand('${CPPCORO_LIB}/cppcoro'), + sources=objects, + ) + +vcproj = project.project( + target=env.expand('${CPPCORO_PROJECT}/cppcoro'), + items={ + 'Include': { + 'Detail': detailIncludes, + 'Net': netIncludes, + '': includes, + }, + 'Source': sources + privateHeaders, + '': extras + }, + output=lib, + ) + +script.setResult( + project=vcproj, + library=lib, + ) diff --git a/lib/cancellation_registration.cpp b/lib/cancellation_registration.cpp new file mode 100644 index 0000000..d9533bb --- /dev/null +++ b/lib/cancellation_registration.cpp @@ -0,0 +1,41 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include + +#include "cancellation_state.hpp" + +#include + +cppcoro::cancellation_registration::~cancellation_registration() +{ + if (m_state != nullptr) + { + m_state->deregister_callback(this); + m_state->release_token_ref(); + } +} + +void cppcoro::cancellation_registration::register_callback(cancellation_token&& token) +{ + auto* state = token.m_state; + if (state != nullptr && state->can_be_cancelled()) + { + m_state = state; + if (state->try_register_callback(this)) + { + token.m_state = nullptr; + } + else + { + m_state = nullptr; + m_callback(); + } + } + else + { + m_state = nullptr; + } +} diff --git a/lib/cancellation_source.cpp b/lib/cancellation_source.cpp new file mode 100644 index 0000000..240cf1d --- /dev/null +++ b/lib/cancellation_source.cpp @@ -0,0 +1,97 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include + +#include "cancellation_state.hpp" + +#include + +cppcoro::cancellation_source::cancellation_source() + : m_state(detail::cancellation_state::create()) +{ +} + +cppcoro::cancellation_source::cancellation_source(const cancellation_source& other) noexcept + : m_state(other.m_state) +{ + if (m_state != nullptr) + { + m_state->add_source_ref(); + } +} + +cppcoro::cancellation_source::cancellation_source(cancellation_source&& other) noexcept + : m_state(other.m_state) +{ + other.m_state = nullptr; +} + +cppcoro::cancellation_source::~cancellation_source() +{ + if (m_state != nullptr) + { + m_state->release_source_ref(); + } +} + +cppcoro::cancellation_source& cppcoro::cancellation_source::operator=(const cancellation_source& other) noexcept +{ + if (m_state != other.m_state) + { + if (m_state != nullptr) + { + m_state->release_source_ref(); + } + + m_state = other.m_state; + + if (m_state != nullptr) + { + m_state->add_source_ref(); + } + } + + return *this; +} + +cppcoro::cancellation_source& cppcoro::cancellation_source::operator=(cancellation_source&& other) noexcept +{ + if (this != &other) + { + if (m_state != nullptr) + { + m_state->release_source_ref(); + } + + m_state = other.m_state; + other.m_state = nullptr; + } + + return *this; +} + +bool cppcoro::cancellation_source::can_be_cancelled() const noexcept +{ + return m_state != nullptr; +} + +cppcoro::cancellation_token cppcoro::cancellation_source::token() const noexcept +{ + return cancellation_token(m_state); +} + +void cppcoro::cancellation_source::request_cancellation() +{ + if (m_state != nullptr) + { + m_state->request_cancellation(); + } +} + +bool cppcoro::cancellation_source::is_cancellation_requested() const noexcept +{ + return m_state != nullptr && m_state->is_cancellation_requested(); +} diff --git a/lib/cancellation_state.cpp b/lib/cancellation_state.cpp new file mode 100644 index 0000000..a81123c --- /dev/null +++ b/lib/cancellation_state.cpp @@ -0,0 +1,624 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include "cancellation_state.hpp" + +#include "cppcoro/config.hpp" + +#include + +#include +#include + +namespace cppcoro +{ + namespace detail + { + struct cancellation_registration_list_chunk + { + static cancellation_registration_list_chunk* allocate(std::uint32_t entryCount); + static void free(cancellation_registration_list_chunk* chunk) noexcept; + + std::atomic m_nextChunk; + cancellation_registration_list_chunk* m_prevChunk; + std::atomic m_approximateFreeCount; + std::uint32_t m_entryCount; + std::atomic m_entries[1]; + }; + + struct cancellation_registration_list + { + static cancellation_registration_list* allocate(); + static void free(cancellation_registration_list* bucket) noexcept; + + std::atomic m_approximateTail; + cancellation_registration_list_chunk m_headChunk; + }; + + struct cancellation_registration_result + { + cancellation_registration_result( + cancellation_registration_list_chunk* chunk, + std::uint32_t entryIndex) + : m_chunk(chunk) + , m_entryIndex(entryIndex) + {} + + cancellation_registration_list_chunk* m_chunk; + std::uint32_t m_entryIndex; + }; + + struct cancellation_registration_state + { + static cancellation_registration_state* allocate(); + static void free(cancellation_registration_state* list) noexcept; + + cancellation_registration_result add_registration( + cppcoro::cancellation_registration* registration); + + std::thread::id m_notificationThreadId; + + // Store N separate lists and randomly apportion threads to a given + // list to reduce chance of contention. + std::uint32_t m_listCount; + std::atomic m_lists[1]; + }; + } +} + +cppcoro::detail::cancellation_registration_list_chunk* +cppcoro::detail::cancellation_registration_list_chunk::allocate(std::uint32_t entryCount) +{ + auto* chunk = static_cast(std::malloc( + sizeof(cancellation_registration_list_chunk) + + (entryCount - 1) * sizeof(cancellation_registration_list_chunk::m_entries[0]))); + if (chunk == nullptr) + { + throw std::bad_alloc{}; + } + + ::new (&chunk->m_nextChunk) std::atomic(nullptr); + chunk->m_prevChunk = nullptr; + ::new (&chunk->m_approximateFreeCount) std::atomic(static_cast(entryCount - 1)); + chunk->m_entryCount = entryCount; + for (std::uint32_t i = 0; i < entryCount; ++i) + { + ::new (&chunk->m_entries[i]) std::atomic(nullptr); + } + + return chunk; +} + +void cppcoro::detail::cancellation_registration_list_chunk::free( + cancellation_registration_list_chunk* chunk) noexcept +{ + std::free(chunk); +} + +cppcoro::detail::cancellation_registration_list* +cppcoro::detail::cancellation_registration_list::allocate() +{ + constexpr std::uint32_t initialChunkSize = 16; + + const std::size_t bufferSize = + sizeof(cancellation_registration_list) + + (initialChunkSize - 1) * sizeof(cancellation_registration_list_chunk::m_entries[0]); + + auto* bucket = static_cast(std::malloc(bufferSize)); + if (bucket == nullptr) + { + throw std::bad_alloc{}; + } + + ::new (&bucket->m_approximateTail) std::atomic(&bucket->m_headChunk); + ::new (&bucket->m_headChunk.m_nextChunk) std::atomic(nullptr); + bucket->m_headChunk.m_prevChunk = nullptr; + ::new (&bucket->m_headChunk.m_approximateFreeCount) + std::atomic(static_cast(initialChunkSize - 1)); + bucket->m_headChunk.m_entryCount = initialChunkSize; + for (std::uint32_t i = 0; i < initialChunkSize; ++i) + { + ::new (&bucket->m_headChunk.m_entries[i]) std::atomic(nullptr); + } + + return bucket; +} + +void cppcoro::detail::cancellation_registration_list::free(cancellation_registration_list* list) noexcept +{ + std::free(list); +} + +cppcoro::detail::cancellation_registration_state* +cppcoro::detail::cancellation_registration_state::allocate() +{ + constexpr std::uint32_t maxListCount = 16; + + auto listCount = std::thread::hardware_concurrency(); + if (listCount > maxListCount) + { + listCount = maxListCount; + } + else if (listCount == 0) + { + listCount = 1; + } + + const std::size_t bufferSize = + sizeof(cancellation_registration_state) + + (listCount - 1) * sizeof(cancellation_registration_state::m_lists[0]); + + auto* state = static_cast(std::malloc(bufferSize)); + if (state == nullptr) + { + throw std::bad_alloc{}; + } + + state->m_listCount = listCount; + for (std::uint32_t i = 0; i < listCount; ++i) + { + ::new (&state->m_lists[i]) std::atomic(nullptr); + } + + return state; +} + +void cppcoro::detail::cancellation_registration_state::free(cancellation_registration_state* state) noexcept +{ + std::free(state); +} + +cppcoro::detail::cancellation_registration_result +cppcoro::detail::cancellation_registration_state::add_registration( + cppcoro::cancellation_registration* registration) +{ + // Pick a list to add to based on the current thread to reduce the + // chance of contention with multiple threads concurrently registering + // callbacks. + const auto threadIdHashCode = std::hash{}(std::this_thread::get_id()); + auto& listPtr = m_lists[threadIdHashCode % m_listCount]; + + auto* list = listPtr.load(std::memory_order_acquire); + if (list == nullptr) + { + auto* newList = cancellation_registration_list::allocate(); + + // Pre-claim the first slot. + registration->m_chunk = &newList->m_headChunk; + registration->m_entryIndex = 0; + ::new (&newList->m_headChunk.m_entries[0]) std::atomic(registration); + + if (listPtr.compare_exchange_strong( + list, + newList, + std::memory_order_seq_cst, + std::memory_order_acquire)) + { + return cancellation_registration_result(&newList->m_headChunk, 0); + } + else + { + cancellation_registration_list::free(newList); + } + } + + while (true) + { + // Navigate to the end of the chain of chunks and work backwards looking for a free slot. + auto* const originalLastChunk = list->m_approximateTail.load(std::memory_order_acquire); + + auto* lastChunk = originalLastChunk; + for (auto* next = lastChunk->m_nextChunk.load(std::memory_order_acquire); + next != nullptr; + next = next->m_nextChunk.load(std::memory_order_acquire)) + { + lastChunk = next; + } + + // Work around false-warning raised by MSVC static analysis complaining that + // warning C28182: Dereferencing NULL pointer. 'lastChunk' contains the same NULL value as 'chunk' did. + // on statement initialising 'elementCount' below. + CPPCORO_ASSUME(lastChunk != nullptr); + + if (lastChunk != originalLastChunk) + { + // Update the cache of last chunk pointer so that subsequent + // registration requests can start there instead. + // Doesn't matter if these writes race as it will eventually + // converge to the true last chunk. + list->m_approximateTail.store(lastChunk, std::memory_order_release); + } + + for (auto* chunk = lastChunk; + chunk != nullptr; + chunk = chunk->m_prevChunk) + { + auto freeCount = chunk->m_approximateFreeCount.load(std::memory_order_relaxed); + + // If it looks like there are no free slots then decrement the count again + // to force it to re-search every so-often, just in case the count has gotten + // out-of-sync with the true free count and is reporting none free even though + // there are some (or possibly all) free slots. + if (freeCount < 1) + { + --freeCount; + chunk->m_approximateFreeCount.store(freeCount, std::memory_order_relaxed); + } + + constexpr std::int32_t forcedSearchThreshold = -10; + if (freeCount > 0 || freeCount < forcedSearchThreshold) + { + const std::uint32_t entryCount = chunk->m_entryCount; + const std::uint32_t indexMask = entryCount - 1; + const std::uint32_t startIndex = entryCount - freeCount; + + registration->m_chunk = chunk; + + for (std::uint32_t i = 0; i < entryCount; ++i) + { + const std::uint32_t entryIndex = (startIndex + i) & indexMask; + auto& entry = chunk->m_entries[entryIndex]; + + // Do a cheap initial read of the entry value to see if the + // entry is likely free. This can potentially read stale values + // and so may lead to falsely thinking it's free or falsely + // thinking it's occupied. But approximate is good enough here. + auto* entryValue = entry.load(std::memory_order_relaxed); + if (entryValue == nullptr) + { + registration->m_entryIndex = entryIndex; + + if (entry.compare_exchange_strong( + entryValue, + registration, + std::memory_order_seq_cst, + std::memory_order_relaxed)) + { + // Successfully claimed the slot. + const std::int32_t newFreeCount = freeCount < 0 ? 0 : freeCount - 1; + chunk->m_approximateFreeCount.store(newFreeCount, std::memory_order_relaxed); + return cancellation_registration_result(chunk, entryIndex); + } + } + } + + // Read through all elements of chunk with no success. + // Clear free-count back to 0. + chunk->m_approximateFreeCount.store(0, std::memory_order_relaxed); + } + } + + // We've traversed through all of the chunks and found no free slots. + // So try and allocate a new chunk and append it to the list. + + constexpr std::uint32_t maxElementCount = 1024; + + const std::uint32_t elementCount = + lastChunk->m_entryCount < maxElementCount ? + lastChunk->m_entryCount * 2 : maxElementCount; + + // May throw std::bad_alloc if out of memory. + auto* newChunk = cancellation_registration_list_chunk::allocate(elementCount); + newChunk->m_prevChunk = lastChunk; + + // Pre-allocate first slot. + registration->m_chunk = newChunk; + registration->m_entryIndex = 0; + ::new (&newChunk->m_entries[0]) std::atomic(registration); + + cancellation_registration_list_chunk* oldNext = nullptr; + if (lastChunk->m_nextChunk.compare_exchange_strong( + oldNext, + newChunk, + std::memory_order_seq_cst, + std::memory_order_relaxed)) + { + list->m_approximateTail.store(newChunk, std::memory_order_release); + return cancellation_registration_result(newChunk, 0); + } + + // Some other thread published a new chunk to the end of the list + // concurrently. Free our chunk and go around the loop again, hopefully + // allocating a slot from the chunk the other thread just allocated. + cancellation_registration_list_chunk::free(newChunk); + } +} + +cppcoro::detail::cancellation_state* cppcoro::detail::cancellation_state::create() +{ + return new cancellation_state(); +} + +cppcoro::detail::cancellation_state::~cancellation_state() +{ + assert((m_state.load(std::memory_order_relaxed) & cancellation_ref_count_mask) == 0); + + // Use relaxed memory order in reads here since we should already have visibility + // to all writes as the ref-count decrement that preceded the call to the destructor + // has acquire-release semantics. + + auto* registrationState = m_registrationState.load(std::memory_order_relaxed); + if (registrationState != nullptr) + { + for (std::uint32_t i = 0; i < registrationState->m_listCount; ++i) + { + auto* list = registrationState->m_lists[i].load(std::memory_order_relaxed); + if (list != nullptr) + { + auto* chunk = list->m_headChunk.m_nextChunk.load(std::memory_order_relaxed); + cancellation_registration_list::free(list); + + while (chunk != nullptr) + { + auto* next = chunk->m_nextChunk.load(std::memory_order_relaxed); + cancellation_registration_list_chunk::free(chunk); + chunk = next; + } + } + } + + cancellation_registration_state::free(registrationState); + } +} + +void cppcoro::detail::cancellation_state::add_token_ref() noexcept +{ + m_state.fetch_add(cancellation_token_ref_increment, std::memory_order_relaxed); +} + +void cppcoro::detail::cancellation_state::release_token_ref() noexcept +{ + const std::uint64_t oldState = m_state.fetch_sub(cancellation_token_ref_increment, std::memory_order_acq_rel); + if ((oldState & cancellation_ref_count_mask) == cancellation_token_ref_increment) + { + delete this; + } +} + +void cppcoro::detail::cancellation_state::add_source_ref() noexcept +{ + m_state.fetch_add(cancellation_source_ref_increment, std::memory_order_relaxed); +} + +void cppcoro::detail::cancellation_state::release_source_ref() noexcept +{ + const std::uint64_t oldState = m_state.fetch_sub(cancellation_source_ref_increment, std::memory_order_acq_rel); + if ((oldState & cancellation_ref_count_mask) == cancellation_source_ref_increment) + { + delete this; + } +} + +bool cppcoro::detail::cancellation_state::can_be_cancelled() const noexcept +{ + return (m_state.load(std::memory_order_acquire) & can_be_cancelled_mask) != 0; +} + +bool cppcoro::detail::cancellation_state::is_cancellation_requested() const noexcept +{ + return (m_state.load(std::memory_order_acquire) & cancellation_requested_flag) != 0; +} + +bool cppcoro::detail::cancellation_state::is_cancellation_notification_complete() const noexcept +{ + return (m_state.load(std::memory_order_acquire) & cancellation_notification_complete_flag) != 0; +} + +void cppcoro::detail::cancellation_state::request_cancellation() +{ + const auto oldState = m_state.fetch_or(cancellation_requested_flag, std::memory_order_seq_cst); + if ((oldState & cancellation_requested_flag) != 0) + { + // Some thread has already called request_cancellation(). + return; + } + + // We are the first caller of request_cancellation. + // Need to execute any registered callbacks to notify them of cancellation. + + // NOTE: We need to use sequentially-consistent operations here to ensure + // that if there is a concurrent call to try_register_callback() on another + // thread that either the other thread will read the prior write to m_state + // after they write to a registration slot or we will read their write to the + // registration slot after the prior write to m_state. + + auto* const registrationState = m_registrationState.load(std::memory_order_seq_cst); + if (registrationState != nullptr) + { + // Note that there should be no data-race in writing to this value here + // as another thread will only read it if they are trying to deregister + // a callback and that fails because we have acquired the pointer to + // the registration inside the loop below. In this case the atomic + // exchange that acquires the pointer below acts as a release-operation + // that synchronises with the failed exchange operation in deregister_callback() + // which has acquire semantics and thus will have visibility of the write to + // the m_notificationThreadId value. + registrationState->m_notificationThreadId = std::this_thread::get_id(); + + for (std::uint32_t listIndex = 0, listCount = registrationState->m_listCount; + listIndex < listCount; + ++listIndex) + { + auto* list = registrationState->m_lists[listIndex].load(std::memory_order_seq_cst); + if (list == nullptr) + { + continue; + } + + auto* chunk = &list->m_headChunk; + do + { + for (std::uint32_t entryIndex = 0, entryCount = chunk->m_entryCount; + entryIndex < entryCount; + ++entryIndex) + { + auto& entry = chunk->m_entries[entryIndex]; + + // Quick read-only operation to check if any registration + // is present. + auto* registration = entry.load(std::memory_order_seq_cst); + if (registration != nullptr) + { + // Try to acquire ownership of the registration by replacing its + // slot with nullptr atomically. This resolves the race between + // a concurrent call to deregister_callback() from the registration's + // destructor. + registration = entry.exchange(nullptr, std::memory_order_seq_cst); + if (registration != nullptr) + { + try + { + registration->m_callback(); + } + catch (...) + { + // TODO: What should behaviour of unhandled exception in a callback be here? + std::terminate(); + } + } + } + } + + chunk = chunk->m_nextChunk.load(std::memory_order_seq_cst); + } while (chunk != nullptr); + } + + m_state.fetch_add(cancellation_notification_complete_flag, std::memory_order_release); + } +} + +bool cppcoro::detail::cancellation_state::try_register_callback( + cancellation_registration* registration) +{ + if (is_cancellation_requested()) + { + return false; + } + + auto* registrationState = m_registrationState.load(std::memory_order_acquire); + if (registrationState == nullptr) + { + // Could throw std::bad_alloc + auto* newRegistrationState = cancellation_registration_state::allocate(); + + // Need to use 'sequentially consistent' on the write here to ensure that if + // we subsequently read a value from m_state at the end of this function that + // doesn't have the cancellation_requested_flag bit set that a subsequent call + // in another thread to request_cancellation() will see this write. + if (m_registrationState.compare_exchange_strong( + registrationState, + newRegistrationState, + std::memory_order_seq_cst, + std::memory_order_acquire)) + { + registrationState = newRegistrationState; + } + else + { + cancellation_registration_state::free(newRegistrationState); + } + } + + // Could throw std::bad_alloc + auto result = registrationState->add_registration(registration); + + // Need to check status again to handle the case where + // another thread calls request_cancellation() concurrently + // but doesn't see our write to the registration list. + // + // Note, we don't call IsCancellationRequested() here since that + // only provides 'acquire' memory semantics and we need 'seq_cst' + // semantics. + if ((m_state.load(std::memory_order_seq_cst) & cancellation_requested_flag) != 0) + { + // Cancellation was requested concurrently with adding the + // registration to the list. Try to remove the registration. + // If successful we return false to indicate that the callback + // has not been registered and the caller should execute the + // callback. If it fails it means that the thread that requested + // cancellation will execute our callback and we need to wait + // until it finishes before returning. + auto& entry = result.m_chunk->m_entries[result.m_entryIndex]; + + // Need to use compare_exchange here rather than just exchange since + // it may be possible that the thread calling request_cancellation() + // acquired our registration and executed the callback, freeing up + // the slot and then a third thread registers a new registration + // that gets allocated to this slot. + // + // Can use relaxed memory order here since in the case that this succeeds + // no other thread will have written to the cancellation_registration record + // so we can safely read from the record without synchronisation. + auto* oldValue = registration; + const bool deregisteredSuccessfully = + entry.compare_exchange_strong(oldValue, nullptr, std::memory_order_relaxed); + if (deregisteredSuccessfully) + { + return false; + } + + // Otherwise, the cancelling thread has taken ownership for executing + // the callback and we can just act as if the registration succeeded. + } + + return true; +} + +void cppcoro::detail::cancellation_state::deregister_callback(cancellation_registration* registration) noexcept +{ + auto* chunk = registration->m_chunk; + auto& entry = chunk->m_entries[registration->m_entryIndex]; + + // Use 'acquire' memory order on failure case so that we synchronise with the write + // to the slot inside request_cancellation() that acquired the registration such that + // we have visibility of its prior write to m_notifyingThreadId. + // + // Could use 'relaxed' memory order on success case as if this succeeds it means that + // no thread will have written to the registration object. + auto* oldValue = registration; + bool deregisteredSuccessfully = entry.compare_exchange_strong( + oldValue, + nullptr, + std::memory_order_acquire); + if (deregisteredSuccessfully) + { + // Increment free-count if it won't make it larger than entry count. + const std::int32_t oldFreeCount = chunk->m_approximateFreeCount.load(std::memory_order_relaxed); + if (oldFreeCount < static_cast(chunk->m_entryCount)) + { + const std::int32_t newFreeCount = oldFreeCount < 0 ? 1 : oldFreeCount + 1; + chunk->m_approximateFreeCount.store(newFreeCount, std::memory_order_relaxed); + } + } + else + { + // A thread executing request_cancellation() has acquired this callback and + // is executing it. Need to wait until it finishes executing before we return + // and the registration object is destructed. + // + // However, we also need to handle the case where the registration is being + // removed from within a callback which would otherwise deadlock waiting + // for the callbacks to finish executing. + + // Use relaxed memory order here as we should already have visibility + // of the write to m_registrationState from when the registration was first + // registered. + auto* registrationState = m_registrationState.load(std::memory_order_relaxed); + if (std::this_thread::get_id() != registrationState->m_notificationThreadId) + { + // TODO: More efficient busy-wait backoff strategy + while (!is_cancellation_notification_complete()) + { + std::this_thread::yield(); + } + } + } +} + +cppcoro::detail::cancellation_state::cancellation_state() noexcept + : m_state(cancellation_source_ref_increment) + , m_registrationState(nullptr) +{ +} diff --git a/lib/cancellation_state.hpp b/lib/cancellation_state.hpp new file mode 100644 index 0000000..9bdb40d --- /dev/null +++ b/lib/cancellation_state.hpp @@ -0,0 +1,108 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_CANCELLATION_STATE_HPP_INCLUDED +#define CPPCORO_CANCELLATION_STATE_HPP_INCLUDED + +#include + +#include +#include +#include + +namespace cppcoro +{ + namespace detail + { + struct cancellation_registration_state; + + class cancellation_state + { + public: + + /// Allocates a new cancellation_state object. + /// + /// \throw std::bad_alloc + /// If there was insufficient memory to allocate one. + static cancellation_state* create(); + + ~cancellation_state(); + + /// Increment the reference count of cancellation_token and + /// cancellation_registration objects referencing this state. + void add_token_ref() noexcept; + + /// Decrement the reference count of cancellation_token and + /// cancellation_registration objects referencing this state. + void release_token_ref() noexcept; + + /// Increment the reference count of cancellation_source objects. + void add_source_ref() noexcept; + + /// Decrement the reference count of cancellation_souce objects. + /// + /// The cancellation_state will no longer be cancellable once the + /// cancellation_source ref count reaches zero. + void release_source_ref() noexcept; + + /// Query if the cancellation_state can have cancellation requested. + /// + /// \return + /// Returns true if there are no more references to a cancellation_source + /// object. + bool can_be_cancelled() const noexcept; + + /// Query if some thread has called request_cancellation(). + bool is_cancellation_requested() const noexcept; + + /// Flag state has having cancellation_requested and execute any + /// registered callbacks. + void request_cancellation(); + + /// Try to register the cancellation_registration as a callback to be executed + /// when cancellation is requested. + /// + /// \return + /// true if the callback was successfully registered, false if the callback was + /// not registered because cancellation had already been requested. + /// + /// \throw std::bad_alloc + /// If callback was unable to be registered due to insufficient memory. + bool try_register_callback(cancellation_registration* registration); + + /// Deregister a callback previously registered successfully in a call to try_register_callback(). + /// + /// If the callback is currently being executed on another + /// thread that is concurrently calling request_cancellation() + /// then this call will block until the callback has finished executing. + void deregister_callback(cancellation_registration* registration) noexcept; + + private: + + cancellation_state() noexcept; + + bool is_cancellation_notification_complete() const noexcept; + + static constexpr std::uint64_t cancellation_requested_flag = 1; + static constexpr std::uint64_t cancellation_notification_complete_flag = 2; + static constexpr std::uint64_t cancellation_source_ref_increment = 4; + static constexpr std::uint64_t cancellation_token_ref_increment = UINT64_C(1) << 33; + static constexpr std::uint64_t can_be_cancelled_mask = cancellation_token_ref_increment - 1; + static constexpr std::uint64_t cancellation_ref_count_mask = + ~(cancellation_requested_flag | cancellation_notification_complete_flag); + + // A value that has: + // - bit 0 - indicates whether cancellation has been requested. + // - bit 1 - indicates whether cancellation notification is complete. + // - bits 2-32 - ref-count for cancellation_source instances. + // - bits 33-63 - ref-count for cancellation_token/cancellation_registration instances. + std::atomic m_state; + + std::atomic m_registrationState; + + }; + } +} + +#endif diff --git a/lib/cancellation_token.cpp b/lib/cancellation_token.cpp new file mode 100644 index 0000000..ad13360 --- /dev/null +++ b/lib/cancellation_token.cpp @@ -0,0 +1,108 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "cancellation_state.hpp" + +#include +#include + +cppcoro::cancellation_token::cancellation_token() noexcept + : m_state(nullptr) +{ +} + +cppcoro::cancellation_token::cancellation_token(const cancellation_token& other) noexcept + : m_state(other.m_state) +{ + if (m_state != nullptr) + { + m_state->add_token_ref(); + } +} + +cppcoro::cancellation_token::cancellation_token(cancellation_token&& other) noexcept + : m_state(other.m_state) +{ + other.m_state = nullptr; +} + +cppcoro::cancellation_token::~cancellation_token() +{ + if (m_state != nullptr) + { + m_state->release_token_ref(); + } +} + +cppcoro::cancellation_token& cppcoro::cancellation_token::operator=(const cancellation_token& other) noexcept +{ + if (other.m_state != m_state) + { + if (m_state != nullptr) + { + m_state->release_token_ref(); + } + + m_state = other.m_state; + + if (m_state != nullptr) + { + m_state->add_token_ref(); + } + } + + return *this; +} + +cppcoro::cancellation_token& cppcoro::cancellation_token::operator=(cancellation_token&& other) noexcept +{ + if (this != &other) + { + if (m_state != nullptr) + { + m_state->release_token_ref(); + } + + m_state = other.m_state; + other.m_state = nullptr; + } + + return *this; +} + +void cppcoro::cancellation_token::swap(cancellation_token& other) noexcept +{ + std::swap(m_state, other.m_state); +} + +bool cppcoro::cancellation_token::can_be_cancelled() const noexcept +{ + return m_state != nullptr && m_state->can_be_cancelled(); +} + +bool cppcoro::cancellation_token::is_cancellation_requested() const noexcept +{ + return m_state != nullptr && m_state->is_cancellation_requested(); +} + +void cppcoro::cancellation_token::throw_if_cancellation_requested() const +{ + if (is_cancellation_requested()) + { + throw operation_cancelled{}; + } +} + +cppcoro::cancellation_token::cancellation_token(detail::cancellation_state* state) noexcept + : m_state(state) +{ + if (m_state != nullptr) + { + m_state->add_token_ref(); + } +} diff --git a/lib/file.cpp b/lib/file.cpp new file mode 100644 index 0000000..0e15585 --- /dev/null +++ b/lib/file.cpp @@ -0,0 +1,168 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include +#include + +#if CPPCORO_OS_WINNT +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +#endif + +cppcoro::file::~file() +{} + +std::uint64_t cppcoro::file::size() const +{ +#if CPPCORO_OS_WINNT + LARGE_INTEGER size; + BOOL ok = ::GetFileSizeEx(m_fileHandle.handle(), &size); + if (!ok) + { + DWORD errorCode = ::GetLastError(); + throw std::system_error + { + static_cast(errorCode), + std::system_category(), + "error getting file size: GetFileSizeEx" + }; + } + + return size.QuadPart; +#endif +} + +cppcoro::file::file(detail::win32::safe_handle&& fileHandle) noexcept + : m_fileHandle(std::move(fileHandle)) +{ +} + +cppcoro::detail::win32::safe_handle cppcoro::file::open( + detail::win32::dword_t fileAccess, + io_service& ioService, + const cppcoro::filesystem::path& path, + file_open_mode openMode, + file_share_mode shareMode, + file_buffering_mode bufferingMode) +{ + DWORD flags = FILE_FLAG_OVERLAPPED; + if ((bufferingMode & file_buffering_mode::random_access) == file_buffering_mode::random_access) + { + flags |= FILE_FLAG_RANDOM_ACCESS; + } + if ((bufferingMode & file_buffering_mode::sequential) == file_buffering_mode::sequential) + { + flags |= FILE_FLAG_SEQUENTIAL_SCAN; + } + if ((bufferingMode & file_buffering_mode::write_through) == file_buffering_mode::write_through) + { + flags |= FILE_FLAG_WRITE_THROUGH; + } + if ((bufferingMode & file_buffering_mode::temporary) == file_buffering_mode::temporary) + { + flags |= FILE_ATTRIBUTE_TEMPORARY; + } + if ((bufferingMode & file_buffering_mode::unbuffered) == file_buffering_mode::unbuffered) + { + flags |= FILE_FLAG_NO_BUFFERING; + } + + DWORD shareFlags = 0; + if ((shareMode & file_share_mode::read) == file_share_mode::read) + { + shareFlags |= FILE_SHARE_READ; + } + if ((shareMode & file_share_mode::write) == file_share_mode::write) + { + shareFlags |= FILE_SHARE_WRITE; + } + if ((shareMode & file_share_mode::delete_) == file_share_mode::delete_) + { + shareFlags |= FILE_SHARE_DELETE; + } + + DWORD creationDisposition = 0; + switch (openMode) + { + case file_open_mode::create_or_open: + creationDisposition = OPEN_ALWAYS; + break; + case file_open_mode::create_always: + creationDisposition = CREATE_ALWAYS; + break; + case file_open_mode::create_new: + creationDisposition = CREATE_NEW; + break; + case file_open_mode::open_existing: + creationDisposition = OPEN_EXISTING; + break; + case file_open_mode::truncate_existing: + creationDisposition = TRUNCATE_EXISTING; + break; + } + + // Open the file + detail::win32::safe_handle fileHandle( + ::CreateFileW( + path.wstring().c_str(), + fileAccess, + shareFlags, + nullptr, + creationDisposition, + flags, + nullptr)); + if (fileHandle.handle() == INVALID_HANDLE_VALUE) + { + const DWORD errorCode = ::GetLastError(); + throw std::system_error + { + static_cast(errorCode), + std::system_category(), + "error opening file: CreateFileW" + }; + } + + // Associate with the I/O service's completion port. + const HANDLE result = ::CreateIoCompletionPort( + fileHandle.handle(), + ioService.native_iocp_handle(), + 0, + 0); + if (result == nullptr) + { + const DWORD errorCode = ::GetLastError(); + throw std::system_error + { + static_cast(errorCode), + std::system_category(), + "error opening file: CreateIoCompletionPort" + }; + } + + // Configure I/O operations to avoid dispatching a completion event + // to the I/O service if the operation completes synchronously. + // This avoids unnecessary suspension/resuption of the awaiting coroutine. + const BOOL ok = ::SetFileCompletionNotificationModes( + fileHandle.handle(), + FILE_SKIP_COMPLETION_PORT_ON_SUCCESS | + FILE_SKIP_SET_EVENT_ON_HANDLE); + if (!ok) + { + const DWORD errorCode = ::GetLastError(); + throw std::system_error + { + static_cast(errorCode), + std::system_category(), + "error opening file: SetFileCompletionNotificationModes" + }; + } + + return std::move(fileHandle); +} diff --git a/lib/file_read_operation.cpp b/lib/file_read_operation.cpp new file mode 100644 index 0000000..ca27489 --- /dev/null +++ b/lib/file_read_operation.cpp @@ -0,0 +1,53 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include + +#if CPPCORO_OS_WINNT +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include + +bool cppcoro::file_read_operation_impl::try_start( + cppcoro::detail::win32_overlapped_operation_base& operation) noexcept +{ + const DWORD numberOfBytesToRead = + m_byteCount <= 0xFFFFFFFF ? + static_cast(m_byteCount) : DWORD(0xFFFFFFFF); + + DWORD numberOfBytesRead = 0; + BOOL ok = ::ReadFile( + m_fileHandle, + m_buffer, + numberOfBytesToRead, + &numberOfBytesRead, + operation.get_overlapped()); + const DWORD errorCode = ok ? ERROR_SUCCESS : ::GetLastError(); + if (errorCode != ERROR_IO_PENDING) + { + // Completed synchronously. + // + // We are assuming that the file-handle has been set to the + // mode where synchronous completions do not post a completion + // event to the I/O completion port and thus can return without + // suspending here. + + operation.m_errorCode = errorCode; + operation.m_numberOfBytesTransferred = numberOfBytesRead; + + return false; + } + + return true; +} + +void cppcoro::file_read_operation_impl::cancel( + cppcoro::detail::win32_overlapped_operation_base& operation) noexcept +{ + (void)::CancelIoEx(m_fileHandle, operation.get_overlapped()); +} + +#endif // CPPCORO_OS_WINNT diff --git a/lib/file_write_operation.cpp b/lib/file_write_operation.cpp new file mode 100644 index 0000000..68a3ac4 --- /dev/null +++ b/lib/file_write_operation.cpp @@ -0,0 +1,53 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include + +#if CPPCORO_OS_WINNT +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include + +bool cppcoro::file_write_operation_impl::try_start( + cppcoro::detail::win32_overlapped_operation_base& operation) noexcept +{ + const DWORD numberOfBytesToWrite = + m_byteCount <= 0xFFFFFFFF ? + static_cast(m_byteCount) : DWORD(0xFFFFFFFF); + + DWORD numberOfBytesWritten = 0; + BOOL ok = ::WriteFile( + m_fileHandle, + m_buffer, + numberOfBytesToWrite, + &numberOfBytesWritten, + operation.get_overlapped()); + const DWORD errorCode = ok ? ERROR_SUCCESS : ::GetLastError(); + if (errorCode != ERROR_IO_PENDING) + { + // Completed synchronously. + // + // We are assuming that the file-handle has been set to the + // mode where synchronous completions do not post a completion + // event to the I/O completion port and thus can return without + // suspending here. + + operation.m_errorCode = errorCode; + operation.m_numberOfBytesTransferred = numberOfBytesWritten; + + return false; + } + + return true; +} + +void cppcoro::file_write_operation_impl::cancel( + cppcoro::detail::win32_overlapped_operation_base& operation) noexcept +{ + (void)::CancelIoEx(m_fileHandle, operation.get_overlapped()); +} + +#endif // CPPCORO_OS_WINNT diff --git a/lib/io_service.cpp b/lib/io_service.cpp new file mode 100644 index 0000000..551c280 --- /dev/null +++ b/lib/io_service.cpp @@ -0,0 +1,1020 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include +#include +#include +#include + +#if CPPCORO_OS_WINNT +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# ifndef NOMINMAX +# define NOMINMAX +# endif +# include +# include +# include +# include +#endif + +namespace +{ +#if CPPCORO_OS_WINNT + cppcoro::detail::win32::safe_handle create_io_completion_port(std::uint32_t concurrencyHint) + { + HANDLE handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, concurrencyHint); + if (handle == NULL) + { + DWORD errorCode = ::GetLastError(); + throw std::system_error + { + static_cast(errorCode), + std::system_category(), + "Error creating io_service: CreateIoCompletionPort" + }; + } + + return cppcoro::detail::win32::safe_handle{ handle }; + } + + cppcoro::detail::win32::safe_handle create_auto_reset_event() + { + HANDLE eventHandle = ::CreateEventW(nullptr, FALSE, FALSE, nullptr); + if (eventHandle == NULL) + { + const DWORD errorCode = ::GetLastError(); + throw std::system_error + { + static_cast(errorCode), + std::system_category(), + "Error creating manual reset event: CreateEventW" + }; + } + + return cppcoro::detail::win32::safe_handle{ eventHandle }; + } + + cppcoro::detail::win32::safe_handle create_waitable_timer_event() + { + const BOOL isManualReset = FALSE; + HANDLE handle = ::CreateWaitableTimerW(nullptr, isManualReset, nullptr); + if (handle == nullptr) + { + const DWORD errorCode = ::GetLastError(); + throw std::system_error + { + static_cast(errorCode), + std::system_category() + }; + } + + return cppcoro::detail::win32::safe_handle{ handle }; + } +#endif +} + +/// \brief +/// A queue of pending timers that supports efficiently determining +/// and dequeueing the earliest-due timers in the queue. +/// +/// Implementation utilises a heap-sorted vector of entries with an +/// additional sorted linked-list that can be used as a fallback in +/// cases that there was insufficient memory to store all timer +/// entries in the vector. +/// +/// This fallback is required to guarantee that all operations on this +/// queue are noexcept.s +class cppcoro::io_service::timer_queue +{ +public: + + using time_point = std::chrono::high_resolution_clock::time_point; + + timer_queue() noexcept; + + ~timer_queue(); + + bool is_empty() const noexcept; + + time_point earliest_due_time() const noexcept; + + void enqueue_timer(cppcoro::io_service::timed_schedule_operation* timer) noexcept; + + void dequeue_due_timers( + time_point currentTime, + cppcoro::io_service::timed_schedule_operation*& timerList) noexcept; + + void remove_cancelled_timers( + cppcoro::io_service::timed_schedule_operation*& timerList) noexcept; + +private: + + struct timer_entry + { + timer_entry(cppcoro::io_service::timed_schedule_operation* timer) + : m_dueTime(timer->m_resumeTime) + , m_timer(timer) + {} + + time_point m_dueTime; + cppcoro::io_service::timed_schedule_operation* m_timer; + }; + + static bool compare_entries(const timer_entry& a, const timer_entry& b) noexcept + { + return a.m_dueTime > b.m_dueTime; + } + + // A heap-sorted list of active timer entries + // Earliest due timer is at the front of the queue + std::vector m_timerEntries; + + // Linked-list of overflow timer entries used in case there was + // insufficient memory available to grow m_timerEntries. + // List is sorted in ascending order of due-time using insertion-sort. + // This is required to support the noexcept guarantee of enqueue_timer(). + cppcoro::io_service::timed_schedule_operation* m_overflowTimers; + +}; + +cppcoro::io_service::timer_queue::timer_queue() noexcept + : m_timerEntries() + , m_overflowTimers(nullptr) +{} + +cppcoro::io_service::timer_queue::~timer_queue() +{ + assert(is_empty()); +} + +bool cppcoro::io_service::timer_queue::is_empty() const noexcept +{ + return m_timerEntries.empty() && m_overflowTimers == nullptr; +} + +cppcoro::io_service::timer_queue::time_point +cppcoro::io_service::timer_queue::earliest_due_time() const noexcept +{ + if (!m_timerEntries.empty()) + { + if (m_overflowTimers != nullptr) + { + return std::min( + m_timerEntries.front().m_dueTime, + m_overflowTimers->m_resumeTime); + } + + return m_timerEntries.front().m_dueTime; + } + else if (m_overflowTimers != nullptr) + { + return m_overflowTimers->m_resumeTime; + } + + return time_point::max(); +} + +void cppcoro::io_service::timer_queue::enqueue_timer( + cppcoro::io_service::timed_schedule_operation* timer) noexcept +{ + try + { + m_timerEntries.emplace_back(timer); + std::push_heap(m_timerEntries.begin(), m_timerEntries.end(), compare_entries); + } + catch (...) + { + const auto& newDueTime = timer->m_resumeTime; + + auto** current = &m_overflowTimers; + while ((*current) != nullptr && (*current)->m_resumeTime <= newDueTime) + { + current = &(*current)->m_next; + } + + timer->m_next = *current; + *current = timer; + } +} + +void cppcoro::io_service::timer_queue::dequeue_due_timers( + time_point currentTime, + cppcoro::io_service::timed_schedule_operation*& timerList) noexcept +{ + while (!m_timerEntries.empty() && m_timerEntries.front().m_dueTime <= currentTime) + { + auto* timer = m_timerEntries.front().m_timer; + std::pop_heap(m_timerEntries.begin(), m_timerEntries.end(), compare_entries); + m_timerEntries.pop_back(); + + timer->m_next = timerList; + timerList = timer; + } + + while (m_overflowTimers != nullptr && m_overflowTimers->m_resumeTime <= currentTime) + { + auto* timer = m_overflowTimers; + m_overflowTimers = timer->m_next; + timer->m_next = timerList; + timerList = timer; + } +} + +void cppcoro::io_service::timer_queue::remove_cancelled_timers( + cppcoro::io_service::timed_schedule_operation*& timerList) noexcept +{ + // Perform a linear scan of all timers looking for any that have + // had cancellation requested. + + const auto addTimerToList = [&](timed_schedule_operation* timer) + { + timer->m_next = timerList; + timerList = timer; + }; + + const auto isTimerCancelled = [](const timer_entry& entry) + { + return entry.m_timer->m_cancellationToken.is_cancellation_requested(); + }; + + auto firstCancelledEntry = std::find_if( + m_timerEntries.begin(), + m_timerEntries.end(), + isTimerCancelled); + if (firstCancelledEntry != m_timerEntries.end()) + { + auto nonCancelledEnd = firstCancelledEntry; + addTimerToList(nonCancelledEnd->m_timer); + + for (auto iter = firstCancelledEntry + 1; + iter != m_timerEntries.end(); + ++iter) + { + if (isTimerCancelled(*iter)) + { + addTimerToList(iter->m_timer); + } + else + { + *nonCancelledEnd++ = std::move(*iter); + } + } + + m_timerEntries.erase(nonCancelledEnd, m_timerEntries.end()); + + std::make_heap( + m_timerEntries.begin(), + m_timerEntries.end(), + compare_entries); + } + + { + timed_schedule_operation** current = &m_overflowTimers; + while ((*current) != nullptr) + { + auto* timer = (*current); + if (timer->m_cancellationToken.is_cancellation_requested()) + { + *current = timer->m_next; + addTimerToList(timer); + } + else + { + current = &timer->m_next; + } + } + } +} + +class cppcoro::io_service::timer_thread_state +{ +public: + + timer_thread_state(); + ~timer_thread_state(); + + timer_thread_state(const timer_thread_state& other) = delete; + timer_thread_state& operator=(const timer_thread_state& other) = delete; + + void request_timer_cancellation() noexcept; + + void run() noexcept; + + void wake_up_timer_thread() noexcept; + +#if CPPCORO_OS_WINNT + detail::win32::safe_handle m_wakeUpEvent; + detail::win32::safe_handle m_waitableTimerEvent; +#endif + + std::atomic m_newlyQueuedTimers; + std::atomic m_timerCancellationRequested; + std::atomic m_shutDownRequested; + + std::thread m_thread; +}; + + + +cppcoro::io_service::io_service() + : io_service(0) +{ +} + +cppcoro::io_service::io_service(std::uint32_t concurrencyHint) + : m_threadState(0) + , m_workCount(0) +#if CPPCORO_OS_WINNT + , m_iocpHandle(create_io_completion_port(concurrencyHint)) + , m_winsockInitialised(false) + , m_winsockInitialisationMutex() +#endif + , m_scheduleOperations(nullptr) + , m_timerState(nullptr) +{ +} + +cppcoro::io_service::~io_service() +{ + assert(m_scheduleOperations.load(std::memory_order_relaxed) == nullptr); + assert(m_threadState.load(std::memory_order_relaxed) < active_thread_count_increment); + + delete m_timerState.load(std::memory_order_relaxed); + +#if CPPCORO_OS_WINNT + if (m_winsockInitialised.load(std::memory_order_relaxed)) + { + // TODO: Should we be checking return-code here? + // Don't want to throw from the destructor, so perhaps just log an error? + (void)::WSACleanup(); + } +#endif +} + +cppcoro::io_service::schedule_operation cppcoro::io_service::schedule() noexcept +{ + return schedule_operation{ *this }; +} + +std::uint64_t cppcoro::io_service::process_events() +{ + std::uint64_t eventCount = 0; + if (try_enter_event_loop()) + { + auto exitLoop = on_scope_exit([&] { exit_event_loop(); }); + + constexpr bool waitForEvent = true; + while (try_process_one_event(waitForEvent)) + { + ++eventCount; + } + } + + return eventCount; +} + +std::uint64_t cppcoro::io_service::process_pending_events() +{ + std::uint64_t eventCount = 0; + if (try_enter_event_loop()) + { + auto exitLoop = on_scope_exit([&] { exit_event_loop(); }); + + constexpr bool waitForEvent = false; + while (try_process_one_event(waitForEvent)) + { + ++eventCount; + } + } + + return eventCount; +} + +std::uint64_t cppcoro::io_service::process_one_event() +{ + std::uint64_t eventCount = 0; + if (try_enter_event_loop()) + { + auto exitLoop = on_scope_exit([&] { exit_event_loop(); }); + + constexpr bool waitForEvent = true; + if (try_process_one_event(waitForEvent)) + { + ++eventCount; + } + } + + return eventCount; +} + +std::uint64_t cppcoro::io_service::process_one_pending_event() +{ + std::uint64_t eventCount = 0; + if (try_enter_event_loop()) + { + auto exitLoop = on_scope_exit([&] { exit_event_loop(); }); + + constexpr bool waitForEvent = false; + if (try_process_one_event(waitForEvent)) + { + ++eventCount; + } + } + + return eventCount; +} + +void cppcoro::io_service::stop() noexcept +{ + const auto oldState = m_threadState.fetch_or(stop_requested_flag, std::memory_order_release); + if ((oldState & stop_requested_flag) == 0) + { + for (auto activeThreadCount = oldState / active_thread_count_increment; + activeThreadCount > 0; + --activeThreadCount) + { + post_wake_up_event(); + } + } +} + +void cppcoro::io_service::reset() +{ + const auto oldState = m_threadState.fetch_and(~stop_requested_flag, std::memory_order_relaxed); + + // Check that there were no active threads running the event loop. + assert(oldState == stop_requested_flag); +} + +bool cppcoro::io_service::is_stop_requested() const noexcept +{ + return (m_threadState.load(std::memory_order_acquire) & stop_requested_flag) != 0; +} + +void cppcoro::io_service::notify_work_started() noexcept +{ + m_workCount.fetch_add(1, std::memory_order_relaxed); +} + +void cppcoro::io_service::notify_work_finished() noexcept +{ + if (m_workCount.fetch_sub(1, std::memory_order_relaxed) == 1) + { + stop(); + } +} + +cppcoro::detail::win32::handle_t cppcoro::io_service::native_iocp_handle() noexcept +{ + return m_iocpHandle.handle(); +} + +#if CPPCORO_OS_WINNT + +void cppcoro::io_service::ensure_winsock_initialised() +{ + if (!m_winsockInitialised.load(std::memory_order_acquire)) + { + std::lock_guard lock(m_winsockInitialisationMutex); + if (!m_winsockInitialised.load(std::memory_order_acquire)) + { + const WORD requestedVersion = MAKEWORD(2, 2); + WSADATA winsockData; + const int result = ::WSAStartup(requestedVersion, &winsockData); + if (result == SOCKET_ERROR) + { + const int errorCode = ::WSAGetLastError(); + throw std::system_error( + errorCode, + std::system_category(), + "Error initialsing winsock: WSAStartup"); + } + + m_winsockInitialised.store(true, std::memory_order_release); + } + } +} + +#endif // CPPCORO_OS_WINNT + +void cppcoro::io_service::schedule_impl(schedule_operation* operation) noexcept +{ +#if CPPCORO_OS_WINNT + const BOOL ok = ::PostQueuedCompletionStatus( + m_iocpHandle.handle(), + 0, + reinterpret_cast(operation->m_awaiter.address()), + nullptr); + if (!ok) + { + // Failed to post to the I/O completion port. + // + // This is most-likely because the queue is currently full. + // + // We'll queue up the operation to a linked-list using a lock-free + // push and defer the dispatch to the completion port until some I/O + // thread next enters its event loop. + auto* head = m_scheduleOperations.load(std::memory_order_acquire); + do + { + operation->m_next = head; + } while (!m_scheduleOperations.compare_exchange_weak( + head, + operation, + std::memory_order_release, + std::memory_order_acquire)); + } +#endif +} + +void cppcoro::io_service::try_reschedule_overflow_operations() noexcept +{ +#if CPPCORO_OS_WINNT + auto* operation = m_scheduleOperations.exchange(nullptr, std::memory_order_acquire); + while (operation != nullptr) + { + auto* next = operation->m_next; + BOOL ok = ::PostQueuedCompletionStatus( + m_iocpHandle.handle(), + 0, + reinterpret_cast(operation->m_awaiter.address()), + nullptr); + if (!ok) + { + // Still unable to queue these operations. + // Put them back on the list of overflow operations. + auto* tail = operation; + while (tail->m_next != nullptr) + { + tail = tail->m_next; + } + + schedule_operation* head = nullptr; + while (!m_scheduleOperations.compare_exchange_weak( + head, + operation, + std::memory_order_release, + std::memory_order_relaxed)) + { + tail->m_next = head; + } + + return; + } + + operation = next; + } +#endif +} + +bool cppcoro::io_service::try_enter_event_loop() noexcept +{ + auto currentState = m_threadState.load(std::memory_order_relaxed); + do + { + if ((currentState & stop_requested_flag) != 0) + { + return false; + } + } while (!m_threadState.compare_exchange_weak( + currentState, + currentState + active_thread_count_increment, + std::memory_order_relaxed)); + + return true; +} + +void cppcoro::io_service::exit_event_loop() noexcept +{ + m_threadState.fetch_sub(active_thread_count_increment, std::memory_order_relaxed); +} + +bool cppcoro::io_service::try_process_one_event(bool waitForEvent) +{ +#if CPPCORO_OS_WINNT + if (is_stop_requested()) + { + return false; + } + + const DWORD timeout = waitForEvent ? INFINITE : 0; + + while (true) + { + // Check for any schedule_operation objects that were unable to be + // queued to the I/O completion port and try to requeue them now. + try_reschedule_overflow_operations(); + + DWORD numberOfBytesTransferred = 0; + ULONG_PTR completionKey = 0; + LPOVERLAPPED overlapped = nullptr; + BOOL ok = ::GetQueuedCompletionStatus( + m_iocpHandle.handle(), + &numberOfBytesTransferred, + &completionKey, + &overlapped, + timeout); + if (overlapped != nullptr) + { + DWORD errorCode = ok ? ERROR_SUCCESS : ::GetLastError(); + + auto* state = static_cast( + reinterpret_cast(overlapped)); + + state->m_callback( + state, + errorCode, + numberOfBytesTransferred, + completionKey); + + return true; + } + else if (ok) + { + if (completionKey != 0) + { + // This was a coroutine scheduled via a call to + // io_service::schedule(). + cppcoro::coroutine_handle<>::from_address( + reinterpret_cast(completionKey)).resume(); + return true; + } + + // Empty event is a wake-up request, typically associated with a + // request to exit the event loop. + // However, there may be spurious such events remaining in the queue + // from a previous call to stop() that has since been reset() so we + // need to check whether stop is still required. + if (is_stop_requested()) + { + return false; + } + } + else + { + const DWORD errorCode = ::GetLastError(); + if (errorCode == WAIT_TIMEOUT) + { + return false; + } + + throw std::system_error + { + static_cast(errorCode), + std::system_category(), + "Error retrieving item from io_service queue: GetQueuedCompletionStatus" + }; + } + } +#endif +} + +void cppcoro::io_service::post_wake_up_event() noexcept +{ +#if CPPCORO_OS_WINNT + // We intentionally ignore the return code here. + // + // Assume that if posting an event failed that it failed because the queue was full + // and the system is out of memory. In this case threads should find other events + // in the queue next time they check anyway and thus wake-up. + (void)::PostQueuedCompletionStatus(m_iocpHandle.handle(), 0, 0, nullptr); +#endif +} + +cppcoro::io_service::timer_thread_state* +cppcoro::io_service::ensure_timer_thread_started() +{ + auto* timerState = m_timerState.load(std::memory_order_acquire); + if (timerState == nullptr) + { + auto newTimerState = std::make_unique(); + if (m_timerState.compare_exchange_strong( + timerState, + newTimerState.get(), + std::memory_order_release, + std::memory_order_acquire)) + { + // We managed to install our timer_thread_state before some + // other thread did, don't free it here - it will be freed in + // the io_service destructor. + timerState = newTimerState.release(); + } + } + + return timerState; +} + +cppcoro::io_service::timer_thread_state::timer_thread_state() +#if CPPCORO_OS_WINNT + : m_wakeUpEvent(create_auto_reset_event()) + , m_waitableTimerEvent(create_waitable_timer_event()) +#endif + , m_newlyQueuedTimers(nullptr) + , m_timerCancellationRequested(false) + , m_shutDownRequested(false) + , m_thread([this] { this->run(); }) +{ +} + +cppcoro::io_service::timer_thread_state::~timer_thread_state() +{ + m_shutDownRequested.store(true, std::memory_order_release); + wake_up_timer_thread(); + m_thread.join(); +} + +void cppcoro::io_service::timer_thread_state::request_timer_cancellation() noexcept +{ + const bool wasTimerCancellationAlreadyRequested = + m_timerCancellationRequested.exchange(true, std::memory_order_release); + if (!wasTimerCancellationAlreadyRequested) + { + wake_up_timer_thread(); + } +} + +void cppcoro::io_service::timer_thread_state::run() noexcept +{ +#if CPPCORO_OS_WINNT + using clock = std::chrono::high_resolution_clock; + using time_point = clock::time_point; + + timer_queue timerQueue; + + const DWORD waitHandleCount = 2; + const HANDLE waitHandles[waitHandleCount] = + { + m_wakeUpEvent.handle(), + m_waitableTimerEvent.handle() + }; + + time_point lastSetWaitEventTime = time_point::max(); + + timed_schedule_operation* timersReadyToResume = nullptr; + + DWORD timeout = INFINITE; + while (!m_shutDownRequested.load(std::memory_order_relaxed)) + { + const DWORD waitResult = ::WaitForMultipleObjectsEx( + waitHandleCount, + waitHandles, + FALSE, // waitAll + timeout, + FALSE); // alertable + if (waitResult == WAIT_OBJECT_0 || waitResult == WAIT_FAILED) + { + // Wake-up event (WAIT_OBJECT_0) + // + // We are only woken up for: + // - handling timer cancellation + // - handling newly queued timers + // - shutdown + // + // We also handle WAIT_FAILED here so that we remain responsive + // to new timers and cancellation even if the OS fails to perform + // the wait operation for some reason. + + // Handle cancelled timers + if (m_timerCancellationRequested.exchange(false, std::memory_order_acquire)) + { + timerQueue.remove_cancelled_timers(timersReadyToResume); + } + + // Handle newly queued timers + auto* newTimers = m_newlyQueuedTimers.exchange(nullptr, std::memory_order_acquire); + while (newTimers != nullptr) + { + auto* timer = newTimers; + newTimers = timer->m_next; + + if (timer->m_cancellationToken.is_cancellation_requested()) + { + timer->m_next = timersReadyToResume; + timersReadyToResume = timer; + } + else + { + timerQueue.enqueue_timer(timer); + } + } + } + else if (waitResult == (WAIT_OBJECT_0 + 1)) + { + lastSetWaitEventTime = time_point::max(); + } + + if (!timerQueue.is_empty()) + { + time_point currentTime = clock::now(); + + timerQueue.dequeue_due_timers(currentTime, timersReadyToResume); + + if (!timerQueue.is_empty()) + { + auto earliestDueTime = timerQueue.earliest_due_time(); + assert(earliestDueTime > currentTime); + + // Set the waitable timer before trying to schedule any of the ready-to-run + // timers to avoid the concept of 'current time' on which we calculate the + // amount of time to wait until the next timer is ready. + if (earliestDueTime != lastSetWaitEventTime) + { + using ticks = std::chrono::duration>; + + auto timeUntilNextDueTime = earliestDueTime - currentTime; + + // Negative value indicates relative time. + LARGE_INTEGER dueTime; + dueTime.QuadPart = -std::chrono::duration_cast(timeUntilNextDueTime).count(); + + // Period of 0 indicates no repeat on the timer. + const LONG period = 0; + + // Don't wake the system from a suspended state just to + // raise the timer event. + const BOOL resumeFromSuspend = FALSE; + + const BOOL ok = ::SetWaitableTimer( + m_waitableTimerEvent.handle(), + &dueTime, + period, + nullptr, + nullptr, + resumeFromSuspend); + if (ok) + { + lastSetWaitEventTime = earliestDueTime; + timeout = INFINITE; + } + else + { + // Not sure what could cause the call to SetWaitableTimer() + // to fail here but we'll just try falling back to using + // the timeout parameter of the WaitForMultipleObjects() call. + // + // wake-up at least once every second and retry setting + // the timer at that point. + using namespace std::literals::chrono_literals; + if (timeUntilNextDueTime > 1s) + { + timeout = 1000; + } + else if (timeUntilNextDueTime > 1ms) + { + timeout = static_cast( + std::chrono::duration_cast( + timeUntilNextDueTime).count()); + } + else + { + timeout = 1; + } + } + } + } + } + + // Now schedule any ready-to-run timers. + while (timersReadyToResume != nullptr) + { + auto* timer = timersReadyToResume; + auto* nextTimer = timer->m_next; + + // Use 'release' memory order to ensure that any prior writes to + // m_next "happen before" any potential uses of that same memory + // back on the thread that is executing timed_schedule_operation::await_suspend() + // which has the synchronising 'acquire' semantics. + if (timer->m_refCount.fetch_sub(1, std::memory_order_release) == 1) + { + timer->m_scheduleOperation.m_service.schedule_impl( + &timer->m_scheduleOperation); + } + + timersReadyToResume = nextTimer; + } + } +#endif +} + +void cppcoro::io_service::timer_thread_state::wake_up_timer_thread() noexcept +{ +#if CPPCORO_OS_WINNT + (void)::SetEvent(m_wakeUpEvent.handle()); +#endif +} + +void cppcoro::io_service::schedule_operation::await_suspend( + cppcoro::coroutine_handle<> awaiter) noexcept +{ + m_awaiter = awaiter; + m_service.schedule_impl(this); +} + +cppcoro::io_service::timed_schedule_operation::timed_schedule_operation( + io_service& service, + std::chrono::high_resolution_clock::time_point resumeTime, + cppcoro::cancellation_token cancellationToken) noexcept + : m_scheduleOperation(service) + , m_resumeTime(resumeTime) + , m_cancellationToken(std::move(cancellationToken)) + , m_refCount(2) +{ +} + +cppcoro::io_service::timed_schedule_operation::timed_schedule_operation( + timed_schedule_operation&& other) noexcept + : m_scheduleOperation(std::move(other.m_scheduleOperation)) + , m_resumeTime(std::move(other.m_resumeTime)) + , m_cancellationToken(std::move(other.m_cancellationToken)) + , m_refCount(2) +{ +} + +cppcoro::io_service::timed_schedule_operation::~timed_schedule_operation() +{ +} + +bool cppcoro::io_service::timed_schedule_operation::await_ready() const noexcept +{ + return m_cancellationToken.is_cancellation_requested(); +} + +void cppcoro::io_service::timed_schedule_operation::await_suspend( + cppcoro::coroutine_handle<> awaiter) +{ + m_scheduleOperation.m_awaiter = awaiter; + + auto& service = m_scheduleOperation.m_service; + + // Ensure the timer state is initialised and the timer thread started. + auto* timerState = service.ensure_timer_thread_started(); + + if (m_cancellationToken.can_be_cancelled()) + { + m_cancellationRegistration.emplace(m_cancellationToken, [timerState] + { + timerState->request_timer_cancellation(); + }); + } + + // Queue the timer schedule to the queue of incoming new timers. + // + // We need to do a careful dance here because it could be possible + // that immediately after queueing the timer this thread could be + // context-switched out, the timer thread could pick it up and + // schedule it to be resumed, it could be resumed on an I/O thread + // and complete its work and the io_service could be destructed. + // All before we get to execute timerState.wake_up_timer_thread() + // below. To work around this race we use a reference-counter + // with initial value 2 and have both the timer thread and this + // thread decrement the count once the awaiter is ready to be + // rescheduled. Whichever thread decrements the ref-count to 0 + // is responsible for scheduling the awaiter for resumption. + + + // Not sure if we need 'acquire' semantics on this load and + // on the failure-case of the compare_exchange below. + // + // It could potentially be made 'release' if we can guarantee + // that a read-with 'acquire' semantics in the timer thread + // of the latest value will synchronise with all prior writes + // to that value that used 'release' semantics. + auto* prev = timerState->m_newlyQueuedTimers.load(std::memory_order_acquire); + do + { + m_next = prev; + } while (!timerState->m_newlyQueuedTimers.compare_exchange_weak( + prev, + this, + std::memory_order_release, + std::memory_order_acquire)); + + if (prev == nullptr) + { + timerState->wake_up_timer_thread(); + } + + // Use 'acquire' semantics here to synchronise with the 'release' + // operation performed on the timer thread to ensure that we have + // seen all potential writes to this object. Without this, it's + // possible that a write to the m_next field by the timer thread + // will race with subsequent writes to that same memory by this + // thread or whatever I/O thread resumes the coroutine. + if (m_refCount.fetch_sub(1, std::memory_order_acquire) == 1) + { + service.schedule_impl(&m_scheduleOperation); + } +} + +void cppcoro::io_service::timed_schedule_operation::await_resume() +{ + m_cancellationRegistration.reset(); + m_cancellationToken.throw_if_cancellation_requested(); +} diff --git a/lib/ip_address.cpp b/lib/ip_address.cpp new file mode 100644 index 0000000..38e490f --- /dev/null +++ b/lib/ip_address.cpp @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include + +std::string cppcoro::net::ip_address::to_string() const +{ + return is_ipv4() ? m_ipv4.to_string() : m_ipv6.to_string(); +} + +std::optional +cppcoro::net::ip_address::from_string(std::string_view string) noexcept +{ + if (auto ipv4 = ipv4_address::from_string(string); ipv4) + { + return *ipv4; + } + + if (auto ipv6 = ipv6_address::from_string(string); ipv6) + { + return *ipv6; + } + + return std::nullopt; +} diff --git a/lib/ip_endpoint.cpp b/lib/ip_endpoint.cpp new file mode 100644 index 0000000..b1b915e --- /dev/null +++ b/lib/ip_endpoint.cpp @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include + +std::string cppcoro::net::ip_endpoint::to_string() const +{ + return is_ipv4() ? m_ipv4.to_string() : m_ipv6.to_string(); +} + +std::optional +cppcoro::net::ip_endpoint::from_string(std::string_view string) noexcept +{ + if (auto ipv4 = ipv4_endpoint::from_string(string); ipv4) + { + return *ipv4; + } + + if (auto ipv6 = ipv6_endpoint::from_string(string); ipv6) + { + return *ipv6; + } + + return std::nullopt; +} diff --git a/lib/ipv4_address.cpp b/lib/ipv4_address.cpp new file mode 100644 index 0000000..686628b --- /dev/null +++ b/lib/ipv4_address.cpp @@ -0,0 +1,174 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include + +namespace +{ + namespace local + { + constexpr bool is_digit(char c) + { + return c >= '0' && c <= '9'; + } + + constexpr std::uint8_t digit_value(char c) + { + return static_cast(c - '0'); + } + } +} + +std::optional +cppcoro::net::ipv4_address::from_string(std::string_view string) noexcept +{ + if (string.empty()) return std::nullopt; + + if (!local::is_digit(string[0])) + { + return std::nullopt; + } + + const auto length = string.length(); + + std::uint8_t partValues[4]; + + if (string[0] == '0' && length > 1) + { + if (local::is_digit(string[1])) + { + // Octal format (not supported) + return std::nullopt; + } + else if (string[1] == 'x') + { + // Hexadecimal format (not supported) + return std::nullopt; + } + } + + // Parse the first integer. + // Could be a single 32-bit integer or first integer in a dotted decimal string. + + std::size_t pos = 0; + + { + constexpr std::uint32_t maxValue = 0xFFFFFFFFu / 10; + constexpr std::uint32_t maxDigit = 0xFFFFFFFFu % 10; + + std::uint32_t partValue = local::digit_value(string[pos]); + ++pos; + + while (pos < length && local::is_digit(string[pos])) + { + const auto digitValue = local::digit_value(string[pos]); + ++pos; + + // Check if this digit would overflow the 32-bit integer + if (partValue > maxValue || (partValue == maxValue && digitValue > maxDigit)) + { + return std::nullopt; + } + + partValue = (partValue * 10) + digitValue; + } + + if (pos == length) + { + // A single-integer string + return ipv4_address{ partValue }; + } + else if (partValue > 255) + { + // Not a valid first component of dotted decimal + return std::nullopt; + } + + partValues[0] = static_cast(partValue); + } + + for (int part = 1; part < 4; ++part) + { + if ((pos + 1) >= length || string[pos] != '.' || !local::is_digit(string[pos + 1])) + { + return std::nullopt; + } + + // Skip the '.' + ++pos; + + // Check for an octal format (not yet supported) + const bool isPartOctal = + (pos + 1) < length && + string[pos] == '0' && + local::is_digit(string[pos + 1]); + if (isPartOctal) + { + return std::nullopt; + } + + std::uint32_t partValue = local::digit_value(string[pos]); + ++pos; + if (pos < length && local::is_digit(string[pos])) + { + partValue = (partValue * 10) + local::digit_value(string[pos]); + ++pos; + if (pos < length && local::is_digit(string[pos])) + { + partValue = (partValue * 10) + local::digit_value(string[pos]); + if (partValue > 255) + { + return std::nullopt; + } + + ++pos; + } + } + + partValues[part] = static_cast(partValue); + } + + if (pos < length) + { + // Extra chars after end of a valid IPv4 string + return std::nullopt; + } + + return ipv4_address{ partValues }; +} + +std::string cppcoro::net::ipv4_address::to_string() const +{ + // Buffer is large enough to hold larges ip address + // "xxx.xxx.xxx.xxx" + char buffer[15]; + + char* c = &buffer[0]; + for (int i = 0; i < 4; ++i) + { + if (i > 0) + { + *c++ = '.'; + } + + if (m_bytes[i] >= 100) + { + *c++ = '0' + (m_bytes[i] / 100); + *c++ = '0' + (m_bytes[i] % 100) / 10; + *c++ = '0' + (m_bytes[i] % 10); + } + else if (m_bytes[i] >= 10) + { + *c++ = '0' + (m_bytes[i] / 10); + *c++ = '0' + (m_bytes[i] % 10); + } + else + { + *c++ = '0' + m_bytes[i]; + } + } + + return std::string{ &buffer[0], c }; +} diff --git a/lib/ipv4_endpoint.cpp b/lib/ipv4_endpoint.cpp new file mode 100644 index 0000000..61d6ead --- /dev/null +++ b/lib/ipv4_endpoint.cpp @@ -0,0 +1,71 @@ +/////////////////////////////////////////////////////////////////////////////// +// Kt C++ Library +// Copyright (c) 2015 Lewis Baker +/////////////////////////////////////////////////////////////////////////////// + +#include + +#include + +namespace +{ + namespace local + { + bool is_digit(char c) + { + return c >= '0' && c <= '9'; + } + + std::uint8_t digit_value(char c) + { + return static_cast(c - '0'); + } + + std::optional parse_port(std::string_view string) + { + if (string.empty()) return std::nullopt; + + std::uint32_t value = 0; + for (auto c : string) + { + if (!is_digit(c)) return std::nullopt; + value = value * 10 + digit_value(c); + if (value > 0xFFFFu) return std::nullopt; + } + + return static_cast(value); + } + } +} + +std::string cppcoro::net::ipv4_endpoint::to_string() const +{ + auto s = m_address.to_string(); + s.push_back(':'); + s.append(std::to_string(m_port)); + return s; +} + +std::optional +cppcoro::net::ipv4_endpoint::from_string(std::string_view string) noexcept +{ + auto colonPos = string.find(':'); + if (colonPos == std::string_view::npos) + { + return std::nullopt; + } + + auto address = ipv4_address::from_string(string.substr(0, colonPos)); + if (!address) + { + return std::nullopt; + } + + auto port = local::parse_port(string.substr(colonPos + 1)); + if (!port) + { + return std::nullopt; + } + + return ipv4_endpoint{ *address, *port }; +} diff --git a/lib/ipv6_address.cpp b/lib/ipv6_address.cpp new file mode 100644 index 0000000..7d5216e --- /dev/null +++ b/lib/ipv6_address.cpp @@ -0,0 +1,362 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include + +namespace +{ + namespace local + { + constexpr bool is_digit(char c) + { + return c >= '0' && c <= '9'; + } + + constexpr std::uint8_t digit_value(char c) + { + return static_cast(c - '0'); + } + + std::optional try_parse_hex_digit(char c) + { + if (c >= '0' && c <= '9') + { + return static_cast(c - '0'); + } + else if (c >= 'a' && c <= 'f') + { + return static_cast(c - 'a' + 10); + } + else if (c >= 'A' && c <= 'F') + { + return static_cast(c - 'A' + 10); + } + + return std::nullopt; + } + + char hex_char(std::uint8_t value) + { + return value < 10 ? + static_cast('0' + value) : + static_cast('a' + value - 10); + } + } +} + +std::optional +cppcoro::net::ipv6_address::from_string(std::string_view string) noexcept +{ + // Longest possible valid IPv6 string is + // "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:nnn.nnn.nnn.nnn" + constexpr std::size_t maxLength = 45; + + if (string.empty() || string.length() > maxLength) + { + return std::nullopt; + } + + const std::size_t length = string.length(); + + std::optional doubleColonPos; + + std::size_t pos = 0; + + if (length >= 2 && string[0] == ':' && string[1] == ':') + { + doubleColonPos = 0; + pos = 2; + } + + int partCount = 0; + std::uint16_t parts[8] = { 0 }; + + while (pos < length && partCount < 8) + { + std::uint8_t digits[4]; + int digitCount = 0; + auto digit = local::try_parse_hex_digit(string[pos]); + if (!digit) + { + return std::nullopt; + } + + do + { + digits[digitCount] = *digit; + ++digitCount; + ++pos; + } while (digitCount < 4 && pos < length && (digit = local::try_parse_hex_digit(string[pos]))); + + // If we're not at the end of the string then there must either be a ':' or a '.' next + // followed by the next part. + if (pos < length) + { + // Check if there's room for anything after the separator. + if ((pos + 1) == length) + { + return std::nullopt; + } + + if (string[pos] == ':') + { + ++pos; + if (string[pos] == ':') + { + if (doubleColonPos) + { + // This is a second double-colon, which is invalid. + return std::nullopt; + } + + doubleColonPos = partCount + 1; + ++pos; + } + } + else if (string[pos] == '.') + { + // Treat the current set of digits as decimal digits and parse + // the remaining three groups as dotted decimal notation. + + // Decimal notation produces two 16-bit parts. + // If we already have more than 6 parts then we'll end up + // with too many. + if (partCount > 6) + { + return std::nullopt; + } + + // Check for over-long or octal notation. + if (digitCount > 3 || (digitCount > 1 && digits[0] == 0)) + { + return std::nullopt; + } + + // Check that digits are valid decimal digits + if (digits[0] > 9 || + (digitCount > 1 && digits[1] > 9) || + (digitCount == 3 && digits[2] > 9)) + { + return std::nullopt; + } + + std::uint16_t decimalParts[4]; + + { + decimalParts[0] = digits[0]; + for (int i = 1; i < digitCount; ++i) + { + decimalParts[0] *= 10; + decimalParts[0] += digits[i]; + } + + if (decimalParts[0] > 255) + { + return std::nullopt; + } + } + + for (int decimalPart = 1; decimalPart < 4; ++decimalPart) + { + if (string[pos] != '.') + { + return std::nullopt; + } + + ++pos; + + if (pos == length || !local::is_digit(string[pos])) + { + // Expected a number after a dot. + return std::nullopt; + } + + const bool hasLeadingZero = string[pos] == '0'; + + decimalParts[decimalPart] = local::digit_value(string[pos]); + ++pos; + digitCount = 1; + while (digitCount < 3 && pos < length && local::is_digit(string[pos])) + { + decimalParts[decimalPart] *= 10; + decimalParts[decimalPart] += local::digit_value(string[pos]); + ++pos; + ++digitCount; + } + + if (decimalParts[decimalPart] > 255) + { + return std::nullopt; + } + + // Detect octal-style number (redundant leading zero) + if (digitCount > 1 && hasLeadingZero) + { + return std::nullopt; + } + } + + parts[partCount] = (decimalParts[0] << 8) + decimalParts[1]; + parts[partCount + 1] = (decimalParts[2] << 8) + decimalParts[3]; + partCount += 2; + + // Dotted decimal notation only appears at end. + // Don't parse any more of the string. + break; + } + else + { + // Invalid separator. + return std::nullopt; + } + } + + // Current part was made up of hex-digits. + std::uint16_t partValue = digits[0]; + for (int i = 1; i < digitCount; ++i) + { + partValue = partValue * 16 + digits[i]; + } + + parts[partCount] = partValue; + ++partCount; + } + + // Finished parsing the IPv6 address, we should have consumed all of the string. + if (pos < length) + { + return std::nullopt; + } + + if (partCount < 8) + { + if (!doubleColonPos) + { + return std::nullopt; + } + + const int preCount = *doubleColonPos; + + //CPPCORO_ASSUME(preCount <= partCount); + + const int postCount = partCount - preCount; + const int zeroCount = 8 - preCount - postCount; + + // Move parts after double colon down to the end. + for (int i = 0; i < postCount; ++i) + { + parts[7 - i] = parts[7 - zeroCount - i]; + } + + // Fill gap with zeroes. + for (int i = 0; i < zeroCount; ++i) + { + parts[preCount + i] = 0; + } + } + else if (doubleColonPos) + { + return std::nullopt; + } + + return ipv6_address{ parts }; +} + +std::string cppcoro::net::ipv6_address::to_string() const +{ + std::uint32_t longestZeroRunStart = 0; + std::uint32_t longestZeroRunLength = 0; + for (std::uint32_t i = 0; i < 8; ) + { + if (m_bytes[2 * i] == 0 && m_bytes[2 * i + 1] == 0) + { + const std::uint32_t zeroRunStart = i; + ++i; + while (i < 8 && m_bytes[2 * i] == 0 && m_bytes[2 * i + 1] == 0) + { + ++i; + } + + std::uint32_t zeroRunLength = i - zeroRunStart; + if (zeroRunLength > longestZeroRunLength) + { + longestZeroRunLength = zeroRunLength; + longestZeroRunStart = zeroRunStart; + } + } + else + { + ++i; + } + } + + // Longest string will be 8 x 4 digits + 7 ':' separators + char buffer[40]; + + char* c = &buffer[0]; + + auto appendPart = [&](std::uint32_t index) + { + const std::uint8_t highByte = m_bytes[index * 2]; + const std::uint8_t lowByte = m_bytes[index * 2 + 1]; + + // Don't output leading zero hex digits in the part string. + if (highByte > 0 || lowByte > 15) + { + if (highByte > 0) + { + if (highByte > 15) + { + *c++ = local::hex_char(highByte >> 4); + } + *c++ = local::hex_char(highByte & 0xF); + } + *c++ = local::hex_char(lowByte >> 4); + } + *c++ = local::hex_char(lowByte & 0xF); + }; + + if (longestZeroRunLength >= 2) + { + for (std::uint32_t i = 0; i < longestZeroRunStart; ++i) + { + if (i > 0) + { + *c++ = ':'; + } + + appendPart(i); + } + + *c++ = ':'; + *c++ = ':'; + + for (std::uint32_t i = longestZeroRunStart + longestZeroRunLength; i < 8; ++i) + { + appendPart(i); + + if (i < 7) + { + *c++ = ':'; + } + } + } + else + { + appendPart(0); + for (std::uint32_t i = 1; i < 8; ++i) + { + *c++ = ':'; + appendPart(i); + } + } + + assert((c - &buffer[0]) <= sizeof(buffer)); + + return std::string{ &buffer[0], c }; +} diff --git a/lib/ipv6_endpoint.cpp b/lib/ipv6_endpoint.cpp new file mode 100644 index 0000000..4f63a1d --- /dev/null +++ b/lib/ipv6_endpoint.cpp @@ -0,0 +1,84 @@ +/////////////////////////////////////////////////////////////////////////////// +// Kt C++ Library +// Copyright (c) 2015 Lewis Baker +/////////////////////////////////////////////////////////////////////////////// + +#include + +#include + +namespace +{ + namespace local + { + bool is_digit(char c) + { + return c >= '0' && c <= '9'; + } + + std::uint8_t digit_value(char c) + { + return static_cast(c - '0'); + } + + std::optional parse_port(std::string_view string) + { + if (string.empty()) return std::nullopt; + + std::uint32_t value = 0; + for (auto c : string) + { + if (!is_digit(c)) return std::nullopt; + value = value * 10 + digit_value(c); + if (value > 0xFFFFu) return std::nullopt; + } + + return static_cast(value); + } + } +} + +std::string cppcoro::net::ipv6_endpoint::to_string() const +{ + std::string result; + result.push_back('['); + result += m_address.to_string(); + result += "]:"; + result += std::to_string(m_port); + return result; +} + +std::optional +cppcoro::net::ipv6_endpoint::from_string(std::string_view string) noexcept +{ + // Shortest valid endpoint is "[::]:0" + if (string.size() < 6) + { + return std::nullopt; + } + + if (string[0] != '[') + { + return std::nullopt; + } + + auto closeBracketPos = string.find("]:", 1); + if (closeBracketPos == std::string_view::npos) + { + return std::nullopt; + } + + auto address = ipv6_address::from_string(string.substr(1, closeBracketPos - 1)); + if (!address) + { + return std::nullopt; + } + + auto port = local::parse_port(string.substr(closeBracketPos + 2)); + if (!port) + { + return std::nullopt; + } + + return ipv6_endpoint{ *address, *port }; +} diff --git a/lib/lightweight_manual_reset_event.cpp b/lib/lightweight_manual_reset_event.cpp new file mode 100644 index 0000000..35b8f16 --- /dev/null +++ b/lib/lightweight_manual_reset_event.cpp @@ -0,0 +1,254 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include + +#if CPPCORO_OS_WINNT +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include + +# if CPPCORO_OS_WINNT >= 0x0602 + +cppcoro::detail::lightweight_manual_reset_event::lightweight_manual_reset_event(bool initiallySet) + : m_value(initiallySet ? 1 : 0) +{} + +cppcoro::detail::lightweight_manual_reset_event::~lightweight_manual_reset_event() +{ +} + +void cppcoro::detail::lightweight_manual_reset_event::set() noexcept +{ + m_value.store(1, std::memory_order_release); + ::WakeByAddressAll(&m_value); +} + +void cppcoro::detail::lightweight_manual_reset_event::reset() noexcept +{ + m_value.store(0, std::memory_order_relaxed); +} + +void cppcoro::detail::lightweight_manual_reset_event::wait() noexcept +{ + wait({}, std::chrono::milliseconds(0)); +} +void cppcoro::detail::lightweight_manual_reset_event::wait( + std::span srvs, std::chrono::system_clock::duration step) noexcept +{ + const DWORD stepMs = static_cast(std::chrono::duration_cast(step).count()); + DWORD delay = srvs.empty() ? INFINITE : stepMs; + + // Wait in a loop as WaitOnAddress() can have spurious wake-ups. + int value = m_value.load(std::memory_order_acquire); + BOOL ok = TRUE; + while (value == 0) + { + if (!srvs.empty()) + { + //if there was one processed event, pass 0 timeout so we get a chance to process more, quickly + //otherwise, wait the full step + uint64_t tasks = 0; + for (auto& srv: srvs) + tasks += srv.process_one_pending_event(); + + delay = tasks > 0 ? 0 : stepMs; + } + else if (!ok) + { + // Previous call to WaitOnAddress() failed for some reason. + // Put thread to sleep to avoid sitting in a busy loop if it keeps failing. + ::Sleep(1); + } + + ok = ::WaitOnAddress(&m_value, &value, sizeof(m_value), delay); + value = m_value.load(std::memory_order_acquire); + } +} + +# else + +cppcoro::detail::lightweight_manual_reset_event::lightweight_manual_reset_event(bool initiallySet) + : m_eventHandle(::CreateEventW(nullptr, TRUE, initiallySet, nullptr)) +{ + if (m_eventHandle == NULL) + { + const DWORD errorCode = ::GetLastError(); + throw std::system_error + { + static_cast(errorCode), + std::system_category() + }; + } +} + +cppcoro::detail::lightweight_manual_reset_event::~lightweight_manual_reset_event() +{ + // Ignore failure to close the object. + // We can't do much here as we want destructor to be noexcept. + (void)::CloseHandle(m_eventHandle); +} + +void cppcoro::detail::lightweight_manual_reset_event::set() noexcept +{ + if (!::SetEvent(m_eventHandle)) + { + std::abort(); + } +} + +void cppcoro::detail::lightweight_manual_reset_event::reset() noexcept +{ + if (!::ResetEvent(m_eventHandle)) + { + std::abort(); + } +} + +void cppcoro::detail::lightweight_manual_reset_event::wait() noexcept +{ + constexpr BOOL alertable = FALSE; + DWORD waitResult = ::WaitForSingleObjectEx(m_eventHandle, INFINITE, alertable); + if (waitResult == WAIT_FAILED) + { + std::abort(); + } +} + +# endif + +#elif CPPCORO_OS_LINUX + +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + namespace local + { + // No futex() function provided by libc. + // Wrap the syscall ourselves here. + int futex( + int* UserAddress, + int FutexOperation, + int Value, + const struct timespec* timeout, + int* UserAddress2, + int Value3) + { + return syscall( + SYS_futex, + UserAddress, + FutexOperation, + Value, + timeout, + UserAddress2, + Value3); + } + } +} + +cppcoro::detail::lightweight_manual_reset_event::lightweight_manual_reset_event(bool initiallySet) + : m_value(initiallySet ? 1 : 0) +{} + +cppcoro::detail::lightweight_manual_reset_event::~lightweight_manual_reset_event() +{ +} + +void cppcoro::detail::lightweight_manual_reset_event::set() noexcept +{ + m_value.store(1, std::memory_order_release); + + constexpr int numberOfWaitersToWakeUp = INT_MAX; + + [[maybe_unused]] int numberOfWaitersWokenUp = local::futex( + reinterpret_cast(&m_value), + FUTEX_WAKE_PRIVATE, + numberOfWaitersToWakeUp, + nullptr, + nullptr, + 0); + + // There are no errors expected here unless this class (or the caller) + // has done something wrong. + assert(numberOfWaitersWokenUp != -1); +} + +void cppcoro::detail::lightweight_manual_reset_event::reset() noexcept +{ + m_value.store(0, std::memory_order_relaxed); +} + +void cppcoro::detail::lightweight_manual_reset_event::wait() noexcept +{ + // Wait in a loop as futex() can have spurious wake-ups. + int oldValue = m_value.load(std::memory_order_acquire); + while (oldValue == 0) + { + int result = local::futex( + reinterpret_cast(&m_value), + FUTEX_WAIT_PRIVATE, + oldValue, + nullptr, + nullptr, + 0); + if (result == -1) + { + if (errno == EAGAIN) + { + // The state was changed from zero before we could wait. + // Must have been changed to 1. + return; + } + + // Other errors we'll treat as transient and just read the + // value and go around the loop again. + } + + oldValue = m_value.load(std::memory_order_acquire); + } +} + +#else + +cppcoro::detail::lightweight_manual_reset_event::lightweight_manual_reset_event(bool initiallySet) + : m_isSet(initiallySet) +{ +} + +cppcoro::detail::lightweight_manual_reset_event::~lightweight_manual_reset_event() +{ +} + +void cppcoro::detail::lightweight_manual_reset_event::set() noexcept +{ + std::lock_guard lock(m_mutex); + m_isSet = true; + m_cv.notify_all(); +} + +void cppcoro::detail::lightweight_manual_reset_event::reset() noexcept +{ + std::lock_guard lock(m_mutex); + m_isSet = false; +} + +void cppcoro::detail::lightweight_manual_reset_event::wait() noexcept +{ + std::unique_lock lock(m_mutex); + m_cv.wait(lock, [this] { return m_isSet; }); +} + +#endif diff --git a/lib/read_only_file.cpp b/lib/read_only_file.cpp new file mode 100644 index 0000000..b278365 --- /dev/null +++ b/lib/read_only_file.cpp @@ -0,0 +1,36 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include + +#if CPPCORO_OS_WINNT +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include + +cppcoro::read_only_file cppcoro::read_only_file::open( + io_service& ioService, + const cppcoro::filesystem::path& path, + file_share_mode shareMode, + file_buffering_mode bufferingMode) +{ + return read_only_file(file::open( + GENERIC_READ, + ioService, + path, + file_open_mode::open_existing, + shareMode, + bufferingMode)); +} + +cppcoro::read_only_file::read_only_file( + detail::win32::safe_handle&& fileHandle) noexcept + : file(std::move(fileHandle)) + , readable_file(detail::win32::safe_handle{}) +{ +} + +#endif diff --git a/lib/read_write_file.cpp b/lib/read_write_file.cpp new file mode 100644 index 0000000..13838ea --- /dev/null +++ b/lib/read_write_file.cpp @@ -0,0 +1,38 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include + +#if CPPCORO_OS_WINNT +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include + +cppcoro::read_write_file cppcoro::read_write_file::open( + io_service& ioService, + const cppcoro::filesystem::path& path, + file_open_mode openMode, + file_share_mode shareMode, + file_buffering_mode bufferingMode) +{ + return read_write_file(file::open( + GENERIC_READ | GENERIC_WRITE, + ioService, + path, + openMode, + shareMode, + bufferingMode)); +} + +cppcoro::read_write_file::read_write_file( + detail::win32::safe_handle&& fileHandle) noexcept + : file(std::move(fileHandle)) + , readable_file(detail::win32::safe_handle{}) + , writable_file(detail::win32::safe_handle{}) +{ +} + +#endif diff --git a/lib/readable_file.cpp b/lib/readable_file.cpp new file mode 100644 index 0000000..12b90f2 --- /dev/null +++ b/lib/readable_file.cpp @@ -0,0 +1,36 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include + +#if CPPCORO_OS_WINNT + +cppcoro::file_read_operation cppcoro::readable_file::read( + std::uint64_t offset, + void* buffer, + std::size_t byteCount) const noexcept +{ + return file_read_operation( + m_fileHandle.handle(), + offset, + buffer, + byteCount); +} + +cppcoro::file_read_operation_cancellable cppcoro::readable_file::read( + std::uint64_t offset, + void* buffer, + std::size_t byteCount, + cancellation_token ct) const noexcept +{ + return file_read_operation_cancellable( + m_fileHandle.handle(), + offset, + buffer, + byteCount, + std::move(ct)); +} + +#endif diff --git a/lib/socket.cpp b/lib/socket.cpp new file mode 100644 index 0000000..fd438a1 --- /dev/null +++ b/lib/socket.cpp @@ -0,0 +1,493 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "socket_helpers.hpp" + +#if CPPCORO_OS_WINNT +# include +# include +# include +# include + +namespace +{ + namespace local + { + std::tuple create_socket( + int addressFamily, + int socketType, + int protocol, + HANDLE ioCompletionPort) + { + // Enumerate available protocol providers for the specified socket type. + + WSAPROTOCOL_INFOW stackInfos[4]; + std::unique_ptr heapInfos; + WSAPROTOCOL_INFOW* selectedProtocolInfo = nullptr; + + { + INT protocols[] = { protocol, 0 }; + DWORD bufferSize = sizeof(stackInfos); + WSAPROTOCOL_INFOW* infos = stackInfos; + + int protocolCount = ::WSAEnumProtocolsW(protocols, infos, &bufferSize); + if (protocolCount == SOCKET_ERROR) + { + int errorCode = ::WSAGetLastError(); + if (errorCode == WSAENOBUFS) + { + DWORD requiredElementCount = bufferSize / sizeof(WSAPROTOCOL_INFOW); + heapInfos = std::make_unique(requiredElementCount); + bufferSize = requiredElementCount * sizeof(WSAPROTOCOL_INFOW); + infos = heapInfos.get(); + protocolCount = ::WSAEnumProtocolsW(protocols, infos, &bufferSize); + if (protocolCount == SOCKET_ERROR) + { + errorCode = ::WSAGetLastError(); + } + } + + if (protocolCount == SOCKET_ERROR) + { + throw std::system_error( + errorCode, + std::system_category(), + "Error creating socket: WSAEnumProtocolsW"); + } + } + + if (protocolCount == 0) + { + throw std::system_error( + std::make_error_code(std::errc::protocol_not_supported)); + } + + for (int i = 0; i < protocolCount; ++i) + { + auto& info = infos[i]; + if (info.iAddressFamily == addressFamily && info.iProtocol == protocol && info.iSocketType == socketType) + { + selectedProtocolInfo = &info; + break; + } + } + + if (selectedProtocolInfo == nullptr) + { + throw std::system_error( + std::make_error_code(std::errc::address_family_not_supported)); + } + } + + // WSA_FLAG_NO_HANDLE_INHERIT for SDKs earlier than Windows 7. + constexpr DWORD flagNoInherit = 0x80; + + const DWORD flags = WSA_FLAG_OVERLAPPED | flagNoInherit; + + const SOCKET socketHandle = ::WSASocketW( + addressFamily, socketType, protocol, selectedProtocolInfo, 0, flags); + if (socketHandle == INVALID_SOCKET) + { + const int errorCode = ::WSAGetLastError(); + throw std::system_error( + errorCode, + std::system_category(), + "Error creating socket: WSASocketW"); + } + + auto closeSocketOnFailure = cppcoro::on_scope_failure([&] + { + ::closesocket(socketHandle); + }); + + // This is needed on operating systems earlier than Windows 7 to prevent + // socket handles from being inherited. On Windows 7 or later this is + // redundant as the WSA_FLAG_NO_HANDLE_INHERIT flag passed to creation + // above causes the socket to be atomically created with this flag cleared. + if (!::SetHandleInformation((HANDLE)socketHandle, HANDLE_FLAG_INHERIT, 0)) + { + const DWORD errorCode = ::GetLastError(); + throw std::system_error( + errorCode, + std::system_category(), + "Error creating socket: SetHandleInformation"); + } + + // Associate the socket with the I/O completion port. + { + const HANDLE result = ::CreateIoCompletionPort( + (HANDLE)socketHandle, + ioCompletionPort, + ULONG_PTR(0), + DWORD(0)); + if (result == nullptr) + { + const DWORD errorCode = ::GetLastError(); + throw std::system_error( + static_cast(errorCode), + std::system_category(), + "Error creating socket: CreateIoCompletionPort"); + } + } + + const bool skipCompletionPortOnSuccess = + (selectedProtocolInfo->dwServiceFlags1 & XP1_IFS_HANDLES) != 0; + + { + UCHAR completionModeFlags = FILE_SKIP_SET_EVENT_ON_HANDLE; + if (skipCompletionPortOnSuccess) + { + completionModeFlags |= FILE_SKIP_COMPLETION_PORT_ON_SUCCESS; + } + + const BOOL ok = ::SetFileCompletionNotificationModes( + (HANDLE)socketHandle, + completionModeFlags); + if (!ok) + { + const DWORD errorCode = ::GetLastError(); + throw std::system_error( + static_cast(errorCode), + std::system_category(), + "Error creating socket: SetFileCompletionNotificationModes"); + } + } + + if (socketType == SOCK_STREAM) + { + // Turn off linger so that the destructor doesn't block while closing + // the socket or silently continue to flush remaining data in the + // background after ::closesocket() is called, which could fail and + // we'd never know about it. + // We expect clients to call Disconnect() or use CloseSend() to cleanly + // shut-down connections instead. + BOOL value = TRUE; + const int result = ::setsockopt(socketHandle, + SOL_SOCKET, + SO_DONTLINGER, + reinterpret_cast(&value), + sizeof(value)); + if (result == SOCKET_ERROR) + { + const int errorCode = ::WSAGetLastError(); + throw std::system_error( + errorCode, + std::system_category(), + "Error creating socket: setsockopt(SO_DONTLINGER)"); + } + } + + return std::make_tuple(socketHandle, skipCompletionPortOnSuccess); + } + } +} + +cppcoro::net::socket cppcoro::net::socket::create_tcpv4(io_service& ioSvc) +{ + ioSvc.ensure_winsock_initialised(); + + auto[socketHandle, skipCompletionPortOnSuccess] = local::create_socket( + AF_INET, SOCK_STREAM, IPPROTO_TCP, ioSvc.native_iocp_handle()); + + socket result(socketHandle, skipCompletionPortOnSuccess); + result.m_localEndPoint = ipv4_endpoint(); + result.m_remoteEndPoint = ipv4_endpoint(); + return result; +} + +cppcoro::net::socket cppcoro::net::socket::create_tcpv6(io_service& ioSvc) +{ + ioSvc.ensure_winsock_initialised(); + + auto[socketHandle, skipCompletionPortOnSuccess] = local::create_socket( + AF_INET6, SOCK_STREAM, IPPROTO_TCP, ioSvc.native_iocp_handle()); + + socket result(socketHandle, skipCompletionPortOnSuccess); + result.m_localEndPoint = ipv6_endpoint(); + result.m_remoteEndPoint = ipv6_endpoint(); + return result; +} + +cppcoro::net::socket cppcoro::net::socket::create_udpv4(io_service& ioSvc) +{ + ioSvc.ensure_winsock_initialised(); + + auto[socketHandle, skipCompletionPortOnSuccess] = local::create_socket( + AF_INET, SOCK_DGRAM, IPPROTO_UDP, ioSvc.native_iocp_handle()); + + socket result(socketHandle, skipCompletionPortOnSuccess); + result.m_localEndPoint = ipv4_endpoint(); + result.m_remoteEndPoint = ipv4_endpoint(); + return result; +} + +cppcoro::net::socket cppcoro::net::socket::create_udpv6(io_service& ioSvc) +{ + ioSvc.ensure_winsock_initialised(); + + auto[socketHandle, skipCompletionPortOnSuccess] = local::create_socket( + AF_INET6, SOCK_DGRAM, IPPROTO_UDP, ioSvc.native_iocp_handle()); + + socket result(socketHandle, skipCompletionPortOnSuccess); + result.m_localEndPoint = ipv6_endpoint(); + result.m_remoteEndPoint = ipv6_endpoint(); + return result; +} + +cppcoro::net::socket::socket(socket&& other) noexcept + : m_handle(std::exchange(other.m_handle, INVALID_SOCKET)) + , m_skipCompletionOnSuccess(other.m_skipCompletionOnSuccess) + , m_localEndPoint(std::move(other.m_localEndPoint)) + , m_remoteEndPoint(std::move(other.m_remoteEndPoint)) +{} + +cppcoro::net::socket::~socket() +{ + if (m_handle != INVALID_SOCKET) + { + ::closesocket(m_handle); + } +} + +cppcoro::net::socket& +cppcoro::net::socket::operator=(socket&& other) noexcept +{ + auto handle = std::exchange(other.m_handle, INVALID_SOCKET); + if (m_handle != INVALID_SOCKET) + { + ::closesocket(m_handle); + } + + m_handle = handle; + m_skipCompletionOnSuccess = other.m_skipCompletionOnSuccess; + m_localEndPoint = other.m_localEndPoint; + m_remoteEndPoint = other.m_remoteEndPoint; + + return *this; +} + +void cppcoro::net::socket::bind(const ip_endpoint& localEndPoint) +{ + SOCKADDR_STORAGE sockaddrStorage = { 0 }; + SOCKADDR* sockaddr = reinterpret_cast(&sockaddrStorage); + if (localEndPoint.is_ipv4()) + { + SOCKADDR_IN& ipv4Sockaddr = *reinterpret_cast(sockaddr); + ipv4Sockaddr.sin_family = AF_INET; + std::memcpy(&ipv4Sockaddr.sin_addr, localEndPoint.to_ipv4().address().bytes(), 4); + ipv4Sockaddr.sin_port = localEndPoint.to_ipv4().port(); + } + else + { + SOCKADDR_IN6& ipv6Sockaddr = *reinterpret_cast(sockaddr); + ipv6Sockaddr.sin6_family = AF_INET6; + std::memcpy(&ipv6Sockaddr.sin6_addr, localEndPoint.to_ipv6().address().bytes(), 16); + ipv6Sockaddr.sin6_port = localEndPoint.to_ipv6().port(); + } + + int result = ::bind(m_handle, sockaddr, sizeof(sockaddrStorage)); + if (result != 0) + { + // WSANOTINITIALISED: WSAStartup not called + // WSAENETDOWN: network subsystem failed + // WSAEACCES: access denied + // WSAEADDRINUSE: port in use + // WSAEADDRNOTAVAIL: address is not an address that can be bound to + // WSAEFAULT: invalid pointer passed to bind() + // WSAEINPROGRESS: a callback is in progress + // WSAEINVAL: socket already bound + // WSAENOBUFS: system failed to allocate memory + // WSAENOTSOCK: socket was not a valid socket. + int errorCode = ::WSAGetLastError(); + throw std::system_error( + errorCode, + std::system_category(), + "Error binding to endpoint: bind()"); + } + + int sockaddrLen = sizeof(sockaddrStorage); + result = ::getsockname(m_handle, sockaddr, &sockaddrLen); + if (result == 0) + { + m_localEndPoint = cppcoro::net::detail::sockaddr_to_ip_endpoint(*sockaddr); + } + else + { + m_localEndPoint = localEndPoint; + } +} + +void cppcoro::net::socket::listen() +{ + int result = ::listen(m_handle, SOMAXCONN); + if (result != 0) + { + int errorCode = ::WSAGetLastError(); + throw std::system_error( + errorCode, + std::system_category(), + "Failed to start listening on bound endpoint: listen"); + } +} + +void cppcoro::net::socket::listen(std::uint32_t backlog) +{ + if (backlog > 0x7FFFFFFF) + { + backlog = 0x7FFFFFFF; + } + + int result = ::listen(m_handle, (int)backlog); + if (result != 0) + { + // WSANOTINITIALISED: WSAStartup not called + // WSAENETDOWN: network subsystem failed + // WSAEADDRINUSE: port in use + // WSAEINPROGRESS: a callback is in progress + // WSAEINVAL: socket not yet bound + // WSAEISCONN: socket already connected + // WSAEMFILE: no more socket descriptors available + // WSAENOBUFS: system failed to allocate memory + // WSAENOTSOCK: socket was not a valid socket. + // WSAEOPNOTSUPP: The socket does not support listening + + int errorCode = ::WSAGetLastError(); + throw std::system_error( + errorCode, + std::system_category(), + "Failed to start listening on bound endpoint: listen"); + } +} + +cppcoro::net::socket_accept_operation +cppcoro::net::socket::accept(socket& acceptingSocket) noexcept +{ + return socket_accept_operation{ *this, acceptingSocket }; +} + +cppcoro::net::socket_accept_operation_cancellable +cppcoro::net::socket::accept(socket& acceptingSocket, cancellation_token ct) noexcept +{ + return socket_accept_operation_cancellable{ *this, acceptingSocket, std::move(ct) }; +} + +cppcoro::net::socket_connect_operation +cppcoro::net::socket::connect(const ip_endpoint& remoteEndPoint) noexcept +{ + return socket_connect_operation{ *this, remoteEndPoint }; +} + +cppcoro::net::socket_connect_operation_cancellable +cppcoro::net::socket::connect(const ip_endpoint& remoteEndPoint, cancellation_token ct) noexcept +{ + return socket_connect_operation_cancellable{ *this, remoteEndPoint, std::move(ct) }; +} + +cppcoro::net::socket_disconnect_operation +cppcoro::net::socket::disconnect() noexcept +{ + return socket_disconnect_operation(*this); +} + +cppcoro::net::socket_disconnect_operation_cancellable +cppcoro::net::socket::disconnect(cancellation_token ct) noexcept +{ + return socket_disconnect_operation_cancellable{ *this, std::move(ct) }; +} + +cppcoro::net::socket_send_operation +cppcoro::net::socket::send(const void* buffer, std::size_t byteCount) noexcept +{ + return socket_send_operation{ *this, buffer, byteCount }; +} + +cppcoro::net::socket_send_operation_cancellable +cppcoro::net::socket::send(const void* buffer, std::size_t byteCount, cancellation_token ct) noexcept +{ + return socket_send_operation_cancellable{ *this, buffer, byteCount, std::move(ct) }; +} + +cppcoro::net::socket_recv_operation +cppcoro::net::socket::recv(void* buffer, std::size_t byteCount) noexcept +{ + return socket_recv_operation{ *this, buffer, byteCount }; +} + +cppcoro::net::socket_recv_operation_cancellable +cppcoro::net::socket::recv(void* buffer, std::size_t byteCount, cancellation_token ct) noexcept +{ + return socket_recv_operation_cancellable{ *this, buffer, byteCount, std::move(ct) }; +} + +cppcoro::net::socket_recv_from_operation +cppcoro::net::socket::recv_from(void* buffer, std::size_t byteCount) noexcept +{ + return socket_recv_from_operation{ *this, buffer, byteCount }; +} + +cppcoro::net::socket_recv_from_operation_cancellable +cppcoro::net::socket::recv_from(void* buffer, std::size_t byteCount, cancellation_token ct) noexcept +{ + return socket_recv_from_operation_cancellable{ *this, buffer, byteCount, std::move(ct) }; +} + +cppcoro::net::socket_send_to_operation +cppcoro::net::socket::send_to(const ip_endpoint& destination, const void* buffer, std::size_t byteCount) noexcept +{ + return socket_send_to_operation{ *this, destination, buffer, byteCount }; +} + +cppcoro::net::socket_send_to_operation_cancellable +cppcoro::net::socket::send_to(const ip_endpoint& destination, const void* buffer, std::size_t byteCount, cancellation_token ct) noexcept +{ + return socket_send_to_operation_cancellable{ *this, destination, buffer, byteCount, std::move(ct) }; +} + +void cppcoro::net::socket::close_send() +{ + int result = ::shutdown(m_handle, SD_SEND); + if (result == SOCKET_ERROR) + { + int errorCode = ::WSAGetLastError(); + throw std::system_error( + errorCode, + std::system_category(), + "failed to close socket send stream: shutdown(SD_SEND)"); + } +} + +void cppcoro::net::socket::close_recv() +{ + int result = ::shutdown(m_handle, SD_RECEIVE); + if (result == SOCKET_ERROR) + { + int errorCode = ::WSAGetLastError(); + throw std::system_error( + errorCode, + std::system_category(), + "failed to close socket receive stream: shutdown(SD_RECEIVE)"); + } +} + +cppcoro::net::socket::socket( + cppcoro::detail::win32::socket_t handle, + bool skipCompletionOnSuccess) noexcept + : m_handle(handle) + , m_skipCompletionOnSuccess(skipCompletionOnSuccess) +{ +} + +#endif diff --git a/lib/socket_accept_operation.cpp b/lib/socket_accept_operation.cpp new file mode 100644 index 0000000..b65ab14 --- /dev/null +++ b/lib/socket_accept_operation.cpp @@ -0,0 +1,129 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "socket_helpers.hpp" + +#include + +#if CPPCORO_OS_WINNT +# include +# include +# include +# include + +// TODO: Eliminate duplication of implementation between socket_accept_operation +// and socket_accept_operation_cancellable. + +bool cppcoro::net::socket_accept_operation_impl::try_start( + cppcoro::detail::win32_overlapped_operation_base& operation) noexcept +{ + static_assert( + (sizeof(m_addressBuffer) / 2) >= (16 + sizeof(SOCKADDR_IN)) && + (sizeof(m_addressBuffer) / 2) >= (16 + sizeof(SOCKADDR_IN6)), + "AcceptEx requires address buffer to be at least 16 bytes more than largest address."); + + // Need to read this flag before starting the operation, otherwise + // it may be possible that the operation will complete immediately + // on another thread and then destroy the socket before we get a + // chance to read it. + const bool skipCompletionOnSuccess = m_listeningSocket.skip_completion_on_success(); + + DWORD bytesReceived = 0; + BOOL ok = ::AcceptEx( + m_listeningSocket.native_handle(), + m_acceptingSocket.native_handle(), + m_addressBuffer, + 0, + sizeof(m_addressBuffer) / 2, + sizeof(m_addressBuffer) / 2, + &bytesReceived, + operation.get_overlapped()); + if (!ok) + { + int errorCode = ::WSAGetLastError(); + if (errorCode != ERROR_IO_PENDING) + { + operation.m_errorCode = static_cast(errorCode); + return false; + } + } + else if (skipCompletionOnSuccess) + { + operation.m_errorCode = ERROR_SUCCESS; + return false; + } + + return true; +} + +void cppcoro::net::socket_accept_operation_impl::cancel( + cppcoro::detail::win32_overlapped_operation_base& operation) noexcept +{ + (void)::CancelIoEx( + reinterpret_cast(m_listeningSocket.native_handle()), + operation.get_overlapped()); +} + +void cppcoro::net::socket_accept_operation_impl::get_result( + cppcoro::detail::win32_overlapped_operation_base& operation) +{ + if (operation.m_errorCode != ERROR_SUCCESS) + { + throw std::system_error{ + static_cast(operation.m_errorCode), + std::system_category(), + "Accepting a connection failed: AcceptEx" + }; + } + + sockaddr* localSockaddr = nullptr; + sockaddr* remoteSockaddr = nullptr; + + INT localSockaddrLength; + INT remoteSockaddrLength; + + ::GetAcceptExSockaddrs( + m_addressBuffer, + 0, + sizeof(m_addressBuffer) / 2, + sizeof(m_addressBuffer) / 2, + &localSockaddr, + &localSockaddrLength, + &remoteSockaddr, + &remoteSockaddrLength); + + m_acceptingSocket.m_localEndPoint = + detail::sockaddr_to_ip_endpoint(*localSockaddr); + + m_acceptingSocket.m_remoteEndPoint = + detail::sockaddr_to_ip_endpoint(*remoteSockaddr); + + { + // Need to set SO_UPDATE_ACCEPT_CONTEXT after the accept completes + // to ensure that ::shutdown() and ::setsockopt() calls work on the + // accepted socket. + SOCKET listenSocket = m_listeningSocket.native_handle(); + const int result = ::setsockopt( + m_acceptingSocket.native_handle(), + SOL_SOCKET, + SO_UPDATE_ACCEPT_CONTEXT, + (const char*)&listenSocket, + sizeof(SOCKET)); + if (result == SOCKET_ERROR) + { + const int errorCode = ::WSAGetLastError(); + throw std::system_error{ + errorCode, + std::system_category(), + "Socket accept operation failed: setsockopt(SO_UPDATE_ACCEPT_CONTEXT)" + }; + } + } +} + +#endif diff --git a/lib/socket_connect_operation.cpp b/lib/socket_connect_operation.cpp new file mode 100644 index 0000000..3e6036f --- /dev/null +++ b/lib/socket_connect_operation.cpp @@ -0,0 +1,178 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include + +#include "socket_helpers.hpp" + +#include +#include + +#if CPPCORO_OS_WINNT +# include +# include +# include +# include + +bool cppcoro::net::socket_connect_operation_impl::try_start( + cppcoro::detail::win32_overlapped_operation_base& operation) noexcept +{ + // Lookup the address of the ConnectEx function pointer for this socket. + LPFN_CONNECTEX connectExPtr; + { + GUID connectExGuid = WSAID_CONNECTEX; + DWORD byteCount = 0; + int result = ::WSAIoctl( + m_socket.native_handle(), + SIO_GET_EXTENSION_FUNCTION_POINTER, + static_cast(&connectExGuid), + sizeof(connectExGuid), + static_cast(&connectExPtr), + sizeof(connectExPtr), + &byteCount, + nullptr, + nullptr); + if (result == SOCKET_ERROR) + { + operation.m_errorCode = ::WSAGetLastError(); + return false; + } + } + + // Need to read this flag before starting the operation, otherwise + // it may be possible that the operation will complete immediately + // on another thread and then destroy the socket before we get a + // chance to read it. + const bool skipCompletionOnSuccess = m_socket.skip_completion_on_success(); + + SOCKADDR_STORAGE remoteSockaddrStorage; + const int sockaddrNameLength = cppcoro::net::detail::ip_endpoint_to_sockaddr( + m_remoteEndPoint, + std::ref(remoteSockaddrStorage)); + + DWORD bytesSent = 0; + const BOOL ok = connectExPtr( + m_socket.native_handle(), + reinterpret_cast(&remoteSockaddrStorage), + sockaddrNameLength, + nullptr, // send buffer + 0, // size of send buffer + &bytesSent, + operation.get_overlapped()); + if (!ok) + { + const int errorCode = ::WSAGetLastError(); + if (errorCode != ERROR_IO_PENDING) + { + // Failed synchronously. + operation.m_errorCode = static_cast(errorCode); + return false; + } + } + else if (skipCompletionOnSuccess) + { + // Successfully completed synchronously and no completion event + // will be posted to an I/O thread so we can return without suspending. + operation.m_errorCode = ERROR_SUCCESS; + return false; + } + + return true; +} + +void cppcoro::net::socket_connect_operation_impl::cancel( + cppcoro::detail::win32_overlapped_operation_base& operation) noexcept +{ + (void)::CancelIoEx( + reinterpret_cast(m_socket.native_handle()), + operation.get_overlapped()); +} + +void cppcoro::net::socket_connect_operation_impl::get_result( + cppcoro::detail::win32_overlapped_operation_base& operation) +{ + if (operation.m_errorCode != ERROR_SUCCESS) + { + if (operation.m_errorCode == ERROR_OPERATION_ABORTED) + { + throw operation_cancelled{}; + } + + throw std::system_error{ + static_cast(operation.m_errorCode), + std::system_category(), + "Connect operation failed: ConnectEx" + }; + } + + // We need to call setsockopt() to update the socket state with information + // about the connection now that it has been successfully connected. + { + const int result = ::setsockopt( + m_socket.native_handle(), + SOL_SOCKET, + SO_UPDATE_CONNECT_CONTEXT, + nullptr, + 0); + if (result == SOCKET_ERROR) + { + // This shouldn't fail, but just in case it does we fall back to + // setting the remote address as specified in the call to Connect(). + // + // Don't really want to throw an exception here since the connection + // has actually been established. + m_socket.m_remoteEndPoint = m_remoteEndPoint; + return; + } + } + + { + SOCKADDR_STORAGE localSockaddr; + int nameLength = sizeof(localSockaddr); + const int result = ::getsockname( + m_socket.native_handle(), + reinterpret_cast(&localSockaddr), + &nameLength); + if (result == 0) + { + m_socket.m_localEndPoint = cppcoro::net::detail::sockaddr_to_ip_endpoint( + *reinterpret_cast(&localSockaddr)); + } + else + { + // Failed to get the updated local-end-point + // Just leave m_localEndPoint set to whatever bind() left it as. + // + // TODO: Should we be throwing an exception here instead? + } + } + + { + SOCKADDR_STORAGE remoteSockaddr; + int nameLength = sizeof(remoteSockaddr); + const int result = ::getpeername( + m_socket.native_handle(), + reinterpret_cast(&remoteSockaddr), + &nameLength); + if (result == 0) + { + m_socket.m_remoteEndPoint = cppcoro::net::detail::sockaddr_to_ip_endpoint( + *reinterpret_cast(&remoteSockaddr)); + } + else + { + // Failed to get the actual remote end-point so just fall back to + // remembering the actual end-point that was passed to connect(). + // + // TODO: Should we be throwing an exception here instead? + m_socket.m_remoteEndPoint = m_remoteEndPoint; + } + } +} + +#endif diff --git a/lib/socket_disconnect_operation.cpp b/lib/socket_disconnect_operation.cpp new file mode 100644 index 0000000..fc87481 --- /dev/null +++ b/lib/socket_disconnect_operation.cpp @@ -0,0 +1,107 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "socket_helpers.hpp" + +#include + +#if CPPCORO_OS_WINNT +# include +# include +# include +# include + +bool cppcoro::net::socket_disconnect_operation_impl::try_start( + cppcoro::detail::win32_overlapped_operation_base& operation) noexcept +{ + // Lookup the address of the DisconnectEx function pointer for this socket. + LPFN_DISCONNECTEX disconnectExPtr; + { + GUID disconnectExGuid = WSAID_DISCONNECTEX; + DWORD byteCount = 0; + const int result = ::WSAIoctl( + m_socket.native_handle(), + SIO_GET_EXTENSION_FUNCTION_POINTER, + static_cast(&disconnectExGuid), + sizeof(disconnectExGuid), + static_cast(&disconnectExPtr), + sizeof(disconnectExPtr), + &byteCount, + nullptr, + nullptr); + if (result == SOCKET_ERROR) + { + operation.m_errorCode = static_cast(::WSAGetLastError()); + return false; + } + } + + // Need to read this flag before starting the operation, otherwise + // it may be possible that the operation will complete immediately + // on another thread and then destroy the socket before we get a + // chance to read it. + const bool skipCompletionOnSuccess = m_socket.skip_completion_on_success(); + + // Need to add TF_REUSE_SOCKET to these flags if we want to allow reusing + // a socket for subsequent connections once the disconnect operation + // completes. + const DWORD flags = 0; + + const BOOL ok = disconnectExPtr( + m_socket.native_handle(), + operation.get_overlapped(), + flags, + 0); + if (!ok) + { + const int errorCode = ::WSAGetLastError(); + if (errorCode != ERROR_IO_PENDING) + { + // Failed synchronously. + operation.m_errorCode = static_cast(errorCode); + return false; + } + } + else if (skipCompletionOnSuccess) + { + // Successfully completed synchronously and no completion event + // will be posted to an I/O thread so we can return without suspending. + operation.m_errorCode = ERROR_SUCCESS; + return false; + } + + return true; +} + +void cppcoro::net::socket_disconnect_operation_impl::cancel( + cppcoro::detail::win32_overlapped_operation_base& operation) noexcept +{ + (void)::CancelIoEx( + reinterpret_cast(m_socket.native_handle()), + operation.get_overlapped()); +} + +void cppcoro::net::socket_disconnect_operation_impl::get_result( + cppcoro::detail::win32_overlapped_operation_base& operation) +{ + if (operation.m_errorCode != ERROR_SUCCESS) + { + if (operation.m_errorCode == ERROR_OPERATION_ABORTED) + { + throw operation_cancelled{}; + } + + throw std::system_error{ + static_cast(operation.m_errorCode), + std::system_category(), + "Disconnect operation failed: DisconnectEx" + }; + } +} + +#endif diff --git a/lib/socket_helpers.cpp b/lib/socket_helpers.cpp new file mode 100644 index 0000000..f00bc09 --- /dev/null +++ b/lib/socket_helpers.cpp @@ -0,0 +1,85 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include "socket_helpers.hpp" + +#include + +#if CPPCORO_OS_WINNT +#include +#include + +#include +#include +#include +#include + + +cppcoro::net::ip_endpoint +cppcoro::net::detail::sockaddr_to_ip_endpoint(const sockaddr& address) noexcept +{ + if (address.sa_family == AF_INET) + { + SOCKADDR_IN ipv4Address; + std::memcpy(&ipv4Address, &address, sizeof(ipv4Address)); + + std::uint8_t addressBytes[4]; + std::memcpy(addressBytes, &ipv4Address.sin_addr, 4); + + return ipv4_endpoint{ + ipv4_address{ addressBytes }, + ntohs(ipv4Address.sin_port) + }; + } + else + { + assert(address.sa_family == AF_INET6); + + SOCKADDR_IN6 ipv6Address; + std::memcpy(&ipv6Address, &address, sizeof(ipv6Address)); + + return ipv6_endpoint{ + ipv6_address{ ipv6Address.sin6_addr.u.Byte }, + ntohs(ipv6Address.sin6_port) + }; + } +} + +int cppcoro::net::detail::ip_endpoint_to_sockaddr( + const ip_endpoint& endPoint, + std::reference_wrapper address) noexcept +{ + if (endPoint.is_ipv4()) + { + const auto& ipv4EndPoint = endPoint.to_ipv4(); + + SOCKADDR_IN ipv4Address; + ipv4Address.sin_family = AF_INET; + std::memcpy(&ipv4Address.sin_addr, ipv4EndPoint.address().bytes(), 4); + ipv4Address.sin_port = htons(ipv4EndPoint.port()); + std::memset(&ipv4Address.sin_zero, 0, sizeof(ipv4Address.sin_zero)); + + std::memcpy(&address.get(), &ipv4Address, sizeof(ipv4Address)); + + return sizeof(SOCKADDR_IN); + } + else + { + const auto& ipv6EndPoint = endPoint.to_ipv6(); + + SOCKADDR_IN6 ipv6Address; + ipv6Address.sin6_family = AF_INET6; + std::memcpy(&ipv6Address.sin6_addr, ipv6EndPoint.address().bytes(), 16); + ipv6Address.sin6_port = htons(ipv6EndPoint.port()); + ipv6Address.sin6_flowinfo = 0; + ipv6Address.sin6_scope_struct = SCOPEID_UNSPECIFIED_INIT; + + std::memcpy(&address.get(), &ipv6Address, sizeof(ipv6Address)); + + return sizeof(SOCKADDR_IN6); + } +} + +#endif // CPPCORO_OS_WINNT diff --git a/lib/socket_helpers.hpp b/lib/socket_helpers.hpp new file mode 100644 index 0000000..2083f3a --- /dev/null +++ b/lib/socket_helpers.hpp @@ -0,0 +1,47 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_PRIVATE_SOCKET_HELPERS_HPP_INCLUDED +#define CPPCORO_PRIVATE_SOCKET_HELPERS_HPP_INCLUDED + +#include + +#if CPPCORO_OS_WINNT +# include +struct sockaddr; +struct sockaddr_storage; +#endif + +namespace cppcoro +{ + namespace net + { + class ip_endpoint; + + namespace detail + { +#if CPPCORO_OS_WINNT + /// Convert a sockaddr to an IP endpoint. + ip_endpoint sockaddr_to_ip_endpoint(const sockaddr& address) noexcept; + + /// Converts an ip_endpoint to a sockaddr structure. + /// + /// \param endPoint + /// The IP endpoint to convert to a sockaddr structure. + /// + /// \param address + /// The sockaddr structure to populate. + /// + /// \return + /// The length of the sockaddr structure that was populated. + int ip_endpoint_to_sockaddr( + const ip_endpoint& endPoint, + std::reference_wrapper address) noexcept; + +#endif + } + } +} + +#endif diff --git a/lib/socket_recv_from_operation.cpp b/lib/socket_recv_from_operation.cpp new file mode 100644 index 0000000..8e994ec --- /dev/null +++ b/lib/socket_recv_from_operation.cpp @@ -0,0 +1,96 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#if CPPCORO_OS_WINNT +# include "socket_helpers.hpp" + +# include +# include +# include +# include + +bool cppcoro::net::socket_recv_from_operation_impl::try_start( + cppcoro::detail::win32_overlapped_operation_base& operation) noexcept +{ + static_assert( + sizeof(m_sourceSockaddrStorage) >= sizeof(SOCKADDR_IN) && + sizeof(m_sourceSockaddrStorage) >= sizeof(SOCKADDR_IN6)); + static_assert( + sockaddrStorageAlignment >= alignof(SOCKADDR_IN) && + sockaddrStorageAlignment >= alignof(SOCKADDR_IN6)); + + // Need to read this flag before starting the operation, otherwise + // it may be possible that the operation will complete immediately + // on another thread, resume the coroutine and then destroy the + // socket before we get a chance to read it. + const bool skipCompletionOnSuccess = m_socket.skip_completion_on_success(); + + m_sourceSockaddrLength = sizeof(m_sourceSockaddrStorage); + + DWORD numberOfBytesReceived = 0; + DWORD flags = 0; + int result = ::WSARecvFrom( + m_socket.native_handle(), + reinterpret_cast(&m_buffer), + 1, // buffer count + &numberOfBytesReceived, + &flags, + reinterpret_cast(&m_sourceSockaddrStorage), + &m_sourceSockaddrLength, + operation.get_overlapped(), + nullptr); + if (result == SOCKET_ERROR) + { + int errorCode = ::WSAGetLastError(); + if (errorCode != WSA_IO_PENDING) + { + // Failed synchronously. + operation.m_errorCode = static_cast(errorCode); + operation.m_numberOfBytesTransferred = numberOfBytesReceived; + return false; + } + } + else if (skipCompletionOnSuccess) + { + // Completed synchronously, no completion event will be posted to the IOCP. + operation.m_errorCode = ERROR_SUCCESS; + operation.m_numberOfBytesTransferred = numberOfBytesReceived; + return false; + } + + // Operation will complete asynchronously. + return true; +} + +void cppcoro::net::socket_recv_from_operation_impl::cancel( + cppcoro::detail::win32_overlapped_operation_base& operation) noexcept +{ + (void)::CancelIoEx( + reinterpret_cast(m_socket.native_handle()), + operation.get_overlapped()); +} + +std::tuple +cppcoro::net::socket_recv_from_operation_impl::get_result( + cppcoro::detail::win32_overlapped_operation_base& operation) +{ + if (operation.m_errorCode != ERROR_SUCCESS) + { + throw std::system_error( + static_cast(operation.m_errorCode), + std::system_category(), + "Error receiving message on socket: WSARecvFrom"); + } + + return std::make_tuple( + static_cast(operation.m_numberOfBytesTransferred), + detail::sockaddr_to_ip_endpoint( + *reinterpret_cast(&m_sourceSockaddrStorage))); +} + +#endif diff --git a/lib/socket_recv_operation.cpp b/lib/socket_recv_operation.cpp new file mode 100644 index 0000000..9930e9b --- /dev/null +++ b/lib/socket_recv_operation.cpp @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#if CPPCORO_OS_WINNT +# include +# include +# include +# include + +bool cppcoro::net::socket_recv_operation_impl::try_start( + cppcoro::detail::win32_overlapped_operation_base& operation) noexcept +{ + // Need to read this flag before starting the operation, otherwise + // it may be possible that the operation will complete immediately + // on another thread and then destroy the socket before we get a + // chance to read it. + const bool skipCompletionOnSuccess = m_socket.skip_completion_on_success(); + + DWORD numberOfBytesReceived = 0; + DWORD flags = 0; + int result = ::WSARecv( + m_socket.native_handle(), + reinterpret_cast(&m_buffer), + 1, // buffer count + &numberOfBytesReceived, + &flags, + operation.get_overlapped(), + nullptr); + if (result == SOCKET_ERROR) + { + int errorCode = ::WSAGetLastError(); + if (errorCode != WSA_IO_PENDING) + { + // Failed synchronously. + operation.m_errorCode = static_cast(errorCode); + operation.m_numberOfBytesTransferred = numberOfBytesReceived; + return false; + } + } + else if (skipCompletionOnSuccess) + { + // Completed synchronously, no completion event will be posted to the IOCP. + operation.m_errorCode = ERROR_SUCCESS; + operation.m_numberOfBytesTransferred = numberOfBytesReceived; + return false; + } + + // Operation will complete asynchronously. + return true; +} + + +void cppcoro::net::socket_recv_operation_impl::cancel( + cppcoro::detail::win32_overlapped_operation_base& operation) noexcept +{ + (void)::CancelIoEx( + reinterpret_cast(m_socket.native_handle()), + operation.get_overlapped()); +} + +#endif diff --git a/lib/socket_send_operation.cpp b/lib/socket_send_operation.cpp new file mode 100644 index 0000000..e5217e1 --- /dev/null +++ b/lib/socket_send_operation.cpp @@ -0,0 +1,64 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#if CPPCORO_OS_WINNT +# include +# include +# include +# include + +bool cppcoro::net::socket_send_operation_impl::try_start( + cppcoro::detail::win32_overlapped_operation_base& operation) noexcept +{ + // Need to read this flag before starting the operation, otherwise + // it may be possible that the operation will complete immediately + // on another thread and then destroy the socket before we get a + // chance to read it. + const bool skipCompletionOnSuccess = m_socket.skip_completion_on_success(); + + DWORD numberOfBytesSent = 0; + int result = ::WSASend( + m_socket.native_handle(), + reinterpret_cast(&m_buffer), + 1, // buffer count + &numberOfBytesSent, + 0, // flags + operation.get_overlapped(), + nullptr); + if (result == SOCKET_ERROR) + { + int errorCode = ::WSAGetLastError(); + if (errorCode != WSA_IO_PENDING) + { + // Failed synchronously. + operation.m_errorCode = static_cast(errorCode); + operation.m_numberOfBytesTransferred = numberOfBytesSent; + return false; + } + } + else if (skipCompletionOnSuccess) + { + // Completed synchronously, no completion event will be posted to the IOCP. + operation.m_errorCode = ERROR_SUCCESS; + operation.m_numberOfBytesTransferred = numberOfBytesSent; + return false; + } + + // Operation will complete asynchronously. + return true; +} + +void cppcoro::net::socket_send_operation_impl::cancel( + cppcoro::detail::win32_overlapped_operation_base& operation) noexcept +{ + (void)::CancelIoEx( + reinterpret_cast(m_socket.native_handle()), + operation.get_overlapped()); +} + +#endif diff --git a/lib/socket_send_to_operation.cpp b/lib/socket_send_to_operation.cpp new file mode 100644 index 0000000..80db248 --- /dev/null +++ b/lib/socket_send_to_operation.cpp @@ -0,0 +1,72 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#if CPPCORO_OS_WINNT +# include "socket_helpers.hpp" + +# include +# include +# include +# include + +bool cppcoro::net::socket_send_to_operation_impl::try_start( + cppcoro::detail::win32_overlapped_operation_base& operation) noexcept +{ + // Need to read this flag before starting the operation, otherwise + // it may be possible that the operation will complete immediately + // on another thread and then destroy the socket before we get a + // chance to read it. + const bool skipCompletionOnSuccess = m_socket.skip_completion_on_success(); + + SOCKADDR_STORAGE destinationAddress; + const int destinationLength = detail::ip_endpoint_to_sockaddr( + m_destination, std::ref(destinationAddress)); + + DWORD numberOfBytesSent = 0; + int result = ::WSASendTo( + m_socket.native_handle(), + reinterpret_cast(&m_buffer), + 1, // buffer count + &numberOfBytesSent, + 0, // flags + reinterpret_cast(&destinationAddress), + destinationLength, + operation.get_overlapped(), + nullptr); + if (result == SOCKET_ERROR) + { + int errorCode = ::WSAGetLastError(); + if (errorCode != WSA_IO_PENDING) + { + // Failed synchronously. + operation.m_errorCode = static_cast(errorCode); + operation.m_numberOfBytesTransferred = numberOfBytesSent; + return false; + } + } + else if (skipCompletionOnSuccess) + { + // Completed synchronously, no completion event will be posted to the IOCP. + operation.m_errorCode = ERROR_SUCCESS; + operation.m_numberOfBytesTransferred = numberOfBytesSent; + return false; + } + + // Operation will complete asynchronously. + return true; +} + +void cppcoro::net::socket_send_to_operation_impl::cancel( + cppcoro::detail::win32_overlapped_operation_base& operation) noexcept +{ + (void)::CancelIoEx( + reinterpret_cast(m_socket.native_handle()), + operation.get_overlapped()); +} + +#endif diff --git a/lib/spin_mutex.cpp b/lib/spin_mutex.cpp new file mode 100644 index 0000000..da0594f --- /dev/null +++ b/lib/spin_mutex.cpp @@ -0,0 +1,37 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include "spin_mutex.hpp" +#include "spin_wait.hpp" + +namespace cppcoro +{ + spin_mutex::spin_mutex() noexcept + : m_isLocked(false) + { + } + + bool spin_mutex::try_lock() noexcept + { + return !m_isLocked.exchange(true, std::memory_order_acquire); + } + + void spin_mutex::lock() noexcept + { + spin_wait wait; + while (!try_lock()) + { + while (m_isLocked.load(std::memory_order_relaxed)) + { + wait.spin_one(); + } + } + } + + void spin_mutex::unlock() noexcept + { + m_isLocked.store(false, std::memory_order_release); + } +} diff --git a/lib/spin_mutex.hpp b/lib/spin_mutex.hpp new file mode 100644 index 0000000..c2a285e --- /dev/null +++ b/lib/spin_mutex.hpp @@ -0,0 +1,47 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_SPIN_MUTEX_HPP_INCLUDED +#define CPPCORO_SPIN_MUTEX_HPP_INCLUDED + +#include + +namespace cppcoro +{ + class spin_mutex + { + public: + + /// Initialise the mutex to the unlocked state. + spin_mutex() noexcept; + + /// Attempt to lock the mutex without blocking + /// + /// \return + /// true if the lock was acquired, false if the lock was already held + /// and could not be immediately acquired. + bool try_lock() noexcept; + + /// Block the current thread until the lock is acquired. + /// + /// This will busy-wait until it acquires the lock. + /// + /// This has 'acquire' memory semantics and synchronises + /// with prior calls to unlock(). + void lock() noexcept; + + /// Release the lock. + /// + /// This has 'release' memory semantics and synchronises with + /// lock() and try_lock(). + void unlock() noexcept; + + private: + + std::atomic m_isLocked; + + }; +} + +#endif diff --git a/lib/spin_wait.cpp b/lib/spin_wait.cpp new file mode 100644 index 0000000..70226e2 --- /dev/null +++ b/lib/spin_wait.cpp @@ -0,0 +1,101 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include "spin_wait.hpp" + +#include +#include + +#if CPPCORO_OS_WINNT +# define WIN32_LEAN_AND_MEAN +# include +#endif + +namespace +{ + namespace local + { + constexpr std::uint32_t yield_threshold = 10; + } +} + +namespace cppcoro +{ + spin_wait::spin_wait() noexcept + { + reset(); + } + + bool spin_wait::next_spin_will_yield() const noexcept + { + return m_count >= local::yield_threshold; + } + + void spin_wait::reset() noexcept + { + static const std::uint32_t initialCount = + std::thread::hardware_concurrency() > 1 ? 0 : local::yield_threshold; + m_count = initialCount; + } + + void spin_wait::spin_one() noexcept + { +#if CPPCORO_OS_WINNT + // Spin strategy taken from .NET System.SpinWait class. + // I assume the Microsoft developers knew what they're doing. + if (!next_spin_will_yield()) + { + // CPU-level pause + // Allow other hyper-threads to run while we busy-wait. + + // Make each busy-spin exponentially longer + const std::uint32_t loopCount = 2u << m_count; + for (std::uint32_t i = 0; i < loopCount; ++i) + { + ::YieldProcessor(); + ::YieldProcessor(); + } + } + else + { + // We've already spun a number of iterations. + // + const auto yieldCount = m_count - local::yield_threshold; + if (yieldCount % 20 == 19) + { + // Yield remainder of time slice to another thread and + // don't schedule this thread for a little while. + ::SleepEx(1, FALSE); + } + else if (yieldCount % 5 == 4) + { + // Yield remainder of time slice to another thread + // that is ready to run (possibly from another processor?). + ::SleepEx(0, FALSE); + } + else + { + // Yield to another thread that is ready to run on the + // current processor. + ::SwitchToThread(); + } + } +#else + if (next_spin_will_yield()) + { + std::this_thread::yield(); + } +#endif + + ++m_count; + if (m_count == 0) + { + // Don't wrap around to zero as this would go back to + // busy-waiting. + m_count = local::yield_threshold; + } + } +} + diff --git a/lib/spin_wait.hpp b/lib/spin_wait.hpp new file mode 100644 index 0000000..c202d2c --- /dev/null +++ b/lib/spin_wait.hpp @@ -0,0 +1,31 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// +#ifndef CPPCORO_SPIN_WAIT_HPP_INCLUDED +#define CPPCORO_SPIN_WAIT_HPP_INCLUDED + +#include + +namespace cppcoro +{ + class spin_wait + { + public: + + spin_wait() noexcept; + + bool next_spin_will_yield() const noexcept; + + void spin_one() noexcept; + + void reset() noexcept; + + private: + + std::uint32_t m_count; + + }; +} + +#endif diff --git a/lib/static_thread_pool.cpp b/lib/static_thread_pool.cpp new file mode 100644 index 0000000..4b919a5 --- /dev/null +++ b/lib/static_thread_pool.cpp @@ -0,0 +1,754 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include + +#include "auto_reset_event.hpp" +#include "spin_mutex.hpp" +#include "spin_wait.hpp" + +#include +#include +#include +#include + +namespace +{ + namespace local + { + // Keep each thread's local queue under 1MB + constexpr std::size_t max_local_queue_size = 1024 * 1024 / sizeof(void*); + constexpr std::size_t initial_local_queue_size = 256; + } +} + +namespace cppcoro +{ + thread_local static_thread_pool::thread_state* static_thread_pool::s_currentState = nullptr; + thread_local static_thread_pool* static_thread_pool::s_currentThreadPool = nullptr; + + class static_thread_pool::thread_state + { + public: + + explicit thread_state() + : m_localQueue( + std::make_unique[]>( + local::initial_local_queue_size)) + , m_mask(local::initial_local_queue_size - 1) + , m_head(0) + , m_tail(0) + , m_isSleeping(false) + { + } + + bool try_wake_up() + { + if (m_isSleeping.load(std::memory_order_seq_cst)) + { + if (m_isSleeping.exchange(false, std::memory_order_seq_cst)) + { + try + { + m_wakeUpEvent.set(); + } + catch (...) + { + // TODO: What do we do here? + } + return true; + } + } + + return false; + } + + void notify_intent_to_sleep() noexcept + { + m_isSleeping.store(true, std::memory_order_relaxed); + } + + void sleep_until_woken() noexcept + { + try + { + m_wakeUpEvent.wait(); + } + catch (...) + { + using namespace std::chrono_literals; + std::this_thread::sleep_for(1ms); + } + } + + bool approx_has_any_queued_work() const noexcept + { + return difference( + m_head.load(std::memory_order_relaxed), + m_tail.load(std::memory_order_relaxed)) > 0; + } + + bool has_any_queued_work() noexcept + { + std::scoped_lock lock{ m_remoteMutex }; + auto tail = m_tail.load(std::memory_order_relaxed); + auto head = m_head.load(std::memory_order_seq_cst); + return difference(head, tail) > 0; + } + + bool try_local_enqueue(schedule_operation*& operation) noexcept + { + // Head is only ever written-to by the current thread so we + // are safe to use relaxed memory order when reading it. + auto head = m_head.load(std::memory_order_relaxed); + + // It is possible this method may be running concurrently with + // try_remote_steal() which may have just speculatively incremented m_tail + // trying to steal the last item in the queue but has not yet read the + // queue item. So we need to make sure we don't write to the last available + // space (at slot m_tail - 1) as this may still contain a pointer to an + // operation that has not yet been executed. + // + // Note that it's ok to read stale values from m_tail since new values + // won't ever decrease the number of available slots by more than 1. + // Reading a stale value can just mean that sometimes the queue appears + // empty when it may actually have slots free. + // + // Here m_mask is equal to buffersize - 1 so we can only write to a slot + // if the number of items consumed in the queue (head - tail) is less than + // the mask. + auto tail = m_tail.load(std::memory_order_relaxed); + if (difference(head, tail) < static_cast(m_mask)) + { + // There is space left in the local buffer. + m_localQueue[head & m_mask].store(operation, std::memory_order_relaxed); + m_head.store(head + 1, std::memory_order_seq_cst); + return true; + } + + if (m_mask == local::max_local_queue_size) + { + // No space in the buffer and we don't want to grow + // it any further. + return false; + } + + // Allocate the new buffer before taking out the lock so that + // we ensure we hold the lock for as short a time as possible. + const size_t newSize = (m_mask + 1) * 2; + + std::unique_ptr[]> newLocalQueue{ + new (std::nothrow) std::atomic[newSize] + }; + if (!newLocalQueue) + { + // Unable to allocate more memory. + return false; + } + + if (!m_remoteMutex.try_lock()) + { + // Don't wait to acquire the lock if we can't get it immediately. + // Fail and let it be enqueued to the global queue. + // TODO: Should we have a per-thread overflow queue instead? + return false; + } + + std::scoped_lock lock{ std::adopt_lock, m_remoteMutex }; + + // We can now re-read tail, guaranteed that we are not seeing a stale version. + tail = m_tail.load(std::memory_order_relaxed); + + // Copy the existing operations. + const size_t newMask = newSize - 1; + for (size_t i = tail; i != head; ++i) + { + newLocalQueue[i & newMask].store( + m_localQueue[i & m_mask].load(std::memory_order_relaxed), + std::memory_order_relaxed); + } + + // Finally, write the new operation to the queue. + newLocalQueue[head & newMask].store(operation, std::memory_order_relaxed); + + m_head.store(head + 1, std::memory_order_relaxed); + m_localQueue = std::move(newLocalQueue); + m_mask = newMask; + return true; + } + + schedule_operation* try_local_pop() noexcept + { + // Cheap, approximate, no memory-barrier check for emptiness + auto head = m_head.load(std::memory_order_relaxed); + auto tail = m_tail.load(std::memory_order_relaxed); + if (difference(head, tail) <= 0) + { + // Empty + return nullptr; + } + + // 3 classes of interleaving of try_local_pop() and try_remote_steal() + // - local pop completes before remote steal (easy) + // - remote steal completes before local pop (easy) + // - both are executed concurrently, both see each other's writes (harder) + + // Speculatively try to acquire the head item of the work queue by + // decrementing the head cursor. This may race with a concurrent call + // to try_remote_steal() that is also trying to speculatively increment + // the tail cursor to steal from the other end of the queue. In the case + // that they both try to dequeue the last/only item in the queue then we + // need to fall back to locking to decide who wins + + auto newHead = head - 1; + m_head.store(newHead, std::memory_order_seq_cst); + + tail = m_tail.load(std::memory_order_seq_cst); + + if (difference(newHead, tail) < 0) + { + // There was a race to get the last item. + // We don't know whether the remote steal saw our write + // and decided to back off or not, so we acquire the mutex + // so that we wait until the remote steal has completed so + // we can see what decision it made. + std::lock_guard lock{ m_remoteMutex }; + + // Use relaxed since the lock guarantees visibility of the writes + // that the remote steal thread performed. + tail = m_tail.load(std::memory_order_relaxed); + + if (difference(newHead, tail) < 0) + { + // The other thread didn't see our write and stole the last item. + // We need to restore the head back to it's old value. + // We hold the mutex so can just use relaxed memory order for this. + m_head.store(head, std::memory_order_relaxed); + return nullptr; + } + } + + // We successfully acquired an item from the queue. + return m_localQueue[newHead & m_mask].load(std::memory_order_relaxed); + } + + schedule_operation* try_steal(bool* lockUnavailable = nullptr) noexcept + { + if (lockUnavailable == nullptr) + { + m_remoteMutex.lock(); + } + else if (!m_remoteMutex.try_lock()) + { + *lockUnavailable = true; + return nullptr; + } + + std::scoped_lock lock{ std::adopt_lock, m_remoteMutex }; + + auto tail = m_tail.load(std::memory_order_relaxed); + auto head = m_head.load(std::memory_order_seq_cst); + if (difference(head, tail) <= 0) + { + return nullptr; + } + + // It looks like there are items in the queue. + // We'll speculatively try to steal one by incrementing + // the tail cursor. As this may be running concurrently + // with try_local_pop() which is also speculatively trying + // to remove an item from the other end of the queue we + // need to re-read the 'head' cursor afterwards to see + // if there was a potential race to dequeue the last item. + // Use seq_cst memory order both here and in try_local_pop() + // to ensure that either we will see their write to head or + // they will see our write to tail or we will both see each + // other's writes. + m_tail.store(tail + 1, std::memory_order_seq_cst); + head = m_head.load(std::memory_order_seq_cst); + + if (difference(head, tail) > 0) + { + // There was still an item in the queue after incrementing tail. + // We managed to steal an item from the bottom of the stack. + return m_localQueue[tail & m_mask].load(std::memory_order_relaxed); + } + else + { + // Otherwise we failed to steal the last item. + // Restore the old tail position. + m_tail.store(tail, std::memory_order_seq_cst); + return nullptr; + } + } + + private: + + using offset_t = std::make_signed_t; + + static constexpr offset_t difference(size_t a, size_t b) + { + return static_cast(a - b); + } + + std::unique_ptr[]> m_localQueue; + std::size_t m_mask; + +#if CPPCORO_COMPILER_MSVC +# pragma warning(push) +# pragma warning(disable : 4324) +#endif + + //alignas(std::hardware_destructive_interference_size) + std::atomic m_head; + + //alignas(std::hardware_destructive_interference_size) + std::atomic m_tail; + + //alignas(std::hardware_destructive_interference_size) + std::atomic m_isSleeping; + spin_mutex m_remoteMutex; + +#if CPPCORO_COMPILER_MSVC +# pragma warning(pop) +#endif + + auto_reset_event m_wakeUpEvent; + + }; + + void static_thread_pool::schedule_operation::await_suspend( + cppcoro::coroutine_handle<> awaitingCoroutine) noexcept + { + m_awaitingCoroutine = awaitingCoroutine; + m_threadPool->schedule_impl(this); + } + + static_thread_pool::static_thread_pool() + : static_thread_pool(std::thread::hardware_concurrency()) + { + } + + static_thread_pool::static_thread_pool(std::uint32_t threadCount) + : m_threadCount(threadCount > 0 ? threadCount : 1) + , m_threadStates(std::make_unique(m_threadCount)) + , m_stopRequested(false) + , m_globalQueueHead(nullptr) + , m_globalQueueTail(nullptr) + , m_sleepingThreadCount(0) + { + m_threads.reserve(threadCount); + try + { + for (std::uint32_t i = 0; i < m_threadCount; ++i) + { + m_threads.emplace_back([this, i] { this->run_worker_thread(i); }); + } + } + catch (...) + { + try + { + shutdown(); + } + catch (...) + { + std::terminate(); + } + + throw; + } + } + + static_thread_pool::~static_thread_pool() + { + shutdown(); + } + + void static_thread_pool::run_worker_thread(std::uint32_t threadIndex) noexcept + { + auto& localState = m_threadStates[threadIndex]; + s_currentState = &localState; + s_currentThreadPool = this; + + auto tryGetRemote = [&]() + { + // Try to get some new work first from the global queue + // then if that queue is empty then try to steal from + // the local queues of other worker threads. + // We try to get new work from the global queue first + // before stealing as stealing from other threads has + // the side-effect of those threads running out of work + // sooner and then having to steal work which increases + // contention. + auto* op = try_global_dequeue(); + if (op == nullptr) + { + op = try_steal_from_other_thread(threadIndex); + } + return op; + }; + + while (true) + { + // Process operations from the local queue. + schedule_operation* op; + + while (true) + { + op = localState.try_local_pop(); + if (op == nullptr) + { + op = tryGetRemote(); + if (op == nullptr) + { + break; + } + } + + op->m_awaitingCoroutine.resume(); + } + + // No more operations in the local queue or remote queue. + // + // We spin for a little while waiting for new items + // to be enqueued. This avoids the expensive operation + // of putting the thread to sleep and waking it up again + // in the case that an external thread is queueing new work + + cppcoro::spin_wait spinWait; + while (true) + { + for (int i = 0; i < 30; ++i) + { + if (is_shutdown_requested()) + { + return; + } + + spinWait.spin_one(); + + if (approx_has_any_queued_work_for(threadIndex)) + { + op = tryGetRemote(); + if (op != nullptr) + { + // Now that we've executed some work we can + // return to normal processing since this work + // might have queued some more work to the local + // queue which we should process first. + goto normal_processing; + } + } + } + + // We didn't find any work after spinning for a while, let's + // put ourselves to sleep and wait to be woken up. + + // First, let other threads know we're going to sleep. + notify_intent_to_sleep(threadIndex); + + // As notifying the other threads that we're sleeping may have + // raced with other threads enqueueing more work, we need to + // re-check whether there is any more work to be done so that + // we don't get into a situation where we go to sleep and another + // thread has enqueued some work and doesn't know to wake us up. + + if (has_any_queued_work_for(threadIndex)) + { + op = tryGetRemote(); + if (op != nullptr) + { + // Try to clear the intent to sleep so that some other thread + // that subsequently enqueues some work won't mistakenly try + // to wake this threadup when we are already running as there + // might have been some other thread that it could have woken + // up instead which could have resulted in increased parallelism. + // + // However, it's possible that some other thread may have already + // tried to wake us up, in which case the auto_reset_event used to + // wake up this thread may already be in the 'set' state. Leaving + // it in this state won't really hurt. It'll just mean we might get + // a spurious wake-up next time we try to go to sleep. + try_clear_intent_to_sleep(threadIndex); + + goto normal_processing; + } + } + + if (is_shutdown_requested()) + { + return; + } + + localState.sleep_until_woken(); + } + + normal_processing: + assert(op != nullptr); + op->m_awaitingCoroutine.resume(); + } + } + + void static_thread_pool::shutdown() + { + m_stopRequested.store(true, std::memory_order_relaxed); + + for (std::uint32_t i = 0; i < m_threads.size(); ++i) + { + auto& threadState = m_threadStates[i]; + + // We should not be shutting down the thread pool if there is any + // outstanding work in the queue. It is up to the application to + // ensure all enqueued work has completed first. + assert(!threadState.has_any_queued_work()); + + threadState.try_wake_up(); + } + + for (auto& t : m_threads) + { + t.join(); + } + } + + void static_thread_pool::schedule_impl(schedule_operation* operation) noexcept + { + if (s_currentThreadPool != this || + !s_currentState->try_local_enqueue(operation)) + { + remote_enqueue(operation); + } + + wake_one_thread(); + } + + void static_thread_pool::remote_enqueue(schedule_operation* operation) noexcept + { + auto* tail = m_globalQueueTail.load(std::memory_order_relaxed); + do + { + operation->m_next = tail; + } while (!m_globalQueueTail.compare_exchange_weak( + tail, + operation, + std::memory_order_seq_cst, + std::memory_order_relaxed)); + } + + bool static_thread_pool::has_any_queued_work_for(std::uint32_t threadIndex) noexcept + { + if (m_globalQueueTail.load(std::memory_order_seq_cst) != nullptr) + { + return true; + } + + if (m_globalQueueHead.load(std::memory_order_seq_cst) != nullptr) + { + return true; + } + + for (std::uint32_t i = 0; i < m_threadCount; ++i) + { + if (i == threadIndex) continue; + if (m_threadStates[i].has_any_queued_work()) + { + return true; + } + } + + return false; + } + + bool static_thread_pool::approx_has_any_queued_work_for(std::uint32_t threadIndex) const noexcept + { + // Cheap, approximate, read-only implementation that checks whether any work has + // been queued in the system somewhere. We try to avoid writes here so that we + // don't bounce cache-lines around between threads/cores unnecessarily when + // multiple threads are all spinning waiting for work. + + if (m_globalQueueTail.load(std::memory_order_relaxed) != nullptr) + { + return true; + } + + if (m_globalQueueHead.load(std::memory_order_relaxed) != nullptr) + { + return true; + } + + for (std::uint32_t i = 0; i < m_threadCount; ++i) + { + if (i == threadIndex) continue; + if (m_threadStates[i].approx_has_any_queued_work()) + { + return true; + } + } + + return false; + } + + bool static_thread_pool::is_shutdown_requested() const noexcept + { + return m_stopRequested.load(std::memory_order_relaxed); + } + + void static_thread_pool::notify_intent_to_sleep(std::uint32_t threadIndex) noexcept + { + // First mark the thread as asleep + m_threadStates[threadIndex].notify_intent_to_sleep(); + + // Then publish the fact that a thread is asleep by incrementing the count + // of threads that are asleep. + m_sleepingThreadCount.fetch_add(1, std::memory_order_seq_cst); + } + + void static_thread_pool::try_clear_intent_to_sleep(std::uint32_t threadIndex) noexcept + { + // First try to claim that we are waking up one of the threads. + std::uint32_t oldSleepingCount = m_sleepingThreadCount.load(std::memory_order_relaxed); + do + { + if (oldSleepingCount == 0) + { + // No more sleeping threads. + // Someone must have woken us up. + return; + } + } while (!m_sleepingThreadCount.compare_exchange_weak( + oldSleepingCount, + oldSleepingCount - 1, + std::memory_order_acquire, + std::memory_order_relaxed)); + + // Then preferentially try to wake up our thread. + // If some other thread has already requested that this thread wake up + // then we will wake up another thread - the one that should have been woken + // up by the thread that woke this thread up. + if (!m_threadStates[threadIndex].try_wake_up()) + { + for (std::uint32_t i = 0; i < m_threadCount; ++i) + { + if (i == threadIndex) continue; + if (m_threadStates[i].try_wake_up()) + { + return; + } + } + } + } + + static_thread_pool::schedule_operation* + static_thread_pool::try_global_dequeue() noexcept + { + std::scoped_lock lock{ m_globalQueueMutex }; + + auto* head = m_globalQueueHead.load(std::memory_order_relaxed); + if (head == nullptr) + { + // Use seq-cst memory order so that when we check for an item in the + // global queue after signalling an intent to sleep that either we + // will see their enqueue or they will see our signal to sleep and + // wake us up. + if (m_globalQueueTail.load(std::memory_order_seq_cst) == nullptr) + { + return nullptr; + } + + // Acquire the entire set of queued operations in a single operation. + auto* tail = m_globalQueueTail.exchange(nullptr, std::memory_order_acquire); + if (tail == nullptr) + { + return nullptr; + } + + // Reverse the list + do + { + auto* next = std::exchange(tail->m_next, head); + head = std::exchange(tail, next); + } while (tail != nullptr); + } + + m_globalQueueHead = head->m_next; + + return head; + } + + static_thread_pool::schedule_operation* + static_thread_pool::try_steal_from_other_thread(std::uint32_t thisThreadIndex) noexcept + { + // Try first with non-blocking steal attempts. + + bool anyLocksUnavailable = false; + for (std::uint32_t otherThreadIndex = 0; otherThreadIndex < m_threadCount; ++otherThreadIndex) + { + if (otherThreadIndex == thisThreadIndex) continue; + auto& otherThreadState = m_threadStates[otherThreadIndex]; + auto* op = otherThreadState.try_steal(&anyLocksUnavailable); + if (op != nullptr) + { + return op; + } + } + + if (anyLocksUnavailable) + { + // We didn't check all of the other threads for work to steal yet. + // Try again, this time waiting to acquire the locks. + for (std::uint32_t otherThreadIndex = 0; otherThreadIndex < m_threadCount; ++otherThreadIndex) + { + if (otherThreadIndex == thisThreadIndex) continue; + auto& otherThreadState = m_threadStates[otherThreadIndex]; + auto* op = otherThreadState.try_steal(); + if (op != nullptr) + { + return op; + } + } + } + + return nullptr; + } + + void static_thread_pool::wake_one_thread() noexcept + { + // First try to claim responsibility for waking up one thread. + // This first read must be seq_cst to ensure that either we have + // visibility of another thread going to sleep or they have + // visibility of our prior enqueue of an item. + std::uint32_t oldSleepingCount = m_sleepingThreadCount.load(std::memory_order_seq_cst); + do + { + if (oldSleepingCount == 0) + { + // No sleeping threads. + // Someone must have woken us up. + return; + } + } while (!m_sleepingThreadCount.compare_exchange_weak( + oldSleepingCount, + oldSleepingCount - 1, + std::memory_order_acquire, + std::memory_order_relaxed)); + + // Now that we have claimed responsibility for waking a thread up + // we need to find a sleeping thread and wake it up. We should be + // guaranteed of finding a thread to wake-up here, but not necessarily + // in a single pass due to threads potentially waking themselves up + // in try_clear_intent_to_sleep(). + while (true) + { + for (std::uint32_t i = 0; i < m_threadCount; ++i) + { + if (m_threadStates[i].try_wake_up()) + { + return; + } + } + } + } +} diff --git a/lib/use.cake b/lib/use.cake new file mode 100644 index 0000000..750331a --- /dev/null +++ b/lib/use.cake @@ -0,0 +1,20 @@ +############################################################################### +# Copyright (c) Lewis Baker +# Licenced under MIT license. See LICENSE.txt for details. +############################################################################### + +import cake.path + +from cake.tools import script, env, compiler, variant + +compiler.addIncludePath(env.expand('${CPPCORO}/include')) + +buildScript = script.get(script.cwd('build.cake')) +compiler.addLibrary(buildScript.getResult('library')) + +if variant.platform == "windows": + compiler.addLibrary("Synchronization") + compiler.addLibrary("kernel32") + compiler.addLibrary("WS2_32") + compiler.addLibrary("Mswsock") + diff --git a/lib/win32.cpp b/lib/win32.cpp new file mode 100644 index 0000000..b7b497b --- /dev/null +++ b/lib/win32.cpp @@ -0,0 +1,20 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include + +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include + +void cppcoro::detail::win32::safe_handle::close() noexcept +{ + if (m_handle != nullptr && m_handle != INVALID_HANDLE_VALUE) + { + ::CloseHandle(m_handle); + m_handle = nullptr; + } +} diff --git a/lib/writable_file.cpp b/lib/writable_file.cpp new file mode 100644 index 0000000..3ba63e7 --- /dev/null +++ b/lib/writable_file.cpp @@ -0,0 +1,75 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include + +#include + +#if CPPCORO_OS_WINNT +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include + +void cppcoro::writable_file::set_size( + std::uint64_t fileSize) +{ + LARGE_INTEGER position; + position.QuadPart = fileSize; + + BOOL ok = ::SetFilePointerEx(m_fileHandle.handle(), position, nullptr, FILE_BEGIN); + if (!ok) + { + DWORD errorCode = ::GetLastError(); + throw std::system_error + { + static_cast(errorCode), + std::system_category(), + "error setting file size: SetFilePointerEx" + }; + } + + ok = ::SetEndOfFile(m_fileHandle.handle()); + if (!ok) + { + DWORD errorCode = ::GetLastError(); + throw std::system_error + { + static_cast(errorCode), + std::system_category(), + "error setting file size: SetEndOfFile" + }; + } +} + +cppcoro::file_write_operation cppcoro::writable_file::write( + std::uint64_t offset, + const void* buffer, + std::size_t byteCount) noexcept +{ + return file_write_operation{ + m_fileHandle.handle(), + offset, + buffer, + byteCount + }; +} + +cppcoro::file_write_operation_cancellable cppcoro::writable_file::write( + std::uint64_t offset, + const void* buffer, + std::size_t byteCount, + cancellation_token ct) noexcept +{ + return file_write_operation_cancellable{ + m_fileHandle.handle(), + offset, + buffer, + byteCount, + std::move(ct) + }; +} + +#endif diff --git a/lib/write_only_file.cpp b/lib/write_only_file.cpp new file mode 100644 index 0000000..0ed46fc --- /dev/null +++ b/lib/write_only_file.cpp @@ -0,0 +1,37 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lewis Baker +// Licenced under MIT license. See LICENSE.txt for details. +/////////////////////////////////////////////////////////////////////////////// + +#include + +#if CPPCORO_OS_WINNT +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include + +cppcoro::write_only_file cppcoro::write_only_file::open( + io_service& ioService, + const cppcoro::filesystem::path& path, + file_open_mode openMode, + file_share_mode shareMode, + file_buffering_mode bufferingMode) +{ + return write_only_file(file::open( + GENERIC_WRITE, + ioService, + path, + openMode, + shareMode, + bufferingMode)); +} + +cppcoro::write_only_file::write_only_file( + detail::win32::safe_handle&& fileHandle) noexcept + : file(std::move(fileHandle)) + , writable_file(detail::win32::safe_handle{}) +{ +} + +#endif diff --git a/release/lib/vs2022/Debug/cppcoro.lib b/release/lib/vs2022/Debug/cppcoro.lib new file mode 100644 index 0000000000000000000000000000000000000000..290833fe149a20aff2f1c204213d543912f02221 GIT binary patch literal 3189190 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

boKox`M% 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�( zE2*oj#V~?aBSDMerLhV*i(v$<#)4K)>$G+6s9H-ni(v$zxm4tgkqWVFazF zg4U;3445fjxn^lc6K)&~BWN`fw0e#`wM=6T<1B^|w5}4gC|(=Yc+KK0h7q)y3tIgz zEHBYm>o|*H1TETws^!;}^A?|ycg|3Je&Q^K5wuzgTJ3&);VX^RwL5X~m~_GjTCD^v z>Oth)HH3C?7Q+Zytp%;Dh=yG>)>6)57(vS-Xi>ZIp_+yVIg4Qgt*ZsCHBsTOYOKyZ z$WQD@AdH~ZM$n>G{R36Y%UKK~XtfozXa=OQHgOii2wD+>R^TU9_Gg5h&vlvFu>L6$>?0o$z8fz_QF^r%^d;hd@ zNcnZG8m})ni(v$So;w**{w0a9#b>C~SOk>sO>!}PQX!Q}a zD8KBgmV>hxM$qajXwi5>V=d<_h7q*ro^dT+q;;#Rb&|6fM$qanXsu~}^iz!$#n&bo zM$j4{Xi?dip=uR!7Q+Zy0|l+^nfrTdtk*e|)LG zLa^vy7$FvkLM&>%`$avC6*f?2F^rJ!NrD#jxsR%`aBvpG2wFo0ts6f0!sDjslG}i?bL;&>F^ARbdoAq||BAk87+i zIg4Qg)^NtEEW0APKbuooWAz#=2Q!So8o^lAIg8qaXViGz$5{*`#4DAtYJ)|3=Og}i zTx0#gSqvj+jSSFQqH0|~M0SB;1g*3HEseF6vlvFu8YO5^yZW@M)h$NWVi-Z|8bOQ3 zEgEYrXEBVRH9A0Rk*YPsDr+%}pp_n=rLneg7Q+Zy8G;t&SBa{X7AtEpjG#3}(4zd( zSerPDVFazQf>vym9gj^@wK~ShS_~s-jT5wJETOT+au&k~TH^&Rnu8RoTC+KeVFaxS zg4V{nTd&qw8##+%n6tkiq?j1^ORgt(#7oj*A*6W%Uc0D<=v%glOp6-gD)`(Ke>9dE zWnZhnqJv=s53gmcNSveElKH3fBjMyDAyNL9Vc5^l5khT@Y=?qeNm%0$LjFR?W2%RQ z@eajxEg|H4gjg!+W9mqjUk#&K-h&YGNmlQU=a~62bIF`EiTO-^(6MO9+R5yPWCI3| zI%5aJuwTPcBneAWI-iRX(i99L#d8{K3}-QnQ0i;}T4PkLrJThug4Sd~Yi`>omujqEIg4QgExVva>+093 zT5-eWcrlEil__Ygah{u|vF_z8h7q(Jf)@3RbyTe{Ig4Qgtt>%n{FlY&HP*xtvWE;K zj3u0mwHT+VPCa{a_SZF3t$m!uFwDTHRQaAXEo3V~sH|xrgGWlz0yRWmHnN#kL!3k5 zmfoB9(T$qcTCnI~7$IIcLcAJ3JK<)H)j3UOF^rIgQy8lTPLtL~OQ-%C>uJtn7=h(t ztXiCv@yVf&G}e`)WG#jfSU0F15@PZ-H(^6F_5XC-$5{*`u%-&EFMmFkps}i6BeNMs zNR3>TMfvsd)Mhan>rT#M7(pvfWszM`tLA7~i(v#Ux5^?dD!rQ4e9mGRN#FkDGZv*f z9ryiuLqRQ;8v6E!VFXq|0IPNYi(!O#-N;xjgm}%J=FQYt zd7Q;Cf|gg%qBV#0s@4w9Vi-ZoCuq@{gT`u?A$!O$f>vRGR$Eo;R?cD=L90m6dMS6% z42{)vjI6~lg4Q%ai{@YHs@AKV#V~>v>xtFf8t>fm_XLeKa;&T+_tyFrphVE3@y|`F z)(@P;FoM=}Azp{mb5b#H9)JIs&$I97)H>V8K9-Hnof{CWEeqf zmY_AY&YNTBsai3d#V~@_ZGsl918A(xoW(FgPc)mcCc_nKJ9Zu}@N`kNhD?+_WEl1{ z=~}tp(L&ND$+KEHL|^LW2(eg_da{>hdE#}lWrh)Aak~(UEAMi>p|K`kFS8g%NU=Kv zt#?{oH9Jj>h0`Xp7)H>VD`?TETVvhBSqvj+v5{_=()!V=S_f5Y6=%t#Vg3HGy9BKt z-+sE2#yZGZ3?pdWEyRmzZX;Ez&SW`W3?syAo}fkhtTfiOoW(GL);)|xqY5ese`ije z(^}P9&RGm2Xw4V24xB%1(^&gBi(v$gT4mH+4oW(GL)3X{=40#V~>vo2RMui{dp{)jG;q@?1_|za9_J(pUo=a%wP)p!GyRy!xtI_i`4) z2=RI{KucpC=PZU1w4Msk8m?-^@EIb*2wG1EXlblPoW(GL)i^YdU8!jG*>`BWS(ESo;3!YE|n=&SDrrYo(w?Yakk{ zN3QH4!w6b0GnT&p(pYbE7Q+avR~Sp*e`&1od9oJ62&`8bOXaS`Qau&k~TB`*us>>Q{8D}w!p!IryR&P~nFK01~ zptUAIOJmi|m*d4Sg4S9=>&fSGRy9$z;yH_91g$p&t#P%_cGOslIg4Qgt#yJHjYY3f zwJvZL!w6dI1uYr_Xsosca=aKu(ApqqQGT^lwNf~XVFay>f)?eM#`1C&!w6cN0<=<8 zt*1DPVFax=1GF^ONzP&zLF<2l7WH3Is@A|8<vlvFu+9GJt zYQ}r2)&kCA7(weTK`Zv7H+8K39@#^N5wzYGv?#xZs#=FQi(v$i!dT>tmILAJQ*lHf3n6J2{ImqShxWD==Qqau#7^ zuMhDM@*8$^?~eJD*}<3YP-6NkXAwqZea2Yfobz(i&oRVwNI_SQ)7+hEW(JaJ&g4(XXQ;?b3kLw<1E66ti6n-_#~5+ zzkcE@!icOd8LK_ly1Hcbc}**9njB0Rk+qMp@TEHxEhlFYMr3`(SoJw)vF)ilG_Bd3 zMHrE_pRtrQT(#g9wDyYD3!Ft5k@YoWDQUQAN&hH~^(|)+Mr3`%SZ%q789DoUYOF-o zYT%x}0M-G<;+Myy>*9V|p|NIg7GXrKgN)UTYkjl!dCZKIcpc&_!icOxjOF00S7Ua> zXsr4raxh^;*0+qcm9yTkbsMX(QaFn+BI__?_2H~*GQN0FW4**#gi%;>V|RqHsMVs{ z(!tqomd2_-T{cD-k#&@@8sap5NDHMGcWSJToJAOsb&RoS{fAicp`_su&LWJ+I?h<+ zAz_CWeK|nW%HS-*h^+5aR$#omoJAOsb%L>!c+IHRE>6>$$616CS>LNHB{mxC8O|b% z$ohe?lz2_P^1?=q^#*4VMr55-S%LBTg0l!CvVLSNC0>WC-FL61b&j(LBeH&CEb4Pf zOFonsUUifFH(^B9&y1zSD|y4Whc&H%oJAO7`5X}`sT0Z4DaN8P4Sw)L(Qn6@(7-sQ)9zuUWUH9&@UznYaESy25ePJ{c)nm>uOfMZ~YXIig0L=CP%x?^1 z)!BJJ0P}l*KcDI`86Zo4Fbpmg_#NFHQ>J?Rke`xtmSMKk^MgoBkP9GPY_7Zle7TG4xvnf*f!$-zbNZYf!3yVcY`n*pkeM^uS&;AX zNpe_BOr&i@zGJG(XZ8BBtk!E1V`Ht!kW)@a1)d%c*IZtkBj4@y+1);y6CM=Wea)yc?!r8$$K|l)y7F8;uhlk82BpW^h5=-=LDl9gb~p=su6#Fa;@Nxt zfmu$k&y!z*h()SMowwH{#wC!)K~Bde#*K}PvNAxFAAbzRmVBKy#qP5PoQy+W#3j)A z7~9Z*v#~6vQkY>|V#w2xnf5H3JvTSsA^ROmy5zU)mET#_s~CSC%N>1$Y(ovWln+83+^eZ z5kG9-y@DH!sk+%4Jx6kf!J3Y1nPkwQUF5!V3 zqdT2x_d27Zt-KKHiTsRKby+OaJOxwiZt~q4Xhp@!DWYL*g>J-tsx!-0)H4{53T^A3$c860itjjrLd(l=!kMdsclT3}YMns^B7?Zgd zk+zXYD37biWzV%`73SrY*nA}gPA#EW8%Av>8eCia6uU<$u4oupoLPxYfDS%!333Uf zhnkiJZ})mpq)TVmhO=f(gO9YMwoS7+Li$xU7NunZ8bYST+pU-g)CLqPWS7gGV=Hnw zr&$xm#6$?Xa&jms7l+D7HO84&;G?v=7z3=Yi;2A`GQ~j74AwGn*JbZ`lNA$*GA%bt zXt5F$&w0O<<>comCkVJ!f*uLO_DgaX$;Gd_C#;IjLifU zSxlj`Tsf%0H0MCoi;XOHWcTjbr;i=OKAJ?c!3~4hXol?!0!)-=k<_oI@wBnADKiaP z;iEHDN(p6~XR+Q8o8+_MZ)ujaDx#V(pH=8pVy$D`g&61*_-sC9suK|t86uY>B4e$n z?PXM9!|f1O*&qeNG<4t!myppcVq_{Zu;r5Hb3ul1finfx1Zk;E1G_*_v^B(7FA(l$ z6OIOA6q6_x37Ed2qr@}_lOdNI-M*VDqQ1co z*hE&zCBxDXX{BIoeyrHyGZVIanLq`e)uYjaa_xDUS$1305Gy*UnDQJJM)y>Qh4h0K z)M69h7)vkPXmw^}%f`fMYy~>fvzO)wEf|*1C<<$qw&6kC#yQGkDzNNlTmqtvjNuE4 z5w!G*c7PR$2{dM6^D&G|dE#I&#^!gn{A`;W;~ONN0;b_BN5v|uVGJ-P^qLrJD!CxC zUs=JXHbb3vGCO)8TiaIk{Jr9%E_8*ePg-|`^;)(7FkW$-${dvd#8xhQ5w@}Ut}ItJ z#>r@?sMzYuC`of1%EvUjCkwS2OfAiHmW&sbbZb8f4MqcNrvH+XzgvL}U0s&12L!Pz zXO!Z$Z^CL7X(!jJE2tC6FpN>kta*j~Kg9T{h3O(z;A9Iu zRGJ$LLsOh?41ql^dluIBu#)3tX&UI3+QY?WV4;gIPSZc1@o) z_$?#ZKXSxZQnVMy=aZ3bCD4QwQJPRYrUZhqWMD`o~g zkv5dqr3F<3CB1o};s3~4ueE;Yb19GcS$z{v!LXw{OWZ812}VR(vE<7}uynTKXH?c+ z$+28I>feyI#TOT|%aMu7Rc*;OIwKyJWt@(w={~z->R7wSD~F|E0WS{SwES24ltN!t z{xml(fWt--UC&R(I%}@e(+fdE)A=9F5M3m9Ito25UkNU(z%s6-6i5tBPNiFQ8OC>6tkwVis8`v0Th#^ph6p?ijN_-KJ^SY zA?R?b!C<=$RL6n>6ceRvOHd4z22;$1-o>C;D+Q$*^WU6+4o2P7pxO!vQccNw3~0I` zH$=+D0@X}VfNH{D2(3{pYqtG!&u>SBKTb6ma%+X^SZI`L%*0L$)ub7$YS_f?4Arn1 ztZKM4FLVW7X;#WWQDu1gmAb`4jf81}B4KiGh$3JXu9{bdI_CF`s8Sa})nqSf+leN9 zadbrPhaSr&SX&Q+V)4LcFo4LTB|kcdcJ%+yk+OneM>5}aPg#T#Jb zpagnDjXJcs7+;L?%ydL_(q-Slq~_d3P?bVcmQ7HKUYR(mP`PfPQe7!utD3Xair~WG zzqvh2i{pR688vB4?HN;jH-}b?mvN_=qEc3xB3H(ZYKmN0X^NbBjiQvDbn=chMXiji zK(R9Hk_*%<3%QKa`mJ_l6c(t8>?QBkQ=GVTLyAk6y8Tb_=#uRy4qfVYLdBs=wxc){ zYxf+B(C zjtbgnsrXcZ3Q8m{ZcC@);6<_(@k`qnsyK0pR#a!oZ=0#=Svi_i+@z7=#qMBL{JJC? zsw0=M8&-AXQfz3B;6hfJb{5knC(VV6Vk_d>xbf0<4zSrNzD(@TRXqPUq?Kr^BPPts z)ouG_+($=I#=4`hMOcYjMcJnt+muH8l3bU!AnPaD~e+dH1&{qGoG_su<*Oh3To8U4aTp%Tvx0SPECRC@F1E1uCeKDCb)MRM*Sf zE;fkEPmPJOmA7eEK{Reb_BkWU-?W;{<#OYK+)L>{TJHOX}RbG zy$eAtL=`Nf&z;L~*M+I<`&a$A%n4$u09=Ly3GRoIAeZB|7^T!-7A-YmrQKvhx8kUt znF5F77s=WYP`Y&6NmLjxK;^kCT+RA_L&Jm@x{1-hC65(IDheb$)f5!tg5wzQf^~EuTi3HK3PO48}46cu1vbsODqIX#U-&8KoS zskvEh5BkvDEI*S5ZmPGT(g>P9`W0;Lu_cBu)!e`H$PqP#{vCM?4gc>x@kE_};Wm~3 z>*=7I5&qvU5QcNq|GP<|n>GJmP6V}=2>FO4wJ{Hk(u~pWjZz+{q}enB)|rmIF7iTgnI8&w zG0Aq>eA6c!J)}gxYRo&Y|LBA3^vU}Fnde%f<9#?~c=VnYD_7DE);@-NfKu_DWZz;sYOHL2I9A0q9;nWvCYT{6<|7 zxM&la8`{{J#1&QimVIIW2+Of%37SN}h}Ta^_Y6s0-29)G8-k>hQYO0P_5ezqN9Au@ zb3D{TE;ScIqBLW4St`UMF*SRo0X37#5HU#qq?DV$)B0y zLGk7=wPh~rlTTx8ef?et*(c75s}r_(t1U7v-kO+}mJmB4aRlCZG1ZMne#Z3H-~{XI z_mo1;mV*r+mZ!I$WF4L|GCm=34HPL}rWQQ70Z^oBFMHzONw%VGJYJR)3fHhYQ_u{gE7#95Q#Q>s~2O zbMR(Ww@)oq(Fw!jho_|AtuZkX@kw4ad}zEiVMOY%)KPJxtno2DW1>fS@^kQP*_hr* zu3V=#COXyS@Z{r#iN2WLV_n`tg&38ZXiXiSkP7Kon2e2$r!N?w?`ZlSMPDBJ%BQa! z^-nwf%A>EC-t?VBUoQH}r7x!{5j7$$erVcAYHBHz?4%1Y>&p z^7B!3^4&R#pOHw`)cDxM)Pzw(%bcw7iLgB)F0O)-H8MWInwm6nWa_A4sXPYk-A6IK zy@i=xhsRZbtj;f_uk4uK9=j5!sKnvc)VNVYMp^wAefS1l`83ft%e%M^CP zNqPgQ;>(MwmQt)NvO>#Jp@2}V zuCPB@O6f|jcG|__Kf0G+JHy-f(LMdb`?2OQ+AuTIN9`2lFaB@M`ob&EDb#ukUY0&glH#_@n7R}u)sO4$q33(c zVf1am+uC;n^V1GFj9wXUl}1^+`<%tTh&;C(DoN{stNno_y|+saX^4L;(x}NYu2_Ld zeerAlZb^C4lQ1YwlE%jkf_j-2O4vm}MLnD!vc&d4l7D`8Nj%@iH*c`$OBy!s&^?{Ey>;<%bpa z_5;)68`<6!_{XUHQI#AI%rhJp%$^1IHUo3ufNZaN5POw@>v0hAI3(k0;vb{(@(^&3 z0Mq%fj0e-c2vd%i|@lY{Uk7v$7Ea${9|OVE9~73%-Z9j z?Ty3fUw}#ZPR3C^H?sFD!fyn|c|yY(S9K(S4 zGK%kZgr5d({b?B$%HAQ431x2+PW}Yki@%g^?-PzG&E5gvo;*{!y>~b!l)are`4MnW zQANQKD!%V>jEpo+zau#LF>q^slTo4Uea$hU>`{6C9=K;|AcG^6y&W7QBaQu|{M`fG zqCaF*D0|yDCX~H{IQbcHuTw?F5zO8&oZAmf`*RE?1#9ogOad^2&da!9^<9e97M1z}-*Y$)weX@n%61aUOdN?W^WR39qWd+*A+%aaZD(C2XXRd z;3m}zZI9~j9F7TPkK%hjaM#rjZEpy0w*&JI#|0}d`+?g7%>t^?8Mv&gLfdNz+&#d&z;T2&@~;I>tOn-8=CVCXXQTYR8sUe5 zsX_!C^lfBs3&QIHvzz0B*`xOFTVSTOl;VpHnKMd;WK~h$Z^5izsG?46_|Uv$o7JjKeD$Nn6Gs>BmWiycN&=cX(0wjD0@qR z`BsNBvPb^?4$QsXLffNtsb_)d(?iD92hYgf7M%V9m`9>yTy5Zt(vRv}-Dr#>@S%gg zjqFi-5Dm=V92cy-(DTdg|-(B8~*?k)jza7 zY7f$Y=`tX+y@|l31GAFj=<@WL&WF5)1zAz-;BXVEI8pM}RqE4Q($A_G-t5 zNd@@O5iI?vdOr)y?l>72Ed9K&(JEfXFoXCqiZ2!S`+<9pCN?;N#g~fRkHADE$vCR# zM)p3#>8F4xNDghU1Ne^tvzg<9rQfT-eGSa~l+gCD1ShQlX4xEd40EUI(ViL>U*X zyrjW~6`1=tE?9i2zO4l2(6zF?VE%Q2y&99kq-cETpl_r2o<#T{U^-qG+Fm!{MgcQ} zNVgd*h1Uu4%{q`k*yiW_jR0n1vtm#(DnuZ zHxHQiI4)Rx*8%q-FmvsG_Soa>6;E(YgLFAY3ANUbw018Lug6on_y%zAa4eMrhBL5t z$fUg!!2M>z-j$hh97^-AIdB~~Hk5yfChesHH^GFxX(sL63fw#s_Fgb)?=|4wG-2;6 zllBe+_p=FmbsXmMqY-ddb8M*mh%sqzC~)Z}?A>V6UI}owo3OXUq`eiuy%a3}%HRsq+`O)8`y;$H^Ep=4HHgOwllE2vx7mcfuT9!J3fyTE_UcVBSAUxT z*Op^L#W&WZy%gZan6T$HY40ZB=9;j#)TF(Yz^yl7Z;wfP2Y~y*guNOrbNLYtTuY7( zl^+95+KUG+&4j%?llBUMn`Oe@B9r!(0k_(Oy^l@W`x3aLChS$d!CZdS0IPw(h3<2#a`SSqB;3qqba5O)9H~?qt-_yXo zz_Fp?yA7B<92Y9SKLGPbDfTG7ji!c4SK&iPsQ5;33JQ-lm zI9-+i_X@{`N|#;0e9dv8(&aQTf0bg7(xrKBm}J3+j!@~+nPV6bUqY%I*tn#U-IuJU}kb$DF5!}m{9&vIh`MXGtQ5PfqRBygZW4HHk-7!4Y*HD*gI{~ z-Z|i^=E?aM%D=W8qos>+e7gYG*Mz+>Chc7ZoXdp0xhC!12i%h;?5#Ix?=9eVm16H& zB-#(aB)R2uru?=_f$7&2;g10GGRLuXLIWJF4}A~J?;OYSjc`TzxxUO?oRtr%M-B63 zO(jgK87UdzB8+ebuRF&m`5P=h`T!Sa!ro+)_ND;mGhy!mllGnf?s*gT-Zg1& zCvbaB*!$h2y}yC0d1LAM(UD_H%a2Il2AQxo(WJdh;M^wc-DA?;L%=OIVefw??QI3_ z6BG7MnY4EnxGJ8~^P>&Nl$IZzf$L+!UWQ3~lYpCI!rmPw?cEF96DI7fGih%Na63)d z``)CzUx54DguNDCu|EpdUPS;G$+4l@zmX>GjRh{V6noTP&ID!w$AubqJ_pRJrP!l! z=Wbv=jx;C|)UQ0dpeXD&ak0 z;6|IUS76d!F>rHC*n8Hby%&L7Yr@`VChhG9?mH9qt|&5>A9aDdiep3NM?aJHtiX*h zVebZ$_B_DdV#3~2Cha{3+^eP7qjqSwNqhT%J64K4YM-l23zHh+Lr19gxg#*WI4)Rz zQ2RU@m~k9OR*l+S;@dd}KiOe~qxLx~0B77j=K@#EvBCT!dykm3w-C4&P1xIR(%whF z?KffXyh(eNigAAcK6HeNZ&!|CKzs!oAM^swYQo<2ChcVd=P_Y#fk}Ih0r#B0J-_uo zn(x02%sv5UwfaAwf%b8q<5(%`y1N4%WW-;b{MT z&j4It{!+Ro1mMsP`Ps_^ZfF2*Q~>T>;9f9+qxj|BEXNf;*}>|spKg1c$q&E<#)B+9 z9Du7I;2+t0Bmfs^&jH+~09;^vw*uFChJQQ)aif4c8Wg7$XexibZ^8a1eCSZiJxdo2 z*AVBX0W*)|2+iu7ACCIfhk<#f6ddWU0OmuE6U(2bOSr?pRJ*lw|Jni5pW}l0NAZXU zW*oRh}6pwZ?~zVD>0o1_NW~I4vGNM??x9 z{lgFHrwf6Z!Eu@{aP){E9d0f#_xa=eo_Es`_{V{Hi{oTnJnzO2*9*AMfvGV|jz=h5 zOJJ@k1!sjlCooG(!I6LKfjMN1%fM-NOv3kX9K(Yo_WU8ol&Ri6D@B#Xt;BPljzL`qU>N_uK+Mtt&sHn!CCc-z>-(SxJV{I65{XZL}>R zF>cII+la)mi6aI_8z4s)x_z!Z=LlD($L=W^oSKkjODJ*M^IVPuXJ%mz7zv3Nhyh=(+886dP}M4 zV?jvp3r!o5FfukZF};nY3X-d{6!)Jg1EUl)t-Yxjd6tL?*ckY)*F;dv03y{LCAq0n(uGu*rBtgmk6U zTAEoRssE}^__K5z-N{1l70+``$8+s0@%ecLcnF{ej|PYc$8!$BiwMUn-aJmbV~Ra9 z*J<FJf7LcCQsR@N7+r75fgb_CHG<$&ptxqS?eI7hD z&zA4Wf=W1rjIw)tE_*Hys)-;E%;y()rK{;Qxn%c1SVy#FBY`sQj;T@`Jp?$-l7?Y% zP|Qqo+Na7=8lWy28K<6*YT@r(m(S_3=X#|E_(Oi`pG^&;DDto(mvfqSq6SW|=hb~;P*x`K zlO4CC;!;aV7aSMTE&uYt4Gb6n_J9GpGB{v>FQ0M^$;FU4mDJ`pex5#Mmvb%pN0Y8^y}$mINX_jCeGiWWNDJec z(MYPSCWIX)NgM~IJf-7imh!HGqFzY(D&rsX!;?=vE(hvip3CPQJ!qtLU(|FdHGp|x%sMCbwe?K9`~?!NDqxk@G&x^kCb%%Y(6>lxOd&S zkg<0fgZtGZq+kAUctp7qJWq)b)yL1J?p&k3VS?!>+$V}O6@V({@TQ#V86CtaOHdI` z@pGz%Iee*kH;v-$=aZ6m#tEe{{PNB?o&4eOh%zF0-g&3wdw5ymHL(lNh# z#d%|IL@<2m8qya$R90vcI&n{08+sz6xgUzt#u=rD!V7Xbc#6=Ig9SG_hjfF(xgQik zD#gZr2-s2!iw#eo_Vwu{_!1BMZDF5RbQ-du54RQBa|f~3)|T$dE5J~Y9$xJoq}DPE zjM(DFB-zqaCML4@lan!q>8i>4mAD3`;D}Ztcapc|WpXlh1RgVOON~t*jz^e=$|kk- zR0^72{F&Ixe8Cy@>S6#`VG+0)s6DiiMP9LdCojXK?#*uDX$_^E>+dB zq!RGxd359H~UW#hrw$zW1n zAkF-TH815_pxv}=p!BLu4Smbb&9_sB%_E`=1+FjwhWE;V-#CX9+j;h4n`~c4nHf@n zD9+-7d^c7@)M0yj(-i0^l~9^F+h_`-`i3_`s6t95lxBWqmIEbaxX|0sy{!B~R2(gZ zl_9n9$jlF|i${29>p~i}?rr)PzZ~@i>cS%QTu|ZJIKI<}(%(gHtvo6h~vq2)D9av&v*dH`r2!j@*}k z2Aq_Qqr`kN8af&{s|+2vv*oLzi%n@m$4iP$8HbLSq@^3nnH)NnmmC{9mfEjhiW;i} zBTUsNTGBBteQdEutx*FMYjR}>tj+#|pRSQ=&F-LZ>$AojBhDNfp9{J2-8SD8j}!B| z+$>1}@=>5a(4LE7CcR<_>%DSY(SujbkuX!}#Zo^@TWWb|%v59Md43q`DpyjlAZ(`P zDJ4VHl%fTVSlS`NeM@l{ltR{(CR2lFh47`SUnC3ivTPxI;loCq z>sdAfU;Nf@*;O2xH`~yxIV0iq81{Bq+q5Z8Zr(jY36NmK`+IO%WY^ziHJF8bP=(8)e#Y2#VaKN(@~FY z-YKqZpQH>inwUxfRa7RE$CVr7*?46m=h?ke+4>c6tIYi8A9MVX`JOzCU-FdPXJ&?S z7s!mcgiCO`jSSK7NA^dOtfu0VUf^`lG~P`ME`n2WI$P3AGi4&3G6PpPX(A6}NS`E~ zjhVNW#fCCymF*}Q%*W)$B|{yR`_(OlTq{(9Xk@i`u!^Zvi+?JI@LnSat6h}CRJ+1v zR+6VMrA8r0{Zb-h(jQ%9P{EWHgcx%vp{rqoxc|M(F;!Wueo|lhPc>7CsIplZQik+3 zsgB`jZO#S5il%hZiY-22D=jmE)V4Gv3Pr2tOf;J~LN?x783|tHsFcWK4%uMHYNs<8 zQ16EOd3GvP-3v72RQeZ|0c@eTA?#1AH9wnYc5h}4pfFBMnJw9L^Y}mER3+UDMX@y6R9h`w-HcwTw?LE zVBdAzx>dEI_eM|70Sh>N$BE{1Ce0$=h8&{DiW=@=(4UHW1}nX zdYKvANjmliG^fwvn{Zf#se71Eydrv#cg{1c(}4?w}#a zmYeVOO6@`-@y2&d(y;5deMs1ig)XPhHqt(l4S0hKv&-MPG;Sm;#l#qk3(1+3Fj%U( zIuyuRYLgSCdiZyT?n7h>~3euuKJ%LApk)2Er<6+n4AU;@c2vERPP0Eb~ypA$6G zrwSO%1${N7%IcqMdUxe~Ba4LM7Tx03ahkti4#n&3Fkory8+;g7>QGU=F5?$*KV9lP zp-Zus8#@KgyPBYI-hL{vGTz$Gt@Bt>3Dc#Mv1u8L8eLba9!|G~pd!&FC~VKK9zGDu zB(`|F4|cJ6Bm?_E(a2X1KZA_2d2P1Q85t>Y=sV+cu{A5f>2-Kq1-J~tOtpn64-F<@ zsxdfrGDQ}2xTcB(Y>6uMaE2@t!ka$5V4^<)CXxwTk;CJ|jz8Q3;Pu&%j<^iu^f=uP z=OCU(7Ix*|(pmm@2=k@@k6z;(tmRY>KZRHS$qS7M&TM;Ou1~p8h>Jh`G7LMdZKdSK zF_^{fs_Nkdbq8h5*T{k%STXTYY=FzGShH{DXtj9iaucfXyu}+ zuR&s9Goq9#E++efZ#CGCntAHwo~3o=?xrjdM@gpok?@Uh4U7Hm+YXjXwGw(8+g zs{N66k0*bcjr0}Q=(jA>4A8d)8K|?S6@5%~*77nbxq|c2pxhl(MjlgD%x0u68LTj{ z4R^uFQKZ}B^4+-5k%e)hr_dpLF(~M5LfBKnGGL$C4A2!Jsu9%Q$jb5xB-IqknBz)n z_@ypigvI?a)x!@f7{7KE3hQlIK2z^OtI4_xR@SDRH>R^5X8c?J0a;* zSDZSiSo6z$HG!3lr5G1i58oLCO{GgN3Qd5bJI{13u*DCSyq%ONp zq@1gDoC?p2YQG=t9%AL6si6);t4 zai}8*vOItBa=h=;f7MbvSDO;SsELPmFc#Iz;bD(rgL|YbRgfDKdcwE z;YL@U4}Q1%gluh$O1v!3#%_fH3Ct?k>7W&?l%z9~Q_{3A;@VUx6>6DQQlG_54b>WO z)Jz)7tWnDv-9@kNqoSpf>fwzQtF(@WT_~7Pc-YXNnW5-nH+J>#r-D`y)@-O%gpVAk zjMh{v`xg|sPm2TObYO=bdTgj0TTp{WJ@@Bo?8F8G-3^VBcLXURs>kG=JQ!CyQVdQp zPNAUz8o8pd*)F2*zLgrku~m-+?1G{V0jD?vo%<=D9l%5Op|W+>OhH*+1vWC2C_{ z4&BC-(i6c5&C9x~ZA^Np*ZNtJ1CP4s-eu=0T{KPE*C^FK)1D=_+pKfj8zjlpksfhB zZpX92U5Hx<3w#*)QU(1qAQ*xf=*p-meMEJ)lp%rAjhbpo6|mft(#ZJSAnqI1Aq#Tt z4w@~|Tl9!ub~+fMCbv0`35e1DLl zpf)*d96^)s8$BGC4##8S9*XE`g-@Hp*xxaP%%R6CS5 z#jx>`J5d^XZ3&5!+jQzs)&|8XWeztJRS#dOz?9*ungb|T9(E^*HY#G{x(;BS2$Hn= z8(7!?f3R`N%5KsexRFxIjP&6P_DL~Ss-Gu1@{|*^NlwVjL1g8HTKOp>Y)xu@VCJc1hi2YtlG{eG^vRX4 zOw!uUX{9N(;Z_1jv-@MS3iI+xv<`i15I^LR0F5c;Dupwk17lO^B*i~A)hT5v&5E3< zHkrhDM@2c+8jgIYM29*XrT^w-gUzPv2k%LFk_EODN?M{_utHs+P2Xib@EO3zJYV}$DFI0HZB+Wc5Ap^>EfYN?^d z_IA1Lbh!%(u_~^NqiMcLWAhxPz^E-mh=G}sbkvj7Ri_Ubu*kz15K%gs^=$?Nx zoAl?^^ry?6k3Z=W1^r2vC@9IWH?(^AJy_JWrDo#BLmwUzK-V{R!UD1*5BE~|oVF=w zJ?XJ)G>UDWB1!&>%SF9x_N*+bvJ4Vy1nHwfsMO>l4+5-cV-{9T?FMF4Bh>WSLI4H~ z$i_4Da!c4$Vyuyx)`GJM$vgv$S`OF<{Nn!qmkSa{x`2T-qVIXxbhci{jN-DaaF2C@rGO77*!nFmsBfc`-4!D7-# zrl?$zlDkoAiJ5=?SFdCjskjhpK zw^q61Nt6(VYc?=3x$|$Czt`D*Xh(F9p-1~Z9(T3%>-I0?tjTJ5W=Uk6B+)a(ER}op zy=_zC6|X=1^mjQ;Hm{oW+>u+>CLMe7eCCU_qF!myZO0l(>H=X)*l-OIxR`}Gu)_w9h&SIlW{C;-RU7K#=ZG*&nZQt z9{+to(Sn274W_@j|87az$8djctx-9r#s~jfw57&NzaOjo+R0u&^f}kzgH}g2Z0L4j z@0a;_dS@llwI926Z;!*a8ILDlao54F*R6VC)#+i&T6ycu?7e06sP8P}@q9Ig`|^j6 z9H$}%f86F|&jpR`AHUoreZtC(VTZ(_wxZZ=E4JTv_yF2MTNTpnw5`jt-3~T< zr}^3WH^0B>wO<c(|j53$wuvO-5Pe#^YH!)d)i*G&41+2 z7k^8RntgZt1L@H>USoY!lA2W|dpC7xa8=g^liwIR;;Z9LC$-w#{mn|dTdsp_45yh2G47_gB4bu;xIjLTQbpMwoojP#lnRCBC z|NPGT59f|~E&Yb3Z(jAr<4->PN#_?PUo#u&%y40O!%7~_dT(j;wQa2D$86u;WA5s+ z5#RL~J!M?i(|4SHJX(^zVYmgyuY9AdxPm=CsxC85d z*!Fpcck0}Dx@z9nw;zsKA9Y~dz}UFquYL7Ia^g)t?2)9e7_N~mZS$yWlgD&Be8-Na z7oJ>qZdRjazkl(;4O=#>yz+)~%|6BbCbdZS=*<~>n?35N>#6-z*cDH_+^zLT-mu!g zPJ8X)5!0tXKk#Mb#~lp!%fb8Sv>5VtkEXXCue|uT%$>(FcHDOCo?d+(d)2-5)+ZPD zM?1uDeV14kG(4UC-oy7^_wlZyE&H~t_J}mG_S~gAMz(+Sqa*D`NK(Jrq#Jhi^D|%T zcK6b|KL2A}?SeMrCfBfhK@72G2d}OF3eamq7)@uCpwS89qIs8o3D(mOGzu~jBZ}i<{T~z(0 z=&w_YR_~sSr!dzc-8VPx?E3h?E(^Y&+~U=q1uYhSu{PhiWMSo&PKz&VPmSxl;@OD| zS8wy&^sZG0X1lDs9 z`JbUo{mO9B?_GcJ5lj8$lW)n$=x~1H#9tD3t$M8M>EVwhfBR?DJ=y3N2G%3pZ|l6Y zugk0>-?(0V``hzxKRIT_-P=C-=KR#B*B*~{Uz6Uptt8E2xK~G4`F&Pu%bRXq*6H<@ zu@8K7WLlfknOk1_w9UDPHa{}z6^A7K#Be>2M&A>kxBQpR#};k-+%0z zy#5Qfe7kVa^XOpvU>s+uye;cgQG4gGee(u-n(v=DvHI3$8;ou@s!i7I+uxgWU6qK# zXzv+rd#7in9;w>mgZEEo_Pb4iUKYf1SoSU~cSk?EyZ`(SxT(qEN|JRou?Jh|V zGTgDncYn6+`g8f8pTF==PiykKJMHxzuh;*r>#J=Ua5{DJjp#qVWw=H~f4yFJRl5Vf z^}6e;9-nuQ-L^5}^s%dtyfCTjt;0NxA9@Op8b#Y?sa*Z|vL9;IzU9q5N6#;M!ufmq z-VL6xdfx>tyEVRI*ZSM$U9&2; z_iy+7vkLvpL52&ved_r?8())GX?JGZgICpWU+qBCJ1u)3zwP05mR4t8s&N5N-ET;` zJ8v8E>)%IOpG!GAB)0DrZM_@+s-AY!Z%c+SZJzW@@SY;1vVve`}Af^HtQ`*IxR3|Cyf-zh3gs-xHHoJ(K;` z+MgGkhc3gt^V{fCzZ6L;AHV9eb*rClQ)TV7!!Dd^(7Vd1A;pc7PMtzosnVG2O>5om z^t;c-+%YA> zb*bx_|NR|jqwm^%;`7<>Ufbkawhf+S6!d6CcpQGdp>yX>0__=%DvF(>ujWPV~pG_m1it_BK_JsCJ(sx%N7l@UY$7h ziHAB%x3%7KvSzDKpZe?C1eBMX8SeO`Ne3dV1z+#pu>FBLpY43)oxydl{_D@}5lLJ6 zri?ly1MYBX!xZ0Kj{uk;wY;g_nZjo{#+c!9VA` z_rliXS>O9A<1Gj+NVo6m8XMDFF6>w7hWGX?zmVxnwT129P%`*zV)Wi$@BHm>Z%KNT z;jZ{##eh*)Uh&tLO>U5u54m=I_viN9G3c*s#~5Gl4j(@L<5tvjhHHG|QhUQr0~?$? zH}yr!*pw}igR5jdc)050C6-%0TD^AH4vaU@rdldLQ)_cl&gvKU^{Y8`=7HN|7QMND z(AN8RjO+L0z?=!En;k`6dx+s;THo^1`A-TSn47ZwiO!aXcD{4w&Q7oGee2QRcl&04 z|4GLYsOJo~?2wchZ&`k@LB9p>N%KBvGwZDmgO=^S_O(wQJvaBS|CKC8zko5SrE=d9yV|5y>i!`$VE{ZA<MZ5}> zD8YpjZ}%wy3YLz={rYs8G|q)<3)8%o;dtK3q^QVADZI!8JH@+Dns5nvyCENej0czk8t;zg1H*uf_9%acJ-M}{clocHQa|jyki!P?Up1u# z_|*)ETGB)OS52uY_646{+!p*-P3bN*Y`z-yh8ng}4LhQSeW!-G+_-}4%Cg|OD0rS0 zCiFPkc_rK%;F8=@kz|*0@heNR;Fm|rkqYr%MkmhDlWpjzxZY8@8pCANuXwyRW0Euq zzU0Fj54_5QZ%Obm7k+thE)~BW?7SD4YE z{EElldHAmo@pA!Fg0Qg&orIhE^YLFUx1Y{Kqi|zkcibl(#lNFqsVC5sat@$L!->C( zS(@d+f(JJ7KrVVixBPD(HDdfnGXAyb0weGnTS+h5f#N0{kA+FnIh4LIX*qtKWxtvN zbe{c6zAGc5e)3%-BC3x|o^^5yn91|7xds39d^h>7IT7pdbK9JVnfQl}XBN;IpxM9p8@tCO{5cc<%-$Y` z0QyA$IzfcR`1gl2e}Uz676Qp6K!2zLui_8YU?rVFI-wXObBo#E2@%D~^D^k`o`}5& zVRlr070y=z4pu^Jubll{#7sc{N}fL=BAF2usDLm48gRhh1hB}S0YK(SW*z<8bEh0W z>)kE*)Ar6z?a=aLEM>@Yg3rG>!m^$!>pH@nSwVJ)m^@!ev9rnZUXR$0p!N0fb>_L` z`42_R#4qw8Le^4$$+;GxJ2mek#i9&_yIVm1VFn4Xyqaeuz|O#|oC;)5{-qP(r-BKz zsJ9jy!rf5JC?s!0Ff`$zVx9x$ibuSEPJ zY!xXDzfQ4Vlkw|k_NxHDeqq06;g^&7cQ1aOWMND2>rYg>D$;WNYK~78luFb+mg{52 zCC@(DF?rti^KPFB_h%oZ;#7b3Qu^cnk@p_pSrlE^@IE96282*WM0|jVG$C{d2%#te zDG?A6flv}4)EGh)1pyVof{KW!h#*!(YzT--6R^Et@91kq!G^v6_dRE3c4s$)Sl;iy zzU!Oh**Sam+;e8m)SaE3MQQ4#3)8%v^|FTSz=Cp}7{A02pPI4A{T2uN&4n z`z`|{7I9;zdCyzNm2ToNl1WQ5E0~IS4Y6245qw|~R=h60IEI(_D<-EJ-SA6WI-Xu3 zxq?@rLOM9l_wc+vv4SzVld)%Dg$j)NV~Um4H+S@y0-ZpBP;oeZ##DMdyp;N*wVs zuCyUMlPk2{9zR#AAXiwUxw%B2SQhph!-C0FY)2sZr!z~~O;vVz;ryaq_Q86={K6tu zm0v8)l3%2fyhaexJWVBe(fmTKVm(1V#+hH4I=_;6V%m5J>`ITvL{il#=AzUnrtxEh zpNK!HN7ZrmNGLxuaE6v2R0^er60NupLgz1Q|s92&Pz!RFd}wWQ6yQ zrV1NGsG);D>_#87M{0*Z?xU?LA`=p^&ywf8guwkG-y3I#LWXV$DUKML;5RR1=;G`& zQ~XU7v9pJaD2}qFnA*{!*n8JVsD*7O%bi3xqK_kG#zk{D6_>Iw1EWXuX6(rAg9ABS zQI8!fO2!WuK3)$TBbiQnhBN*Al9K5^+e{~wl+ea=Wyon~B7nhmOy8=k09C0;-CzC*x?YX0sQMWuuHtfEY{{0N-nWZ*C3ulq^p5eNy^NhJ-Trki4yRc_aXmy??BXcq!eYWIT zr}5tL;KadsObKQ6#y)Mb5nDNLXa$LONpAx#ntL_Ejbj>_gU7(f9fWe2XPv`zp9H@l z{F?B)!ao`Q+3@4=X_H#;c`x+?EGgBSRFe0;<{W_E$?<$=Wy!)0|B> z#6kPbv$mk7l~ft-XD_d}VGg(P3Q8OtmvNPvgdrET-O}+hnm^NNBVLWg0EyFC-X`R< z_opJ~{S=#$@H`5{ZZrVA)@c(3dup`EXIyn0FA1VKCS#}EppKU^YS52}&U^oTH6GhY z>t>AG`X?iq&RNek8CO(}8TKE--fX^_&T9;Wb3>U~J5B-kDHt+Q^)ylp&j1hG27t#p z#LP;>T)lMsiQWaE?ofzpK$TTjm*U6>C#viyr>NC9u2OP|puWM66L#Z5#X12zYWN+$ zuh;;JlUB$SYkmnCZ&8k)ku??DJY!El_0jm8Y(3C8LRpt?Ces87pO(@N6GtrR!*J@9 z^lG8vk9KmLe1QH$TxsKrXJU6h+$G4a)Sj7y8YZ;{7g0yrR+yxNj%i#~D!eeT>UNP4-h<&b z8C|HJXfvCrs^M+CK_iZ&@Wqt6Qb5xIHjb$jXGXe==72h?Deg03teRS3e1+xT8?b?v z;!@J%=U4o~m7xQq$M|lA4hYyTl!c-^&KJYSD9XDQJ~7w9?*X6JnLg}Cp$g6Ku#XfP zQc2#uxF$SWNO(IfZ;$2uYX#(t!V3uV{Q!O_33^~<3W(xhHdar`N*7*OVL8?omQuE` zB-z3uJQ}}rA%#V-i*R+jDnO>#ya3L`P_elIJenN!(7V1G4&v;{D_m^s1-%8n8Z+sB z-XEyR;4a>vxTWeg>=uCzK3J;mRII{Fl^K>Hu7~ks5iySG`8&mm={LoSV_Yd#q>{X6 za7}o$pzuDjJZ7};++rnpEA38j{MCR%wKi&~R-S|MHhiWf4UR1ra=KW?X)H}LPOAlK zrOMLNL2Xl1Pf)ij%4G8baN38m`CRar&1d7cA>2B2%|U-Q2^-6*F`ItK5r?F4r48Yw z>YLtFa1u~;k!kE-*nPDD3yp(6P%{H(7E|LGkMJlAS*U9L_wZTke}K=Sz>n}bGW`{P zGx!(+t5MjW@R^QSOj-dnFgm+PC3&~tn($U?DtyZn@3avX^9nb299Q_{+P^2hADrxv zK^uZcgEFFf!ea&Bpxm)Kcj8~VuZbf><6Oh@CWeOZYj0xM)zj|!CWcuN82(b$IL4QT z$3MR9B5n^R8kmOX;WHgC!fyn>f;A|qByXqX?a@@kpdnLA!KGOkf^W%(z{w3+lCfbd zupx%mCt5Ve=V13tWkr5QFee}1Y5Et;$u8|Ln3Jtc(3*^M*qX0sYrX-WX?asy^LrFE zX-!BasR=USJr612$>86g?z#|Hx`yn;vcS%gzk8x~LPI@i223P-r0eco+Ft;y^GlTJ z)st~8(5tKR!}Qj(7#XZGy~s?=mx!y2>c_a?*_J9bzuI(?!m1=(6W$U{vDBy~AoC6- z?@CNT{bTPqZ)aeh?;Zr6CD@uVNmE^6ryhk(@FjVR;*eI5<@lSE(k#j-?hP01b0&@&j`y_w(nK`J+qzFS-ET0*sBcbLw--28*W)Dkj7J$=pMSH7Cza&Q z$2H+C(3CBvZbC1?X$nKi^SD;5GG4& z7w@3IHB6dEv2@7ha)>zX_K|6p{FC|4J1ou1!{* z=obFMdxGK?{}R?Hq-1z1JXQqZxicMVom2V&T*Z)n-zIdJYEw;^!CRo_ z{5kN)K$VXn*w4swMw#$z3f?h_X9lkigA<;WDJa~$M76S6lZ!}Y|~@B-DM$ULWF zV};UG^toc(RDg|hdmJttOUI?Nq{r#W`4N27QO$a0fIk;1`^4P&sah&1%zDDN_fbI= zjB~hy;!HWyftshD7jmYYw+V?hA4ny64_F?pA-p}7_q^p5nKw-10sIQh8$ETc@5*%M zuqO;>j?846%y|&O^$Jynv%q7b&cN@BP_q}woWL~nU&@+O+p2OO$(q6@q;1wbyG&#vhb;(ImNgne`c(j!8KC(R49pM$)FC1+Ia41w2^q1uHxZga5fe!0RTdI)x z8Z2flyq)2wV-N1^gCqabvBHG+njPSC;haaY9Rbr zXmy-TY+fE-L!6YBhJ8-c(wvP>i*EtFLfcp%Tmt@z0l0Wt3_wZ-!opjL6bkQe8DLX! z4G>+s2gTMEUIg^w%YVZFT>dBqASDJ6-bzG5c!e5Z8ZH-gvpcS+;;uX6;tq18zvcSv ze_rG{xR3;sl6yblEk=rjS7?Ig;d0MV;~5;`Zw@t{rpSleP51d20=2I2%)a+{)zkee ziD$+Wo_K@^_y(`9UHQvOfs zIhQ<2!bv4z>AWn1ETd+3gjZ<7FNR>ZA`;G`shvvegh^9#!p|twipAnLZ=qxtKB5n| z@EN*=@2*?;9=e792_tezI4McE@Hnj{Je_c?D&r$<^EeW#j^t4ehbEr`>_5tR7M$xt zMqzu0UI*V8_q;Ws#?N0H?T;u}4I(R~jj;9VdY4mLuZ4_ZT!vUmB) zC^UsxS&0#H>aO&-dVrw~R0;6s90PG6aYM*J4Z)*<__XcLBO0jq%fSEM;_+gdD6l%* z%q7PWZ{wJjJ@_HfcIk44zIS0!krGEr);0={Ln+}EQR481Z_v~kyVI)yrp>)OJ?@{( z<9lo@oI9XL-j;bqQRe1kJ+93NO=@E(W1x{9jRnkm+b{VEIj?4ONOB6=NJ1fA#&u~)}};%fLrkE0MSmrdm2Gw)4B zne6`&ocluAA6)WsE;?52RMU+X30o&&?f_r9l!*hyX6tP}oT*xJx#x*=YH4ZzFaT9x z(oK}$m$tN7dXWiEdDSc0_e%$Yb&_0CQ&FKYnEBF_}Zw-GT z{5J4ej9!N|r5KS)^2*{Uykt$`h9UUQTfETjqcVbGlj?UL+rSCG&`}3GJ}^BAzdJ&$ z?kdbSvol)TU(ymufiyubh? zV>h@`u>y|~mx7fQD$(q3d27eQ+~@B$Xq~4Q%s{(FPZ8uLz&#GzNPwF$O8Q0~6j#eU*a| zzn-D}O=d-_reEGjMi;5_h;4YFu-puEcxsONc>mu3zd@n3lla896tJp zt8*A1nH%*7PIF;B#_vymv0F5U^^uP$pn^%>tFE*3G(Rxv~(mv;;2+zb5#d^?%STh24`d zF5#+$CSeZahq$YSygX+w!)5y{PJA*b4Hl^+Z>8n2=@MR~Y8BQt@&53q=38YOqI;$N z;h;C1bI8_qXWz6m zOBS=R4T~1GY$8df-EHd$@A6*9INdSt-RYPeAiL5gvWNvR~c+7aGBbP0culP2CwL<&dBg{1))Lzz2`h2dY@JhZIwj zO7b@1n((%0%56Dmv%t_^kK?Q{jR}_n9G+`#2p)$h_3>No4^#AqgaW-S^LBt@nXl1FA&uN#GHx3&K4JV>+v$44M2v4w_*LQef}f)Kl;LhQ zVmeYXh7%sgaKiHoD0Y8Geh1FvIKhoWrAEG&y(Q~YlJ z$2Mev7H7&NV-m7q9IWxhu_5CYwqZZmjPX4iK3lQA@M*jL+UJ%PVnb45L*dbe!VAu| zu|YMnYpQ9)xZHaUQ2*xqIGnu}>XUg>o`fHxa1IaR%x%?#ynKwsa#_?o^R}-Oj`>) zniexS-hi-ai)F90w2S|j6OxD*OB@S{lr&O-3NURNI7w6I9_+5iv|4?@Q!|6Zd<39{R zmG4Z%%(!SHKMa=w6NuahAp<}fW#mp_1f_zu} z=$?nv@OQw^hQAa3Wca(_vzWaFn@cexmE`foUg0&;lqq`t zJ^hWq4GZNHQ_lNk^<%3nPFk#DRx33f#@h7{ro}kMh->Ba7_acGSPMNX#>PU@PD*CQ zgts0j;RPFWd%K~Un`FqW1I};Br-73mvJ3CV*xXdcuSaMcW^c_^N&MTl>8gw{FCVe# zA!YInn>YpMiEZ2|+%z5O zZbdg(Dy0>XE*UMet-8-ib7A?F3Mu9n>rj_an(h4u5^CvUrYXT0zuKmrlssS;-ZDrDFEABZenWa`KkM-$2c8t z^s%&Hi{7Jc@G=qM6>EbR3KnmJmpMwmtkdQs^cXdNQV-MsMR8a)PEi@4?m)P*H_JrD zn*d&xq6$D=ps1OkRw+3%zkIKWz6?2Pt5mmbLI2CC$zA|T_~`-(GL z!=~eOji1Tf8|6$bV)jazuFu`QQrc)PJ;s?egXv=FryGx&z;wXk>Y-{Le5UCFT|>Tr zC8RKrO7d3Vn($U>D#=@Cd9;+sQIE(yZ+X!|Q|q8xs$@$2q)=&DZ(3_FKS9yxqG_M}laAy|b00?RS5NA#rpQ;RvU z2|O8^Nw8`sj;z_v!(s_q6+1rib90YeXLx~^5eVo8E z^Af3M8#A@L89L|07^f@R7`EEoEH%U5-K=fp*p#Dn+slzD#p<>xSgdZl{H5ctR{(c( zOXrwQr+`mJkhF%|WQGNs#$_buCvo$*j3(2L7Rft`8%YWlGm|R-8E2G7PD^+vf|Br3K}mS+ zKuLJ#fs*isfs*h>gOczjfO5wzUBC&y?$KIh1q&j%C35!+NaM?P-rh{0b(n)XZRAkR7+oI5-rf8^*HVd5; zU_6*V`1exqqw5X3GH!j~GisUI&RdZxu`?-I)g-)?kP=?tw%ETVW<_2UGQe@*@s^nP z-{)~qB2FsT|6sdd7>|3)jLOZQT%fFHG|~^&PJb8Z$U_4bZkp9NrXg&+Ay}l(bPa{i zw4v!yh4ejZJW{e)P<2*Nv9+H8`l)BXjEqJovO7W-@K`}O z1RfDCyTzS}?m0YvbdFw{jAy!|vF<5b70h4>i<&kaI>)tQi*Fa3sYkcu8^`$3u;@GS zsWNdDFeA-4SAt&^er5Qq{Kvy*I;z2^pCkTn#@PD$@4`||$PKxIk?-ZL$W-xfY?l?I=A{)WwS zQux>)j>4;XC>57Ni+$NJF@ubwezxmu$J=Y>b6BRzIQ<7c z>(5^Jarpb-*M|Qxe8%@R?e9b?rNJU4bI8J51}Wj$_C8%6xH7VV2dJHdi^5ZlLg^Im03u$QjP}b4YSXMzMI4e4HACHqe2* z13t&39rgKpIG4)7{A{DS^i=#+di}|~W;*|x!)K9b0UuS-YpL^(rBw2dlt8_C{sqHa*pWG1E@tcZKi6yDY?Dhn?iOx&=7 z1Nj0#<=Sopi{9%Mi#AKe=LI+3+X9*JGR$${u?Xkz_t&y<%0xFKlM#e*(Tt4aQXnIP z8^U$KB|R)*v&b+?p@#D&XkyNEu2q$t;FyI2c~v{comG;`dTQQN$SS61EBq?(x4~!F zPs2Y0{x10a;O~Zi4*Wgvnf7Pkvx2Z%NEVZlrNP3xTVGA`_E|Y*tjGl)e5r5eac~jn z^7gTw>h%rtxGBo1fIbZs{?P43a4rqivZmm%wQh*tplUdX` zND0q1eXuL45L&%_uzZMt0iJ%hP&VJKi$Hg)Olb}387F&IgL7^udpd!~XtM+DjUubv z5gWlG4IVde_|f`93kK?sS;o9q8p6;kVHts-7{_qO^$AKl8-G_1=t`$Og^H#3OZaO?3237uQ{%AGwQT z`k3>H@Y%M}wMLFI&28Yfgx?l^SNLfc!kKnUtuqsKm zlS=Z~u?g=DO@;69(wT+oW#Blef$Z$$En#&VFr|mem;*rTn{L$@2i^xhsBR7f!e%*e ziBNer`Lm6{heN_FH}hV<4S=DO`!+y5|3x_`)PpL@C^PBRGXC5u3Q}+njGE}NzVWs> z5u55s=aq;aMF#%zRGl|iiC!LfZ!2oHMXUt%yW+9MWyhDOz7YGoqW%Dnw-1TxE2M&D zt^WqUAMp#XMr{pQ7MrHTR0ARIUm8~QA3iQeeX9iDke9JUy3qi?w55;owzD&qFzfsE zK6v`p*yDURE0kudZcyD8%c!4KXphy0)(`3B(1SN?v?E=6-0;#Co#AuYQy2Jk;CF-H z1pZm@)8Y4m-v@qg_-DiK1OI&Z{os#<-yePf{Bz*XfPWtRh42T#zXSgH@E?Rf82(oH zL*Q?RKNLRO%q;jN5Wf-dE5jcNzb^c2_{^sq_^hgLf|jaEN?z9%UNX*wm(Fh}q6@Y| zPVv*yLCxYoPeudf|MyhOx&5Fu9Krz-U-*juS;bdlq)S=Xa6zz z*jZaW?+rcjEV7HNfDZ(k54Hx!i`2CMjUJjlI~{#`OlDL&z-Jsf!l!YbLTbb~r0{~f z<;~YrVAdj?wKvnR=7AHL%IK*Dc-N(CzP{CFV<#7b>%k?s^f;Oq)sE;dQ%d8ZS`Z1h zzCg`Qnt}!PzsN)b7DseFX|Z^!>Zn1*SzNJac&fJ%iR8DKJT^*Lq1`oBnxC7nO_y$h zFh7r zJPzXitp+7G8&hHS3l>F`q9ZgZ!Mn|#h#I>{IBv4c*2C;X7FkA7VsOve+M}w<)2iN_nhVJ)l`yK8dpTF ztfm5W0@Z;}!_A#*+?2gQ=^aiHUWha0EP2D!RW$-oyJM*?((+Imb>&G#2U(gI^+FS9 zX>&&NtrjEuh8%2e73hMV?iTd8E$FDhdz2m)bUazEjR;AxO$Q~#n?t1+kx==P*l&tj z0N#HT#a_TI-h2W$HPqbgh7_}P8-CyYZ;E&B#9Vm>l?ffjl{SQD3idE?0{7iV=oW+J zJqw7_Bpgb&0jW!O-{I5vf~|T9Ak}B9&m`h2BhlKyi5PzQshsws!C1dAu-Dc zn3*5e;|!YJK8D$@pZv-PF_@1vQ~-WHvPC1-IL4269KoKq13r1eICq54c&Edsxmm@; z+@$0|u<%yutMc4PcpEM6FPQcZ1YDSDIjRcJYX(i*@Q9`j-|DNkU$C@P8^5@=4tyHe z%*!0n)@DCb#QC3?`#WoHQnER%@MsO;?a@>jwc)Aox?*o9=Y3%J$!I4wz3Hm?KUke~ zM#i6ec$y(?GVYsH*T6MJ-qZ>lY@o+5qsoIX9Bgj`s8>h;^?2ij0C4lB0w_o6dgV7@ z@Uo!v!F_^N)1$0P(vq{AVNfwgW~OReK>w_6t4$AEUre&EJJye(vEgu%UcG1w&uYms>NLcKMvlV z@O#6*3qD&|VCJxwxCcIUu7!UM{QKdvWnBlKgAtUhIkfLX@LAYzTvJJ2A>}eSlY4wuK9EOu@9e^Huxj}y!R1zEZ5E;Q*n!17PV4$b zsHs*hyNulprG8;rk87Es?wE2v-qTf z6Dd<|z>JisbTIug#aw5mlWQE~%S^`&oPD-`C+>)t22`RsaroE{LCpwZF{j!@-~sr| zL=Jb!q!8$kEma6n#vVn>5XoJi6(Qd*1?LpXuaefFsITM>-T5V4Br zX(Pz0O2k<>DIBDv5($r$NO)gss*IhtOY#aSFu_)@Dzi7z=vB%X2QDh1YVq_qG}PiD zVcxfhN}}4GA65Zn?%!X-wdtW2uMc?4cn-Wvaw1urjE_P~5Ai+Zg8bpR1(U;D02Dr& zile6u-Mhz4`0#@zr9$z(*T*WJ4yaQ^{JEoyK8o@o%qh5IC_UW+auQ=3j-k6;i@0)Qm?e?F`&Cm7&xk}6V3XtNA&mZk#pR%i~0x$MVB(I`t zk?8o0I>T?L4~0#bPq<-Gt@bc&qX(>wNXaKIgm)#Rg%>Lm^UCDm6b{O*tA*m1fb?S~ zMo}!s3ltT@6PXek!Ln;yZHo|!h^qyW9P^Sjg1v}wbu2db6cHao|2%(6$QxNzjM7d^3O2_F&9R8^m zAruj71rbO`hXA6UMF>U2LxKpTqj~^Q-y(z}Vq-){n*gGLMF>U2lY%%xIvQGpP(haj6y|6cHZ?B9QW6I+|L9P(&OM1k-Vyl-(t$cg8id2%(7hQV@YU$X4FC<`y9o z5#I^on3yLeS9TjVh!z$h6cN7&B9M+|MjU=iix7$kc0~zZERY|a0*F=?ArukE2!c9v zjp8kWajh*vC?d-GIx32-CL3}1Z7f14A}T6GmRjHHi?TaoEA@9>AcIs8)o`o^O)<5s z@&rZ2;z(D%*n3bwQCk~Jp%}}P{*T47j*VrC#1ai$`Fycub|98%HkLv$mi1IDRSs*! z4FN5Z|~?79kW7eFYJyKf$)9vqcC+ z#6Up=>L`Xr)^)K6p@|*6H8nFnWh{zU1AO|r;WZfASArui~BM5ShJJTYB z;lC&DxxQ_L}~=1!Yh8h+^1y7-_3(| zJ#A=05wk`~4xuJ#@T35uk3|SY#126OYE-aI%(MuhhHG0 zix7&4R|QeFgjY7N%rFY`{=~R`79kW7Z~L*TD0#s4pioTUrwYYb46v~f zsxo-L*)Ut<%s7b$2O~l;oG+Cm-ueIY05r0z84sW5l%eC@XRy!(v-eyZGoct_2`Iqe zEKp4SJ9Bg-79kW7r3DcfEY|_oxbrMRC?fF90i&aDw7D2$5ke7BSrCD$;NK5pou5Sr zMMU)?bqux$p@@hVsbh#m2t`C)L9lbtjeiEX#tpRyp@=|fWXg|#$g&8bh-fAV4s-Mn zgws^U4YLTLh`>5?qobL0Nx|X4aElO%hz=1%ictW6ghdENL{}f7Q=T0_jI;=$i0C1R zKtmIp4#>6$p@_&7L?F+D&0mg12t~vIK~yT?Rccl~j}Z#qOpdY$p@j-RAruiK zA_#Jg8)Fed@!FUOBAAX`ix7&4iGpA$$(J0w!YF`0)*^%=qCgO=wYo;72N2^dLMS3; z`iN#y2ZK{5<1IocBIYQB8cOMMMHRf_ciC4e8S>BNLAwbyG@*#OOi2!-1l!7M)G6dt z%cHxA-~e)>4MQk~ah(Fij!;4-S%gqTEGrU`XAwdXu|g1m8XFusUtkeJ5phS6I`S<- zC?f7H5;55#gd$>nk%$6|5Q>NmMIxqHgiu6mDH1W&B7`DhyC4F#>I<%M(=0+LBJeIC z+o~hv;B<=+iU_>;OGKcK2d5imScFhSyy7GJN~@4zq6B}YMF>R%Ug;(DJvFjliHLMS5eJ{WaWPVg$PO3o`k3@o_e;;G|B79|u>hZL&lI{1^4VGzN-{$d-N zPz>#`k{m`+*1=!ZDddinAG2*3LNSa#6zE8ZITj%l5s4U*968S~u?V4vND@S#T%853 zadRy~C?b-J)G^N@gd(DiyITOcCoHT7>+)n%#2DiL9Hk`*o;aHJEh$}7Xi4Y2J7R0d# zXZQ?m5F3}z!xR#L&qAs2xRYCg8fvGhgk!9FL`V5_B}GG>sVEMQdnzgnYuvHZfWlsO zNXN60^mHZN3qa@(IF5>W%3IfqV^aPMEZ9iHR#TbS8fTI>8pq*y3owqy?z!H0 zy!t*F*Lr~-sjg3k%qVVoqL_?zNQ z#I*u^igYlLU2yD=E0chg@cU_QQ{1CA_L}446mo2ekeWj}7xWP;mDrYaF{#@QtMEmtrkB4#>Q!BFm^2-j5DbS)9|{0b{t zgF1q8L7KX|C@qZbJVi0KZ20}yq7Sl;h|8R-_L3&9P*>R;`tdh$DJuRF4>q0>4}%GZ zA3SGlq|s&kud(rG7v#s^r)0|JI_GLIydZspO^2k2J&K8jVk3T`x8mwLz-5@xyBp zH&T9>oTRFbFn?|@*3mCtU=zf=@xw>vC~T(1k`n9yuS%8wGfX-aMgx zKQ%etHEnQq&eXvpu(Bw3azXCM!38-Z#|$2yJ7V%+y^>_`q$vet4DOmUV#;X4ZJd`q z!u$5{H&;G&Z`Cc!wmo$0QzgGVf6vr28?{RKwamY8+up~U-11;KC0L#ZRmFs-mdYV?mKFa@3^XB=b?2^9a;MF zcCVLg7i&HD{WY7fEWI#!>aylnEg70v(D|_;`<~nV^7ji*sr>znl^>nlXUF188!e50 zJmJwBZoO#qUTgkMC0^RLx=i`{ zAARxZ{W;0^?ayv}e9M#H`r*U_wJ-Sj{^WhHy!w0Uss=M=milSc{Hf-A*yT%3-t>Of zZRY%|VZ%-+G5p*=&H3tCYv$#Bx4FMLANT!5zxO>n=`nMj-F?vY+3(kR*PKs1Vec{3 zD`t;2=ht48-J<&|yPr4b^*_9#cJ<6FE1g>V*sgEpetmY2%(;!%zIoD&j;~c4{bu?n z``&0+{^pFbp7?KyxMv9n)B>)ZrplZ(@&Dj z`Dv|EFKj(8?E!OM;*syqSo-IZEOUPMfK3aB^_ykm*YxnJ3qJbhi&p0Pj#qx`kk)J4 z;*_6%P0u|yGxe<+SIy4b{d(R7sT+=Yy7MJ7+g+Hx@%yH$M!x&z^!Z&9Z=JmM>Lq8i ztW@UL`p>_7>4*+*-J1R4RWH}x*6i&j57u2WV#!74&p+6s+bz`|sQlT^X^ZBJEZL|1 z+ndkpx%aE`=6uMvTd%D@yGF-RA2&Jeg)bk@tMJE~hgYJ>Dja{t_LtvyxMPjxzb9N?bL=VqS@B!%{po$j-F2BcU-H=aSDt+F!hsEQ%axw? z;fgPp&+JlgQ`sB;thu7bfyv$nb-tqH5J=&V9Y%e+TBA7CZda=qhI}n7`+Sgsr32biefU z5AWa5b=1=f+pYX#`2PEcv^sfZ=iNIh#<#x~`?UQZ_g(m2jk`?w+|q0E-C6aPC4Ri= zqLZf`H|6$ME?f8Cuix2xmO0<^%I!_M_n)w~!EaaY>onzy1&hnHy5P7CFMQX!-)|GA zmrs3r{})%4ZFBg9Uz%*5(s=8?H}D;>X8Q9?w{WM=d~ujUE-z3PHlJG z)h2&t{Pfz2b#=bE(AcL;(^E2jJ!@IoW50g6c2~b2FKW8wt_8=ft~&kVL4EF?`_RD; zZfG+1juIc$efH7Zr+ZbXU318cr+$BOl6Py$lH5aU@_xDbwkN-NJb(M6LvQ-^(VGS@ z8ushnw~n9n-^N`Job!739jDxU|Mv}F8r8q`1A87ktI=DV&b{^Hodeoz`?&7m+}xIr zfBf4$sUwEGJap;BRlc0n`|3qad$hUf#_y_}zA$0+vVr$}zp~-fAHQAke#Ud9$5cJz z#7@Ud`1GugU+90sJ1-4v(k!#`==XZ{{jeo*?;M{1tD`{L!D-Noo`I!lGu3dHY1+PAlGyCqX57f$dx!RnQ&KPycv>vC#K7POYw+Z)M zKKA|*WiwxWyWPIeT6}PE!fLN;uREKy?D$%#-jgr=_^qo;^;pq#)Ty!Ll;=A3YP4kW znc1h-?exJp16~{W(fIEBKYC&HoXbM|Uw2>P@%Nqe z&|A5U_c!nMe0ra)FSI_b{jKA6KU5-de!bkb)1OJGUTI9q^94;NEPtgz`EmdK_Qhe1 zx1`_Rp6>Vc+zv>7t!cZ2W$+=~;NZ5%$p z;QPJze8&rq+w`@${_^=dpStCdKOPR_jeP#^56!*cftFLvd2#Wz`fs{s?K_X3eR^i! z!M#^C=^DmgG4l0kQxk9d_~5SAYes#3_%&mnSzq3MZOvz%UGePrUTr^apY`G|!{%*o znBDL}gKyqw_7g2GIQXWC|FnBLR9^2b#&AcBh5x@Y{K>204i{1b0HxU}pK2k$-R%DQczIK6l0 zOXtjeYLJPx<-1UVM3LzdZpRp!=*YG1 z_3+fW9}YR~%1?F-T5!YEGgf~$@8+@JcwgpSZsKF?W6rOrm;dQSpV#bR>@~8@4bS~} zxK*XZQRQEHC7yhXNl(U8pS*s@TRC5rDpP4|;%D8mTJ+iU%3~LGd+FSA@wQ)_cyV1L zAOB!p$6szKIX5i7e{W8;**o5uI_;tgcfR`eQ+X!bUze5rddKANKdbQP6HmPO<;DBM zxP-UfT-$WyF~8oP@W+Z~bPlNvFw&@O5M7 z4PPc7JLc@S>+im6OvcHrH-FQ;M2jhjmsL95l#|<%8l61*@YrgrOP_Xl`V=+81xzes!rce%td|!-+>?*o(`Xz^0V~Jhn~Bz@yS1j z%a1w#a8a2Fm}V(3cvHTOolJXV;%DrdUhV3--~3qrV^jab*Uh;pZ|2^fpX+toFm}vR^RvGwt1n?>_a`^wC$Gcwa*QHJ@GlLEUhfP??zu(ze%sD zKjG{D^xTC1_9ch@yYt+f2g2bQ``qn(@h$0m-uvCi_(6T|XV>RtEL+-f!FY&_w?0ZV^Kf5eox9vgQw z>(KQ2S+_2}dhdpZ2JEjn{^tAp-=6WMIX8a7uu1J^f0l7Y+PlA2uJQUaJD)94rh2dW zt*-Aj`p5i*r=Rh{yBBq8IIHZv>&{<4>8Y|;)Jy*8*$-b`+x^jAKTNolvzzbgH8zhlx)x_tMuyUbm2 z`p8KW@*3x6&zVs&#)<0$FMU+b@Pfvvsf%N=Ihr$d()h*`vOUge2&Zv&e$L2(sW}XV zvlI!jA4oc`aW?ORQ`AyMA`@ci7t6*GzF6aY?t?7noP|l?;x08av*6o>dMRy6zius3 z+qO_ox|EEkIn6l}<#1Z0hdC|RhdHh82y7=W!z10h7me5x4W|;WB*cEg(d1XfNI0r=#<(~s9y-jyvtHG5{@e6F)qJgIKSUC?5SutTndp8iz6JC zHo9t&aQOZ}LM#C?EJ+92oqc~a9L`QA#FhlYsU8W3Gjs_tE;*sDKOb1tCK?Wx$R)(e z2GUg{5>8De!c{a@eL2l;;MKa2hEYv&iX(@}KUChI5*dc?3rjpGJ{zP%WXW=x~}SnLUAU z8b`uOEk-z8y_*o*5(p*B*fTbvVHD&&Mg@1gv(DqCG!T3yh7JE5>9_`6Jn+x{Q9h0(cOi^IY-G*kx5to zNH_zO40Da>V}9HVV}!$DubmM44M!8sfJit4l?=xT9BqHIEeDTL!{MB#WV#08GcXbk zx?$*I4^I0Gcy3YGXgKF98P-!1pFxpu1}hoUpYH1RC@MiXK0}mDuwD#~gfp}l;bcX^ z85#*^n38FPBi$G0tWS@|XE?4T#NNlzq-$6toDoW<=yqeIk_o13L?oPSCBxR0Rw?

iXpDZs@GS>6)Nqg5ivh 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%0A0QEzLMl5up^P^e@ifIUcs3+wb9Xmy>? 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 z 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

;!h zbGP-%1)(PN6=ueU)^BfCTH8WcN%t;?nM z1e>&qOkC9;YwL-XU@(;=6~dKJKUCEd`_e1Kh@@9SiYth9hn9-PfXIhtk(CLuJci0Z zwaB9@`Ugh|gKp^~%HJiplqy@UTy!U-VhKN;c~BBWhDwdCZ? zw2mW4Y2ni}IAU39uHZ*iL6HmA53RSRs>#wxzj6RZ^q~;Tx_m`AYKV)7oNFI9VAz<^ z%(~^JMyHIAU(-MrAK$8yB#{tSDQ5W4(+Abk-ujX@of%7Z+Mmuel+03T4iv~_^#ac= z#B}qTTp(Q~#*a(aMGpxLIDRD7Q6FVz5*n&laH~nlm!p@(;HFIVtdf_zl@eJy9vM0- zhpV2CTKbyiS=h48#Za5ukdLoLrIG}tu8ql&npK{Z^Y*1q6WIyDD_as8vSaR4S_?!x zD#lF0GN4U8aU&8taD=9UZwBbgg|&CTpk+L}`X%29pbm0H1+vqWympb!>m zlffv|A6Pm4*z($|(d5h(D3!uOer5p|U$!l~OSkBr-G$^z$7WdZs$RlrZUISxE4P+; zj@G<|O!v#eEyA_8P&7u7Ejw(~-oZPef+?N8!YNE2ZuzmT1LGvwDcdrZZJmjR)_z_q zDGXd+NKBccD+nv>H5Df{<5W|%4OYxAd(T~ZZG-KsY{wGFido=vL)2^SqBn0_%5ngVC6+!< ze5!o9ZYZIo1i(j@=>H0Z4|Q97Y5)r)=Rj)0dj6E-0Y! zdo`qF#&57)X5jJ~JGj!##dx1$7kuYoQ9jf3cgal4!1$u&yCaVMEBpSvFcB{$F zDL>5IL-FymNMrC1`92p12fpXxViX*HoGMi%Kfx!M7hY%g7!n0IxaaBrkpfyfBcAvl zE1kjNAx8&-8~hBe0&`c1%$*?66{*E}+XL}xtYHZPsT^M;dVSYyfMLBFqrC9nX*+gY zxXpBSRq*`(-2YN3t%YF8|6&mhk|5nQg4cK#48Cd~6O^0A1Cn~{j-tLk=PB6Xf%?iB z8{kLcHV0|i56f{)5t~R|(=u|WyVQ)JVJlBbRA^o7G zG+ZRDb(gY4D7j^n&n+JoO=sm%ruDo;2CV|0F*MX7)tRCyP$v12X``>h3&!6ZR3-SL zWL61&n76Slb5h)F%`$r(?p4QhXCZSmvDY=cUb|8<=(e}Cj1p&5{d-0v7RqIcgJshQB^hg-4Nf5=A)vPwS>Uok_1XeGoGi|^EHi{?nl&r`202u0TkwFez(L6B8V207ClxVZq=8alJ>xp_Hm<^(cKTKeqM zyc~kYo{T(6SA~T7FS*7**4npL^-~tUzR$ZXK0NrIPCr>C8cmi-Y09KhM4LgD1TImf zFhD2^Ec)7H(VhC%LDX-kQLG&83(Zy1v5sdajJimCfw?7!?h7lfrDlx{q*=S_b)uE6 z+&y*OO0hl4H#NF+?h)Hlzv+i8PD(4N$Sqz`RKA=*LWmlgAjry<9xhR44$&3s9b{It z;6e9rsX}@K5;jTEupo}QwxFq;@>TvVTC?UYh(VdR9=M4Ar6;SDCLF`3+iwzEDS5|$ zjWk8sVI$K__cI1{P7W<^G0oJNcPG)V0E7R?;m*MY!ulm^;8+ML?pSkVPInZ!_+52r zc~1SHd!0pD^(C*ON0I`N(qljVCjfT?Xs!^!s^_{DolPgNn-6Yu?W zJuFk>Y7N1QLZ_AF_<6smNNvbc1(q(qs7Pl>RFa=Y`5ce>MMa7>LD1?dQ9V&Wy(jwui>q8FW-N4#a|G<|C$-f_s?TC(2|mlyhBORs{MWU!>L3Gb_fH^ninXUtD z;q0^(`D^LUrN!i5#!<$hYhmFj~Y65 z_}~#^SYJZ`vYQ<-(ms0Zzyy2JsF4E)j~>ldLeYEar5KqscvSqDVIxP_M~oa}$B*H| z#*7&}hz-&SP9DNAYVhchV@C}fY#%f@eh@BrywN^>h3{Km(eg;XUzU6`)OI2XFF<$IgUi=~Y{u7=q4bvq<2(1_H#zc?gL6_S zQWj)0jba^M5WRsJ8R-()d&*4-9GR77q6!=P7RleGFc18qA`L9(1`QpHpB}<5x{{d) zeo>XoMDUBML?(iNOht-XrRqy1Q|JRkNqkTKvSJA@c8xI|KWJ>rGC)Udd6N)EZ*eMR z3HjD)p~8EKd!Bu(g>KPZdKf%A((<@QjEQ{9Pe5XUCnUBqpcMv+Qq>7H>$^@}m8#R7 zI%+Mr?__FvlB-GbwJ;k)Okxbkn2KR_W)7AI;@)?=J3Y^dDYVQ~=9D2o=^{1(Ix?|$ zHjA#sCYLz@b`r!L0W|q89P7r`M|Bi$s}%nwKD^&Ep>xsnNwzanP3eo(@V@JX74jYg zp(2PD@lNEmXjk`gNe`8vKkpd2skb6GZ>#xaOKoJO@SpX7>v|2NZIx7vx4ZF zO`WN)p=e1lQMsi3Q8qP&l9D6HQgt_c6sT+li7Rm7EYzm~7coj%;i6u~w>vniN`BL`dUH=0&w-OAUt)ysw{_+6;p!|sryB{SU?fJwy29?cO&a@>Cg%sm5PJc z`}BxzPb)BS*BlOyF~Qp7se5*&GNAUf*+Z4pi~ThPc)+THVm!p!?2(R(+7FXF&>Q?kIkmj zQ0>#xF`Jy9UEs{aA`L9Uki#=ii_lwh8=B78qp}hR{TTdMFCa4N2}))<`$E|sG*=XFo^8tCQ=7@z9<{W<*k&=Yz8j6ihJ;%#pcsuaZ!*O>ly=Cd zJ=dM*QUfi?v7>ytngiCBIvGhkPfoGwU;?6}<|PA>>L4mF?=T?)Jky?$orc>?u@vt1 ze5ckyK#F=;LDE*9!VKJh4Ktjinh*=Oj}^EhYf8q{{G5E3GK0#XQY9J?1tbxA8huBF zvbBAy65%@s=W#tg6jY!N$FuRhV{^ydJvNAr zn}CAtxEXA)9XA8^?6`F+O&yKuTjJzZBTD2fjTsn5V#}!L6!d|y%0qPaMo8)&8iLpx zaJzuekch&WWOm0CauG0R1HBZCCSJlEWN*ngzEMw_hf6+F?e3iE4orXC;mpfnT^9j} z8w(rQ(o zAQ{e-u3dXF-@k7dtZ|--jn#e;W#y#iXXf~aq57fBZLZU@-~Ai zmCzn|i6xB%H3RF4Avy?XPxW9P)=>)>@f+HJG`GK^095FKARvVh%MR67^?=jZ64ap@ z)V3FujbbPV3C314){M6sVWhSd1<1zH`Ebmr1aL(L@r}lMsUNCJ3rwC(jxRB9qsPvy#^;N|O`CL=rW3q7y}Mm#m=}j|WI6 z$U-M?`6i1wGoA>9F{wCHUQ{%?sDz1%C>@CkWn^7CJ%uP2QO$R`%-|@|4M-5oP?I>* zG|ZHyvGO2223!WF^u2+a7VFsWz_6cVR6-LV+H32y!V_TQw04H<@Nt^a*KWG*$9r%c zsKzubeniw*D6;>0jjcDKKJ-6QD#N~0(mV#%uwZ<4Fr<<5Y0i~cS?nb8okXy{oD`G2 zv2Tx=SIY`c);%XNOj0R#vA!r!?vSLi%b(mDzDJsRVR=tsJ#sZdkvf%=rEuVwIN!=C z5tu^yB;?i8nGrJY-}Uzjd5 z?jRD0(`ig3lJKJNvaZ&J_XI}KhX8l!`#?EE5v%YBqed)92)1Y8ct{rdiSmT$=K=b+ zOu4XwUfg|b8g`jz1ymlCrGWuaRvdM02`%U<8^M}SIbse9swP-cHCSz9)Wv0kiL|P< z*$MI~yIVpCHWr4dgdk07VssO|bOTi|t{l8rlUINX`pUtJHGMr`4FvXNw~`aMB;IPP zjzKmRv99%mLrKd76<$V&xLeX7+{TfH5*xH3b4wDOLFg=Di3R+d@nQ{uhmc8)B#!Mj zF^!%=FoHDW#ep>ez`+Z0Hd3&yDS;Y~NY#g-xENp1K$4{2x?Au{D9R@nC|E04AE{7G zd0=sXVk#9S3Q2SFR7mUoRApyWKx~9eX{=?*G7Sny({_e#$-IY8ZzxdEYXn+b3y

j!nw$>38WG$f(Z&Fjur3;Si0&49rZKw{y)&4zin^eyi1|RuQU{`Yn;4~wh z^1dX776UiOSD1aGVNLF${#X@uvMNa1#M%;V@O)5JY>^FvmHZ*Z4!kt#?8+eKJE|mg zr&(1%-N5I~DxeKeCP_PA+m4cq8>Uz5C!k$wEJ&)>C}VHloALG%AIThms}bfvOQd91 z+pbVeT~WP}pG>b4h(C+VQlQ#mQs#6EwcF|%Q9@S7N${{;;1F10W`&!oDhc`p!mt)rh!8?!4@+bYTeXM zctD4Zu&i_rsK6l3{O%k8Y##7*SD{m>NiwIhowXmc6%ws*V5KOp;L~%eS(bqcb!Vay}4gQ(knRa(Y0H&-qWie=tOHsOm{Yp5Etcegd8r5&0y*#nN3Jz zMd9kl*_Rd?ag|FH!@+vKgmez zacKhX0+w_R_|6HOHJ=0mgkq$i938JhA5}j&trm2o=)IJFF!?@On8^Lh$B#Y;g zuv#2*qLKBOjyz2^X4tLNIIv$tHa~*-LF$)P4-zH)@UFBYBq3mctH>F|dvb!D3cm5}{Km(S=13`w>>1CtIT=%X3%Mz^@A&wy4Q?Fa*AlVpt) z%Y)Kl+7}U=e1$G*3hKzp#Euk8gS^B}7AM1jo5rV#0)3Hx0Yina&KGQUQPGV{&mYEj$!P*J8 zvW3bfYuqI*s%)tes5^Gbm|0RKR_u=JNMKw(+xVS*qQbDo7+qDpx^YHlFl5EKG_?!` zZyBC&(MS*?#fDfeRCHJK;6YGVookklhLrekzqDN?|EUcoEBiiZ_Uzx#mcPbJQwT8V&>W^-K0BdT+ZeF}61w#STNH1;zqPlwHhaMrcXR zjT9!y&|M>sYaHdwV>e#s_2r{$G!^${nT6a;6*fg|RC^&ts?$SE1Q$lSWDV19I{9Ey z%zQ9x;Dt%Br{3{U<3%qhPq-_f99*t%~b`vvK~5Ub%JJ~q}a^;7dd%%lL_*xJL< zs@U?{bk;d5mdk2}mPqg?sfygqERxCvomCp=`q>rU;ItPJ_|)K)s*j58f+klQsxB%v z=&UX{;$AGQI%2$lpf&*T7!9pB^GdIlJ;;_krYZgocvt<44LCfng)QY zO5f-MPBdcEU9zP#Js=YBbYEVZwBn5qL(qVSEgu6O@PU$UcR&>}B}HmeE?xrzVc-1v z_?#wl3O01u<1ef+>v z(ZL@yhVqH*tw~mwLs7cEwA#b7G^HUaiWr}J&eZ%e9+hgHx?yGHKrN1%r5R(+g?m(s zHi=ekHl$`}6Ap%|>dn(uMOO}u0V9o^Z=|dnT%c@}DF`_lBS)D$Xvqm_N5uKsL**_c zRciLqhziB7j6vdP$Vk!CHi4Qg0{iys8}Wql2tGUy7jYtZIa8rn7}rrSY#)bMW$^02 zD{#=T4f{+;;e$!RYgv4zSK5e(s)fx>oK_Cs<#q)Oga(iRL9IHUn6$EoqNszVF;U4e zHaZjqiv_G{ws_)q_QKkr!H`6AP`<95)(Lk*1Fgcu;zSaAVy8|zw0!aql_ncSwT5Oo zFr`lM!+QpmCL#ed(=gxO!EA*xRS879;Zq2k%T*5GR1`S(W9^JQr4Z7Vpa=Eu$;y7# zf~}h{j05^$!KS1hEI>vs@&VoggcW;7@ZlZ?hd!PoiV-TAWez9A$lOtKRx5Sd*sfAk zI}}8VWHr=I;(J3NgevnN)E_d`djQK3R5q&~J_O|mB@+F4-T8~fR^peO4E|2t&={#KJV z-1NWLYH-4^=2u_3IzI?!l^|h@cW||D$B+H3$*_nqw>N*e`)1P5MH;`KeP~+r?i+EV zj#z>xD9StrcV$$y^_w$B|2#5evj3Hmy{d#Hl(p0w`eIDmpbaIuZ@>AKqTFI|;}(D2 zYTBNk-deM#=e2V$HmiCjGU!z4Z-)N3_LBh z&GDvmdu;A-`{Js^p<}vMoqJ^c%G1qzJkn%Ljf^KlXYMKe)ycNo6lDd2>%HXguK7FL z^{cmL%-x+ITiYi!oqg@-ycgDf()Y^?0XGAn)~+zPQ(G_Z`?k@Z($8Ein)Ks~XS;6= zJT3OziLtFb5 zPj#wy?sqW5A_n)z;^z;PyEi3f)>D%M@7`*YQsvm{tYafS_%r$PcN34FZQLJ+lrXs4 zj_esFYEDZYaAM=v8_OIXu=;35pGxhD_geVYPyf`6{r$e8^a0OUyi1mt*&`-KLQHgrs^_jS{;PrZ96A?MEtM-*i_gUiTn=yT*ua?0%+^*$S7d7|AyrNn!+ zp7N_zb>`S-zpio#Lii7Z`)Yww?8&&|SL!b9fA6t2`_k^;EYf1tp2}a`zH#{4@IiO` zD9V$?DBVidfjb9188)QF*_RGfz4PXlTjMKL`}^1zPw(2cy28`9svT97cNkoQ@;`;W zy0i7YK24j|Xy*O&(#XX{yMNy3z}eHQUi|yfQ|$rgQ=IT!J3Vt^&2INvRUP+>_u?DT zUtWkf@WO>@ZQ9LSo4j}2n~OUt%5VmE{<(+~)#k>ONqc00SFtzNw5W3^-RqIR#;lv& z@7ZVH?Yw5UqHJSudk0Lvl~Q!vPuqPQJ2E5x=yc}!vyV2b^ZDVqPo&qqcK961;q6Q5 zMhrX}GobRBMSr}~Y~)|?jI<`+8%lgG~B+Ap=tsCYH*v)QkV zJp9%9TJ38UpQDU;WYV$&0~*dfbgn@^McK#Tyz0K2v#!O<%cgw$&#<;{j!fS4j`z`{ zmZVk6OOyP&{psIHQ5u(^bY~UoRPN`fpwd4CPFlC>+mqM-IJ+_X{=E^s*Ds0N{o$W8 z{#BG|4DOXumEU@@-GipSzWH!-`|ZJtd{+hi*gtc_!BL9xJA>Qt(U;BV zcWyT0*HJaswoa|N@YshbwxtWbYuPN0*yAOhf+zX$l9X=Lg>ffZowYtcKdji4)6GY& ze{cQON0--5FPqbL*M>nCEyERM1A{BOb5eNoqMhUH!S9BTx)%28lcU#P@QP^}wD{_Z z#aSorLLb~=a3|6~Yt;1IILC*h7P;_um2--+hQYO(VqeCk6C`*mj?|*nM$@0wW z2d>O&_}ADbuPVyOM=0H#&!2z3!o_1lf1bQ$`x7%#``G_U{pxJl?OAIp_WFCuC$+~a z$|nqN?68HaziIG#=*M$*+Gh-FyJgGV%d@(spP1L8=h(DE;FFBR+nyfR&J?3 zD`QjDZNuNNwVuBI&9x`%!Lzf8!5y9d^@F{Cb`~MD}m$>u7 zluN~izON{i%TT(Lo_%LwoqFT@e;YF(Yh=LSa!2>ADp}rfaY*xXe@}X^`lnwg$|weR z>!e*NV&pGRMB{q(G!6UNSpZ+Kc!{L50hdp8ap{giJz`^pxTTgA2c=N)^ukzH!t z_x^b7=+`FJuJ#)AkCsKU!U0a#?|PljVCRHye3gQG6>BzN!ZX`&1q_bHes^3rfB+ zxauim`;sLg%){qRfG$l5zw?wI>i7wbyvxq#Jg ztVx>=TWB_ei>N%NQMuO3!bYF(Tl&k-8vPP+y36shIl=uuJDt`1^5lMy-@h5${*!O` z&)vSJpj zsi=P^wD@5B_Zw3q!zNxjV2!S)C?7DmU*Gz?Q>91xjajpM=oel4G#Yw1Wpm$OR=0Tm z`JZAOPaeH70{RMeyv2KW)!~O4DleUXx8{{yE!wue{9Dq1y%oAto%8(EY4=_T{A&i% zWpE=`r`}(3v&N{lW$!N;vHb7vzj>v7*P4 zbo-?1)84u~DD!;vD^+8Bdn{@6@s623#gi4~9)oMyveDyD-s|n(_C`HRz4ITOoVcuP ziSCnD|NQ)x4-WilX}%flQ8min?NVR$+xvm#;K{Bhi|qLE_@&67p86>=^3gw+TT+`g z%^32mqU>aFzeGl!@()h^@!+=oua*Ah%Q<_xmZ^L9_J04~yW001bZO!wMX6Ao@HIVF zdhh6Wv%kBze^cofett1!O~>VfEVCN648He9x2|jM&H}$Mxa9g>&u4bMH{9~k?ud!q zrz|^nO*WL{IHd0BhUTN^zC+;pi{`|p_^Cq7BCvsVjI%s3w zU~q9;w$6S(BIdPb^&{%E9x=O(^)KI=mukL{8M1HX{#VbQYKL}}!JW?f1k z^+Mfq??pBr_h?$>*B8JJV{lFOHG8|o>56-5+?@X0=iAp^tJJeskNB167G3|UQDU)I zs|6~`9}KSMi36E8%3e>{v1`!jO8=R(zeuY^)4JNq*V`4C7@KhJh(%EbVR5F#+v~;A z|K6_rcv6vr(e+PPFW0d6sj8DLC+5E}dyA#^^;ISAD9YOm?(EfXd+*lT`)Y5{4*#gl7cvf1IQV=0-xQ@NYZ1yZqn=gX+b;xc{?>BYpg# zPrqVtmCnDhZQJ+LPgpLs*>dy1Z{5-z%WnR%!gBMYg};6|Fz49wiqfhMrQ4@e>BR0| z+^z6P=8sPg{AO#b`l~)JdoH2P;!Ptz|H@In-B?AL$>5sYPI_$FS-;Z>V@55oEZN?7 z?^n0e%MSgq?1J!j{c8rVj6{Er!43QL`(kCMK^2PK{jSQ> z%8G7JZf*I_@t3;Xjf)xLXxr%P`M>XlJ;dOal-k)le#86UcPKeJ=hTbc7wtINW$(-b z!#cd#IsS>O)y_jle!%fC)XXBdu!6&kFyt}U1e}>+P|>9SFw$= z-?|uIW#{_Hch3Fi!`>I({5SgjQh^`TY;j-{>W#sDQlw*lL33+Vg zo1Z^2C#3zYR}<%-{9)(!ic-5ir90>KV^uF)8R$6jN5dJV=Q+Ci6%8r#_JD-F1AWg- z>9qKVP(?{#aPvNF`q}LsGw0N-_S=o!>o0_CY=6tg5^;4|@{YTuFF*6!5=Hrl!8MzE ze1_wz(p5@St6#0pH{l<&>a*=y(f%=BIlc$3E?Qcv1=97WbS=+KTD|$}i&H24`pMC- z=Fhc$Z_qDk>%xAnGxOe+@Bdx;80?(M4DOl0nmdYT#)SLER`2?3#LLguDAsFAsV&d# zeZ2hpwUx($$1BQZ2Dj?0V{m}qf!be04}RP0>%}MUy*ap3scBzt?)$;@%g6e5M*e6; zoW;9&Xw`tS)y`bX44C)btF1>p+x_ ^2kd`@UoI%{L!!y)8*mb}_hKCwGrIJfqLa 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

b8B>52#S6$)1l-zpy!TR>b0a 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 z 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�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