Skip to content

Commit 35a3e31

Browse files
asioexec::completion_token & ::use_sender (#1503)
* asioexec::completion_token & ::use_sender Adds two completion tokens for interop with Asio (either Boost.Asio or standalone Asio). asioexec::completion_token performs the most basic transformations necessary to transform an Asio initiating function into a sender factory: - The initiating function returns a sender - Initiation is deferred until the above-mentioned sender is connected and the resulting operation state is started - The completion handler provided to the initiation (see asio:: async_initiate) has the following properties: - Invocation results in the arguments thereto being sent via a value completion signal (this means that errors transmitted via a leading error_code parameter (i.e. in Asio style) are delivered via the value channel, see below) - Abandonment thereof (i.e. allowing the lifetime of the completion handler, and all objects transitively derived by moving therefrom, to end without invoking any of them) results in a stopped completion signal - Any exception thrown from any intermediate completion handler, or the final completion handler, is sent via an error completion signal with a std::exception_ptr representing that exception (this is accomplished by wrapping the associated executor) - The cancellation slot is connected to a cancellation signal which is sent when a stop request is received via the receiver's associated stop token The fact that invocations of the completion handler are passed to the value channel untouched reflects the design intent that the above- described completion token perform only "the most basic transformations necessary." This means that the full context of partial success must be made available and since the error channel is unary this must be transmitted in the value channel. For a more ergonomic experience than that described above asioexec:: use_sender is also provided. This uses asioexec::completion_token to adapt an Asio initiating function into a sender factory and wraps the returned sender with an additional layer which performs the following transformations to value completion signals with a leading error_code parameter (note that when configured for standalone Asio std::error_code is matched whereas when configured for Boost.Asio both boost::system:: error_code and std::error_code are matched): - If that argument compares equal to errc::operation_cancelled transforms the value completion signal into a stopped completion signal, otherwise - If that argument is truthy transforms the value completion signal into an error completion signal with an appropriate std::exception_ptr (i.e. one which points to a std::system_error for std::error_code, boost::system::system_error for boost::system::error_code), otherwise - Sends the remainder of the arguments (i.e. all but the error_code) as a value completion signal * add ASIO tests to the CI matrix --------- Co-authored-by: Eric Niebler <eniebler@nvidia.com>
1 parent aacec6f commit 35a3e31

11 files changed

+1807
-1
lines changed

.github/workflows/ci.cpu.yml

+4
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ jobs:
6767
-DCMAKE_BUILD_TYPE=${{ matrix.build }} \
6868
-DCMAKE_CXX_FLAGS="${{ matrix.cxxflags }}" \
6969
-DSTDEXEC_ENABLE_TBB:BOOL=${{ !contains(matrix.cxxflags, '-fsanitize') }} \
70+
-DSTDEXEC_ENABLE_ASIO:BOOL=TRUE \
71+
-DSTDEXEC_ASIO_IMPLEMENTATION:STRING=boost \
7072
;
7173
7274
# Compile
@@ -148,6 +150,8 @@ jobs:
148150
cmake -S. -Bbuild -GNinja \
149151
-DCMAKE_BUILD_TYPE=${{ matrix.build }} \
150152
-DCMAKE_CXX_COMPILER=${{ matrix.compiler }} \
153+
-DSTDEXEC_ENABLE_ASIO:BOOL=TRUE \
154+
-DSTDEXEC_ASIO_IMPLEMENTATION:STRING=boost \
151155
-DCMAKE_CXX_STANDARD=20
152156
cmake --build build/ -v
153157
cd build

.github/workflows/test-windows.ps1

+5-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ if (Test-Path -PathType Container $BuildDirectory) {
1919
}
2020
New-Item -ItemType Directory $BuildDirectory | Out-Null
2121

22-
Invoke-NativeCommand cmake -B $BuildDirectory -G Ninja "-DCMAKE_BUILD_TYPE=$Config" "-DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT:STRING=Embedded" .
22+
Invoke-NativeCommand cmake -B $BuildDirectory -G Ninja `
23+
"-DCMAKE_BUILD_TYPE=$Config" `
24+
"-DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT:STRING=Embedded" `
25+
"-DSTDEXEC_ENABLE_ASIO:BOOL=TRUE" `
26+
"-DSTDEXEC_ASIO_IMPLEMENTATION:STRING=boost" .
2327
Invoke-NativeCommand cmake --build $BuildDirectory
2428
Invoke-NativeCommand ctest --test-dir $BuildDirectory

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ callgrind.*
1515
a.out
1616
*.code-workspace
1717
sanitizer-ignorelist.txt
18+
/include/asioexec/asio_config.hpp

CMakeLists.txt

+27
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,13 @@ if(STDEXEC_ENABLE_ASIO)
433433
set(STDEXEC_ASIO_CONFIG_FILE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/include/execpools/asio)
434434
configure_file(include/execpools/asio/asio_config.hpp.in ${STDEXEC_ASIO_CONFIG_FILE_PATH}/asio_config.hpp)
435435

436+
set(ASIOEXEC_USES_BOOST ${STDEXEC_ASIO_USES_BOOST})
437+
set(ASIOEXEC_USES_STANDALONE ${STDEXEC_ASIO_USES_STANDALONE})
438+
439+
file(GLOB_RECURSE asioexec_sources include/asioexec/*.hpp)
440+
set(ASIOEXEC_ASIO_CONFIG_FILE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/include/asioexec)
441+
configure_file(include/asioexec/asio_config.hpp.in ${ASIOEXEC_ASIO_CONFIG_FILE_PATH}/asio_config.hpp)
442+
436443
if(${STDEXEC_ASIO_USES_BOOST})
437444
set(BOOST_ENABLE_COMPATIBILITY_TARGETS TRUE)
438445
rapids_cpm_find(Boost 1.86.0
@@ -449,6 +456,16 @@ if(STDEXEC_ENABLE_ASIO)
449456
STDEXEC::stdexec
450457
Boost::boost
451458
)
459+
460+
add_library(asioexec_boost INTERFACE ${asioexec_sources})
461+
list(APPEND stdexec_export_targets asioexec_boost)
462+
add_library(STDEXEC::asioexec_boost ALIAS asioexec_boost)
463+
464+
target_link_libraries(asioexec_boost
465+
INTERFACE
466+
STDEXEC::stdexec
467+
Boost::boost
468+
)
452469
elseif(${STDEXEC_ASIO_USES_STANDALONE})
453470
include(cmake/import_standalone_asio.cmake)
454471
import_standalone_asio(
@@ -464,6 +481,16 @@ if(STDEXEC_ENABLE_ASIO)
464481
STDEXEC::stdexec
465482
asio
466483
)
484+
485+
add_library(asioexec_asio INTERFACE ${asioexec_sources})
486+
list(APPEND stdexec_export_targets asioexec_asio)
487+
add_library(STDEXEC::asioexec_asio ALIAS asioexec_asio)
488+
489+
target_link_libraries(asioexec_asio
490+
INTERFACE
491+
STDEXEC::stdexec
492+
asio
493+
)
467494
else()
468495
message(FATAL_ERROR "ASIO implementation is not configured")
469496
endif()

include/asioexec/asio_config.hpp.in

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
* Copyright (c) 2025 Robert Leahy. All rights reserved.
4+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5+
*
6+
* Licensed under the Apache License, Version 2.0 with LLVM Exceptions (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* https://llvm.org/LICENSE.txt
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#pragma once
20+
21+
#cmakedefine01 ASIOEXEC_USES_STANDALONE
22+
#cmakedefine01 ASIOEXEC_USES_BOOST
23+
24+
#if ASIOEXEC_USES_BOOST
25+
# include <boost/asio.hpp>
26+
# include <boost/system/errc.hpp>
27+
# include <boost/system/error_code.hpp>
28+
# include <boost/system/system_error.hpp>
29+
# define ASIOEXEC_ASIO_NAMESPACE boost::asio
30+
#elif ASIOEXEC_USES_STANDALONE
31+
# include <system_error>
32+
# include <asio.hpp>
33+
# define ASIOEXEC_ASIO_NAMESPACE asio
34+
#endif
35+
36+
namespace asioexec {
37+
#if ASIOEXEC_USES_BOOST
38+
namespace asio_impl = ::boost::asio;
39+
using error_code = ::boost::system::error_code;
40+
using error_condition = ::boost::system::error_condition;
41+
namespace errc = ::boost::system::errc;
42+
using system_error = ::boost::system::system_error;
43+
#elif ASIOEXEC_USES_STANDALONE
44+
namespace asio_impl = ::asio;
45+
using error_code = std::error_code;
46+
using error_condition = std::error_condition;
47+
using errc = std::errc;
48+
using system_error = std::system_error;
49+
#endif
50+
}

0 commit comments

Comments
 (0)