diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e94d23cf..5a40aea81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,7 @@ if(BOOST_COROSIO_IS_ROOT AND BUILD_SHARED_LIBS) endif() option(BOOST_COROSIO_BUILD_TESTS "Build boost::corosio tests" ${BUILD_TESTING}) -option(BOOST_COROSIO_BUILD_PERF "Build boost::corosio performance tools" ${BOOST_COROSIO_IS_ROOT}) +option(BOOST_COROSIO_BUILD_BENCH "Build boost::corosio benchmarks" ${BOOST_COROSIO_IS_ROOT}) option(BOOST_COROSIO_BUILD_EXAMPLES "Build boost::corosio examples" ${BOOST_COROSIO_IS_ROOT}) option(BOOST_COROSIO_MRDOCS_BUILD "Building for MrDocs documentation generation" OFF) @@ -124,6 +124,6 @@ if (BOOST_COROSIO_BUILD_EXAMPLES) add_subdirectory(example) endif () -if (BOOST_COROSIO_BUILD_PERF) - add_subdirectory(perf) +if (BOOST_COROSIO_BUILD_BENCH) + add_subdirectory(bench) endif () diff --git a/perf/bench/CMakeLists.txt b/bench/CMakeLists.txt similarity index 86% rename from perf/bench/CMakeLists.txt rename to bench/CMakeLists.txt index 625c9a9b6..c6643b4cb 100644 --- a/perf/bench/CMakeLists.txt +++ b/bench/CMakeLists.txt @@ -7,6 +7,19 @@ # Official repository: https://github.com/cppalliance/corosio # +# Find Boost.Asio for comparison benchmarks (sibling or system-installed). +# This lives here (not in the root CMakeLists.txt) because the Boost +# superproject's dependency scanner greps Boost::* from the root file +# and would pull in Asio's full transitive dependency tree. +if(NOT TARGET Boost::asio) + find_package(Boost 1.84 QUIET COMPONENTS asio) + if(TARGET Boost::asio) + message(STATUS "Found system Boost.Asio -- comparison benchmarks enabled") + else() + message(STATUS "Boost.Asio not found -- comparison benchmarks disabled") + endif() +endif() + # Check LTO support for benchmarks # MinGW GCC LTO mishandles virtual thunks from multiple inheritance, # discarding COMDAT sections that contain needed thunk relocations. @@ -40,7 +53,7 @@ target_link_libraries(corosio_bench target_compile_options(corosio_bench PRIVATE $<$:/EHsc>) -set_property(TARGET corosio_bench PROPERTY FOLDER "perf/benchmarks") +set_property(TARGET corosio_bench PROPERTY FOLDER "bench") if (COROSIO_BENCH_LTO_SUPPORTED) set_property(TARGET corosio_bench PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) diff --git a/perf/bench/asio/callback/accept_churn_bench.cpp b/bench/asio/callback/accept_churn_bench.cpp similarity index 66% rename from perf/bench/asio/callback/accept_churn_bench.cpp rename to bench/asio/callback/accept_churn_bench.cpp index 297c1f7fb..9d68c7110 100644 --- a/perf/bench/asio/callback/accept_churn_bench.cpp +++ b/bench/asio/callback/accept_churn_bench.cpp @@ -37,35 +37,37 @@ namespace { // to avoid TIME_WAIT accumulation. Reducing SO_SNDBUF/SO_RCVBUF from // the macOS default of 128 KB each prevents ENOBUFS during rapid // socket creation in concurrent/burst workloads. -static void configure_churn_socket( tcp_socket& s ) +static void +configure_churn_socket(tcp_socket& s) { - s.set_option( asio::socket_base::send_buffer_size( 1024 ) ); - s.set_option( asio::socket_base::receive_buffer_size( 1024 ) ); - s.set_option( asio::socket_base::linger( true, 0 ) ); + s.set_option(asio::socket_base::send_buffer_size(1024)); + s.set_option(asio::socket_base::receive_buffer_size(1024)); + s.set_option(asio::socket_base::linger(true, 0)); } // Creates a listening acceptor with retry. Under rapid socket churn the // kernel may temporarily lack buffer space (ENOBUFS); a short back-off // lets resources drain from the previous benchmark run. -static tcp_acceptor make_churn_acceptor( asio::io_context& ioc ) +static tcp_acceptor +make_churn_acceptor(asio::io_context& ioc) { boost::system::error_code ec; - for( int attempt = 0; attempt < 20; ++attempt ) + for (int attempt = 0; attempt < 20; ++attempt) { - if( attempt > 0 ) - std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) ); - tcp_acceptor acc( ioc.get_executor() ); - ec = acc.open( tcp::v4(), ec ); - if( !ec ) - ec = acc.set_option( tcp_acceptor::reuse_address( true ), ec ); - if( !ec ) - ec = acc.bind( tcp::endpoint( tcp::v4(), 0 ), ec ); - if( !ec ) - ec = acc.listen( asio::socket_base::max_listen_connections, ec ); - if( !ec ) + if (attempt > 0) + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + tcp_acceptor acc(ioc.get_executor()); + ec = acc.open(tcp::v4(), ec); + if (!ec) + ec = acc.set_option(tcp_acceptor::reuse_address(true), ec); + if (!ec) + ec = acc.bind(tcp::endpoint(tcp::v4(), 0), ec); + if (!ec) + ec = acc.listen(asio::socket_base::max_listen_connections, ec); + if (!ec) return acc; } - throw boost::system::system_error( ec ); + throw boost::system::system_error(ec); } // Connect+accept+exchange 1 byte+close, repeat @@ -92,18 +94,18 @@ struct sequential_churn_op sw.reset(); connect_done = false; - accept_done = false; - client = tcp_socket( ioc.get_executor() ); - server = tcp_socket( ioc.get_executor() ); + accept_done = false; + client = tcp_socket(ioc.get_executor()); + server = tcp_socket(ioc.get_executor()); boost::system::error_code ec; - ec = client.open( tcp::v4(), ec ); - if( ec ) + ec = client.open(tcp::v4(), ec); + if (ec) { - asio::post( ioc, [this]() { start(); } ); + asio::post(ioc, [this]() { start(); }); return; } - configure_churn_socket( client ); + configure_churn_socket(client); client.async_connect(ep, [this](boost::system::error_code ec) { if (ec) @@ -163,22 +165,30 @@ void bench_sequential_churn(bench::state& state) { asio::io_context ioc; - auto acc = make_churn_acceptor( ioc ); - auto ep = tcp::endpoint( asio::ip::address_v4::loopback(), acc.local_endpoint().port() ); + auto acc = make_churn_acceptor(ioc); + auto ep = tcp::endpoint( + asio::ip::address_v4::loopback(), acc.local_endpoint().port()); std::atomic running{true}; - sequential_churn_op op{ioc, acc, ep, running, state.latency(), - state.ops(), - tcp_socket(ioc.get_executor()), - tcp_socket(ioc.get_executor()), {}}; + sequential_churn_op op{ + ioc, + acc, + ep, + running, + state.latency(), + state.ops(), + tcp_socket(ioc.get_executor()), + tcp_socket(ioc.get_executor()), + {}}; perf::stopwatch total_sw; op.start(); std::thread timer([&]() { - std::this_thread::sleep_for(std::chrono::duration(state.duration())); + std::this_thread::sleep_for( + std::chrono::duration(state.duration())); running.store(false, std::memory_order_relaxed); ioc.stop(); }); @@ -194,22 +204,30 @@ void bench_sequential_churn_lockless(bench::state& state) { asio::io_context ioc(BOOST_ASIO_CONCURRENCY_HINT_UNSAFE); - auto acc = make_churn_acceptor( ioc ); - auto ep = tcp::endpoint( asio::ip::address_v4::loopback(), acc.local_endpoint().port() ); + auto acc = make_churn_acceptor(ioc); + auto ep = tcp::endpoint( + asio::ip::address_v4::loopback(), acc.local_endpoint().port()); std::atomic running{true}; - sequential_churn_op op{ioc, acc, ep, running, state.latency(), - state.ops(), - tcp_socket(ioc.get_executor()), - tcp_socket(ioc.get_executor()), {}}; + sequential_churn_op op{ + ioc, + acc, + ep, + running, + state.latency(), + state.ops(), + tcp_socket(ioc.get_executor()), + tcp_socket(ioc.get_executor()), + {}}; perf::stopwatch total_sw; op.start(); std::thread timer([&]() { - std::this_thread::sleep_for(std::chrono::duration(state.duration())); + std::this_thread::sleep_for( + std::chrono::duration(state.duration())); running.store(false, std::memory_order_relaxed); ioc.stop(); }); @@ -226,16 +244,16 @@ bench_sequential_churn_lockless(bench::state& state) void bench_concurrent_churn(bench::state& state) { - int num_loops = static_cast(state.range(0)); + int num_loops = static_cast(state.range(0)); state.counters["num_loops"] = num_loops; asio::io_context ioc; std::atomic running{true}; std::vector acceptors; - acceptors.reserve( num_loops ); - for( int i = 0; i < num_loops; ++i ) - acceptors.push_back( make_churn_acceptor( ioc ) ); + acceptors.reserve(num_loops); + for (int i = 0; i < num_loops; ++i) + acceptors.push_back(make_churn_acceptor(ioc)); std::vector> ops; ops.reserve(num_loops); @@ -245,17 +263,25 @@ bench_concurrent_churn(bench::state& state) for (int i = 0; i < num_loops; ++i) { auto ep = tcp::endpoint( - asio::ip::address_v4::loopback(), acceptors[i].local_endpoint().port() ); - ops.push_back( std::make_unique( - sequential_churn_op{ ioc, acceptors[i], ep, running, - state.latency(), state.ops(), - tcp_socket(ioc.get_executor()), - tcp_socket(ioc.get_executor()), {} } ) ); + asio::ip::address_v4::loopback(), + acceptors[i].local_endpoint().port()); + ops.push_back( + std::make_unique(sequential_churn_op{ + ioc, + acceptors[i], + ep, + running, + state.latency(), + state.ops(), + tcp_socket(ioc.get_executor()), + tcp_socket(ioc.get_executor()), + {}})); ops.back()->start(); } std::thread stopper([&]() { - std::this_thread::sleep_for(std::chrono::duration(state.duration())); + std::this_thread::sleep_for( + std::chrono::duration(state.duration())); running.store(false, std::memory_order_relaxed); ioc.stop(); }); @@ -264,7 +290,7 @@ bench_concurrent_churn(bench::state& state) stopper.join(); state.set_elapsed(total_sw.elapsed_seconds()); - for( auto& a : acceptors ) + for (auto& a : acceptors) a.close(); } @@ -299,27 +325,26 @@ struct burst_churn_op // Open all client sockets before issuing async operations so a // partial failure doesn't leave dangling async_accept operations. - for( int i = 0; i < burst_size; ++i ) + for (int i = 0; i < burst_size; ++i) { - clients.emplace_back( ioc.get_executor() ); + clients.emplace_back(ioc.get_executor()); boost::system::error_code ec; - ec = clients.back().open( tcp::v4(), ec ); - if( ec ) + ec = clients.back().open(tcp::v4(), ec); + if (ec) { clients.clear(); - asio::post( ioc, [this]() { start(); } ); + asio::post(ioc, [this]() { start(); }); return; } - configure_churn_socket( clients.back() ); + configure_churn_socket(clients.back()); } // Initiate all connects and accepts - for( int i = 0; i < burst_size; ++i ) + for (int i = 0; i < burst_size; ++i) { - clients[i].async_connect( ep, - [](boost::system::error_code) {} ); + clients[i].async_connect(ep, [](boost::system::error_code) {}); - servers.emplace_back( ioc.get_executor() ); + servers.emplace_back(ioc.get_executor()); acc.async_accept( servers.back(), [this](boost::system::error_code ec) { if (ec) @@ -350,17 +375,18 @@ struct burst_churn_op void bench_burst_churn(bench::state& state) { - int burst_size = static_cast(state.range(0)); + int burst_size = static_cast(state.range(0)); state.counters["burst_size"] = burst_size; asio::io_context ioc; - auto acc = make_churn_acceptor( ioc ); - auto ep = tcp::endpoint( asio::ip::address_v4::loopback(), acc.local_endpoint().port() ); + auto acc = make_churn_acceptor(ioc); + auto ep = tcp::endpoint( + asio::ip::address_v4::loopback(), acc.local_endpoint().port()); std::atomic running{true}; - burst_churn_op op{ioc, acc, ep, running, state.latency(), - state.ops(), burst_size, {}, {}, {}, + burst_churn_op op{ioc, acc, ep, running, state.latency(), + state.ops(), burst_size, {}, {}, {}, {}}; perf::stopwatch total_sw; @@ -368,7 +394,8 @@ bench_burst_churn(bench::state& state) op.start(); std::thread stopper([&]() { - std::this_thread::sleep_for(std::chrono::duration(state.duration())); + std::this_thread::sleep_for( + std::chrono::duration(state.duration())); running.store(false, std::memory_order_relaxed); ioc.stop(); }); @@ -383,17 +410,18 @@ bench_burst_churn(bench::state& state) void bench_burst_churn_lockless(bench::state& state) { - int burst_size = static_cast(state.range(0)); + int burst_size = static_cast(state.range(0)); state.counters["burst_size"] = burst_size; asio::io_context ioc(BOOST_ASIO_CONCURRENCY_HINT_UNSAFE); - auto acc = make_churn_acceptor( ioc ); - auto ep = tcp::endpoint( asio::ip::address_v4::loopback(), acc.local_endpoint().port() ); + auto acc = make_churn_acceptor(ioc); + auto ep = tcp::endpoint( + asio::ip::address_v4::loopback(), acc.local_endpoint().port()); std::atomic running{true}; - burst_churn_op op{ioc, acc, ep, running, state.latency(), - state.ops(), burst_size, {}, {}, {}, + burst_churn_op op{ioc, acc, ep, running, state.latency(), + state.ops(), burst_size, {}, {}, {}, {}}; perf::stopwatch total_sw; @@ -401,7 +429,8 @@ bench_burst_churn_lockless(bench::state& state) op.start(); std::thread stopper([&]() { - std::this_thread::sleep_for(std::chrono::duration(state.duration())); + std::this_thread::sleep_for( + std::chrono::duration(state.duration())); running.store(false, std::memory_order_relaxed); ioc.stop(); }); @@ -423,11 +452,11 @@ make_accept_churn_suite() .add("sequential", bench_sequential_churn) .add("sequential_lockless", bench_sequential_churn_lockless) .add("concurrent", bench_concurrent_churn) - .args({1, 4, 16}) + .args({1, 4, 16}) .add("burst", bench_burst_churn) - .args({10, 100}) + .args({10, 100}) .add("burst_lockless", bench_burst_churn_lockless) - .args({10, 100}); + .args({10, 100}); } } // namespace asio_callback_bench diff --git a/perf/bench/asio/callback/benchmarks.hpp b/bench/asio/callback/benchmarks.hpp similarity index 100% rename from perf/bench/asio/callback/benchmarks.hpp rename to bench/asio/callback/benchmarks.hpp diff --git a/perf/bench/asio/callback/fan_out_bench.cpp b/bench/asio/callback/fan_out_bench.cpp similarity index 95% rename from perf/bench/asio/callback/fan_out_bench.cpp rename to bench/asio/callback/fan_out_bench.cpp index b3ba64d3e..719fa0d43 100644 --- a/perf/bench/asio/callback/fan_out_bench.cpp +++ b/bench/asio/callback/fan_out_bench.cpp @@ -106,8 +106,7 @@ struct sub_request_op : std::enable_shared_from_this auto self = shared_from_this(); asio::async_read( client, asio::buffer(recv_buf, 64), - [self]([[maybe_unused]] boost::system::error_code ec, - std::size_t) { + [self]([[maybe_unused]] boost::system::error_code ec, std::size_t) { self->finish(); }); } @@ -162,7 +161,7 @@ struct fork_join_op void bench_fork_join(bench::state& state) { - int fan_out = static_cast(state.range(0)); + int fan_out = static_cast(state.range(0)); state.counters["fan_out"] = fan_out; asio::io_context ioc; @@ -324,8 +323,8 @@ bench_nested(bench::state& state) echo->start(); } - nested_op op{ioc, clients, servers, groups, subs_per_group, - state, {}, {}, {}}; + nested_op op{ioc, clients, servers, groups, subs_per_group, + state, {}, {}, {}}; op.start(); @@ -449,8 +448,8 @@ bench_concurrent_parents(bench::state& state) { parent_ops.push_back( std::make_unique( - ioc, clients, servers, p * fan_out, fan_out, num_parents, - state, parents_done)); + ioc, clients, servers, p * fan_out, fan_out, num_parents, state, + parents_done)); parent_ops.back()->start(); } @@ -470,7 +469,7 @@ bench_concurrent_parents(bench::state& state) void bench_fork_join_lockless(bench::state& state) { - int fan_out = static_cast(state.range(0)); + int fan_out = static_cast(state.range(0)); state.counters["fan_out"] = fan_out; asio::io_context ioc(BOOST_ASIO_CONCURRENCY_HINT_UNSAFE); @@ -540,8 +539,8 @@ bench_nested_lockless(bench::state& state) echo->start(); } - nested_op op{ioc, clients, servers, groups, subs_per_group, - state, {}, {}, {}}; + nested_op op{ioc, clients, servers, groups, subs_per_group, + state, {}, {}, {}}; op.start(); @@ -597,8 +596,8 @@ bench_concurrent_parents_lockless(bench::state& state) { parent_ops.push_back( std::make_unique( - ioc, clients, servers, p * fan_out, fan_out, num_parents, - state, parents_done)); + ioc, clients, servers, p * fan_out, fan_out, num_parents, state, + parents_done)); parent_ops.back()->start(); } @@ -623,17 +622,17 @@ make_fan_out_suite() using F = bench::bench_flags; return bench::benchmark_suite("fan_out", F::needs_conntrack_drain) .add("fork_join", bench_fork_join) - .args({1, 4, 16, 64}) + .args({1, 4, 16, 64}) .add("fork_join_lockless", bench_fork_join_lockless) - .args({1, 4, 16, 64}) + .args({1, 4, 16, 64}) .add("nested", bench_nested) - .args({4, 16}) + .args({4, 16}) .add("nested_lockless", bench_nested_lockless) - .args({4, 16}) + .args({4, 16}) .add("concurrent_parents", bench_concurrent_parents) - .args({1, 4, 16}) + .args({1, 4, 16}) .add("concurrent_parents_lockless", bench_concurrent_parents_lockless) - .args({1, 4, 16}); + .args({1, 4, 16}); } } // namespace asio_callback_bench diff --git a/perf/bench/asio/callback/http_server_bench.cpp b/bench/asio/callback/http_server_bench.cpp similarity index 94% rename from perf/bench/asio/callback/http_server_bench.cpp rename to bench/asio/callback/http_server_bench.cpp index 8404fea42..d98b15781 100644 --- a/perf/bench/asio/callback/http_server_bench.cpp +++ b/bench/asio/callback/http_server_bench.cpp @@ -212,7 +212,7 @@ bench_single_connection_lockless(bench::state& state) void bench_concurrent_connections(bench::state& state) { - int num_connections = static_cast(state.range(0)); + int num_connections = static_cast(state.range(0)); state.counters["connections"] = num_connections; asio::io_context ioc; @@ -237,11 +237,9 @@ bench_concurrent_connections(bench::state& state) for (int i = 0; i < num_connections; ++i) { - sops.push_back( - std::make_unique(server_op{servers[i], {}})); + sops.push_back(std::make_unique(server_op{servers[i], {}})); cops.push_back( - std::make_unique( - client_op{clients[i], state, {}, {}})); + std::make_unique(client_op{clients[i], state, {}, {}})); sops.back()->start(); cops.back()->start(); } @@ -295,11 +293,9 @@ bench_multithread(bench::state& state) for (int i = 0; i < num_connections; ++i) { - sops.push_back( - std::make_unique(server_op{servers[i], {}})); + sops.push_back(std::make_unique(server_op{servers[i], {}})); cops.push_back( - std::make_unique( - client_op{clients[i], state, {}, {}})); + std::make_unique(client_op{clients[i], state, {}, {}})); sops.back()->start(); cops.back()->start(); } @@ -341,9 +337,9 @@ make_http_server_suite() .add("single_conn", bench_single_connection) .add("single_conn_lockless", bench_single_connection_lockless) .add("concurrent", bench_concurrent_connections) - .args({1, 4, 16, 32}) + .args({1, 4, 16, 32}) .add("multithread", bench_multithread) - .args({1, 2, 4, 8, 16}); + .args({1, 2, 4, 8, 16}); } } // namespace asio_callback_bench diff --git a/perf/bench/asio/callback/io_context_bench.cpp b/bench/asio/callback/io_context_bench.cpp similarity index 99% rename from perf/bench/asio/callback/io_context_bench.cpp rename to bench/asio/callback/io_context_bench.cpp index c7e16e966..691df9090 100644 --- a/perf/bench/asio/callback/io_context_bench.cpp +++ b/bench/asio/callback/io_context_bench.cpp @@ -238,10 +238,10 @@ make_io_context_suite() return bench::benchmark_suite("io_context", F::is_microbenchmark) .add("single_threaded", bench_single_threaded_post) .add("multithreaded", bench_multithreaded_scaling) - .args({8}) + .args({8}) .add("interleaved", bench_interleaved_post_run) .add("concurrent", bench_concurrent_post_run) - .args({4}) + .args({4}) .add("single_threaded_lockless", bench_single_threaded_lockless) .add("interleaved_lockless", bench_interleaved_lockless); } diff --git a/perf/bench/asio/callback/local_socket_latency_bench.cpp b/bench/asio/callback/local_socket_latency_bench.cpp similarity index 94% rename from perf/bench/asio/callback/local_socket_latency_bench.cpp rename to bench/asio/callback/local_socket_latency_bench.cpp index da44a50e2..b74153f0f 100644 --- a/perf/bench/asio/callback/local_socket_latency_bench.cpp +++ b/bench/asio/callback/local_socket_latency_bench.cpp @@ -126,7 +126,7 @@ struct unix_pingpong_op void bench_pingpong_latency(bench::state& state) { - auto message_size = static_cast(state.range(0)); + auto message_size = static_cast(state.range(0)); state.counters["message_size"] = static_cast(message_size); asio::io_context ioc; @@ -154,7 +154,7 @@ bench_pingpong_latency(bench::state& state) void bench_concurrent_latency(bench::state& state) { - int num_pairs = static_cast(state.range(0)); + int num_pairs = static_cast(state.range(0)); state.counters["num_pairs"] = num_pairs; asio::io_context ioc; @@ -203,7 +203,7 @@ bench_concurrent_latency(bench::state& state) void bench_pingpong_latency_lockless(bench::state& state) { - auto message_size = static_cast(state.range(0)); + auto message_size = static_cast(state.range(0)); state.counters["message_size"] = static_cast(message_size); asio::io_context ioc(BOOST_ASIO_CONCURRENCY_HINT_UNSAFE); @@ -231,7 +231,7 @@ bench_pingpong_latency_lockless(bench::state& state) void bench_concurrent_latency_lockless(bench::state& state) { - int num_pairs = static_cast(state.range(0)); + int num_pairs = static_cast(state.range(0)); state.counters["num_pairs"] = num_pairs; asio::io_context ioc(BOOST_ASIO_CONCURRENCY_HINT_UNSAFE); @@ -285,13 +285,13 @@ make_local_socket_latency_suite() using F = bench::bench_flags; return bench::benchmark_suite("local_socket_latency", F::none) .add("pingpong", bench_pingpong_latency) - .args({1, 64, 1024}) + .args({1, 64, 1024}) .add("pingpong_lockless", bench_pingpong_latency_lockless) - .args({1, 64, 1024}) + .args({1, 64, 1024}) .add("concurrent", bench_concurrent_latency) - .args({1, 4, 16}) + .args({1, 4, 16}) .add("concurrent_lockless", bench_concurrent_latency_lockless) - .args({1, 4, 16}); + .args({1, 4, 16}); } } // namespace asio_callback_bench diff --git a/perf/bench/asio/callback/local_socket_throughput_bench.cpp b/bench/asio/callback/local_socket_throughput_bench.cpp similarity index 93% rename from perf/bench/asio/callback/local_socket_throughput_bench.cpp rename to bench/asio/callback/local_socket_throughput_bench.cpp index e6b47f59d..59269c537 100644 --- a/perf/bench/asio/callback/local_socket_throughput_bench.cpp +++ b/bench/asio/callback/local_socket_throughput_bench.cpp @@ -72,7 +72,7 @@ struct unix_read_op void bench_throughput(bench::state& state) { - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); asio::io_context ioc; @@ -111,7 +111,7 @@ bench_throughput(bench::state& state) void bench_bidirectional_throughput(bench::state& state) { - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); asio::io_context ioc; @@ -158,7 +158,7 @@ bench_bidirectional_throughput(bench::state& state) void bench_throughput_lockless(bench::state& state) { - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); asio::io_context ioc(BOOST_ASIO_CONCURRENCY_HINT_UNSAFE); @@ -197,7 +197,7 @@ bench_throughput_lockless(bench::state& state) void bench_bidirectional_throughput_lockless(bench::state& state) { - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); asio::io_context ioc(BOOST_ASIO_CONCURRENCY_HINT_UNSAFE); @@ -249,13 +249,13 @@ make_local_socket_throughput_suite() using F = bench::bench_flags; return bench::benchmark_suite("local_socket_throughput", F::none) .add("unidirectional", bench_throughput) - .range(1024, 1048576, 4) + .range(1024, 1048576, 4) .add("unidirectional_lockless", bench_throughput_lockless) - .range(1024, 1048576, 4) + .range(1024, 1048576, 4) .add("bidirectional", bench_bidirectional_throughput) - .range(1024, 1048576, 4) + .range(1024, 1048576, 4) .add("bidirectional_lockless", bench_bidirectional_throughput_lockless) - .range(1024, 1048576, 4); + .range(1024, 1048576, 4); } } // namespace asio_callback_bench diff --git a/perf/bench/asio/callback/socket_latency_bench.cpp b/bench/asio/callback/socket_latency_bench.cpp similarity index 92% rename from perf/bench/asio/callback/socket_latency_bench.cpp rename to bench/asio/callback/socket_latency_bench.cpp index afef42497..208dbf51b 100644 --- a/perf/bench/asio/callback/socket_latency_bench.cpp +++ b/bench/asio/callback/socket_latency_bench.cpp @@ -127,7 +127,7 @@ struct pingpong_op void bench_pingpong_latency(bench::state& state) { - auto message_size = static_cast(state.range(0)); + auto message_size = static_cast(state.range(0)); state.counters["message_size"] = static_cast(message_size); asio::io_context ioc; @@ -155,7 +155,7 @@ bench_pingpong_latency(bench::state& state) void bench_concurrent_latency(bench::state& state) { - int num_pairs = static_cast(state.range(0)); + int num_pairs = static_cast(state.range(0)); state.counters["num_pairs"] = num_pairs; asio::io_context ioc; @@ -179,8 +179,7 @@ bench_concurrent_latency(bench::state& state) for (int p = 0; p < num_pairs; ++p) { ops.push_back( - std::make_unique( - clients[p], servers[p], 64, state)); + std::make_unique(clients[p], servers[p], 64, state)); ops.back()->start(); } @@ -205,7 +204,7 @@ bench_concurrent_latency(bench::state& state) void bench_pingpong_latency_lockless(bench::state& state) { - auto message_size = static_cast(state.range(0)); + auto message_size = static_cast(state.range(0)); state.counters["message_size"] = static_cast(message_size); asio::io_context ioc(BOOST_ASIO_CONCURRENCY_HINT_UNSAFE); @@ -233,7 +232,7 @@ bench_pingpong_latency_lockless(bench::state& state) void bench_concurrent_latency_lockless(bench::state& state) { - int num_pairs = static_cast(state.range(0)); + int num_pairs = static_cast(state.range(0)); state.counters["num_pairs"] = num_pairs; asio::io_context ioc(BOOST_ASIO_CONCURRENCY_HINT_UNSAFE); @@ -257,8 +256,7 @@ bench_concurrent_latency_lockless(bench::state& state) for (int p = 0; p < num_pairs; ++p) { ops.push_back( - std::make_unique( - clients[p], servers[p], 64, state)); + std::make_unique(clients[p], servers[p], 64, state)); ops.back()->start(); } @@ -288,13 +286,13 @@ make_socket_latency_suite() using F = bench::bench_flags; return bench::benchmark_suite("socket_latency", F::needs_conntrack_drain) .add("pingpong", bench_pingpong_latency) - .args({1, 64, 1024}) + .args({1, 64, 1024}) .add("pingpong_lockless", bench_pingpong_latency_lockless) - .args({1, 64, 1024}) + .args({1, 64, 1024}) .add("concurrent", bench_concurrent_latency) - .args({1, 4, 16}) + .args({1, 4, 16}) .add("concurrent_lockless", bench_concurrent_latency_lockless) - .args({1, 4, 16}); + .args({1, 4, 16}); } } // namespace asio_callback_bench diff --git a/perf/bench/asio/callback/socket_throughput_bench.cpp b/bench/asio/callback/socket_throughput_bench.cpp similarity index 91% rename from perf/bench/asio/callback/socket_throughput_bench.cpp rename to bench/asio/callback/socket_throughput_bench.cpp index d4c539166..46c64ea16 100644 --- a/perf/bench/asio/callback/socket_throughput_bench.cpp +++ b/bench/asio/callback/socket_throughput_bench.cpp @@ -73,7 +73,7 @@ struct read_op void bench_throughput(bench::state& state) { - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); asio::io_context ioc; @@ -94,7 +94,8 @@ bench_throughput(bench::state& state) rop.start(); std::thread timer([&]() { - std::this_thread::sleep_for(std::chrono::duration(state.duration())); + std::this_thread::sleep_for( + std::chrono::duration(state.duration())); running.store(false, std::memory_order_relaxed); }); @@ -111,7 +112,7 @@ bench_throughput(bench::state& state) void bench_bidirectional_throughput(bench::state& state) { - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); asio::io_context ioc; @@ -142,7 +143,8 @@ bench_bidirectional_throughput(bench::state& state) rop2.start(); std::thread timer([&]() { - std::this_thread::sleep_for(std::chrono::duration(state.duration())); + std::this_thread::sleep_for( + std::chrono::duration(state.duration())); running.store(false, std::memory_order_relaxed); }); @@ -159,7 +161,7 @@ bench_bidirectional_throughput(bench::state& state) void bench_throughput_lockless(bench::state& state) { - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); asio::io_context ioc(BOOST_ASIO_CONCURRENCY_HINT_UNSAFE); @@ -180,7 +182,8 @@ bench_throughput_lockless(bench::state& state) rop.start(); std::thread timer([&]() { - std::this_thread::sleep_for(std::chrono::duration(state.duration())); + std::this_thread::sleep_for( + std::chrono::duration(state.duration())); running.store(false, std::memory_order_relaxed); }); @@ -197,7 +200,7 @@ bench_throughput_lockless(bench::state& state) void bench_bidirectional_throughput_lockless(bench::state& state) { - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); asio::io_context ioc(BOOST_ASIO_CONCURRENCY_HINT_UNSAFE); @@ -228,7 +231,8 @@ bench_bidirectional_throughput_lockless(bench::state& state) rop2.start(); std::thread timer([&]() { - std::this_thread::sleep_for(std::chrono::duration(state.duration())); + std::this_thread::sleep_for( + std::chrono::duration(state.duration())); running.store(false, std::memory_order_relaxed); }); @@ -363,7 +367,8 @@ bench_multithread_throughput(bench::state& state) threads.emplace_back([&ioc] { ioc.run(); }); std::thread timer([&]() { - std::this_thread::sleep_for(std::chrono::duration(state.duration())); + std::this_thread::sleep_for( + std::chrono::duration(state.duration())); running.store(false, std::memory_order_relaxed); }); @@ -391,15 +396,15 @@ make_socket_throughput_suite() using F = bench::bench_flags; return bench::benchmark_suite("socket_throughput", F::needs_conntrack_drain) .add("unidirectional", bench_throughput) - .range(1024, 1048576, 4) + .range(1024, 1048576, 4) .add("unidirectional_lockless", bench_throughput_lockless) - .range(1024, 1048576, 4) + .range(1024, 1048576, 4) .add("bidirectional", bench_bidirectional_throughput) - .range(1024, 1048576, 4) + .range(1024, 1048576, 4) .add("bidirectional_lockless", bench_bidirectional_throughput_lockless) - .range(1024, 1048576, 4) + .range(1024, 1048576, 4) .add("multithread", bench_multithread_throughput) - .args({2, 4, 8}); + .args({2, 4, 8}); } } // namespace asio_callback_bench diff --git a/perf/bench/asio/coroutine/accept_churn_bench.cpp b/bench/asio/coroutine/accept_churn_bench.cpp similarity index 98% rename from perf/bench/asio/coroutine/accept_churn_bench.cpp rename to bench/asio/coroutine/accept_churn_bench.cpp index eafa532bf..7b70f225d 100644 --- a/perf/bench/asio/coroutine/accept_churn_bench.cpp +++ b/bench/asio/coroutine/accept_churn_bench.cpp @@ -207,7 +207,7 @@ bench_sequential_churn_lockless(bench::state& state) void bench_concurrent_churn(bench::state& state) { - int num_loops = static_cast(state.range(0)); + int num_loops = static_cast(state.range(0)); state.counters["num_loops"] = num_loops; asio::io_context ioc; @@ -288,7 +288,7 @@ bench_concurrent_churn(bench::state& state) void bench_burst_churn(bench::state& state) { - int burst_size = static_cast(state.range(0)); + int burst_size = static_cast(state.range(0)); state.counters["burst_size"] = burst_size; asio::io_context ioc; @@ -376,7 +376,7 @@ bench_burst_churn(bench::state& state) void bench_burst_churn_lockless(bench::state& state) { - int burst_size = static_cast(state.range(0)); + int burst_size = static_cast(state.range(0)); state.counters["burst_size"] = burst_size; asio::io_context ioc(BOOST_ASIO_CONCURRENCY_HINT_UNSAFE); @@ -471,11 +471,11 @@ make_accept_churn_suite() .add("sequential", bench_sequential_churn) .add("sequential_lockless", bench_sequential_churn_lockless) .add("concurrent", bench_concurrent_churn) - .args({1, 4, 16}) + .args({1, 4, 16}) .add("burst", bench_burst_churn) - .args({10, 100}) + .args({10, 100}) .add("burst_lockless", bench_burst_churn_lockless) - .args({10, 100}); + .args({10, 100}); } } // namespace asio_bench diff --git a/perf/bench/asio/coroutine/benchmarks.hpp b/bench/asio/coroutine/benchmarks.hpp similarity index 100% rename from perf/bench/asio/coroutine/benchmarks.hpp rename to bench/asio/coroutine/benchmarks.hpp diff --git a/perf/bench/asio/coroutine/fan_out_bench.cpp b/bench/asio/coroutine/fan_out_bench.cpp similarity index 96% rename from perf/bench/asio/coroutine/fan_out_bench.cpp rename to bench/asio/coroutine/fan_out_bench.cpp index 7c07eebbf..d6bc1f09c 100644 --- a/perf/bench/asio/coroutine/fan_out_bench.cpp +++ b/bench/asio/coroutine/fan_out_bench.cpp @@ -91,7 +91,7 @@ sub_request(tcp_socket& client, fan_out_notifier notifier) void bench_fork_join(bench::state& state) { - int fan_out = static_cast(state.range(0)); + int fan_out = static_cast(state.range(0)); state.counters["fan_out"] = fan_out; asio::io_context ioc; @@ -192,8 +192,7 @@ bench_nested(bench::state& state) std::atomic running{true}; - auto group_task = [&](int base_idx, int n, - fan_out_notifier groups_notifier) + auto group_task = [&](int base_idx, int n, fan_out_notifier groups_notifier) -> asio::awaitable { std::atomic subs_remaining{n}; timer_type t(ioc); @@ -212,7 +211,8 @@ bench_nested(bench::state& state) // registering. while (subs_remaining.load(std::memory_order_acquire) > 0) { - [[maybe_unused]] auto [ec] = co_await t.async_wait(asio::as_tuple(asio::deferred)); + [[maybe_unused]] auto [ec] = + co_await t.async_wait(asio::as_tuple(asio::deferred)); } groups_notifier.arrive(); @@ -358,7 +358,7 @@ bench_concurrent_parents(bench::state& state) void bench_fork_join_lockless(bench::state& state) { - int fan_out = static_cast(state.range(0)); + int fan_out = static_cast(state.range(0)); state.counters["fan_out"] = fan_out; asio::io_context ioc(BOOST_ASIO_CONCURRENCY_HINT_UNSAFE); @@ -458,8 +458,7 @@ bench_nested_lockless(bench::state& state) std::atomic running{true}; - auto group_task = [&](int base_idx, int n, - fan_out_notifier groups_notifier) + auto group_task = [&](int base_idx, int n, fan_out_notifier groups_notifier) -> asio::awaitable { std::atomic subs_remaining{n}; timer_type t(ioc); @@ -478,7 +477,8 @@ bench_nested_lockless(bench::state& state) // registering. while (subs_remaining.load(std::memory_order_acquire) > 0) { - [[maybe_unused]] auto [ec] = co_await t.async_wait(asio::as_tuple(asio::deferred)); + [[maybe_unused]] auto [ec] = + co_await t.async_wait(asio::as_tuple(asio::deferred)); } groups_notifier.arrive(); @@ -628,17 +628,17 @@ make_fan_out_suite() using F = bench::bench_flags; return bench::benchmark_suite("fan_out", F::needs_conntrack_drain) .add("fork_join", bench_fork_join) - .args({1, 4, 16, 64}) + .args({1, 4, 16, 64}) .add("fork_join_lockless", bench_fork_join_lockless) - .args({1, 4, 16, 64}) + .args({1, 4, 16, 64}) .add("nested", bench_nested) - .args({4, 16}) + .args({4, 16}) .add("nested_lockless", bench_nested_lockless) - .args({4, 16}) + .args({4, 16}) .add("concurrent_parents", bench_concurrent_parents) - .args({1, 4, 16}) + .args({1, 4, 16}) .add("concurrent_parents_lockless", bench_concurrent_parents_lockless) - .args({1, 4, 16}); + .args({1, 4, 16}); } } // namespace asio_bench diff --git a/perf/bench/asio/coroutine/http_server_bench.cpp b/bench/asio/coroutine/http_server_bench.cpp similarity index 89% rename from perf/bench/asio/coroutine/http_server_bench.cpp rename to bench/asio/coroutine/http_server_bench.cpp index f9d1aba0a..7e32ef606 100644 --- a/perf/bench/asio/coroutine/http_server_bench.cpp +++ b/bench/asio/coroutine/http_server_bench.cpp @@ -122,10 +122,8 @@ bench_single_connection(bench::state& state) asio::io_context ioc; auto [client, server] = make_socket_pair(ioc); - asio::co_spawn( - ioc, server_task(server), asio::detached); - asio::co_spawn( - ioc, client_task(client, state), asio::detached); + asio::co_spawn(ioc, server_task(server), asio::detached); + asio::co_spawn(ioc, client_task(client, state), asio::detached); std::thread timer([&]() { std::this_thread::sleep_for( @@ -148,10 +146,8 @@ bench_single_connection_lockless(bench::state& state) asio::io_context ioc(BOOST_ASIO_CONCURRENCY_HINT_UNSAFE); auto [client, server] = make_socket_pair(ioc); - asio::co_spawn( - ioc, server_task(server), asio::detached); - asio::co_spawn( - ioc, client_task(client, state), asio::detached); + asio::co_spawn(ioc, server_task(server), asio::detached); + asio::co_spawn(ioc, client_task(client, state), asio::detached); std::thread timer([&]() { std::this_thread::sleep_for( @@ -171,7 +167,7 @@ bench_single_connection_lockless(bench::state& state) void bench_concurrent_connections(bench::state& state) { - int num_connections = static_cast(state.range(0)); + int num_connections = static_cast(state.range(0)); state.counters["connections"] = num_connections; asio::io_context ioc; @@ -191,10 +187,8 @@ bench_concurrent_connections(bench::state& state) for (int i = 0; i < num_connections; ++i) { - asio::co_spawn( - ioc, server_task(servers[i]), asio::detached); - asio::co_spawn( - ioc, client_task(clients[i], state), asio::detached); + asio::co_spawn(ioc, server_task(servers[i]), asio::detached); + asio::co_spawn(ioc, client_task(clients[i], state), asio::detached); } std::thread timer([&]() { @@ -241,10 +235,8 @@ bench_multithread(bench::state& state) for (int i = 0; i < num_connections; ++i) { - asio::co_spawn( - ioc, server_task(servers[i]), asio::detached); - asio::co_spawn( - ioc, client_task(clients[i], state), asio::detached); + asio::co_spawn(ioc, server_task(servers[i]), asio::detached); + asio::co_spawn(ioc, client_task(clients[i], state), asio::detached); } perf::stopwatch sw; @@ -285,9 +277,9 @@ make_http_server_suite() .add("single_conn", bench_single_connection) .add("single_conn_lockless", bench_single_connection_lockless) .add("concurrent", bench_concurrent_connections) - .args({1, 4, 16, 32}) + .args({1, 4, 16, 32}) .add("multithread", bench_multithread) - .args({1, 2, 4, 8, 16}); + .args({1, 2, 4, 8, 16}); } } // namespace asio_bench diff --git a/perf/bench/asio/coroutine/io_context_bench.cpp b/bench/asio/coroutine/io_context_bench.cpp similarity index 99% rename from perf/bench/asio/coroutine/io_context_bench.cpp rename to bench/asio/coroutine/io_context_bench.cpp index 6fa7a6ea8..a0f525823 100644 --- a/perf/bench/asio/coroutine/io_context_bench.cpp +++ b/bench/asio/coroutine/io_context_bench.cpp @@ -250,10 +250,10 @@ make_io_context_suite() return bench::benchmark_suite("io_context", F::is_microbenchmark) .add("single_threaded", bench_single_threaded_post) .add("multithreaded", bench_multithreaded_scaling) - .args({8}) + .args({8}) .add("interleaved", bench_interleaved_post_run) .add("concurrent", bench_concurrent_post_run) - .args({4}) + .args({4}) .add("single_threaded_lockless", bench_single_threaded_lockless) .add("interleaved_lockless", bench_interleaved_lockless); } diff --git a/perf/bench/asio/coroutine/local_socket_latency_bench.cpp b/bench/asio/coroutine/local_socket_latency_bench.cpp similarity index 88% rename from perf/bench/asio/coroutine/local_socket_latency_bench.cpp rename to bench/asio/coroutine/local_socket_latency_bench.cpp index 79819c30b..8d6506d38 100644 --- a/perf/bench/asio/coroutine/local_socket_latency_bench.cpp +++ b/bench/asio/coroutine/local_socket_latency_bench.cpp @@ -71,7 +71,7 @@ pingpong_client_task( void bench_pingpong_latency(bench::state& state) { - auto message_size = static_cast(state.range(0)); + auto message_size = static_cast(state.range(0)); state.counters["message_size"] = static_cast(message_size); asio::io_context ioc; @@ -80,9 +80,7 @@ bench_pingpong_latency(bench::state& state) std::atomic running{true}; asio::co_spawn( - ioc, - pingpong_client_task( - client, server, message_size, running, state), + ioc, pingpong_client_task(client, server, message_size, running, state), asio::detached); std::thread timer([&]() { @@ -103,7 +101,7 @@ bench_pingpong_latency(bench::state& state) void bench_concurrent_latency(bench::state& state) { - int num_pairs = static_cast(state.range(0)); + int num_pairs = static_cast(state.range(0)); state.counters["num_pairs"] = num_pairs; asio::io_context ioc; @@ -127,8 +125,7 @@ bench_concurrent_latency(bench::state& state) { asio::co_spawn( ioc, - pingpong_client_task( - clients[p], servers[p], 64, running, state), + pingpong_client_task(clients[p], servers[p], 64, running, state), asio::detached); } @@ -153,7 +150,7 @@ bench_concurrent_latency(bench::state& state) void bench_pingpong_latency_lockless(bench::state& state) { - auto message_size = static_cast(state.range(0)); + auto message_size = static_cast(state.range(0)); state.counters["message_size"] = static_cast(message_size); asio::io_context ioc(BOOST_ASIO_CONCURRENCY_HINT_UNSAFE); @@ -162,9 +159,7 @@ bench_pingpong_latency_lockless(bench::state& state) std::atomic running{true}; asio::co_spawn( - ioc, - pingpong_client_task( - client, server, message_size, running, state), + ioc, pingpong_client_task(client, server, message_size, running, state), asio::detached); std::thread timer([&]() { @@ -185,7 +180,7 @@ bench_pingpong_latency_lockless(bench::state& state) void bench_concurrent_latency_lockless(bench::state& state) { - int num_pairs = static_cast(state.range(0)); + int num_pairs = static_cast(state.range(0)); state.counters["num_pairs"] = num_pairs; asio::io_context ioc(BOOST_ASIO_CONCURRENCY_HINT_UNSAFE); @@ -209,8 +204,7 @@ bench_concurrent_latency_lockless(bench::state& state) { asio::co_spawn( ioc, - pingpong_client_task( - clients[p], servers[p], 64, running, state), + pingpong_client_task(clients[p], servers[p], 64, running, state), asio::detached); } @@ -239,13 +233,13 @@ make_local_socket_latency_suite() { return bench::benchmark_suite("local_socket_latency") .add("pingpong", bench_pingpong_latency) - .args({1, 64, 1024}) + .args({1, 64, 1024}) .add("pingpong_lockless", bench_pingpong_latency_lockless) - .args({1, 64, 1024}) + .args({1, 64, 1024}) .add("concurrent", bench_concurrent_latency) - .args({1, 4, 16}) + .args({1, 4, 16}) .add("concurrent_lockless", bench_concurrent_latency_lockless) - .args({1, 4, 16}); + .args({1, 4, 16}); } } // namespace asio_bench diff --git a/perf/bench/asio/coroutine/local_socket_throughput_bench.cpp b/bench/asio/coroutine/local_socket_throughput_bench.cpp similarity index 96% rename from perf/bench/asio/coroutine/local_socket_throughput_bench.cpp rename to bench/asio/coroutine/local_socket_throughput_bench.cpp index 1174a8140..96bc9849a 100644 --- a/perf/bench/asio/coroutine/local_socket_throughput_bench.cpp +++ b/bench/asio/coroutine/local_socket_throughput_bench.cpp @@ -30,7 +30,7 @@ namespace { void bench_throughput(bench::state& state) { - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); asio::io_context ioc; @@ -98,7 +98,7 @@ bench_throughput(bench::state& state) void bench_bidirectional_throughput(bench::state& state) { - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); asio::io_context ioc; @@ -202,7 +202,7 @@ bench_bidirectional_throughput(bench::state& state) void bench_throughput_lockless(bench::state& state) { - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); asio::io_context ioc(BOOST_ASIO_CONCURRENCY_HINT_UNSAFE); @@ -270,7 +270,7 @@ bench_throughput_lockless(bench::state& state) void bench_bidirectional_throughput_lockless(bench::state& state) { - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); asio::io_context ioc(BOOST_ASIO_CONCURRENCY_HINT_UNSAFE); @@ -378,13 +378,13 @@ make_local_socket_throughput_suite() { return bench::benchmark_suite("local_socket_throughput") .add("unidirectional", bench_throughput) - .range(1024, 1048576, 4) + .range(1024, 1048576, 4) .add("unidirectional_lockless", bench_throughput_lockless) - .range(1024, 1048576, 4) + .range(1024, 1048576, 4) .add("bidirectional", bench_bidirectional_throughput) - .range(1024, 1048576, 4) + .range(1024, 1048576, 4) .add("bidirectional_lockless", bench_bidirectional_throughput_lockless) - .range(1024, 1048576, 4); + .range(1024, 1048576, 4); } } // namespace asio_bench diff --git a/perf/bench/asio/coroutine/socket_latency_bench.cpp b/bench/asio/coroutine/socket_latency_bench.cpp similarity index 88% rename from perf/bench/asio/coroutine/socket_latency_bench.cpp rename to bench/asio/coroutine/socket_latency_bench.cpp index d5e18acf8..53a63d718 100644 --- a/perf/bench/asio/coroutine/socket_latency_bench.cpp +++ b/bench/asio/coroutine/socket_latency_bench.cpp @@ -71,7 +71,7 @@ pingpong_client_task( void bench_pingpong_latency(bench::state& state) { - auto message_size = static_cast(state.range(0)); + auto message_size = static_cast(state.range(0)); state.counters["message_size"] = static_cast(message_size); asio::io_context ioc; @@ -80,9 +80,7 @@ bench_pingpong_latency(bench::state& state) std::atomic running{true}; asio::co_spawn( - ioc, - pingpong_client_task( - client, server, message_size, running, state), + ioc, pingpong_client_task(client, server, message_size, running, state), asio::detached); std::thread timer([&]() { @@ -103,7 +101,7 @@ bench_pingpong_latency(bench::state& state) void bench_concurrent_latency(bench::state& state) { - int num_pairs = static_cast(state.range(0)); + int num_pairs = static_cast(state.range(0)); state.counters["num_pairs"] = num_pairs; asio::io_context ioc; @@ -127,8 +125,7 @@ bench_concurrent_latency(bench::state& state) { asio::co_spawn( ioc, - pingpong_client_task( - clients[p], servers[p], 64, running, state), + pingpong_client_task(clients[p], servers[p], 64, running, state), asio::detached); } @@ -153,7 +150,7 @@ bench_concurrent_latency(bench::state& state) void bench_pingpong_latency_lockless(bench::state& state) { - auto message_size = static_cast(state.range(0)); + auto message_size = static_cast(state.range(0)); state.counters["message_size"] = static_cast(message_size); asio::io_context ioc(BOOST_ASIO_CONCURRENCY_HINT_UNSAFE); @@ -162,9 +159,7 @@ bench_pingpong_latency_lockless(bench::state& state) std::atomic running{true}; asio::co_spawn( - ioc, - pingpong_client_task( - client, server, message_size, running, state), + ioc, pingpong_client_task(client, server, message_size, running, state), asio::detached); std::thread timer([&]() { @@ -185,7 +180,7 @@ bench_pingpong_latency_lockless(bench::state& state) void bench_concurrent_latency_lockless(bench::state& state) { - int num_pairs = static_cast(state.range(0)); + int num_pairs = static_cast(state.range(0)); state.counters["num_pairs"] = num_pairs; asio::io_context ioc(BOOST_ASIO_CONCURRENCY_HINT_UNSAFE); @@ -209,8 +204,7 @@ bench_concurrent_latency_lockless(bench::state& state) { asio::co_spawn( ioc, - pingpong_client_task( - clients[p], servers[p], 64, running, state), + pingpong_client_task(clients[p], servers[p], 64, running, state), asio::detached); } @@ -240,13 +234,13 @@ make_socket_latency_suite() using F = bench::bench_flags; return bench::benchmark_suite("socket_latency", F::needs_conntrack_drain) .add("pingpong", bench_pingpong_latency) - .args({1, 64, 1024}) + .args({1, 64, 1024}) .add("pingpong_lockless", bench_pingpong_latency_lockless) - .args({1, 64, 1024}) + .args({1, 64, 1024}) .add("concurrent", bench_concurrent_latency) - .args({1, 4, 16}) + .args({1, 4, 16}) .add("concurrent_lockless", bench_concurrent_latency_lockless) - .args({1, 4, 16}); + .args({1, 4, 16}); } } // namespace asio_bench diff --git a/perf/bench/asio/coroutine/socket_throughput_bench.cpp b/bench/asio/coroutine/socket_throughput_bench.cpp similarity index 95% rename from perf/bench/asio/coroutine/socket_throughput_bench.cpp rename to bench/asio/coroutine/socket_throughput_bench.cpp index 5f714af1f..d6c6ef4d2 100644 --- a/perf/bench/asio/coroutine/socket_throughput_bench.cpp +++ b/bench/asio/coroutine/socket_throughput_bench.cpp @@ -30,7 +30,7 @@ namespace { void bench_throughput(bench::state& state) { - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); asio::io_context ioc; @@ -98,7 +98,7 @@ bench_throughput(bench::state& state) void bench_bidirectional_throughput(bench::state& state) { - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); asio::io_context ioc; @@ -202,7 +202,7 @@ bench_bidirectional_throughput(bench::state& state) void bench_throughput_lockless(bench::state& state) { - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); asio::io_context ioc(BOOST_ASIO_CONCURRENCY_HINT_UNSAFE); @@ -270,7 +270,7 @@ bench_throughput_lockless(bench::state& state) void bench_bidirectional_throughput_lockless(bench::state& state) { - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); asio::io_context ioc(BOOST_ASIO_CONCURRENCY_HINT_UNSAFE); @@ -394,10 +394,7 @@ mt_write_coro( } asio::awaitable -mt_read_coro( - tcp_socket& sock, - std::size_t chunk_size, - bench::state& state) +mt_read_coro(tcp_socket& sock, std::size_t chunk_size, bench::state& state) { try { @@ -461,14 +458,12 @@ bench_multithread_throughput(bench::state& state) ioc, mt_write_coro(sock1s[i], bufs[i].wbuf1, chunk_size, running), asio::detached); asio::co_spawn( - ioc, mt_read_coro(sock2s[i], chunk_size, state), - asio::detached); + ioc, mt_read_coro(sock2s[i], chunk_size, state), asio::detached); asio::co_spawn( ioc, mt_write_coro(sock2s[i], bufs[i].wbuf2, chunk_size, running), asio::detached); asio::co_spawn( - ioc, mt_read_coro(sock1s[i], chunk_size, state), - asio::detached); + ioc, mt_read_coro(sock1s[i], chunk_size, state), asio::detached); } perf::stopwatch sw; @@ -506,15 +501,15 @@ make_socket_throughput_suite() using F = bench::bench_flags; return bench::benchmark_suite("socket_throughput", F::needs_conntrack_drain) .add("unidirectional", bench_throughput) - .range(1024, 1048576, 4) + .range(1024, 1048576, 4) .add("unidirectional_lockless", bench_throughput_lockless) - .range(1024, 1048576, 4) + .range(1024, 1048576, 4) .add("bidirectional", bench_bidirectional_throughput) - .range(1024, 1048576, 4) + .range(1024, 1048576, 4) .add("bidirectional_lockless", bench_bidirectional_throughput_lockless) - .range(1024, 1048576, 4) + .range(1024, 1048576, 4) .add("multithread", bench_multithread_throughput) - .args({2, 4, 8}); + .args({2, 4, 8}); } } // namespace asio_bench diff --git a/perf/bench/asio/local_socket_utils.hpp b/bench/asio/local_socket_utils.hpp similarity index 100% rename from perf/bench/asio/local_socket_utils.hpp rename to bench/asio/local_socket_utils.hpp diff --git a/perf/bench/asio/socket_utils.hpp b/bench/asio/socket_utils.hpp similarity index 93% rename from perf/bench/asio/socket_utils.hpp rename to bench/asio/socket_utils.hpp index db6253a7a..b4c704e8b 100644 --- a/perf/bench/asio/socket_utils.hpp +++ b/bench/asio/socket_utils.hpp @@ -27,9 +27,9 @@ using executor_type = asio::io_context::executor_type; using tcp_socket = asio::basic_stream_socket; using tcp_acceptor = asio::basic_socket_acceptor; using timer_type = asio::basic_waitable_timer< - std::chrono::steady_clock, - asio::wait_traits, - executor_type>; + std::chrono::steady_clock, + asio::wait_traits, + executor_type>; /** Create a connected pair of TCP sockets for benchmarking. */ inline std::pair diff --git a/perf/common/backend_selection.hpp b/bench/common/backend_selection.hpp similarity index 94% rename from perf/common/backend_selection.hpp rename to bench/common/backend_selection.hpp index 5e881b430..011a397d7 100644 --- a/perf/common/backend_selection.hpp +++ b/bench/common/backend_selection.hpp @@ -49,8 +49,8 @@ print_available_backends() #if BOOST_COROSIO_HAS_IOCP std::cout << " iocp - Windows I/O Completion Ports (default)\n"; #endif -#if BOOST_COROSIO_HAS_IO_URING - std::cout << " io_uring - Linux io_uring\n"; +#if BOOST_COROSIO_HAS_URING + std::cout << " uring - Linux io_uring\n"; #endif #if BOOST_COROSIO_HAS_EPOLL std::cout << " epoll - Linux epoll (default)\n"; @@ -80,14 +80,14 @@ dispatch_backend(const char* backend, Func&& func) { namespace corosio = boost::corosio; -#if BOOST_COROSIO_HAS_IO_URING - if (std::strcmp(backend, "io_uring") == 0) +#if BOOST_COROSIO_HAS_URING + if (std::strcmp(backend, "uring") == 0) { func( []() -> std::unique_ptr { - return std::make_unique(corosio::io_uring); + return std::make_unique(corosio::uring); }, - corosio::io_uring, "io_uring"); + corosio::uring, "uring"); return 0; } #endif diff --git a/perf/bench/common/benchmark.hpp b/bench/common/benchmark.hpp similarity index 93% rename from perf/bench/common/benchmark.hpp rename to bench/common/benchmark.hpp index 231dc97ed..f3eb199e8 100644 --- a/perf/bench/common/benchmark.hpp +++ b/bench/common/benchmark.hpp @@ -10,7 +10,7 @@ #ifndef BOOST_COROSIO_BENCH_RESULT_HPP #define BOOST_COROSIO_BENCH_RESULT_HPP -#include "../../common/perf.hpp" +#include "perf.hpp" #include #include @@ -39,10 +39,7 @@ struct benchmark_result std::string name; std::vector metrics; - benchmark_result( - std::string lib, - std::string cat, - std::string n) + benchmark_result(std::string lib, std::string cat, std::string n) : library(std::move(lib)) , category(std::move(cat)) , name(std::move(n)) @@ -169,10 +166,10 @@ class result_collector auto const& r = results_[i]; oss << " {\n"; if (!r.library.empty()) - oss << " \"library\": \"" - << escape_json(r.library) << "\",\n"; - oss << " \"category\": \"" - << escape_json(r.category) << "\",\n"; + oss << " \"library\": \"" << escape_json(r.library) + << "\",\n"; + oss << " \"category\": \"" << escape_json(r.category) + << "\",\n"; oss << " \"name\": \"" << escape_json(r.name) << "\""; for (auto const& m : r.metrics) diff --git a/perf/bench/common/http_protocol.hpp b/bench/common/http_protocol.hpp similarity index 100% rename from perf/bench/common/http_protocol.hpp rename to bench/common/http_protocol.hpp diff --git a/perf/common/native_includes.hpp b/bench/common/native_includes.hpp similarity index 68% rename from perf/common/native_includes.hpp rename to bench/common/native_includes.hpp index 224d57cc7..6c08bd8bb 100644 --- a/perf/common/native_includes.hpp +++ b/bench/common/native_includes.hpp @@ -43,25 +43,25 @@ #define COROSIO_SUITE_INSTANTIATE_IOCP(decl) #endif -#if BOOST_COROSIO_HAS_IO_URING -#define COROSIO_SUITE_INSTANTIATE_IO_URING(decl) \ - template bench::benchmark_suite decl(); +#if BOOST_COROSIO_HAS_URING +#define COROSIO_SUITE_INSTANTIATE_URING(decl) \ + template bench::benchmark_suite decl(); #else -#define COROSIO_SUITE_INSTANTIATE_IO_URING(decl) +#define COROSIO_SUITE_INSTANTIATE_URING(decl) #endif -#define COROSIO_SUITE_INSTANTIATE(decl) \ - COROSIO_SUITE_INSTANTIATE_EPOLL(decl) \ - COROSIO_SUITE_INSTANTIATE_KQUEUE(decl) \ - COROSIO_SUITE_INSTANTIATE_SELECT(decl) \ - COROSIO_SUITE_INSTANTIATE_IOCP(decl) \ - COROSIO_SUITE_INSTANTIATE_IO_URING(decl) +#define COROSIO_SUITE_INSTANTIATE(decl) \ + COROSIO_SUITE_INSTANTIATE_EPOLL(decl) \ + COROSIO_SUITE_INSTANTIATE_KQUEUE(decl) \ + COROSIO_SUITE_INSTANTIATE_SELECT(decl) \ + COROSIO_SUITE_INSTANTIATE_IOCP(decl) \ + COROSIO_SUITE_INSTANTIATE_URING(decl) // POSIX-only instantiation (no IOCP) for Unix domain socket benchmarks -#define COROSIO_SUITE_INSTANTIATE_POSIX(decl) \ - COROSIO_SUITE_INSTANTIATE_EPOLL(decl) \ - COROSIO_SUITE_INSTANTIATE_KQUEUE(decl) \ - COROSIO_SUITE_INSTANTIATE_SELECT(decl) \ - COROSIO_SUITE_INSTANTIATE_IO_URING(decl) +#define COROSIO_SUITE_INSTANTIATE_POSIX(decl) \ + COROSIO_SUITE_INSTANTIATE_EPOLL(decl) \ + COROSIO_SUITE_INSTANTIATE_KQUEUE(decl) \ + COROSIO_SUITE_INSTANTIATE_SELECT(decl) \ + COROSIO_SUITE_INSTANTIATE_URING(decl) #endif // BOOST_COROSIO_PERF_NATIVE_INCLUDES_HPP diff --git a/perf/common/perf.hpp b/bench/common/perf.hpp similarity index 97% rename from perf/common/perf.hpp rename to bench/common/perf.hpp index beb3a769d..51c7e167e 100644 --- a/perf/common/perf.hpp +++ b/bench/common/perf.hpp @@ -307,9 +307,8 @@ await_conntrack_drain() // TIME_WAIT sockets from previous benchmark runs can exhaust // ephemeral ports. Poll the TCP PCB count and wait for it to // drop below 75% of the ephemeral port range. - auto sysctl_int = [](char const* name) -> long - { - int val = 0; + auto sysctl_int = [](char const* name) -> long { + int val = 0; std::size_t len = sizeof(val); if (sysctlbyname(name, &val, &len, nullptr, 0) == 0) return static_cast(val); @@ -322,15 +321,15 @@ await_conntrack_drain() return; long threshold = (last - first + 1) * 3 / 4; - long count = sysctl_int("net.inet.tcp.pcbcount"); + long count = sysctl_int("net.inet.tcp.pcbcount"); if (count < 0 || count <= threshold) return; std::cout << " [tcp] " << count << " PCBs, waiting to drain below " << threshold << " ..." << std::flush; - using clock = std::chrono::steady_clock; - auto deadline = clock::now() + std::chrono::seconds( 30 ); + using clock = std::chrono::steady_clock; + auto deadline = clock::now() + std::chrono::seconds(30); while (clock::now() < deadline) { diff --git a/perf/bench/common/suite.hpp b/bench/common/suite.hpp similarity index 87% rename from perf/bench/common/suite.hpp rename to bench/common/suite.hpp index 2f1b3684b..d7f0bec51 100644 --- a/perf/bench/common/suite.hpp +++ b/bench/common/suite.hpp @@ -11,7 +11,7 @@ #define BOOST_COROSIO_BENCH_SUITE_HPP #include "benchmark.hpp" -#include "../../common/perf.hpp" +#include "perf.hpp" #include #include @@ -67,9 +67,7 @@ class lap_guard public: lap_guard( - perf::statistics& stats, - std::atomic& ops, - std::mutex& mtx) + perf::statistics& stats, std::atomic& ops, std::mutex& mtx) : stats_(stats) , ops_(ops) , mtx_(mtx) @@ -137,8 +135,7 @@ class state void wait() { perf::stopwatch sw; - std::this_thread::sleep_for( - std::chrono::duration(duration_s_)); + std::this_thread::sleep_for(std::chrono::duration(duration_s_)); running_.store(false, std::memory_order_relaxed); elapsed_ = sw.elapsed_seconds(); } @@ -287,8 +284,7 @@ class benchmark_suite /// Add a benchmark with no parameters. benchmark_suite& - add(std::string name, bench_fn fn, - bench_flags flags = bench_flags::none) + add(std::string name, bench_fn fn, bench_flags flags = bench_flags::none) { entries_.push_back({std::move(name), std::move(fn), flags, {}}); return *this; @@ -315,12 +311,27 @@ class benchmark_suite } /// Set the library name (called by the runner). - void set_library(std::string lib) { library_ = std::move(lib); } + void set_library(std::string lib) + { + library_ = std::move(lib); + } - std::string const& library() const { return library_; } - std::string const& category() const { return category_; } - bench_flags flags() const { return flags_; } - std::vector const& entries() const { return entries_; } + std::string const& library() const + { + return library_; + } + std::string const& category() const + { + return category_; + } + bench_flags flags() const + { + return flags_; + } + std::vector const& entries() const + { + return entries_; + } }; /** Orchestrate benchmark execution, output, and result collection. */ @@ -360,7 +371,10 @@ class benchmark_runner warmup_duration_s_ = seconds; } - double warmup_duration() const { return warmup_duration_s_; } + double warmup_duration() const + { + return warmup_duration_s_; + } /// Add a suite to the runner. void add_suite(benchmark_suite suite) @@ -392,8 +406,7 @@ class benchmark_runner else { for (auto v : entry.args) - std::cout << " " << entry.name - << "/" << v << "\n"; + std::cout << " " << entry.name << "/" << v << "\n"; } } } @@ -409,20 +422,20 @@ class benchmark_runner `is_microbenchmark` are skipped unless explicitly selected by category_filter. */ - void run( - char const* category_filter, + void + run(char const* category_filter, char const* bench_filter, bool enable_microbenchmarks) { - bool run_all_cats = !category_filter || - std::strcmp(category_filter, "all") == 0; + bool run_all_cats = + !category_filter || std::strcmp(category_filter, "all") == 0; auto want_bench = [&](std::string const& name) { if (!bench_filter || std::strcmp(bench_filter, "all") == 0) return true; // Prefix match - return name.compare( - 0, std::strlen(bench_filter), bench_filter) == 0; + return name.compare(0, std::strlen(bench_filter), bench_filter) == + 0; }; for (auto const& suite : suites_) @@ -441,10 +454,9 @@ class benchmark_runner for (auto const& entry : suite.entries()) { bool needs_drain = - has_flag(suite.flags(), - bench_flags::needs_conntrack_drain) || - has_flag(entry.flags, - bench_flags::needs_conntrack_drain); + has_flag( + suite.flags(), bench_flags::needs_conntrack_drain) || + has_flag(entry.flags, bench_flags::needs_conntrack_drain); if (entry.args.empty()) { @@ -452,8 +464,8 @@ class benchmark_runner continue; run_entry( - suite.library(), suite.category(), - entry.name, entry.fn, {}, needs_drain); + suite.library(), suite.category(), entry.name, entry.fn, + {}, needs_drain); } else { @@ -461,13 +473,12 @@ class benchmark_runner { std::string full_name = entry.name + "/" + std::to_string(v); - if (!want_bench(entry.name) && - !want_bench(full_name)) + if (!want_bench(entry.name) && !want_bench(full_name)) continue; run_entry( - suite.library(), suite.category(), - full_name, entry.fn, {v}, needs_drain); + suite.library(), suite.category(), full_name, + entry.fn, {v}, needs_drain); } } } @@ -532,8 +543,8 @@ class benchmark_runner { double ops_per_sec = static_cast(ops) / elapsed; std::cout << " Ops: " << ops << "\n"; - std::cout << " Throughput: " - << perf::format_rate(ops_per_sec) << "\n"; + std::cout << " Throughput: " << perf::format_rate(ops_per_sec) + << "\n"; } int64_t items = st.total_items(); @@ -541,8 +552,8 @@ class benchmark_runner { double items_per_sec = static_cast(items) / elapsed; std::cout << " Items: " << items << "\n"; - std::cout << " Rate: " - << perf::format_rate(items_per_sec) << "\n"; + std::cout << " Rate: " << perf::format_rate(items_per_sec) + << "\n"; } int64_t bytes = st.total_bytes(); @@ -554,8 +565,8 @@ class benchmark_runner << perf::format_throughput(bytes_per_sec) << "\n"; } - std::cout << " Elapsed: " << std::fixed - << std::setprecision(3) << elapsed << " s\n"; + std::cout << " Elapsed: " << std::fixed << std::setprecision(3) + << elapsed << " s\n"; if (st.latency().count() > 0) perf::print_latency_stats(st.latency(), "Latency"); @@ -585,8 +596,7 @@ class benchmark_runner } } label += ':'; - std::cout << " " << std::left << std::setw(15) - << label; + std::cout << " " << std::left << std::setw(15) << label; if (v == static_cast(v)) std::cout << static_cast(v); else @@ -614,24 +624,21 @@ class benchmark_runner if (ops > 0) { result.add("ops", static_cast(ops)); - result.add("ops_per_sec", - static_cast(ops) / elapsed); + result.add("ops_per_sec", static_cast(ops) / elapsed); } int64_t items = st.total_items(); if (items > 0) { result.add("items", static_cast(items)); - result.add("items_per_sec", - static_cast(items) / elapsed); + result.add("items_per_sec", static_cast(items) / elapsed); } int64_t bytes = st.total_bytes(); if (bytes > 0) { result.add("bytes", static_cast(bytes)); - result.add("bytes_per_sec", - static_cast(bytes) / elapsed); + result.add("bytes_per_sec", static_cast(bytes) / elapsed); } if (st.latency().count() > 0) diff --git a/perf/bench/corosio/accept_churn_bench.cpp b/bench/corosio/accept_churn_bench.cpp similarity index 97% rename from perf/bench/corosio/accept_churn_bench.cpp rename to bench/corosio/accept_churn_bench.cpp index 904ae2ff9..434100717 100644 --- a/perf/bench/corosio/accept_churn_bench.cpp +++ b/bench/corosio/accept_churn_bench.cpp @@ -26,7 +26,7 @@ #include #include -#include "../../common/native_includes.hpp" +#include "../common/native_includes.hpp" namespace corosio = boost::corosio; namespace capy = boost::capy; @@ -214,7 +214,7 @@ bench_concurrent_churn(bench::state& state) using socket_type = corosio::native_tcp_socket; using acceptor_type = corosio::native_tcp_acceptor; - int num_loops = static_cast(state.range(0)); + int num_loops = static_cast(state.range(0)); state.counters["num_loops"] = num_loops; corosio::native_io_context ioc; @@ -224,7 +224,7 @@ bench_concurrent_churn(bench::state& state) for (int i = 0; i < num_loops; ++i) { acceptors.emplace_back(ioc); - auto& acc = acceptors.back(); + auto& acc = acceptors.back(); std::ignore = acc.open(); acc.set_option(corosio::native_socket_option::reuse_address(true)); if (auto ec = acc.bind( @@ -307,7 +307,7 @@ bench_burst_churn(bench::state& state) using socket_type = corosio::native_tcp_socket; using acceptor_type = corosio::native_tcp_acceptor; - int burst_size = static_cast(state.range(0)); + int burst_size = static_cast(state.range(0)); state.counters["burst_size"] = burst_size; corosio::native_io_context ioc; @@ -390,7 +390,7 @@ bench_burst_churn_lockless(bench::state& state) using socket_type = corosio::native_tcp_socket; using acceptor_type = corosio::native_tcp_acceptor; - int burst_size = static_cast(state.range(0)); + int burst_size = static_cast(state.range(0)); state.counters["burst_size"] = burst_size; corosio::io_context_options opts; @@ -479,11 +479,11 @@ make_accept_churn_suite() .add("sequential", bench_sequential_churn) .add("sequential_lockless", bench_sequential_churn_lockless) .add("concurrent", bench_concurrent_churn) - .args({1, 4, 16}) + .args({1, 4, 16}) .add("burst", bench_burst_churn) - .args({10, 100}) + .args({10, 100}) .add("burst_lockless", bench_burst_churn_lockless) - .args({10, 100}); + .args({10, 100}); } } // namespace corosio_bench diff --git a/perf/bench/corosio/benchmarks.hpp b/bench/corosio/benchmarks.hpp similarity index 100% rename from perf/bench/corosio/benchmarks.hpp rename to bench/corosio/benchmarks.hpp diff --git a/perf/bench/corosio/fan_out_bench.cpp b/bench/corosio/fan_out_bench.cpp similarity index 96% rename from perf/bench/corosio/fan_out_bench.cpp rename to bench/corosio/fan_out_bench.cpp index 5a383a5f2..cf573d10b 100644 --- a/perf/bench/corosio/fan_out_bench.cpp +++ b/bench/corosio/fan_out_bench.cpp @@ -26,7 +26,7 @@ #include #include -#include "../../common/native_includes.hpp" +#include "../common/native_includes.hpp" namespace corosio = boost::corosio; namespace capy = boost::capy; @@ -73,8 +73,7 @@ struct fan_out_latch template capy::task<> -sub_request( - corosio::native_tcp_socket& client, fan_out_latch& latch) +sub_request(corosio::native_tcp_socket& client, fan_out_latch& latch) { char send_buf[64] = {}; char recv_buf[64]; @@ -99,7 +98,7 @@ bench_fork_join(bench::state& state) { using socket_type = corosio::native_tcp_socket; - int fan_out = static_cast(state.range(0)); + int fan_out = static_cast(state.range(0)); state.counters["fan_out"] = fan_out; corosio::native_io_context ioc; @@ -322,7 +321,7 @@ bench_fork_join_lockless(bench::state& state) { using socket_type = corosio::native_tcp_socket; - int fan_out = static_cast(state.range(0)); + int fan_out = static_cast(state.range(0)); state.counters["fan_out"] = fan_out; corosio::io_context_options opts; @@ -552,17 +551,19 @@ make_fan_out_suite() using F = bench::bench_flags; return bench::benchmark_suite("fan_out", F::needs_conntrack_drain) .add("fork_join", bench_fork_join) - .args({1, 4, 16, 64}) + .args({1, 4, 16, 64}) .add("fork_join_lockless", bench_fork_join_lockless) - .args({1, 4, 16, 64}) + .args({1, 4, 16, 64}) .add("nested", bench_nested) - .args({4, 16}) + .args({4, 16}) .add("nested_lockless", bench_nested_lockless) - .args({4, 16}) + .args({4, 16}) .add("concurrent_parents", bench_concurrent_parents) - .args({1, 4, 16}) - .add("concurrent_parents_lockless", bench_concurrent_parents_lockless) - .args({1, 4, 16}); + .args({1, 4, 16}) + .add( + "concurrent_parents_lockless", + bench_concurrent_parents_lockless) + .args({1, 4, 16}); } } // namespace corosio_bench diff --git a/perf/bench/corosio/http_server_bench.cpp b/bench/corosio/http_server_bench.cpp similarity index 95% rename from perf/bench/corosio/http_server_bench.cpp rename to bench/corosio/http_server_bench.cpp index ecb28dde8..5fd7669e8 100644 --- a/perf/bench/corosio/http_server_bench.cpp +++ b/bench/corosio/http_server_bench.cpp @@ -31,7 +31,7 @@ #include #include "../common/http_protocol.hpp" -#include "../../common/native_includes.hpp" +#include "../common/native_includes.hpp" namespace corosio = boost::corosio; namespace capy = boost::capy; @@ -89,9 +89,7 @@ server_task(corosio::native_tcp_socket& sock) template capy::task<> -client_task( - corosio::native_tcp_socket& sock, - bench::state& state) +client_task(corosio::native_tcp_socket& sock, bench::state& state) { std::string buf; @@ -212,7 +210,7 @@ bench_concurrent_connections(bench::state& state) { using socket_type = corosio::native_tcp_socket; - int num_connections = static_cast(state.range(0)); + int num_connections = static_cast(state.range(0)); state.counters["connections"] = num_connections; corosio::native_io_context ioc; @@ -235,8 +233,7 @@ bench_concurrent_connections(bench::state& state) for (int i = 0; i < num_connections; ++i) { - capy::run_async(ioc.get_executor())( - server_task(servers[i])); + capy::run_async(ioc.get_executor())(server_task(servers[i])); capy::run_async(ioc.get_executor())( client_task(clients[i], state)); } @@ -291,8 +288,7 @@ bench_multithread(bench::state& state) for (int i = 0; i < num_connections; ++i) { - capy::run_async(ioc.get_executor())( - server_task(servers[i])); + capy::run_async(ioc.get_executor())(server_task(servers[i])); capy::run_async(ioc.get_executor())( client_task(clients[i], state)); } @@ -336,9 +332,9 @@ make_http_server_suite() .add("single_conn", bench_single_connection) .add("single_conn_lockless", bench_single_connection_lockless) .add("concurrent", bench_concurrent_connections) - .args({1, 4, 16, 32}) + .args({1, 4, 16, 32}) .add("multithread", bench_multithread) - .args({1, 2, 4, 8, 16}); + .args({1, 2, 4, 8, 16}); } } // namespace corosio_bench diff --git a/perf/bench/corosio/io_context_bench.cpp b/bench/corosio/io_context_bench.cpp similarity index 98% rename from perf/bench/corosio/io_context_bench.cpp rename to bench/corosio/io_context_bench.cpp index 83e615a72..be38f756b 100644 --- a/perf/bench/corosio/io_context_bench.cpp +++ b/bench/corosio/io_context_bench.cpp @@ -18,7 +18,7 @@ #include #include -#include "../../common/native_includes.hpp" +#include "../common/native_includes.hpp" namespace corosio = boost::corosio; namespace capy = boost::capy; @@ -332,13 +332,14 @@ make_io_context_suite() return bench::benchmark_suite("io_context", F::is_microbenchmark) .add("single_threaded", bench_single_threaded_post) .add("multithreaded", bench_multithreaded_scaling) - .args({8}) + .args({8}) .add("interleaved", bench_interleaved_post_run) .add("concurrent", bench_concurrent_post_run) - .args({4}) + .args({4}) .add("high_inline_budget", bench_high_inline_budget) .add("large_event_buffer", bench_large_event_buffer) - .add("single_threaded_lockless", bench_single_threaded_lockless) + .add( + "single_threaded_lockless", bench_single_threaded_lockless) .add("interleaved_lockless", bench_interleaved_lockless); } diff --git a/perf/bench/corosio/local_socket_latency_bench.cpp b/bench/corosio/local_socket_latency_bench.cpp similarity index 86% rename from perf/bench/corosio/local_socket_latency_bench.cpp rename to bench/corosio/local_socket_latency_bench.cpp index 6987a85f2..159ea67c9 100644 --- a/perf/bench/corosio/local_socket_latency_bench.cpp +++ b/bench/corosio/local_socket_latency_bench.cpp @@ -9,7 +9,7 @@ #include "benchmarks.hpp" #include -#include "../../common/native_includes.hpp" +#include "../common/native_includes.hpp" #if BOOST_COROSIO_POSIX @@ -82,7 +82,7 @@ bench_unix_pingpong_latency(bench::state& state) { using socket_type = corosio::native_local_stream_socket; - auto message_size = static_cast(state.range(0)); + auto message_size = static_cast(state.range(0)); state.counters["message_size"] = static_cast(message_size); corosio::native_io_context ioc; @@ -90,8 +90,8 @@ bench_unix_pingpong_latency(bench::state& state) if (auto ec = corosio::connect_pair(client, server)) throw std::system_error(ec, "connect_pair"); - capy::run_async(ioc.get_executor())( - unix_pingpong_client_task(client, server, message_size, state)); + capy::run_async(ioc.get_executor())(unix_pingpong_client_task( + client, server, message_size, state)); std::thread timer([&]() { std::this_thread::sleep_for( @@ -114,7 +114,7 @@ bench_unix_concurrent_latency(bench::state& state) { using socket_type = corosio::native_local_stream_socket; - int num_pairs = static_cast(state.range(0)); + int num_pairs = static_cast(state.range(0)); state.counters["num_pairs"] = num_pairs; corosio::native_io_context ioc; @@ -136,8 +136,8 @@ bench_unix_concurrent_latency(bench::state& state) for (int p = 0; p < num_pairs; ++p) { - capy::run_async(ioc.get_executor())( - unix_pingpong_client_task(clients[p], servers[p], 64, state)); + capy::run_async(ioc.get_executor())(unix_pingpong_client_task( + clients[p], servers[p], 64, state)); } std::thread timer([&]() { @@ -164,7 +164,7 @@ bench_unix_pingpong_latency_lockless(bench::state& state) { using socket_type = corosio::native_local_stream_socket; - auto message_size = static_cast(state.range(0)); + auto message_size = static_cast(state.range(0)); state.counters["message_size"] = static_cast(message_size); corosio::io_context_options opts; @@ -174,8 +174,8 @@ bench_unix_pingpong_latency_lockless(bench::state& state) if (auto ec = corosio::connect_pair(client, server)) throw std::system_error(ec, "connect_pair"); - capy::run_async(ioc.get_executor())( - unix_pingpong_client_task(client, server, message_size, state)); + capy::run_async(ioc.get_executor())(unix_pingpong_client_task( + client, server, message_size, state)); std::thread timer([&]() { std::this_thread::sleep_for( @@ -198,7 +198,7 @@ bench_unix_concurrent_latency_lockless(bench::state& state) { using socket_type = corosio::native_local_stream_socket; - int num_pairs = static_cast(state.range(0)); + int num_pairs = static_cast(state.range(0)); state.counters["num_pairs"] = num_pairs; corosio::io_context_options opts; @@ -222,8 +222,8 @@ bench_unix_concurrent_latency_lockless(bench::state& state) for (int p = 0; p < num_pairs; ++p) { - capy::run_async(ioc.get_executor())( - unix_pingpong_client_task(clients[p], servers[p], 64, state)); + capy::run_async(ioc.get_executor())(unix_pingpong_client_task( + clients[p], servers[p], 64, state)); } std::thread timer([&]() { @@ -254,13 +254,15 @@ make_local_socket_latency_suite() return bench::benchmark_suite("local_socket_latency", F::none) .add("pingpong", bench_unix_pingpong_latency) - .args({1, 64, 1024}) + .args({1, 64, 1024}) .add("pingpong_lockless", bench_unix_pingpong_latency_lockless) - .args({1, 64, 1024}) + .args({1, 64, 1024}) .add("concurrent", bench_unix_concurrent_latency) - .args({1, 4, 16}) - .add("concurrent_lockless", bench_unix_concurrent_latency_lockless) - .args({1, 4, 16}); + .args({1, 4, 16}) + .add( + "concurrent_lockless", + bench_unix_concurrent_latency_lockless) + .args({1, 4, 16}); } } // namespace corosio_bench diff --git a/perf/bench/corosio/local_socket_throughput_bench.cpp b/bench/corosio/local_socket_throughput_bench.cpp similarity index 88% rename from perf/bench/corosio/local_socket_throughput_bench.cpp rename to bench/corosio/local_socket_throughput_bench.cpp index f3282b044..1aad2b72f 100644 --- a/perf/bench/corosio/local_socket_throughput_bench.cpp +++ b/bench/corosio/local_socket_throughput_bench.cpp @@ -9,7 +9,7 @@ #include "benchmarks.hpp" #include -#include "../../common/native_includes.hpp" +#include "../common/native_includes.hpp" #if BOOST_COROSIO_POSIX @@ -41,7 +41,7 @@ bench_unix_throughput(bench::state& state) { using socket_type = corosio::native_local_stream_socket; - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); corosio::native_io_context ioc; @@ -63,7 +63,8 @@ bench_unix_throughput(bench::state& state) if (ec) break; } - std::ignore = writer.shutdown(corosio::local_stream_socket::shutdown_send); + std::ignore = + writer.shutdown(corosio::local_stream_socket::shutdown_send); }; auto read_task = [&]() -> capy::task<> { @@ -103,7 +104,7 @@ bench_unix_bidirectional_throughput(bench::state& state) { using socket_type = corosio::native_local_stream_socket; - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); corosio::native_io_context ioc; @@ -126,7 +127,8 @@ bench_unix_bidirectional_throughput(bench::state& state) if (ec) break; } - std::ignore = sock1.shutdown(corosio::local_stream_socket::shutdown_send); + std::ignore = + sock1.shutdown(corosio::local_stream_socket::shutdown_send); }; auto read1_task = [&]() -> capy::task<> { @@ -149,7 +151,8 @@ bench_unix_bidirectional_throughput(bench::state& state) if (ec) break; } - std::ignore = sock2.shutdown(corosio::local_stream_socket::shutdown_send); + std::ignore = + sock2.shutdown(corosio::local_stream_socket::shutdown_send); }; auto read2_task = [&]() -> capy::task<> { @@ -192,7 +195,7 @@ bench_unix_throughput_lockless(bench::state& state) { using socket_type = corosio::native_local_stream_socket; - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); corosio::io_context_options opts; @@ -216,7 +219,8 @@ bench_unix_throughput_lockless(bench::state& state) if (ec) break; } - std::ignore = writer.shutdown(corosio::local_stream_socket::shutdown_send); + std::ignore = + writer.shutdown(corosio::local_stream_socket::shutdown_send); }; auto read_task = [&]() -> capy::task<> { @@ -256,7 +260,7 @@ bench_unix_bidirectional_throughput_lockless(bench::state& state) { using socket_type = corosio::native_local_stream_socket; - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); corosio::io_context_options opts; @@ -281,7 +285,8 @@ bench_unix_bidirectional_throughput_lockless(bench::state& state) if (ec) break; } - std::ignore = sock1.shutdown(corosio::local_stream_socket::shutdown_send); + std::ignore = + sock1.shutdown(corosio::local_stream_socket::shutdown_send); }; auto read1_task = [&]() -> capy::task<> { @@ -304,7 +309,8 @@ bench_unix_bidirectional_throughput_lockless(bench::state& state) if (ec) break; } - std::ignore = sock2.shutdown(corosio::local_stream_socket::shutdown_send); + std::ignore = + sock2.shutdown(corosio::local_stream_socket::shutdown_send); }; auto read2_task = [&]() -> capy::task<> { @@ -351,17 +357,20 @@ make_local_socket_throughput_suite() return bench::benchmark_suite("local_socket_throughput", F::none) .add("unidirectional", bench_unix_throughput) - .range(1024, 1048576, 4) + .range(1024, 1048576, 4) .add("unidirectional_lockless", bench_unix_throughput_lockless) - .range(1024, 1048576, 4) + .range(1024, 1048576, 4) .add("bidirectional", bench_unix_bidirectional_throughput) - .range(1024, 1048576, 4) - .add("bidirectional_lockless", bench_unix_bidirectional_throughput_lockless) - .range(1024, 1048576, 4); + .range(1024, 1048576, 4) + .add( + "bidirectional_lockless", + bench_unix_bidirectional_throughput_lockless) + .range(1024, 1048576, 4); } } // namespace corosio_bench -COROSIO_SUITE_INSTANTIATE_POSIX(corosio_bench::make_local_socket_throughput_suite) +COROSIO_SUITE_INSTANTIATE_POSIX( + corosio_bench::make_local_socket_throughput_suite) #endif // BOOST_COROSIO_POSIX diff --git a/perf/bench/corosio/socket_latency_bench.cpp b/bench/corosio/socket_latency_bench.cpp similarity index 94% rename from perf/bench/corosio/socket_latency_bench.cpp rename to bench/corosio/socket_latency_bench.cpp index a9505d250..bc3eeb4bf 100644 --- a/perf/bench/corosio/socket_latency_bench.cpp +++ b/bench/corosio/socket_latency_bench.cpp @@ -26,7 +26,7 @@ #include #include -#include "../../common/native_includes.hpp" +#include "../common/native_includes.hpp" namespace corosio = boost::corosio; namespace capy = boost::capy; @@ -79,7 +79,7 @@ bench_pingpong_latency(bench::state& state) { using socket_type = corosio::native_tcp_socket; - auto message_size = static_cast(state.range(0)); + auto message_size = static_cast(state.range(0)); state.counters["message_size"] = static_cast(message_size); corosio::native_io_context ioc; @@ -113,7 +113,7 @@ bench_concurrent_latency(bench::state& state) { using socket_type = corosio::native_tcp_socket; - int num_pairs = static_cast(state.range(0)); + int num_pairs = static_cast(state.range(0)); state.counters["num_pairs"] = num_pairs; corosio::native_io_context ioc; @@ -164,7 +164,7 @@ bench_pingpong_latency_lockless(bench::state& state) { using socket_type = corosio::native_tcp_socket; - auto message_size = static_cast(state.range(0)); + auto message_size = static_cast(state.range(0)); state.counters["message_size"] = static_cast(message_size); corosio::io_context_options opts; @@ -200,7 +200,7 @@ bench_concurrent_latency_lockless(bench::state& state) { using socket_type = corosio::native_tcp_socket; - int num_pairs = static_cast(state.range(0)); + int num_pairs = static_cast(state.range(0)); state.counters["num_pairs"] = num_pairs; corosio::io_context_options opts; @@ -257,13 +257,13 @@ make_socket_latency_suite() return bench::benchmark_suite("socket_latency", F::needs_conntrack_drain) .add("pingpong", bench_pingpong_latency) - .args({1, 64, 1024}) + .args({1, 64, 1024}) .add("pingpong_lockless", bench_pingpong_latency_lockless) - .args({1, 64, 1024}) + .args({1, 64, 1024}) .add("concurrent", bench_concurrent_latency) - .args({1, 4, 16}) + .args({1, 4, 16}) .add("concurrent_lockless", bench_concurrent_latency_lockless) - .args({1, 4, 16}); + .args({1, 4, 16}); } } // namespace corosio_bench diff --git a/perf/bench/corosio/socket_throughput_bench.cpp b/bench/corosio/socket_throughput_bench.cpp similarity index 95% rename from perf/bench/corosio/socket_throughput_bench.cpp rename to bench/corosio/socket_throughput_bench.cpp index ff096f4b1..43345f4b2 100644 --- a/perf/bench/corosio/socket_throughput_bench.cpp +++ b/bench/corosio/socket_throughput_bench.cpp @@ -32,7 +32,7 @@ #include #endif -#include "../../common/native_includes.hpp" +#include "../common/native_includes.hpp" namespace corosio = boost::corosio; namespace capy = boost::capy; @@ -60,7 +60,7 @@ bench_throughput(bench::state& state) { using socket_type = corosio::native_tcp_socket; - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); corosio::native_io_context ioc; @@ -124,7 +124,7 @@ bench_bidirectional_throughput(bench::state& state) { using socket_type = corosio::native_tcp_socket; - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); corosio::native_io_context ioc; @@ -251,7 +251,7 @@ bench_throughput_lockless(bench::state& state) { using socket_type = corosio::native_tcp_socket; - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); corosio::io_context_options opts; @@ -317,7 +317,7 @@ bench_bidirectional_throughput_lockless(bench::state& state) { using socket_type = corosio::native_tcp_socket; - auto chunk_size = static_cast(state.range(0)); + auto chunk_size = static_cast(state.range(0)); state.counters["chunk_size"] = static_cast(chunk_size); corosio::io_context_options opts; @@ -498,15 +498,17 @@ make_socket_throughput_suite() return bench::benchmark_suite("socket_throughput", F::needs_conntrack_drain) .add("unidirectional", bench_throughput) - .range(1024, 1048576, 4) + .range(1024, 1048576, 4) .add("unidirectional_lockless", bench_throughput_lockless) - .range(1024, 1048576, 4) + .range(1024, 1048576, 4) .add("bidirectional", bench_bidirectional_throughput) - .range(1024, 1048576, 4) - .add("bidirectional_lockless", bench_bidirectional_throughput_lockless) - .range(1024, 1048576, 4) + .range(1024, 1048576, 4) + .add( + "bidirectional_lockless", + bench_bidirectional_throughput_lockless) + .range(1024, 1048576, 4) .add("multithread", bench_multithread_throughput) - .args({2, 4, 8}); + .args({2, 4, 8}); } } // namespace corosio_bench diff --git a/perf/bench/main.cpp b/bench/main.cpp similarity index 84% rename from perf/bench/main.cpp rename to bench/main.cpp index f98f0802b..c6e50ca6d 100644 --- a/perf/bench/main.cpp +++ b/bench/main.cpp @@ -20,7 +20,7 @@ #include #include -#include "../common/backend_selection.hpp" +#include "common/backend_selection.hpp" #include "common/suite.hpp" namespace { @@ -42,8 +42,7 @@ print_usage(char const* program_name) "(default: 3.0)\n"; std::cout << " --warmup Self-warmup duration per benchmark " "(default: 0,\n"; - std::cout - << " disabled; try 0.5 for rigor)\n"; + std::cout << " disabled; try 0.5 for rigor)\n"; std::cout << " --output Write JSON results to file\n"; std::cout << " --enable-microbenchmarks\n"; std::cout @@ -73,15 +72,25 @@ template void add_corosio_suites(bench::benchmark_runner& runner, BackendTag) { - runner.add_suite("corosio", corosio_bench::make_io_context_suite()); - runner.add_suite("corosio", corosio_bench::make_socket_throughput_suite()); - runner.add_suite("corosio", corosio_bench::make_socket_latency_suite()); - runner.add_suite("corosio", corosio_bench::make_http_server_suite()); - runner.add_suite("corosio", corosio_bench::make_accept_churn_suite()); - runner.add_suite("corosio", corosio_bench::make_fan_out_suite()); + runner.add_suite( + "corosio", corosio_bench::make_io_context_suite()); + runner.add_suite( + "corosio", corosio_bench::make_socket_throughput_suite()); + runner.add_suite( + "corosio", corosio_bench::make_socket_latency_suite()); + runner.add_suite( + "corosio", corosio_bench::make_http_server_suite()); + runner.add_suite( + "corosio", corosio_bench::make_accept_churn_suite()); + runner.add_suite( + "corosio", corosio_bench::make_fan_out_suite()); #if BOOST_COROSIO_POSIX - runner.add_suite("corosio", corosio_bench::make_local_socket_throughput_suite()); - runner.add_suite("corosio", corosio_bench::make_local_socket_latency_suite()); + runner.add_suite( + "corosio", + corosio_bench::make_local_socket_throughput_suite()); + runner.add_suite( + "corosio", + corosio_bench::make_local_socket_latency_suite()); #endif } @@ -102,14 +111,24 @@ add_asio_suites(bench::benchmark_runner& runner) void add_asio_callback_suites(bench::benchmark_runner& runner) { - runner.add_suite("asio_callback", asio_callback_bench::make_io_context_suite()); - runner.add_suite("asio_callback", asio_callback_bench::make_socket_throughput_suite()); - runner.add_suite("asio_callback", asio_callback_bench::make_socket_latency_suite()); - runner.add_suite("asio_callback", asio_callback_bench::make_http_server_suite()); - runner.add_suite("asio_callback", asio_callback_bench::make_accept_churn_suite()); - runner.add_suite("asio_callback", asio_callback_bench::make_fan_out_suite()); - runner.add_suite("asio_callback", asio_callback_bench::make_local_socket_throughput_suite()); - runner.add_suite("asio_callback", asio_callback_bench::make_local_socket_latency_suite()); + runner.add_suite( + "asio_callback", asio_callback_bench::make_io_context_suite()); + runner.add_suite( + "asio_callback", asio_callback_bench::make_socket_throughput_suite()); + runner.add_suite( + "asio_callback", asio_callback_bench::make_socket_latency_suite()); + runner.add_suite( + "asio_callback", asio_callback_bench::make_http_server_suite()); + runner.add_suite( + "asio_callback", asio_callback_bench::make_accept_churn_suite()); + runner.add_suite( + "asio_callback", asio_callback_bench::make_fan_out_suite()); + runner.add_suite( + "asio_callback", + asio_callback_bench::make_local_socket_throughput_suite()); + runner.add_suite( + "asio_callback", + asio_callback_bench::make_local_socket_latency_suite()); } #endif @@ -301,8 +320,7 @@ main(int argc, char* argv[]) std::cout << "Boost.Corosio Benchmarks\n"; std::cout << "========================\n"; std::cout << "Backend: " << name << "\n"; - std::cout << "Duration: " << duration_s - << "s per benchmark\n"; + std::cout << "Duration: " << duration_s << "s per benchmark\n"; std::cout << "Warmup: " << warmup_duration_s << "s per benchmark" << (warmup_duration_s <= 0.0 ? " (disabled)" : "") diff --git a/build/has_liburing.cpp b/build/has_liburing.cpp index 9a77c57e3..820e610b7 100644 --- a/build/has_liburing.cpp +++ b/build/has_liburing.cpp @@ -18,7 +18,8 @@ #include -int main() +int +main() { struct io_uring ring; struct io_uring_params params{}; diff --git a/cmake/CorosioBuild.cmake b/cmake/CorosioBuild.cmake index ca10e19eb..605a35e69 100644 --- a/cmake/CorosioBuild.cmake +++ b/cmake/CorosioBuild.cmake @@ -22,7 +22,7 @@ macro(corosio_resolve_deps) if(BOOST_COROSIO_IS_ROOT AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../../tools/cmake/include/BoostRoot.cmake") set(BOOST_INCLUDE_LIBRARIES capy) - if(BOOST_COROSIO_BUILD_PERF) + if(BOOST_COROSIO_BUILD_BENCH) list(APPEND BOOST_INCLUDE_LIBRARIES asio) endif() set(BOOST_EXCLUDE_LIBRARIES corosio) diff --git a/example/client/http_client.cpp b/example/client/http_client.cpp index 90f796790..4760fbcbf 100644 --- a/example/client/http_client.cpp +++ b/example/client/http_client.cpp @@ -25,30 +25,32 @@ // tag::assume[] namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; // end::assume[] // tag::build_request[] -std::string build_request(std::string_view host) +std::string +build_request(std::string_view host) { return "GET / HTTP/1.1\r\n" - "Host: " + std::string(host) + "\r\n" - "Connection: close\r\n" - "\r\n"; + "Host: " + + std::string(host) + + "\r\n" + "Connection: close\r\n" + "\r\n"; } // end::build_request[] // tag::do_request[] // Coroutine that performs the HTTP GET request capy::task -do_request( - corosio::io_stream& stream, - std::string_view host) +do_request(corosio::io_stream& stream, std::string_view host) { // Build and send the request std::string request = build_request(host); if (auto [ec, n] = co_await capy::write( - stream, capy::const_buffer(request.data(), request.size())); ec) + stream, capy::const_buffer(request.data(), request.size())); + ec) throw std::system_error(ec); // Read the entire response until EOF, one fixed chunk at a time @@ -78,9 +80,7 @@ do_request( // Parent coroutine that creates and connects the socket capy::task run_client( - corosio::io_context& ioc, - corosio::ipv4_address addr, - std::uint16_t port) + corosio::io_context& ioc, corosio::ipv4_address addr, std::uint16_t port) { // connect() opens the socket automatically corosio::tcp_socket s(ioc); @@ -99,10 +99,9 @@ main(int argc, char* argv[]) { if (argc != 3) { - std::cerr << - "Usage: http_client \n" - "Example:\n" - " http_client 35.190.118.110 80\n"; + std::cerr << "Usage: http_client \n" + "Example:\n" + " http_client 35.190.118.110 80\n"; return EXIT_FAILURE; } @@ -125,8 +124,7 @@ main(int argc, char* argv[]) // Create I/O context and run corosio::io_context ioc; - capy::run_async(ioc.get_executor())( - run_client(ioc, addr, port)); + capy::run_async(ioc.get_executor())(run_client(ioc, addr, port)); ioc.run(); return EXIT_SUCCESS; diff --git a/example/echo-server/echo_server.cpp b/example/echo-server/echo_server.cpp index 872a45355..698561df2 100644 --- a/example/echo-server/echo_server.cpp +++ b/example/echo-server/echo_server.cpp @@ -19,7 +19,7 @@ // tag::assume[] namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; // end::assume[] // tag::worker_class[] @@ -30,11 +30,7 @@ class echo_worker : public corosio::tcp_server::worker_base char buf_[4096]; public: - explicit echo_worker(corosio::io_context& ctx) - : ctx_(ctx) - , sock_(ctx) - { - } + explicit echo_worker(corosio::io_context& ctx) : ctx_(ctx), sock_(ctx) {} corosio::tcp_socket& socket() override { @@ -51,15 +47,16 @@ class echo_worker : public corosio::tcp_server::worker_base // end::worker_class[] // tag::session[] -capy::task<> echo_worker::do_session() +capy::task<> +echo_worker::do_session() { for (;;) { - auto [ec, n] = co_await sock_.read_some( - capy::mutable_buffer(buf_, sizeof buf_)); + auto [ec, n] = + co_await sock_.read_some(capy::mutable_buffer(buf_, sizeof buf_)); - auto [wec, wn] = co_await capy::write( - sock_, capy::const_buffer(buf_, n)); + auto [wec, wn] = + co_await capy::write(sock_, capy::const_buffer(buf_, n)); if (wec || ec) break; @@ -92,14 +89,14 @@ class echo_server : public corosio::tcp_server // end::server[] // tag::main[] -int main(int argc, char* argv[]) +int +main(int argc, char* argv[]) { if (argc != 3) { - std::cerr << - "Usage: echo_server \n" - "Example:\n" - " echo_server 8080 10\n"; + std::cerr << "Usage: echo_server \n" + "Example:\n" + " echo_server 8080 10\n"; return EXIT_FAILURE; } @@ -134,8 +131,8 @@ int main(int argc, char* argv[]) return EXIT_FAILURE; } - std::cout << "Echo server listening on port " << port - << " with " << max_workers << " workers\n"; + std::cout << "Echo server listening on port " << port << " with " + << max_workers << " workers\n"; // Start accepting connections server.start(); diff --git a/example/hash-server/hash_server.cpp b/example/hash-server/hash_server.cpp index 9d3ee7b70..0cb6946e9 100644 --- a/example/hash-server/hash_server.cpp +++ b/example/hash-server/hash_server.cpp @@ -26,13 +26,13 @@ // tag::assume[] namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; // end::assume[] /// Compute FNV-1a hash on the thread pool. // tag::hash_function[] capy::task -compute_fnv1a( char const* data, std::size_t len ) +compute_fnv1a(char const* data, std::size_t len) { constexpr std::uint64_t basis = 14695981039346656037ULL; constexpr std::uint64_t prime = 1099511628211ULL; @@ -40,7 +40,7 @@ compute_fnv1a( char const* data, std::size_t len ) std::uint64_t h = basis; for (std::size_t i = 0; i < len; ++i) { - h ^= static_cast( data[i] ); + h ^= static_cast(data[i]); h *= prime; } co_return h; @@ -49,10 +49,10 @@ compute_fnv1a( char const* data, std::size_t len ) /// Format a 64-bit value as 16 lowercase hex characters. std::string -to_hex( std::uint64_t v ) +to_hex(std::uint64_t v) { static constexpr char digits[] = "0123456789abcdef"; - std::string s( 16, '0' ); + std::string s(16, '0'); for (int i = 15; i >= 0; --i) { s[i] = digits[v & 0xf]; @@ -64,15 +64,13 @@ to_hex( std::uint64_t v ) /// Handle a single client connection. // tag::session[] capy::task<> -do_session( - corosio::tcp_socket sock, - capy::thread_pool& pool ) +do_session(corosio::tcp_socket sock, capy::thread_pool& pool) { char buf[4096]; // Read data from client (on io_context) - auto [ec, n] = co_await sock.read_some( - capy::mutable_buffer( buf, sizeof( buf ) ) ); + auto [ec, n] = + co_await sock.read_some(capy::mutable_buffer(buf, sizeof(buf))); if (ec) { @@ -83,15 +81,13 @@ do_session( // Switch to thread pool for CPU-bound hash computation, // then automatically resume on io_context when done // tag::run_switch[] - auto hash = co_await capy::run( pool.get_executor() )( - compute_fnv1a( buf, n ) ); + auto hash = co_await capy::run(pool.get_executor())(compute_fnv1a(buf, n)); // end::run_switch[] // Send hex result back to client (on io_context) - auto result = to_hex( hash ) + "\n"; + auto result = to_hex(hash) + "\n"; [[maybe_unused]] auto [wec, wn] = co_await capy::write( - sock, - capy::const_buffer( result.data(), result.size() ) ); + sock, capy::const_buffer(result.data(), result.size())); sock.close(); } @@ -103,53 +99,50 @@ capy::task<> do_accept( corosio::io_context& ioc, corosio::tcp_acceptor& acc, - capy::thread_pool& pool ) + capy::thread_pool& pool) { for (;;) { - corosio::tcp_socket peer( ioc ); - auto [ec] = co_await acc.accept( peer ); + corosio::tcp_socket peer(ioc); + auto [ec] = co_await acc.accept(peer); if (ec) break; // Fire-and-forget: each session runs independently - capy::run_async( ioc.get_executor() )( - do_session( std::move( peer ), pool ) ); + capy::run_async(ioc.get_executor())(do_session(std::move(peer), pool)); } } // end::accept[] // tag::main[] int -main( int argc, char* argv[] ) +main(int argc, char* argv[]) { if (argc != 2) { - std::cerr << - "Usage: hash_server \n" - "Example:\n" - " hash_server 8080\n"; + std::cerr << "Usage: hash_server \n" + "Example:\n" + " hash_server 8080\n"; return EXIT_FAILURE; } - int port_int = std::atoi( argv[1] ); + int port_int = std::atoi(argv[1]); if (port_int <= 0 || port_int > 65535) { std::cerr << "Invalid port: " << argv[1] << "\n"; return EXIT_FAILURE; } - auto port = static_cast( port_int ); + auto port = static_cast(port_int); corosio::io_context ioc; - capy::thread_pool pool( 4 ); + capy::thread_pool pool(4); // Convenience ctor: open + SO_REUSEADDR + bind + listen - corosio::tcp_acceptor acc( ioc, corosio::endpoint( port ) ); + corosio::tcp_acceptor acc(ioc, corosio::endpoint(port)); std::cout << "Hash server listening on port " << port << "\n"; - capy::run_async( ioc.get_executor() )( - do_accept( ioc, acc, pool ) ); + capy::run_async(ioc.get_executor())(do_accept(ioc, acc, pool)); ioc.run(); pool.join(); diff --git a/example/https-client/https_client.cpp b/example/https-client/https_client.cpp index 9bd7860da..ee40b3785 100644 --- a/example/https-client/https_client.cpp +++ b/example/https-client/https_client.cpp @@ -25,27 +25,29 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; -std::string build_request(std::string_view host) +std::string +build_request(std::string_view host) { return "GET / HTTP/1.1\r\n" - "Host: " + std::string(host) + "\r\n" - "Connection: close\r\n" - "\r\n"; + "Host: " + + std::string(host) + + "\r\n" + "Connection: close\r\n" + "\r\n"; } // tag::tls_client[] // Coroutine that performs the HTTPS GET request capy::task -do_request( - corosio::tls_stream& stream, - std::string_view host) +do_request(corosio::tls_stream& stream, std::string_view host) { // Build and send the request std::string request = build_request(host); if (auto [ec, n] = co_await capy::write( - stream, capy::const_buffer(request.data(), request.size())); ec) + stream, capy::const_buffer(request.data(), request.size())); + ec) throw std::system_error(ec); // Read the entire response until EOF, one fixed chunk at a time @@ -112,10 +114,9 @@ main(int argc, char* argv[]) { if (argc < 3 || argc > 4) { - std::cerr << - "Usage: https_client [hostname]\n" - "Example:\n" - " https_client 35.190.118.110 443 www.boost.org\n"; + std::cerr << "Usage: https_client [hostname]\n" + "Example:\n" + " https_client 35.190.118.110 443 www.boost.org\n"; return EXIT_FAILURE; } @@ -147,12 +148,12 @@ main(int argc, char* argv[]) run_client(ioc, addr, port, hostname)); ioc.run(); } - catch(std::system_error const& e) + catch (std::system_error const& e) { std::cerr << "Error: " << e.what() << "\n"; return EXIT_FAILURE; } - catch(std::exception const& e) + catch (std::exception const& e) { std::cerr << "Error: " << e.what() << "\n"; return EXIT_FAILURE; diff --git a/example/nslookup/nslookup.cpp b/example/nslookup/nslookup.cpp index 764de5d68..c827ed7d7 100644 --- a/example/nslookup/nslookup.cpp +++ b/example/nslookup/nslookup.cpp @@ -19,16 +19,14 @@ // tag::assume[] namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; // end::assume[] // Coroutine that performs the DNS lookup // tag::lookup[] capy::task do_lookup( - corosio::io_context& ioc, - std::string_view host, - std::string_view service) + corosio::io_context& ioc, std::string_view host, std::string_view service) { corosio::resolver r(ioc); @@ -49,13 +47,13 @@ do_lookup( auto ep = entry.get_endpoint(); if (ep.is_v4()) { - std::cout << " IPv4: " << ep.v4_address().to_string() - << ":" << ep.port() << "\n"; + std::cout << " IPv4: " << ep.v4_address().to_string() << ":" + << ep.port() << "\n"; } else { - std::cout << " IPv6: " << ep.v6_address().to_string() - << ":" << ep.port() << "\n"; + std::cout << " IPv6: " << ep.v6_address().to_string() << ":" + << ep.port() << "\n"; } } @@ -69,21 +67,19 @@ main(int argc, char* argv[]) { if (argc < 2 || argc > 3) { - std::cerr << - "Usage: nslookup [service]\n" - "Examples:\n" - " nslookup www.google.com\n" - " nslookup www.google.com https\n" - " nslookup localhost 8080\n"; + std::cerr << "Usage: nslookup [service]\n" + "Examples:\n" + " nslookup www.google.com\n" + " nslookup www.google.com https\n" + " nslookup localhost 8080\n"; return EXIT_FAILURE; } - std::string_view host = argv[1]; + std::string_view host = argv[1]; std::string_view service = (argc == 3) ? argv[2] : ""; corosio::io_context ioc; - capy::run_async(ioc.get_executor())( - do_lookup(ioc, host, service)); + capy::run_async(ioc.get_executor())(do_lookup(ioc, host, service)); ioc.run(); return EXIT_SUCCESS; diff --git a/example/tls_context_examples.cpp b/example/tls_context_examples.cpp index 6265fd123..b55b286ee 100644 --- a/example/tls_context_examples.cpp +++ b/example/tls_context_examples.cpp @@ -43,7 +43,8 @@ must(std::error_code ec) // tag::https_client[] // Basic HTTPS client that trusts system CAs -tls_context make_https_client() +tls_context +make_https_client() { tls_context ctx; @@ -51,38 +52,40 @@ tls_context make_https_client() must(ctx.set_default_verify_paths()); // Verify the server certificate - must(ctx.set_verify_mode( tls_verify_mode::peer )); + must(ctx.set_verify_mode(tls_verify_mode::peer)); // Modern TLS only - must(ctx.set_min_protocol_version( tls_version::tls_1_2 )); + must(ctx.set_min_protocol_version(tls_version::tls_1_2)); return ctx; } // end::https_client[] // HTTPS client with pinned CA (don't trust system store) -tls_context make_pinned_ca_client( std::string_view ca_pem ) +tls_context +make_pinned_ca_client(std::string_view ca_pem) { tls_context ctx; // Only trust this specific CA - must(ctx.add_certificate_authority( ca_pem )); + must(ctx.add_certificate_authority(ca_pem)); - must(ctx.set_verify_mode( tls_verify_mode::peer )); + must(ctx.set_verify_mode(tls_verify_mode::peer)); return ctx; } // HTTP/2 client with ALPN -tls_context make_http2_client() +tls_context +make_http2_client() { tls_context ctx; must(ctx.set_default_verify_paths()); - must(ctx.set_verify_mode( tls_verify_mode::peer )); + must(ctx.set_verify_mode(tls_verify_mode::peer)); // Prefer HTTP/2, fall back to HTTP/1.1 - must(ctx.set_alpn( { "h2", "http/1.1" } )); + must(ctx.set_alpn({"h2", "http/1.1"})); return ctx; } @@ -93,70 +96,73 @@ tls_context make_http2_client() // tag::basic_server[] // Basic TLS server (no client verification) -tls_context make_basic_server() +tls_context +make_basic_server() { tls_context ctx; // Load certificate chain and private key - must(ctx.use_certificate_chain_file( "server-fullchain.pem" )); - must(ctx.use_private_key_file( "server.key", tls_file_format::pem )); + must(ctx.use_certificate_chain_file("server-fullchain.pem")); + must(ctx.use_private_key_file("server.key", tls_file_format::pem)); // Don't verify clients (no mTLS) - must(ctx.set_verify_mode( tls_verify_mode::none )); + must(ctx.set_verify_mode(tls_verify_mode::none)); return ctx; } // end::basic_server[] // mTLS server (requires client certificates) -tls_context make_mtls_server() +tls_context +make_mtls_server() { tls_context ctx; // Server credentials - must(ctx.use_certificate_chain_file( "server-fullchain.pem" )); - must(ctx.use_private_key_file( "server.key", tls_file_format::pem )); + must(ctx.use_certificate_chain_file("server-fullchain.pem")); + must(ctx.use_private_key_file("server.key", tls_file_format::pem)); // Trust this CA for client certificates - must(ctx.load_verify_file( "client-ca.crt" )); + must(ctx.load_verify_file("client-ca.crt")); // Require clients to present a valid certificate - must(ctx.set_verify_mode( tls_verify_mode::require_peer )); + must(ctx.set_verify_mode(tls_verify_mode::require_peer)); return ctx; } // Server with PKCS#12 credentials -tls_context make_server_from_pfx() +tls_context +make_server_from_pfx() { tls_context ctx; // Load all credentials from a single file - must(ctx.use_pkcs12_file( "server.pfx", "bundle-password" )); + must(ctx.use_pkcs12_file("server.pfx", "bundle-password")); - must(ctx.set_verify_mode( tls_verify_mode::none )); + must(ctx.set_verify_mode(tls_verify_mode::none)); return ctx; } // Server with encrypted private key -tls_context make_server_encrypted_key() +tls_context +make_server_encrypted_key() { tls_context ctx; // Set password callback before loading encrypted key ctx.set_password_callback( - []( [[maybe_unused]] std::size_t max_len, - [[maybe_unused]] tls_password_purpose purpose ) - { + []([[maybe_unused]] std::size_t max_len, + [[maybe_unused]] tls_password_purpose purpose) { // Read from environment or secret manager - char const* pw = std::getenv( "TLS_KEY_PASSWORD" ); - return std::string( pw ? pw : "" ); + char const* pw = std::getenv("TLS_KEY_PASSWORD"); + return std::string(pw ? pw : ""); }); - must(ctx.use_certificate_chain_file( "server.crt" )); - must(ctx.use_private_key_file( - "server-encrypted.key", tls_file_format::pem )); + must(ctx.use_certificate_chain_file("server.crt")); + must( + ctx.use_private_key_file("server-encrypted.key", tls_file_format::pem)); return ctx; } @@ -167,17 +173,18 @@ tls_context make_server_encrypted_key() // tag::mtls_client[] // Client with client certificate for mTLS -tls_context make_mtls_client() +tls_context +make_mtls_client() { tls_context ctx; // Client credentials for mTLS - must(ctx.use_certificate_file( "client.crt", tls_file_format::pem )); - must(ctx.use_private_key_file( "client.key", tls_file_format::pem )); + must(ctx.use_certificate_file("client.crt", tls_file_format::pem)); + must(ctx.use_private_key_file("client.key", tls_file_format::pem)); // Trust specific CA for server verification - must(ctx.load_verify_file( "server-ca.crt" )); - must(ctx.set_verify_mode( tls_verify_mode::peer )); + must(ctx.load_verify_file("server-ca.crt")); + must(ctx.set_verify_mode(tls_verify_mode::peer)); return ctx; } @@ -188,29 +195,31 @@ tls_context make_mtls_client() // // TLS 1.3 only -tls_context make_tls13_only() +tls_context +make_tls13_only() { tls_context ctx; - must(ctx.set_min_protocol_version( tls_version::tls_1_3 )); - must(ctx.set_max_protocol_version( tls_version::tls_1_3 )); + must(ctx.set_min_protocol_version(tls_version::tls_1_3)); + must(ctx.set_max_protocol_version(tls_version::tls_1_3)); must(ctx.set_default_verify_paths()); - must(ctx.set_verify_mode( tls_verify_mode::peer )); + must(ctx.set_verify_mode(tls_verify_mode::peer)); return ctx; } // Allow TLS 1.2+ (default behavior made explicit) -tls_context make_tls12_plus() +tls_context +make_tls12_plus() { tls_context ctx; - must(ctx.set_min_protocol_version( tls_version::tls_1_2 )); + must(ctx.set_min_protocol_version(tls_version::tls_1_2)); // No max = allow newest must(ctx.set_default_verify_paths()); - must(ctx.set_verify_mode( tls_verify_mode::peer )); + must(ctx.set_verify_mode(tls_verify_mode::peer)); return ctx; } @@ -220,18 +229,19 @@ tls_context make_tls12_plus() // // High-security cipher configuration -tls_context make_high_security() +tls_context +make_high_security() { tls_context ctx; // Only ECDHE key exchange with AESGCM or ChaCha20 - must(ctx.set_ciphersuites( "ECDHE+AESGCM:ECDHE+CHACHA20" )); + must(ctx.set_ciphersuites("ECDHE+AESGCM:ECDHE+CHACHA20")); // TLS 1.3 only - must(ctx.set_min_protocol_version( tls_version::tls_1_3 )); + must(ctx.set_min_protocol_version(tls_version::tls_1_3)); must(ctx.set_default_verify_paths()); - must(ctx.set_verify_mode( tls_verify_mode::peer )); + must(ctx.set_verify_mode(tls_verify_mode::peer)); return ctx; } @@ -241,31 +251,33 @@ tls_context make_high_security() // // Client with CRL checking -tls_context make_client_with_crl( std::string_view crl_path ) +tls_context +make_client_with_crl(std::string_view crl_path) { tls_context ctx; must(ctx.set_default_verify_paths()); - must(ctx.add_crl_file( crl_path )); + must(ctx.add_crl_file(crl_path)); // Fail if certificate is revoked, allow if status unknown - ctx.set_revocation_policy( tls_revocation_policy::soft_fail ); + ctx.set_revocation_policy(tls_revocation_policy::soft_fail); - must(ctx.set_verify_mode( tls_verify_mode::peer )); + must(ctx.set_verify_mode(tls_verify_mode::peer)); return ctx; } // Strict revocation checking -tls_context make_hardened_client() +tls_context +make_hardened_client() { tls_context ctx; must(ctx.set_default_verify_paths()); - must(ctx.set_verify_mode( tls_verify_mode::peer )); + must(ctx.set_verify_mode(tls_verify_mode::peer)); // Fail if revocation status cannot be determined - ctx.set_revocation_policy( tls_revocation_policy::hard_fail ); + ctx.set_revocation_policy(tls_revocation_policy::hard_fail); return ctx; } @@ -275,18 +287,18 @@ tls_context make_hardened_client() // // Client that pins a specific certificate via a verification callback. -tls_context make_client_custom_verify( std::span pin ) +tls_context +make_client_custom_verify(std::span pin) { tls_context ctx; must(ctx.set_default_verify_paths()); - must(ctx.set_verify_mode( tls_verify_mode::peer )); + must(ctx.set_verify_mode(tls_verify_mode::peer)); ctx.set_verify_callback( - [pin]( bool preverified, verify_context& verify_ctx ) -> bool - { + [pin](bool preverified, verify_context& verify_ctx) -> bool { // Require the chain to verify normally first. - if( !preverified ) + if (!preverified) return false; // Then pin: accept only if the certificate's DER matches. The @@ -295,22 +307,23 @@ tls_context make_client_custom_verify( std::span pin ) // through verify_ctx.native_handle() for backend-specific use. auto der = verify_ctx.certificate(); return der.size() == pin.size() && - std::equal( der.begin(), der.end(), pin.begin() ); + std::equal(der.begin(), der.end(), pin.begin()); }); return ctx; } // Verify depth limit -tls_context make_client_limited_depth() +tls_context +make_client_limited_depth() { tls_context ctx; must(ctx.set_default_verify_paths()); - must(ctx.set_verify_mode( tls_verify_mode::peer )); + must(ctx.set_verify_mode(tls_verify_mode::peer)); // Allow at most 2 intermediate certificates - must(ctx.set_verify_depth( 2 )); + must(ctx.set_verify_depth(2)); return ctx; } @@ -320,32 +333,33 @@ tls_context make_client_limited_depth() // // Load all credentials from memory buffers -tls_context make_from_memory( +tls_context +make_from_memory( std::string_view cert_pem, std::string_view key_pem, - std::string_view ca_pem ) + std::string_view ca_pem) { tls_context ctx; // From vault/secret manager - must(ctx.use_certificate_chain( cert_pem )); - must(ctx.use_private_key( key_pem, tls_file_format::pem )); - must(ctx.add_certificate_authority( ca_pem )); + must(ctx.use_certificate_chain(cert_pem)); + must(ctx.use_private_key(key_pem, tls_file_format::pem)); + must(ctx.add_certificate_authority(ca_pem)); - must(ctx.set_verify_mode( tls_verify_mode::peer )); + must(ctx.set_verify_mode(tls_verify_mode::peer)); return ctx; } // Load PKCS#12 from memory -tls_context make_from_pkcs12_memory( - std::string_view pkcs12_data, - std::string_view passphrase ) +tls_context +make_from_pkcs12_memory( + std::string_view pkcs12_data, std::string_view passphrase) { tls_context ctx; - must(ctx.use_pkcs12( pkcs12_data, passphrase )); - must(ctx.set_verify_mode( tls_verify_mode::peer )); + must(ctx.use_pkcs12(pkcs12_data, passphrase)); + must(ctx.set_verify_mode(tls_verify_mode::peer)); return ctx; } @@ -355,12 +369,13 @@ tls_context make_from_pkcs12_memory( // // Load DER-encoded certificate and key -tls_context make_from_der() +tls_context +make_from_der() { tls_context ctx; - must(ctx.use_certificate_file( "server.der", tls_file_format::der )); - must(ctx.use_private_key_file( "server.key.der", tls_file_format::der )); + must(ctx.use_certificate_file("server.der", tls_file_format::der)); + must(ctx.use_private_key_file("server.key.der", tls_file_format::der)); return ctx; } @@ -370,12 +385,13 @@ tls_context make_from_der() // // Demonstrate shared ownership -void demonstrate_sharing() +void +demonstrate_sharing() { // Create a context tls_context original; must(original.set_default_verify_paths()); - must(original.set_verify_mode( tls_verify_mode::peer )); + must(original.set_verify_mode(tls_verify_mode::peer)); // Share via copy - both point to same underlying state [[maybe_unused]] tls_context copy1 = original; @@ -385,7 +401,7 @@ void demonstrate_sharing() // (they all share the same impl) // Move transfers ownership - [[maybe_unused]] tls_context moved = std::move( original ); + [[maybe_unused]] tls_context moved = std::move(original); // original is now empty } @@ -394,31 +410,33 @@ void demonstrate_sharing() // // Throw on error (simple code, let exceptions propagate) -void load_throwing() +void +load_throwing() { tls_context ctx; - must(ctx.use_certificate_chain_file( "cert.pem" )); // throws on error - must(ctx.use_private_key_file( "key.pem", tls_file_format::pem )); + must(ctx.use_certificate_chain_file("cert.pem")); // throws on error + must(ctx.use_private_key_file("key.pem", tls_file_format::pem)); must(ctx.set_default_verify_paths()); } // Check errors explicitly -bool load_checked( tls_context& ctx, std::string& error_msg ) +bool +load_checked(tls_context& ctx, std::string& error_msg) { - if( auto ec = ctx.use_certificate_chain_file( "cert.pem" ); ec ) + if (auto ec = ctx.use_certificate_chain_file("cert.pem"); ec) { error_msg = "Certificate: " + ec.message(); return false; } - if( auto ec = ctx.use_private_key_file( "key.pem", tls_file_format::pem ); ec ) + if (auto ec = ctx.use_private_key_file("key.pem", tls_file_format::pem); ec) { error_msg = "Key: " + ec.message(); return false; } - if( auto ec = ctx.set_default_verify_paths(); ec ) + if (auto ec = ctx.set_default_verify_paths(); ec) { error_msg = "CA store: " + ec.message(); return false; @@ -428,12 +446,13 @@ bool load_checked( tls_context& ctx, std::string& error_msg ) } // Mixed approach - throw for programmer errors, check for runtime errors -void load_mixed() +void +load_mixed() { tls_context ctx; // File loading might fail at runtime - if( auto ec = ctx.use_certificate_chain_file( "cert.pem" ); ec ) + if (auto ec = ctx.use_certificate_chain_file("cert.pem"); ec) { // Handle missing file gracefully std::cerr << "Certificate not found: " << ec.message() << "\n"; @@ -441,15 +460,16 @@ void load_mixed() } // Protocol settings won't fail if arguments are valid - must(ctx.set_min_protocol_version( tls_version::tls_1_2 )); - must(ctx.set_verify_mode( tls_verify_mode::peer )); + must(ctx.set_min_protocol_version(tls_version::tls_1_2)); + must(ctx.set_verify_mode(tls_verify_mode::peer)); } // // Main // -int main() +int +main() { // These examples demonstrate API ergonomics try @@ -458,7 +478,7 @@ int main() [[maybe_unused]] auto server = make_basic_server(); [[maybe_unused]] auto mtls = make_mtls_server(); } - catch( std::exception const& e ) + catch (std::exception const& e) { std::cerr << "error: " << e.what() << "\n"; return 1; diff --git a/include/boost/corosio/backend.hpp b/include/boost/corosio/backend.hpp index 091c2cf65..42d9a177c 100644 --- a/include/boost/corosio/backend.hpp +++ b/include/boost/corosio/backend.hpp @@ -63,22 +63,24 @@ struct epoll_t using tcp_acceptor_type = detail::epoll_tcp_acceptor; using tcp_acceptor_service_type = detail::epoll_tcp_acceptor_service; - using local_stream_socket_type = detail::epoll_local_stream_socket; - using local_stream_service_type = detail::epoll_local_stream_service; - using local_stream_acceptor_type = detail::epoll_local_stream_acceptor; - using local_stream_acceptor_service_type = detail::epoll_local_stream_acceptor_service; - using local_datagram_socket_type = detail::epoll_local_datagram_socket; - using local_datagram_service_type = detail::epoll_local_datagram_service; + using local_stream_socket_type = detail::epoll_local_stream_socket; + using local_stream_service_type = detail::epoll_local_stream_service; + using local_stream_acceptor_type = detail::epoll_local_stream_acceptor; + using local_stream_acceptor_service_type = + detail::epoll_local_stream_acceptor_service; + using local_datagram_socket_type = detail::epoll_local_datagram_socket; + using local_datagram_service_type = detail::epoll_local_datagram_service; using signal_type = detail::posix_signal; using signal_service_type = detail::posix_signal_service; using resolver_type = detail::posix_resolver; using resolver_service_type = detail::posix_resolver_service; - using stream_file_type = detail::posix_stream_file; - using stream_file_service_type = detail::posix_stream_file_service; - using random_access_file_type = detail::posix_random_access_file; - using random_access_file_service_type = detail::posix_random_access_file_service; + using stream_file_type = detail::posix_stream_file; + using stream_file_service_type = detail::posix_stream_file_service; + using random_access_file_type = detail::posix_random_access_file; + using random_access_file_service_type = + detail::posix_random_access_file_service; /// Create the scheduler and services for this backend. BOOST_COROSIO_DECL static detail::scheduler& @@ -130,22 +132,24 @@ struct select_t using tcp_acceptor_type = detail::select_tcp_acceptor; using tcp_acceptor_service_type = detail::select_tcp_acceptor_service; - using local_stream_socket_type = detail::select_local_stream_socket; - using local_stream_service_type = detail::select_local_stream_service; - using local_stream_acceptor_type = detail::select_local_stream_acceptor; - using local_stream_acceptor_service_type = detail::select_local_stream_acceptor_service; - using local_datagram_socket_type = detail::select_local_datagram_socket; - using local_datagram_service_type = detail::select_local_datagram_service; + using local_stream_socket_type = detail::select_local_stream_socket; + using local_stream_service_type = detail::select_local_stream_service; + using local_stream_acceptor_type = detail::select_local_stream_acceptor; + using local_stream_acceptor_service_type = + detail::select_local_stream_acceptor_service; + using local_datagram_socket_type = detail::select_local_datagram_socket; + using local_datagram_service_type = detail::select_local_datagram_service; using signal_type = detail::posix_signal; using signal_service_type = detail::posix_signal_service; using resolver_type = detail::posix_resolver; using resolver_service_type = detail::posix_resolver_service; - using stream_file_type = detail::posix_stream_file; - using stream_file_service_type = detail::posix_stream_file_service; - using random_access_file_type = detail::posix_random_access_file; - using random_access_file_service_type = detail::posix_random_access_file_service; + using stream_file_type = detail::posix_stream_file; + using stream_file_service_type = detail::posix_stream_file_service; + using random_access_file_type = detail::posix_random_access_file; + using random_access_file_service_type = + detail::posix_random_access_file_service; /// Create the scheduler and services for this backend. BOOST_COROSIO_DECL static detail::scheduler& @@ -197,22 +201,24 @@ struct kqueue_t using tcp_acceptor_type = detail::kqueue_tcp_acceptor; using tcp_acceptor_service_type = detail::kqueue_tcp_acceptor_service; - using local_stream_socket_type = detail::kqueue_local_stream_socket; - using local_stream_service_type = detail::kqueue_local_stream_service; - using local_stream_acceptor_type = detail::kqueue_local_stream_acceptor; - using local_stream_acceptor_service_type = detail::kqueue_local_stream_acceptor_service; - using local_datagram_socket_type = detail::kqueue_local_datagram_socket; - using local_datagram_service_type = detail::kqueue_local_datagram_service; + using local_stream_socket_type = detail::kqueue_local_stream_socket; + using local_stream_service_type = detail::kqueue_local_stream_service; + using local_stream_acceptor_type = detail::kqueue_local_stream_acceptor; + using local_stream_acceptor_service_type = + detail::kqueue_local_stream_acceptor_service; + using local_datagram_socket_type = detail::kqueue_local_datagram_socket; + using local_datagram_service_type = detail::kqueue_local_datagram_service; using signal_type = detail::posix_signal; using signal_service_type = detail::posix_signal_service; using resolver_type = detail::posix_resolver; using resolver_service_type = detail::posix_resolver_service; - using stream_file_type = detail::posix_stream_file; - using stream_file_service_type = detail::posix_stream_file_service; - using random_access_file_type = detail::posix_random_access_file; - using random_access_file_service_type = detail::posix_random_access_file_service; + using stream_file_type = detail::posix_stream_file; + using stream_file_service_type = detail::posix_stream_file_service; + using random_access_file_type = detail::posix_random_access_file; + using random_access_file_service_type = + detail::posix_random_access_file_service; /// Create the scheduler and services for this backend. BOOST_COROSIO_DECL static detail::scheduler& @@ -224,27 +230,27 @@ inline constexpr kqueue_t kqueue{}; #endif // BOOST_COROSIO_HAS_KQUEUE -#if BOOST_COROSIO_HAS_IO_URING +#if BOOST_COROSIO_HAS_URING namespace detail { -class io_uring_tcp_socket; -class io_uring_tcp_service; -class io_uring_udp_socket; -class io_uring_udp_service; -class io_uring_tcp_acceptor; -class io_uring_tcp_acceptor_service; -class io_uring_local_stream_socket; -class io_uring_local_stream_service; -class io_uring_local_stream_acceptor; -class io_uring_local_stream_acceptor_service; -class io_uring_local_datagram_socket; -class io_uring_local_datagram_service; -class io_uring_stream_file; -class io_uring_stream_file_service; -class io_uring_random_access_file; -class io_uring_random_access_file_service; -class io_uring_scheduler; +class uring_tcp_socket; +class uring_tcp_service; +class uring_udp_socket; +class uring_udp_service; +class uring_tcp_acceptor; +class uring_tcp_acceptor_service; +class uring_local_stream_socket; +class uring_local_stream_service; +class uring_local_stream_acceptor; +class uring_local_stream_acceptor_service; +class uring_local_datagram_socket; +class uring_local_datagram_service; +class uring_stream_file; +class uring_stream_file_service; +class uring_random_access_file; +class uring_random_access_file_service; +class uring_scheduler; class posix_signal; class posix_signal_service; @@ -254,32 +260,34 @@ class posix_resolver_service; } // namespace detail /// Backend tag for the Linux io_uring proactor. -struct io_uring_t +struct uring_t { - using scheduler_type = detail::io_uring_scheduler; - using tcp_socket_type = detail::io_uring_tcp_socket; - using tcp_service_type = detail::io_uring_tcp_service; - using udp_socket_type = detail::io_uring_udp_socket; - using udp_service_type = detail::io_uring_udp_service; - using tcp_acceptor_type = detail::io_uring_tcp_acceptor; - using tcp_acceptor_service_type = detail::io_uring_tcp_acceptor_service; - - using local_stream_socket_type = detail::io_uring_local_stream_socket; - using local_stream_service_type = detail::io_uring_local_stream_service; - using local_stream_acceptor_type = detail::io_uring_local_stream_acceptor; - using local_stream_acceptor_service_type = detail::io_uring_local_stream_acceptor_service; - using local_datagram_socket_type = detail::io_uring_local_datagram_socket; - using local_datagram_service_type = detail::io_uring_local_datagram_service; + using scheduler_type = detail::uring_scheduler; + using tcp_socket_type = detail::uring_tcp_socket; + using tcp_service_type = detail::uring_tcp_service; + using udp_socket_type = detail::uring_udp_socket; + using udp_service_type = detail::uring_udp_service; + using tcp_acceptor_type = detail::uring_tcp_acceptor; + using tcp_acceptor_service_type = detail::uring_tcp_acceptor_service; + + using local_stream_socket_type = detail::uring_local_stream_socket; + using local_stream_service_type = detail::uring_local_stream_service; + using local_stream_acceptor_type = detail::uring_local_stream_acceptor; + using local_stream_acceptor_service_type = + detail::uring_local_stream_acceptor_service; + using local_datagram_socket_type = detail::uring_local_datagram_socket; + using local_datagram_service_type = detail::uring_local_datagram_service; using signal_type = detail::posix_signal; using signal_service_type = detail::posix_signal_service; using resolver_type = detail::posix_resolver; using resolver_service_type = detail::posix_resolver_service; - using stream_file_type = detail::io_uring_stream_file; - using stream_file_service_type = detail::io_uring_stream_file_service; - using random_access_file_type = detail::io_uring_random_access_file; - using random_access_file_service_type = detail::io_uring_random_access_file_service; + using stream_file_type = detail::uring_stream_file; + using stream_file_service_type = detail::uring_stream_file_service; + using random_access_file_type = detail::uring_random_access_file; + using random_access_file_service_type = + detail::uring_random_access_file_service; /// Create the scheduler and services for this backend. BOOST_COROSIO_DECL static detail::scheduler& @@ -287,9 +295,9 @@ struct io_uring_t }; /// Tag value for selecting the io_uring backend. -inline constexpr io_uring_t io_uring{}; +inline constexpr uring_t uring{}; -#endif // BOOST_COROSIO_HAS_IO_URING +#endif // BOOST_COROSIO_HAS_URING #if BOOST_COROSIO_HAS_IOCP @@ -339,10 +347,11 @@ struct iocp_t /// @name Unix domain socket types /// @{ - using local_stream_socket_type = detail::win_local_stream_socket; - using local_stream_service_type = detail::win_local_stream_service; - using local_stream_acceptor_type = detail::win_local_stream_acceptor; - using local_stream_acceptor_service_type = detail::win_local_stream_acceptor_service; + using local_stream_socket_type = detail::win_local_stream_socket; + using local_stream_service_type = detail::win_local_stream_service; + using local_stream_acceptor_type = detail::win_local_stream_acceptor; + using local_stream_acceptor_service_type = + detail::win_local_stream_acceptor_service; /// @} using signal_type = detail::win_signal; @@ -350,10 +359,11 @@ struct iocp_t using resolver_type = detail::win_resolver; using resolver_service_type = detail::win_resolver_service; - using stream_file_type = detail::win_stream_file; - using stream_file_service_type = detail::win_file_service; - using random_access_file_type = detail::win_random_access_file; - using random_access_file_service_type = detail::win_random_access_file_service; + using stream_file_type = detail::win_stream_file; + using stream_file_service_type = detail::win_file_service; + using random_access_file_type = detail::win_random_access_file; + using random_access_file_service_type = + detail::win_random_access_file_service; /** Create the scheduler and services for this backend. diff --git a/include/boost/corosio/connect.hpp b/include/boost/corosio/connect.hpp index 7221696a6..04a119cf2 100644 --- a/include/boost/corosio/connect.hpp +++ b/include/boost/corosio/connect.hpp @@ -185,8 +185,9 @@ connect(Socket& s, Range endpoints, ConnectCondition cond) { endpoint_type ep = e; - if (!cond(static_cast(last_ec), - static_cast(ep))) + if (!cond( + static_cast(last_ec), + static_cast(ep))) continue; if (s.is_open()) @@ -240,9 +241,7 @@ capy::task> connect(Socket& s, Iter begin, Iter end) { return corosio::connect( - s, - std::move(begin), - std::move(end), + s, std::move(begin), std::move(end), detail::default_connect_condition{}); } @@ -280,8 +279,9 @@ connect(Socket& s, Iter begin, Iter end, ConnectCondition cond) { endpoint_type ep = *it; - if (!cond(static_cast(last_ec), - static_cast(ep))) + if (!cond( + static_cast(last_ec), + static_cast(ep))) continue; if (s.is_open()) diff --git a/include/boost/corosio/delay.hpp b/include/boost/corosio/delay.hpp index d36be3f64..5d945c561 100644 --- a/include/boost/corosio/delay.hpp +++ b/include/boost/corosio/delay.hpp @@ -47,30 +47,27 @@ clamp_to_ns(std::chrono::duration dur) noexcept if (dur != dur) return nanoseconds::zero(); } - return dsec(dur) >= dsec((nanoseconds::max)()) - ? (nanoseconds::max)() + return dsec(dur) >= dsec((nanoseconds::max)()) ? (nanoseconds::max)() : dsec(dur) <= dsec((nanoseconds::min)()) - ? (nanoseconds::min)() - : duration_cast(dur); + ? (nanoseconds::min)() + : duration_cast(dur); } // A non-io_context executor cannot supply a timer service, and // await_suspend is driven through a noexcept wrapper, so translate // the service-lookup failure into a clear terminate. inline void -emplace_delay_timer( - std::optional& t, capy::execution_context& ctx) +emplace_delay_timer(std::optional& t, capy::execution_context& ctx) { try { t.emplace(ctx); } - catch(std::logic_error const&) + catch (std::logic_error const&) { - throw_logic_error( - "delay requires an io_context-backed executor"); + throw_logic_error("delay requires an io_context-backed executor"); } - catch(std::exception const& e) + catch (std::exception const& e) { throw_logic_error(e.what()); } @@ -119,20 +116,18 @@ class delay_awaitable std::chrono::steady_clock::time_point deadline_{}; std::chrono::nanoseconds dur_{}; bool has_deadline_ = false; - bool canceled_ = false; + bool canceled_ = false; std::optional timer_; std::optional wait_; public: /// Construct an awaitable that waits for `dur` nanoseconds. - explicit delay_awaitable(std::chrono::nanoseconds dur) noexcept - : dur_(dur) + explicit delay_awaitable(std::chrono::nanoseconds dur) noexcept : dur_(dur) { } /// Construct an awaitable that waits until `tp`. - explicit delay_awaitable( - std::chrono::steady_clock::time_point tp) noexcept + explicit delay_awaitable(std::chrono::steady_clock::time_point tp) noexcept : deadline_(tp) , has_deadline_(true) { @@ -142,9 +137,9 @@ class delay_awaitable // Only moved before await_suspend; wait_ is engaged after. delay_awaitable(delay_awaitable&&) = default; - delay_awaitable(delay_awaitable const&) = delete; + delay_awaitable(delay_awaitable const&) = delete; delay_awaitable& operator=(delay_awaitable const&) = delete; - delay_awaitable& operator=(delay_awaitable&&) = delete; + delay_awaitable& operator=(delay_awaitable&&) = delete; /// Return false unconditionally; see await_suspend. // The elapsed-deadline fast path must run after the stop-token @@ -158,7 +153,7 @@ class delay_awaitable std::coroutine_handle<> await_suspend(std::coroutine_handle<> h, capy::io_env const* env) { - if(env->stop_token.stop_requested()) + if (env->stop_token.stop_requested()) { canceled_ = true; return h; @@ -166,14 +161,13 @@ class delay_awaitable // Elapsed deadlines complete synchronously, but only once a // pending stop request has already been ruled out above. - if(has_deadline_ ? - deadline_ <= std::chrono::steady_clock::now() : - dur_.count() <= 0) + if (has_deadline_ ? deadline_ <= std::chrono::steady_clock::now() + : dur_.count() <= 0) return h; detail::emplace_delay_timer(timer_, env->executor.context()); - if(has_deadline_) + if (has_deadline_) timer_->expires_at(deadline_); else timer_->expires_after(dur_); @@ -185,9 +179,9 @@ class delay_awaitable /// Return empty on expiry, `error::canceled` if stop won. [[nodiscard]] capy::io_result<> await_resume() noexcept { - if(canceled_) + if (canceled_) return {capy::error::canceled}; - if(wait_) + if (wait_) return wait_->await_resume(); return {}; } @@ -230,8 +224,7 @@ class clock_delay_awaitable std::chrono::nanoseconds next_wait(typename Clock::time_point now) const noexcept { - return detail::clamp_to_ns( - Traits::to_wait_duration(deadline_ - now)); + return detail::clamp_to_ns(Traits::to_wait_duration(deadline_ - now)); } // Runs on the scheduler thread executing the completion op, @@ -241,14 +234,14 @@ class clock_delay_awaitable { auto* self = static_cast(ctx); // Canceled: resume and surface the error - if(self->w_.ec_) + if (self->w_.ec_) return false; auto now = Clock::now(); - if(now >= self->deadline_) + if (now >= self->deadline_) return false; // Re-publish and return without touching the node again: // the wait may complete on another thread immediately after. - if(self->timer_->rearm_wait(self->w_, self->next_wait(now))) + if (self->timer_->rearm_wait(self->w_, self->next_wait(now))) return true; // Heap growth failed; finish the wait with an error rather // than strand the frame with an unbalanced work count. @@ -258,8 +251,7 @@ class clock_delay_awaitable public: /// Construct an awaitable that waits until `tp` on `Clock`. - explicit clock_delay_awaitable( - typename Clock::time_point tp) noexcept + explicit clock_delay_awaitable(typename Clock::time_point tp) noexcept : deadline_(tp) { } @@ -271,11 +263,9 @@ class clock_delay_awaitable { } - clock_delay_awaitable(clock_delay_awaitable const&) = delete; - clock_delay_awaitable& - operator=(clock_delay_awaitable const&) = delete; - clock_delay_awaitable& - operator=(clock_delay_awaitable&&) = delete; + clock_delay_awaitable(clock_delay_awaitable const&) = delete; + clock_delay_awaitable& operator=(clock_delay_awaitable const&) = delete; + clock_delay_awaitable& operator=(clock_delay_awaitable&&) = delete; /// Return false unconditionally; see await_suspend. // The elapsed-deadline fast path must run after the stop-token @@ -289,14 +279,14 @@ class clock_delay_awaitable std::coroutine_handle<> await_suspend(std::coroutine_handle<> h, capy::io_env const* env) { - if(env->stop_token.stop_requested()) + if (env->stop_token.stop_requested()) { canceled_ = true; return h; } auto now = Clock::now(); - if(now >= deadline_) + if (now >= deadline_) return h; detail::emplace_delay_timer(timer_, env->executor.context()); @@ -315,9 +305,9 @@ class clock_delay_awaitable /// Return empty on deadline, `error::canceled` if stop won. [[nodiscard]] capy::io_result<> await_resume() noexcept { - if(canceled_) + if (canceled_) return {capy::error::canceled}; - if(timer_) + if (timer_) return {w_.ec_}; return {}; } @@ -386,13 +376,13 @@ delay(std::chrono::steady_clock::time_point tp) noexcept @return A @ref clock_delay_awaitable yielding `io_result<>`. */ template - requires (!std::same_as) && - (std::is_void_v || WaitTraits) + requires(!std::same_as) && + (std::is_void_v || WaitTraits) [[nodiscard]] auto delay(std::chrono::time_point tp) noexcept { - using traits_type = std::conditional_t< - std::is_void_v, wait_traits, Traits>; + using traits_type = + std::conditional_t, wait_traits, Traits>; // ceil preserves completes-at-or-after when Duration is coarser // than the clock's native duration return clock_delay_awaitable( diff --git a/include/boost/corosio/detail/buffer_param.hpp b/include/boost/corosio/detail/buffer_param.hpp index 65514569f..4ba5e5faf 100644 --- a/include/boost/corosio/detail/buffer_param.hpp +++ b/include/boost/corosio/detail/buffer_param.hpp @@ -164,7 +164,7 @@ namespace boost::corosio { } // CORRECT: Use unrolled buffers for system call now - submit_to_io_uring(vecs, n, h); + submit_to_uring(vecs, n, h); // After this function returns, 'p' must not be used again. // The iovec array is safe because it contains copies of diff --git a/include/boost/corosio/detail/conditionally_enabled_event.hpp b/include/boost/corosio/detail/conditionally_enabled_event.hpp index 7d58b4e7f..c14406131 100644 --- a/include/boost/corosio/detail/conditionally_enabled_event.hpp +++ b/include/boost/corosio/detail/conditionally_enabled_event.hpp @@ -36,8 +36,9 @@ class conditionally_enabled_event { } - conditionally_enabled_event(conditionally_enabled_event const&) = delete; - conditionally_enabled_event& operator=(conditionally_enabled_event const&) = delete; + conditionally_enabled_event(conditionally_enabled_event const&) = delete; + conditionally_enabled_event& + operator=(conditionally_enabled_event const&) = delete; void set_enabled(bool v) noexcept { diff --git a/include/boost/corosio/detail/conditionally_enabled_mutex.hpp b/include/boost/corosio/detail/conditionally_enabled_mutex.hpp index 37e6c3be1..ff3ac0d77 100644 --- a/include/boost/corosio/detail/conditionally_enabled_mutex.hpp +++ b/include/boost/corosio/detail/conditionally_enabled_mutex.hpp @@ -35,8 +35,9 @@ class conditionally_enabled_mutex { } - conditionally_enabled_mutex(conditionally_enabled_mutex const&) = delete; - conditionally_enabled_mutex& operator=(conditionally_enabled_mutex const&) = delete; + conditionally_enabled_mutex(conditionally_enabled_mutex const&) = delete; + conditionally_enabled_mutex& + operator=(conditionally_enabled_mutex const&) = delete; bool enabled() const noexcept { @@ -49,9 +50,20 @@ class conditionally_enabled_mutex } // Lockable interface — allows std::lock_guard - void lock() { if (enabled_) mutex_.lock(); } - void unlock() { if (enabled_) mutex_.unlock(); } - bool try_lock() { return !enabled_ || mutex_.try_lock(); } + void lock() + { + if (enabled_) + mutex_.lock(); + } + void unlock() + { + if (enabled_) + mutex_.unlock(); + } + bool try_lock() + { + return !enabled_ || mutex_.try_lock(); + } class scoped_lock { diff --git a/include/boost/corosio/detail/config.hpp b/include/boost/corosio/detail/config.hpp index cabcc37a1..0e7d14108 100644 --- a/include/boost/corosio/detail/config.hpp +++ b/include/boost/corosio/detail/config.hpp @@ -22,13 +22,13 @@ // silence C4251/C4275 (dll-interface) on exported classes whose private // members are std:: or detail:: types the clients never touch. #ifdef _MSC_VER -# define BOOST_COROSIO_MSVC_WARNING_PUSH __pragma(warning(push)) -# define BOOST_COROSIO_MSVC_WARNING_DISABLE(x) __pragma(warning(disable: x)) -# define BOOST_COROSIO_MSVC_WARNING_POP __pragma(warning(pop)) +#define BOOST_COROSIO_MSVC_WARNING_PUSH __pragma(warning(push)) +#define BOOST_COROSIO_MSVC_WARNING_DISABLE(x) __pragma(warning(disable : x)) +#define BOOST_COROSIO_MSVC_WARNING_POP __pragma(warning(pop)) #else -# define BOOST_COROSIO_MSVC_WARNING_PUSH -# define BOOST_COROSIO_MSVC_WARNING_DISABLE(x) -# define BOOST_COROSIO_MSVC_WARNING_POP +#define BOOST_COROSIO_MSVC_WARNING_PUSH +#define BOOST_COROSIO_MSVC_WARNING_DISABLE(x) +#define BOOST_COROSIO_MSVC_WARNING_POP #endif // GCC warning suppression helpers, for GCC-only diagnostics (e.g. -Wtsan). @@ -36,14 +36,15 @@ // on real GCC; the warning name is passed as a string, e.g. // BOOST_COROSIO_GCC_WARNING_DISABLE("-Wtsan"). #if defined(__GNUC__) && !defined(__clang__) -# define BOOST_COROSIO_GCC_DO_PRAGMA(x) _Pragma(#x) -# define BOOST_COROSIO_GCC_WARNING_PUSH _Pragma("GCC diagnostic push") -# define BOOST_COROSIO_GCC_WARNING_DISABLE(w) BOOST_COROSIO_GCC_DO_PRAGMA(GCC diagnostic ignored w) -# define BOOST_COROSIO_GCC_WARNING_POP _Pragma("GCC diagnostic pop") +#define BOOST_COROSIO_GCC_DO_PRAGMA(x) _Pragma(#x) +#define BOOST_COROSIO_GCC_WARNING_PUSH _Pragma("GCC diagnostic push") +#define BOOST_COROSIO_GCC_WARNING_DISABLE(w) \ + BOOST_COROSIO_GCC_DO_PRAGMA(GCC diagnostic ignored w) +#define BOOST_COROSIO_GCC_WARNING_POP _Pragma("GCC diagnostic pop") #else -# define BOOST_COROSIO_GCC_WARNING_PUSH -# define BOOST_COROSIO_GCC_WARNING_DISABLE(w) -# define BOOST_COROSIO_GCC_WARNING_POP +#define BOOST_COROSIO_GCC_WARNING_PUSH +#define BOOST_COROSIO_GCC_WARNING_DISABLE(w) +#define BOOST_COROSIO_GCC_WARNING_POP #endif // Symbol export/import for shared libraries diff --git a/include/boost/corosio/detail/file_service.hpp b/include/boost/corosio/detail/file_service.hpp index 9de447ff7..b6e3e5fff 100644 --- a/include/boost/corosio/detail/file_service.hpp +++ b/include/boost/corosio/detail/file_service.hpp @@ -51,7 +51,7 @@ class BOOST_COROSIO_DECL file_service file_base::flags mode) = 0; protected: - file_service() = default; + file_service() = default; ~file_service() override = default; }; diff --git a/include/boost/corosio/detail/intrusive.hpp b/include/boost/corosio/detail/intrusive.hpp index aacbf9bb7..f5267634f 100644 --- a/include/boost/corosio/detail/intrusive.hpp +++ b/include/boost/corosio/detail/intrusive.hpp @@ -71,7 +71,7 @@ class intrusive_list void push_back(T* w) noexcept { - auto* n = static_cast(w); + auto* n = static_cast(w); n->next_ = nullptr; n->prev_ = tail_; if (tail_) @@ -87,9 +87,9 @@ class intrusive_list return; if (tail_) { - static_cast(tail_)->next_ = other.head_; - static_cast(other.head_)->prev_ = tail_; - tail_ = other.tail_; + static_cast(tail_)->next_ = other.head_; + static_cast(other.head_)->prev_ = tail_; + tail_ = other.tail_; } else { @@ -112,7 +112,7 @@ class intrusive_list tail_ = nullptr; // Defensive: clear stale linkage so remove() on a // popped node cannot corrupt the list. - auto* n = static_cast(w); + auto* n = static_cast(w); n->next_ = nullptr; n->prev_ = nullptr; return w; diff --git a/include/boost/corosio/detail/local_datagram_service.hpp b/include/boost/corosio/detail/local_datagram_service.hpp index 075460e54..69546f3f4 100644 --- a/include/boost/corosio/detail/local_datagram_service.hpp +++ b/include/boost/corosio/detail/local_datagram_service.hpp @@ -71,8 +71,7 @@ class BOOST_COROSIO_DECL local_datagram_service @return Error code on failure, empty on success. */ virtual std::error_code assign_socket( - local_datagram_socket::implementation& impl, - native_handle_type fd) = 0; + local_datagram_socket::implementation& impl, native_handle_type fd) = 0; /** Bind a datagram socket to a local endpoint. @@ -88,7 +87,7 @@ class BOOST_COROSIO_DECL local_datagram_service corosio::local_endpoint ep) = 0; protected: - local_datagram_service() = default; + local_datagram_service() = default; ~local_datagram_service() override = default; }; diff --git a/include/boost/corosio/detail/local_stream_acceptor_service.hpp b/include/boost/corosio/detail/local_stream_acceptor_service.hpp index 058825a24..4e5a856f9 100644 --- a/include/boost/corosio/detail/local_stream_acceptor_service.hpp +++ b/include/boost/corosio/detail/local_stream_acceptor_service.hpp @@ -66,8 +66,7 @@ class BOOST_COROSIO_DECL local_stream_acceptor_service @return Error code on failure, empty on success. */ virtual std::error_code assign_socket( - local_stream_acceptor::implementation& impl, - native_handle_type fd) = 0; + local_stream_acceptor::implementation& impl, native_handle_type fd) = 0; /** Bind an open acceptor to a local endpoint. @@ -78,8 +77,7 @@ class BOOST_COROSIO_DECL local_stream_acceptor_service @return Error code on failure, empty on success. */ virtual std::error_code bind_acceptor( - local_stream_acceptor::implementation& impl, - local_endpoint ep) = 0; + local_stream_acceptor::implementation& impl, local_endpoint ep) = 0; /** Start listening for incoming connections. @@ -89,11 +87,10 @@ class BOOST_COROSIO_DECL local_stream_acceptor_service @return Error code on failure, empty on success. */ virtual std::error_code listen_acceptor( - local_stream_acceptor::implementation& impl, - int backlog) = 0; + local_stream_acceptor::implementation& impl, int backlog) = 0; protected: - local_stream_acceptor_service() = default; + local_stream_acceptor_service() = default; ~local_stream_acceptor_service() override = default; }; diff --git a/include/boost/corosio/detail/local_stream_service.hpp b/include/boost/corosio/detail/local_stream_service.hpp index 4cf41b215..277bd152c 100644 --- a/include/boost/corosio/detail/local_stream_service.hpp +++ b/include/boost/corosio/detail/local_stream_service.hpp @@ -64,11 +64,10 @@ class BOOST_COROSIO_DECL local_stream_service @return Error code on failure, empty on success. */ virtual std::error_code assign_socket( - local_stream_socket::implementation& impl, - native_handle_type fd) = 0; + local_stream_socket::implementation& impl, native_handle_type fd) = 0; protected: - local_stream_service() = default; + local_stream_service() = default; ~local_stream_service() override = default; }; diff --git a/include/boost/corosio/detail/op_base.hpp b/include/boost/corosio/detail/op_base.hpp index afcc05c6f..e4758099c 100644 --- a/include/boost/corosio/detail/op_base.hpp +++ b/include/boost/corosio/detail/op_base.hpp @@ -61,8 +61,7 @@ class bytes_op_base -> std::coroutine_handle<> { token_ = env->stop_token; - return static_cast(this)->dispatch( - h, env->executor); + return static_cast(this)->dispatch(h, env->executor); } }; @@ -107,8 +106,7 @@ class value_op_base -> std::coroutine_handle<> { token_ = env->stop_token; - return static_cast(this)->dispatch( - h, env->executor); + return static_cast(this)->dispatch(h, env->executor); } }; @@ -151,8 +149,7 @@ class void_op_base -> std::coroutine_handle<> { token_ = env->stop_token; - return static_cast(this)->dispatch( - h, env->executor); + return static_cast(this)->dispatch(h, env->executor); } }; diff --git a/include/boost/corosio/detail/platform.hpp b/include/boost/corosio/detail/platform.hpp index a31704316..7afd49331 100644 --- a/include/boost/corosio/detail/platform.hpp +++ b/include/boost/corosio/detail/platform.hpp @@ -24,7 +24,7 @@ #define BOOST_COROSIO_HAS_EPOLL 1 #define BOOST_COROSIO_HAS_KQUEUE 1 #define BOOST_COROSIO_HAS_SELECT 1 -#define BOOST_COROSIO_HAS_IO_URING 1 +#define BOOST_COROSIO_HAS_URING 1 #define BOOST_COROSIO_POSIX 1 #else // !BOOST_COROSIO_MRDOCS @@ -62,9 +62,9 @@ // Single-threaded mode additionally requires Linux 6.1+ for // IORING_SETUP_DEFER_TASKRUN; multi-threaded mode runs on 6.0. #if defined(__linux__) && BOOST_COROSIO_HAVE_LIBURING -#define BOOST_COROSIO_HAS_IO_URING 1 +#define BOOST_COROSIO_HAS_URING 1 #else -#define BOOST_COROSIO_HAS_IO_URING 0 +#define BOOST_COROSIO_HAS_URING 0 #endif // POSIX APIs (signals, resolver, etc.) diff --git a/include/boost/corosio/detail/random_access_file_service.hpp b/include/boost/corosio/detail/random_access_file_service.hpp index 32a6bd164..74cfc95c7 100644 --- a/include/boost/corosio/detail/random_access_file_service.hpp +++ b/include/boost/corosio/detail/random_access_file_service.hpp @@ -45,7 +45,7 @@ class BOOST_COROSIO_DECL random_access_file_service file_base::flags mode) = 0; protected: - random_access_file_service() = default; + random_access_file_service() = default; ~random_access_file_service() override = default; }; diff --git a/include/boost/corosio/detail/ready_queue.hpp b/include/boost/corosio/detail/ready_queue.hpp index 986472f3e..279588226 100644 --- a/include/boost/corosio/detail/ready_queue.hpp +++ b/include/boost/corosio/detail/ready_queue.hpp @@ -64,8 +64,8 @@ ready_as_cont(std::uintptr_t e) noexcept */ class ready_queue { - std::uintptr_t head_ = 0; // tagged first entry, 0 when empty - std::uintptr_t tail_ = 0; // tagged last entry, 0 when empty + std::uintptr_t head_ = 0; // tagged first entry, 0 when empty + std::uintptr_t tail_ = 0; // tagged last entry, 0 when empty // Read a node's next-link by value. A continuation's link lives in its // void* `reserved` slot; bit_cast keeps us from forming a uintptr_t @@ -76,16 +76,14 @@ class ready_queue // branch against the smaller object. Fixed in GCC 14. BOOST_COROSIO_GCC_WARNING_PUSH BOOST_COROSIO_GCC_WARNING_DISABLE("-Warray-bounds") - static std::uintptr_t - next_of(std::uintptr_t e) noexcept + static std::uintptr_t next_of(std::uintptr_t e) noexcept { if (ready_is_continuation(e)) return std::bit_cast(ready_as_cont(e)->reserved); return ready_as_op(e)->q_next_; } - static void - set_next(std::uintptr_t e, std::uintptr_t nxt) noexcept + static void set_next(std::uintptr_t e, std::uintptr_t nxt) noexcept { if (ready_is_continuation(e)) ready_as_cont(e)->reserved = std::bit_cast(nxt); @@ -94,8 +92,7 @@ class ready_queue } BOOST_COROSIO_GCC_WARNING_POP - void - push_entry(std::uintptr_t e) noexcept + void push_entry(std::uintptr_t e) noexcept { set_next(e, 0); if (tail_) @@ -108,9 +105,7 @@ class ready_queue public: ready_queue() = default; - ready_queue(ready_queue&& o) noexcept - : head_(o.head_) - , tail_(o.tail_) + ready_queue(ready_queue&& o) noexcept : head_(o.head_), tail_(o.tail_) { o.head_ = 0; o.tail_ = 0; @@ -121,7 +116,10 @@ class ready_queue ready_queue& operator=(ready_queue&&) = delete; /// Return true if the queue holds no entries. - bool empty() const noexcept { return head_ == 0; } + bool empty() const noexcept + { + return head_ == 0; + } /// Append a scheduler_op to the back of the queue. void push(scheduler_op* op) noexcept @@ -144,7 +142,7 @@ class ready_queue set_next(tail_, other.head_); else head_ = other.head_; - tail_ = other.tail_; + tail_ = other.tail_; other.head_ = 0; other.tail_ = 0; } diff --git a/include/boost/corosio/detail/scheduler.hpp b/include/boost/corosio/detail/scheduler.hpp index 5d5fd86da..42b62bb57 100644 --- a/include/boost/corosio/detail/scheduler.hpp +++ b/include/boost/corosio/detail/scheduler.hpp @@ -109,13 +109,13 @@ struct BOOST_COROSIO_DECL scheduler struct threading_config { /// Scheduler mutex/condvar enabled. Off only in the `unsafe` tier. - bool scheduler_locking = true; - /// Per-descriptor (reactor) or ring (io_uring) I/O lock enabled. + bool scheduler_locking = true; + /// Per-descriptor (reactor) or ring (uring) I/O lock enabled. /// Off in the `unsafe_io` and `unsafe` tiers. bool reactor_io_locking = true; /// A single run thread is guaranteed (a lockless tier): elide /// inter-run-thread wakeups. - bool one_thread = false; + bool one_thread = false; }; /// True in the fully-lockless (`unsafe`) tier. The resolver and POSIX diff --git a/include/boost/corosio/detail/tcp_acceptor_service.hpp b/include/boost/corosio/detail/tcp_acceptor_service.hpp index f594b0b49..58c3c8516 100644 --- a/include/boost/corosio/detail/tcp_acceptor_service.hpp +++ b/include/boost/corosio/detail/tcp_acceptor_service.hpp @@ -63,8 +63,7 @@ class BOOST_COROSIO_DECL tcp_acceptor_service @return Error code on failure, empty on success. */ virtual std::error_code assign_socket( - tcp_acceptor::implementation& impl, - native_handle_type fd) = 0; + tcp_acceptor::implementation& impl, native_handle_type fd) = 0; /** Bind an open acceptor to a local endpoint. diff --git a/include/boost/corosio/detail/tcp_service.hpp b/include/boost/corosio/detail/tcp_service.hpp index bf7720547..4fbcad801 100644 --- a/include/boost/corosio/detail/tcp_service.hpp +++ b/include/boost/corosio/detail/tcp_service.hpp @@ -61,9 +61,8 @@ class BOOST_COROSIO_DECL tcp_service @param fd The native socket handle to adopt. @return Error code on failure, empty on success. */ - virtual std::error_code assign_socket( - tcp_socket::implementation& impl, - native_handle_type fd) = 0; + virtual std::error_code + assign_socket(tcp_socket::implementation& impl, native_handle_type fd) = 0; /** Bind a stream socket to a local endpoint. diff --git a/include/boost/corosio/detail/thread_pool.hpp b/include/boost/corosio/detail/thread_pool.hpp index 469af5d7c..2eb6bbc35 100644 --- a/include/boost/corosio/detail/thread_pool.hpp +++ b/include/boost/corosio/detail/thread_pool.hpp @@ -123,8 +123,7 @@ class BOOST_COROSIO_SYMBOL_VISIBLE thread_pool final @throws std::logic_error If `num_threads` is 0. */ explicit thread_pool( - [[maybe_unused]] capy::execution_context& ctx, - unsigned num_threads = 1) + [[maybe_unused]] capy::execution_context& ctx, unsigned num_threads = 1) : num_threads_(num_threads) { if (!num_threads) @@ -335,8 +334,7 @@ class thread_pool_ref @param ctx The context whose pool is used. */ - explicit thread_pool_ref(capy::execution_context& ctx) noexcept - : ctx_(ctx) + explicit thread_pool_ref(capy::execution_context& ctx) noexcept : ctx_(ctx) { } diff --git a/include/boost/corosio/detail/timeout_awaitable.hpp b/include/boost/corosio/detail/timeout_awaitable.hpp index 706fdb3ba..c46973131 100644 --- a/include/boost/corosio/detail/timeout_awaitable.hpp +++ b/include/boost/corosio/detail/timeout_awaitable.hpp @@ -53,13 +53,11 @@ namespace boost::corosio::detail { // await_resume needs to distinguish io_result from other return types. template struct is_io_result : std::false_type -{ -}; +{}; template struct is_io_result> : std::true_type -{ -}; +{}; template inline constexpr bool is_io_result_v = is_io_result::value; @@ -178,11 +176,10 @@ struct timeout_awaitable } catch (std::logic_error const&) { - throw_logic_error( - "timeout requires an io_context-backed executor"); + throw_logic_error("timeout requires an io_context-backed executor"); } - auto ex = static_cast( - env->executor.context()).get_executor(); + auto ex = + static_cast(env->executor.context()).get_executor(); if (has_deadline_) timer_->expires_at(deadline_); @@ -237,8 +234,7 @@ struct timeout_awaitable // inner op (e.g. a socket cancel issued from elsewhere) // landing in the same window as the deadline firing is // reported as a timeout. - if (fired && !parent && - std::get<0>(r) == capy::cond::canceled) + if (fired && !parent && std::get<0>(r) == capy::cond::canceled) { std::remove_cvref_t t{}; std::get<0>(t) = make_error_code(capy::error::timeout); diff --git a/include/boost/corosio/detail/timeout_coro.hpp b/include/boost/corosio/detail/timeout_coro.hpp index 53649d503..e7db54514 100644 --- a/include/boost/corosio/detail/timeout_coro.hpp +++ b/include/boost/corosio/detail/timeout_coro.hpp @@ -74,7 +74,7 @@ struct timeout_coro std::stop_token token, std::pmr::memory_resource* alloc) { - owned_ex_ = ex; + owned_ex_ = ex; env_storage_ = {owned_ex_, std::move(token), alloc}; set_environment(&env_storage_); } diff --git a/include/boost/corosio/detail/timer.hpp b/include/boost/corosio/detail/timer.hpp index 6073dade7..33b0eed2d 100644 --- a/include/boost/corosio/detail/timer.hpp +++ b/include/boost/corosio/detail/timer.hpp @@ -135,8 +135,7 @@ class BOOST_COROSIO_DECL timer : public io_object bool already_expired() const noexcept { return heap_index_.load(std::memory_order_relaxed) == npos && - (expiry_ == - (std::chrono::steady_clock::time_point::min)() || + (expiry_ == (std::chrono::steady_clock::time_point::min)() || expiry_ <= std::chrono::steady_clock::now()); } @@ -270,9 +269,8 @@ class BOOST_COROSIO_DECL timer : public io_object // (e.g. delay(hours::max())) would wrap now() + d past the // clock's range and appear already elapsed. auto const now = clock_type::now(); - impl.expiry_ = ((time_point::max)() - now < d) - ? (time_point::max)() - : now + d; + impl.expiry_ = + ((time_point::max)() - now < d) ? (time_point::max)() : now + d; } } diff --git a/include/boost/corosio/detail/timer_service.hpp b/include/boost/corosio/detail/timer_service.hpp index 82e7f2b2b..36b3dc3da 100644 --- a/include/boost/corosio/detail/timer_service.hpp +++ b/include/boost/corosio/detail/timer_service.hpp @@ -334,7 +334,7 @@ timer_service::construct() timer::implementation* impl = try_pop_tl_cache(this); if (impl) { - impl->svc_ = this; + impl->svc_ = this; // Reset expiry_ too: a recycled impl must behave like a fresh // one, whose default expiry reads as already elapsed impl->expiry_ = {}; @@ -349,11 +349,11 @@ timer_service::construct() std::lock_guard lock(mutex_); if (free_list_) { - impl = free_list_; - free_list_ = impl->next_free_; - impl->next_free_ = nullptr; - impl->svc_ = this; - impl->expiry_ = {}; + impl = free_list_; + free_list_ = impl->next_free_; + impl->next_free_ = nullptr; + impl->svc_ = this; + impl->expiry_ = {}; impl->heap_index_.store( (std::numeric_limits::max)(), std::memory_order_relaxed); @@ -422,8 +422,7 @@ timer_service::insert_waiter(timer::implementation& impl, waiter_node* w) if (impl.heap_index_.load(std::memory_order_relaxed) == (std::numeric_limits::max)() && heap_.size() == heap_.capacity()) - heap_.reserve( - heap_.capacity() == 0 ? 16 : 2 * heap_.capacity()); + heap_.reserve(heap_.capacity() == 0 ? 16 : 2 * heap_.capacity()); // Publish: from here the waiter is visible to the fire path and // to its own stop callback (impl_ non-null enables cancel_waiter). w->impl_ = &impl; @@ -433,8 +432,7 @@ timer_service::insert_waiter(timer::implementation& impl, waiter_node* w) impl.heap_index_.store(heap_.size(), std::memory_order_relaxed); heap_.push_back({impl.expiry_, &impl}); up_heap(heap_.size() - 1); - notify = - (impl.heap_index_.load(std::memory_order_relaxed) == 0); + notify = (impl.heap_index_.load(std::memory_order_relaxed) == 0); refresh_cached_nearest(); } BOOST_COROSIO_ASSERT(impl.waiter_ == nullptr); @@ -511,8 +509,7 @@ timer_service::cancel_waiter(waiter_node* w) w->impl_ = nullptr; impl->waiter_ = nullptr; remove_timer_impl(*impl); - impl->might_have_pending_waits_.store( - false, std::memory_order_relaxed); + impl->might_have_pending_waits_.store(false, std::memory_order_relaxed); refresh_cached_nearest(); } @@ -623,9 +620,9 @@ timer_service::down_heap(std::size_t index) inline void timer_service::swap_heap(std::size_t i1, std::size_t i2) { - heap_entry tmp = heap_[i1]; - heap_[i1] = heap_[i2]; - heap_[i2] = tmp; + heap_entry tmp = heap_[i1]; + heap_[i1] = heap_[i2]; + heap_[i2] = tmp; heap_[i1].timer_->heap_index_.store(i1, std::memory_order_relaxed); heap_[i2].timer_->heap_index_.store(i2, std::memory_order_relaxed); } diff --git a/include/boost/corosio/detail/udp_service.hpp b/include/boost/corosio/detail/udp_service.hpp index a575fa9d4..1c1a85beb 100644 --- a/include/boost/corosio/detail/udp_service.hpp +++ b/include/boost/corosio/detail/udp_service.hpp @@ -63,9 +63,8 @@ class BOOST_COROSIO_DECL udp_service @param fd The native socket handle to adopt. @return Error code on failure, empty on success. */ - virtual std::error_code assign_socket( - udp_socket::implementation& impl, - native_handle_type fd) = 0; + virtual std::error_code + assign_socket(udp_socket::implementation& impl, native_handle_type fd) = 0; /** Bind a datagram socket to a local endpoint. diff --git a/include/boost/corosio/host_name.hpp b/include/boost/corosio/host_name.hpp index 37b2d875e..42e8e3fc7 100644 --- a/include/boost/corosio/host_name.hpp +++ b/include/boost/corosio/host_name.hpp @@ -38,8 +38,7 @@ namespace boost::corosio { @return The error code, empty on success, and the hostname as a UTF-8 string — empty on failure. */ -[[nodiscard]] BOOST_COROSIO_DECL capy::io_result -host_name(); +[[nodiscard]] BOOST_COROSIO_DECL capy::io_result host_name(); } // namespace boost::corosio diff --git a/include/boost/corosio/io/io_read_stream.hpp b/include/boost/corosio/io/io_read_stream.hpp index 40d0d402d..a41d7825e 100644 --- a/include/boost/corosio/io/io_read_stream.hpp +++ b/include/boost/corosio/io/io_read_stream.hpp @@ -54,10 +54,13 @@ class BOOST_COROSIO_DECL io_read_stream : virtual public io_object read_some_awaitable( io_read_stream& ios, MutableBufferSequence buffers) noexcept - : ios_(ios), buffers_(std::move(buffers)) {} + : ios_(ios) + , buffers_(std::move(buffers)) + { + } - std::coroutine_handle<> dispatch( - std::coroutine_handle<> h, capy::executor_ref ex) const + std::coroutine_handle<> + dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const { return ios_.do_read_some( h, ex, buffers_, this->token_, &this->ec_, &this->bytes_); diff --git a/include/boost/corosio/io/io_write_stream.hpp b/include/boost/corosio/io/io_write_stream.hpp index 362d04abb..34da5871b 100644 --- a/include/boost/corosio/io/io_write_stream.hpp +++ b/include/boost/corosio/io/io_write_stream.hpp @@ -54,10 +54,13 @@ class BOOST_COROSIO_DECL io_write_stream : virtual public io_object write_some_awaitable( io_write_stream& ios, ConstBufferSequence buffers) noexcept - : ios_(ios), buffers_(std::move(buffers)) {} + : ios_(ios) + , buffers_(std::move(buffers)) + { + } - std::coroutine_handle<> dispatch( - std::coroutine_handle<> h, capy::executor_ref ex) const + std::coroutine_handle<> + dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const { return ios_.do_write_some( h, ex, buffers_, this->token_, &this->ec_, &this->bytes_); diff --git a/include/boost/corosio/io_context.hpp b/include/boost/corosio/io_context.hpp index fe7b94147..ec2cc2b7a 100644 --- a/include/boost/corosio/io_context.hpp +++ b/include/boost/corosio/io_context.hpp @@ -240,8 +240,7 @@ class BOOST_COROSIO_DECL io_context : public capy::execution_context these options is created here, so a failure to create it throws from the constructor. */ void apply_options_post_( - io_context_options const& opts, - unsigned concurrency_hint); + io_context_options const& opts, unsigned concurrency_hint); /** Create the blocking-I/O thread pool and apply only the decomposed threading configuration (locking tiers), then finish bringing the @@ -511,7 +510,7 @@ class BOOST_COROSIO_DECL io_context : public capy::execution_context typename Clock::time_point now = Clock::now(); for (;;) { - auto rel_time = abs_time - now; + auto rel_time = abs_time - now; using rel_type = decltype(rel_time); if (rel_time < rel_type::zero()) rel_time = rel_type::zero(); diff --git a/include/boost/corosio/local_datagram_socket.hpp b/include/boost/corosio/local_datagram_socket.hpp index 94e1ef1ed..914fb3001 100644 --- a/include/boost/corosio/local_datagram_socket.hpp +++ b/include/boost/corosio/local_datagram_socket.hpp @@ -281,8 +281,7 @@ class BOOST_COROSIO_DECL local_datagram_socket : public io_object @param ep The local endpoint to bind to. @return Error code on failure, empty on success. */ - virtual std::error_code - bind(corosio::local_endpoint ep) noexcept = 0; + virtual std::error_code bind(corosio::local_endpoint ep) noexcept = 0; }; /** Represent the awaitable returned by @ref send_to. @@ -290,8 +289,7 @@ class BOOST_COROSIO_DECL local_datagram_socket : public io_object Captures the destination endpoint and buffer, then dispatches to the backend implementation on suspension. */ - struct send_to_awaitable - : detail::bytes_op_base + struct send_to_awaitable : detail::bytes_op_base { local_datagram_socket& s_; buffer_param buf_; @@ -299,12 +297,19 @@ class BOOST_COROSIO_DECL local_datagram_socket : public io_object int flags_; send_to_awaitable( - local_datagram_socket& s, buffer_param buf, - corosio::local_endpoint dest, int flags = 0) noexcept - : s_(s), buf_(buf), dest_(dest), flags_(flags) {} + local_datagram_socket& s, + buffer_param buf, + corosio::local_endpoint dest, + int flags = 0) noexcept + : s_(s) + , buf_(buf) + , dest_(dest) + , flags_(flags) + { + } - std::coroutine_handle<> dispatch( - std::coroutine_handle<> h, capy::executor_ref ex) const + std::coroutine_handle<> + dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const { return s_.get().send_to( h, ex, buf_, dest_, flags_, token_, &ec_, &bytes_); @@ -316,8 +321,7 @@ class BOOST_COROSIO_DECL local_datagram_socket : public io_object Captures the source endpoint reference and buffer, then dispatches to the backend implementation on suspension. */ - struct recv_from_awaitable - : detail::bytes_op_base + struct recv_from_awaitable : detail::bytes_op_base { local_datagram_socket& s_; buffer_param buf_; @@ -325,12 +329,19 @@ class BOOST_COROSIO_DECL local_datagram_socket : public io_object int flags_; recv_from_awaitable( - local_datagram_socket& s, buffer_param buf, - corosio::local_endpoint& source, int flags = 0) noexcept - : s_(s), buf_(buf), source_(source), flags_(flags) {} + local_datagram_socket& s, + buffer_param buf, + corosio::local_endpoint& source, + int flags = 0) noexcept + : s_(s) + , buf_(buf) + , source_(source) + , flags_(flags) + { + } - std::coroutine_handle<> dispatch( - std::coroutine_handle<> h, capy::executor_ref ex) const + std::coroutine_handle<> + dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const { return s_.get().recv_from( h, ex, buf_, &source_, flags_, token_, &ec_, &bytes_); @@ -342,37 +353,39 @@ class BOOST_COROSIO_DECL local_datagram_socket : public io_object Captures the target endpoint, then dispatches to the backend implementation on suspension. */ - struct connect_awaitable - : detail::void_op_base + struct connect_awaitable : detail::void_op_base { local_datagram_socket& s_; corosio::local_endpoint endpoint_; connect_awaitable( - local_datagram_socket& s, - corosio::local_endpoint ep) noexcept - : s_(s), endpoint_(ep) {} + local_datagram_socket& s, corosio::local_endpoint ep) noexcept + : s_(s) + , endpoint_(ep) + { + } - std::coroutine_handle<> dispatch( - std::coroutine_handle<> h, capy::executor_ref ex) const + std::coroutine_handle<> + dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const { - return s_.get().connect( - h, ex, endpoint_, token_, &ec_); + return s_.get().connect(h, ex, endpoint_, token_, &ec_); } }; /// Represent the awaitable returned by @ref wait. - struct wait_awaitable - : detail::void_op_base + struct wait_awaitable : detail::void_op_base { local_datagram_socket& s_; wait_type w_; wait_awaitable(local_datagram_socket& s, wait_type w) noexcept - : s_(s), w_(w) {} + : s_(s) + , w_(w) + { + } - std::coroutine_handle<> dispatch( - std::coroutine_handle<> h, capy::executor_ref ex) const + std::coroutine_handle<> + dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const { return s_.get().wait(h, ex, w_, token_, &ec_); } @@ -383,23 +396,24 @@ class BOOST_COROSIO_DECL local_datagram_socket : public io_object Captures the buffer, then dispatches to the backend implementation on suspension. Requires a prior connect(). */ - struct send_awaitable - : detail::bytes_op_base + struct send_awaitable : detail::bytes_op_base { local_datagram_socket& s_; buffer_param buf_; int flags_; send_awaitable( - local_datagram_socket& s, buffer_param buf, - int flags = 0) noexcept - : s_(s), buf_(buf), flags_(flags) {} + local_datagram_socket& s, buffer_param buf, int flags = 0) noexcept + : s_(s) + , buf_(buf) + , flags_(flags) + { + } - std::coroutine_handle<> dispatch( - std::coroutine_handle<> h, capy::executor_ref ex) const + std::coroutine_handle<> + dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const { - return s_.get().send( - h, ex, buf_, flags_, token_, &ec_, &bytes_); + return s_.get().send(h, ex, buf_, flags_, token_, &ec_, &bytes_); } }; @@ -408,23 +422,24 @@ class BOOST_COROSIO_DECL local_datagram_socket : public io_object Captures the buffer, then dispatches to the backend implementation on suspension. Requires a prior connect(). */ - struct recv_awaitable - : detail::bytes_op_base + struct recv_awaitable : detail::bytes_op_base { local_datagram_socket& s_; buffer_param buf_; int flags_; recv_awaitable( - local_datagram_socket& s, buffer_param buf, - int flags = 0) noexcept - : s_(s), buf_(buf), flags_(flags) {} + local_datagram_socket& s, buffer_param buf, int flags = 0) noexcept + : s_(s) + , buf_(buf) + , flags_(flags) + { + } - std::coroutine_handle<> dispatch( - std::coroutine_handle<> h, capy::executor_ref ex) const + std::coroutine_handle<> + dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const { - return s_.get().recv( - h, ex, buf_, flags_, token_, &ec_, &bytes_); + return s_.get().recv(h, ex, buf_, flags_, token_, &ec_, &bytes_); } }; @@ -448,8 +463,8 @@ class BOOST_COROSIO_DECL local_datagram_socket : public io_object @param ex The executor whose context will own the socket. */ template - requires( - !std::same_as, local_datagram_socket>) && + requires(!std:: + same_as, local_datagram_socket>) && capy::Executor explicit local_datagram_socket(Ex const& ex) : local_datagram_socket(ex.context()) @@ -657,7 +672,8 @@ class BOOST_COROSIO_DECL local_datagram_socket : public io_object /// @overload template - [[nodiscard]] auto recv_from(Buffers const& buf, corosio::local_endpoint& source) + [[nodiscard]] auto + recv_from(Buffers const& buf, corosio::local_endpoint& source) { return recv_from(buf, source, corosio::message_flags::none); } @@ -793,8 +809,7 @@ class BOOST_COROSIO_DECL local_datagram_socket : public io_object std::error_code ec = get().set_option( Option::level(), Option::name(), opt.data(), opt.size()); if (ec) - detail::throw_system_error( - ec, "local_datagram_socket::set_option"); + detail::throw_system_error(ec, "local_datagram_socket::set_option"); } /** Get a socket option. @@ -820,8 +835,7 @@ class BOOST_COROSIO_DECL local_datagram_socket : public io_object std::error_code ec = get().get_option(Option::level(), Option::name(), opt.data(), &sz); if (ec) - detail::throw_system_error( - ec, "local_datagram_socket::get_option"); + detail::throw_system_error(ec, "local_datagram_socket::get_option"); opt.resize(sz); return opt; } @@ -875,8 +889,7 @@ class BOOST_COROSIO_DECL local_datagram_socket : public io_object local_datagram_socket() noexcept = default; /// Construct from a pre-built handle. - explicit local_datagram_socket(handle h) noexcept - : io_object(std::move(h)) + explicit local_datagram_socket(handle h) noexcept : io_object(std::move(h)) { } diff --git a/include/boost/corosio/local_endpoint.hpp b/include/boost/corosio/local_endpoint.hpp index a213ac697..118f57cb2 100644 --- a/include/boost/corosio/local_endpoint.hpp +++ b/include/boost/corosio/local_endpoint.hpp @@ -68,7 +68,6 @@ class BOOST_COROSIO_DECL local_endpoint */ explicit local_endpoint(std::string_view path); - /** Return the socket path. For abstract sockets, the returned view includes the @@ -104,8 +103,7 @@ class BOOST_COROSIO_DECL local_endpoint friend bool operator==(local_endpoint const& a, local_endpoint const& b) noexcept { - return a.len_ == b.len_ && - std::memcmp(a.path_, b.path_, a.len_) == 0; + return a.len_ == b.len_ && std::memcmp(a.path_, b.path_, a.len_) == 0; } /** Format the endpoint for stream output. diff --git a/include/boost/corosio/local_stream_acceptor.hpp b/include/boost/corosio/local_stream_acceptor.hpp index 29a3e1cb8..edb98fbfc 100644 --- a/include/boost/corosio/local_stream_acceptor.hpp +++ b/include/boost/corosio/local_stream_acceptor.hpp @@ -69,17 +69,19 @@ enum class bind_option */ class BOOST_COROSIO_DECL local_stream_acceptor : public io_object { - struct wait_awaitable - : detail::void_op_base + struct wait_awaitable : detail::void_op_base { local_stream_acceptor& acc_; wait_type w_; wait_awaitable(local_stream_acceptor& acc, wait_type w) noexcept - : acc_(acc), w_(w) {} + : acc_(acc) + , w_(w) + { + } - std::coroutine_handle<> dispatch( - std::coroutine_handle<> h, capy::executor_ref ex) const + std::coroutine_handle<> + dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const { return acc_.get().wait(h, ex, w_, token_, &ec_); } @@ -92,8 +94,7 @@ class BOOST_COROSIO_DECL local_stream_acceptor : public io_object mutable std::error_code ec_; mutable io_object::implementation* peer_impl_ = nullptr; - explicit move_accept_awaitable( - local_stream_acceptor& acc) noexcept + explicit move_accept_awaitable(local_stream_acceptor& acc) noexcept : acc_(acc) { } @@ -105,11 +106,13 @@ class BOOST_COROSIO_DECL local_stream_acceptor : public io_object return static_cast(ec_) || token_.stop_requested(); } - [[nodiscard]] capy::io_result await_resume() const noexcept + [[nodiscard]] capy::io_result + await_resume() const noexcept { if (token_.stop_requested()) - return {make_error_code(std::errc::operation_canceled), - local_stream_socket()}; + return { + make_error_code(std::errc::operation_canceled), + local_stream_socket()}; if (ec_ || !peer_impl_) return {ec_, local_stream_socket()}; @@ -210,9 +213,11 @@ class BOOST_COROSIO_DECL local_stream_acceptor : public io_object conversion from move). */ template - requires(!std::same_as, local_stream_acceptor>) && + requires(!std:: + same_as, local_stream_acceptor>) && capy::Executor - explicit local_stream_acceptor(Ex const& ex) : local_stream_acceptor(ex.context()) + explicit local_stream_acceptor(Ex const& ex) + : local_stream_acceptor(ex.context()) { } @@ -262,7 +267,8 @@ class BOOST_COROSIO_DECL local_stream_acceptor : public io_object */ local_stream_acceptor& operator=(local_stream_acceptor&& other) noexcept { - assert(&ctx_ == &other.ctx_ && + assert( + &ctx_ == &other.ctx_ && "move-assign requires the same execution_context"); if (this != &other) { @@ -297,9 +303,9 @@ class BOOST_COROSIO_DECL local_stream_acceptor : public io_object A closed acceptor reports `errc::bad_file_descriptor`. */ - [[nodiscard]] std::error_code - bind(corosio::local_endpoint ep, - bind_option opt = bind_option::none) noexcept; + [[nodiscard]] std::error_code bind( + corosio::local_endpoint ep, + bind_option opt = bind_option::none) noexcept; /** Start listening for incoming connections. diff --git a/include/boost/corosio/local_stream_socket.hpp b/include/boost/corosio/local_stream_socket.hpp index a80383934..624e67c4a 100644 --- a/include/boost/corosio/local_stream_socket.hpp +++ b/include/boost/corosio/local_stream_socket.hpp @@ -179,35 +179,39 @@ class BOOST_COROSIO_DECL local_stream_socket : public io_stream }; /// Represent the awaitable returned by @ref connect. - struct connect_awaitable - : detail::void_op_base + struct connect_awaitable : detail::void_op_base { local_stream_socket& s_; corosio::local_endpoint endpoint_; connect_awaitable( local_stream_socket& s, corosio::local_endpoint ep) noexcept - : s_(s), endpoint_(ep) {} + : s_(s) + , endpoint_(ep) + { + } - std::coroutine_handle<> dispatch( - std::coroutine_handle<> h, capy::executor_ref ex) const + std::coroutine_handle<> + dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const { return s_.get().connect(h, ex, endpoint_, token_, &ec_); } }; /// Represent the awaitable returned by @ref wait. - struct wait_awaitable - : detail::void_op_base + struct wait_awaitable : detail::void_op_base { local_stream_socket& s_; wait_type w_; wait_awaitable(local_stream_socket& s, wait_type w) noexcept - : s_(s), w_(w) {} + : s_(s) + , w_(w) + { + } - std::coroutine_handle<> dispatch( - std::coroutine_handle<> h, capy::executor_ref ex) const + std::coroutine_handle<> + dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const { return s_.get().wait(h, ex, w_, token_, &ec_); } @@ -235,7 +239,8 @@ class BOOST_COROSIO_DECL local_stream_socket : public io_stream template requires(!std::same_as, local_stream_socket>) && capy::Executor - explicit local_stream_socket(Ex const& ex) : local_stream_socket(ex.context()) + explicit local_stream_socket(Ex const& ex) + : local_stream_socket(ex.context()) { } diff --git a/include/boost/corosio/message_flags.hpp b/include/boost/corosio/message_flags.hpp index b6ae645cd..84d1c5812 100644 --- a/include/boost/corosio/message_flags.hpp +++ b/include/boost/corosio/message_flags.hpp @@ -21,11 +21,11 @@ namespace boost::corosio { enum class message_flags : int { /// No flags set. - none = 0, + none = 0, /// Peek at incoming data without consuming it (MSG_PEEK). - peek = 1, + peek = 1, /// Send or receive out-of-band data (MSG_OOB). - out_of_band = 2, + out_of_band = 2, /// Bypass routing tables (MSG_DONTROUTE). do_not_route = 4 }; @@ -50,8 +50,7 @@ operator&(message_flags a, message_flags b) noexcept inline constexpr message_flags operator~(message_flags a) noexcept { - constexpr int mask = - static_cast(message_flags::peek) | + constexpr int mask = static_cast(message_flags::peek) | static_cast(message_flags::out_of_band) | static_cast(message_flags::do_not_route); return static_cast(~static_cast(a) & mask); diff --git a/include/boost/corosio/native/detail/coro_op.hpp b/include/boost/corosio/native/detail/coro_op.hpp index ecdf59815..460bb6c87 100644 --- a/include/boost/corosio/native/detail/coro_op.hpp +++ b/include/boost/corosio/native/detail/coro_op.hpp @@ -50,7 +50,7 @@ namespace boost::corosio::detail { /** Non-template op envelope shared by every native backend's operations. - `reactor_op_base`, `io_uring_op`, and `overlapped_op` all derive from this. + `reactor_op_base`, `uring_op`, and `overlapped_op` all derive from this. Derives from scheduler_op so ops queue intrusively and dispatch through the function-pointer (io_uring/IOCP) or virtual (reactors) completion path — hence both a default and a func_type constructor. @@ -70,27 +70,30 @@ struct coro_op : scheduler_op struct canceller { coro_op* op; - void operator()() const noexcept { op->on_cancel(); } + void operator()() const noexcept + { + op->on_cancel(); + } }; - std::coroutine_handle<> h; - capy::continuation cont; - capy::executor_ref ex; - std::error_code* ec_out = nullptr; - std::size_t* bytes_out = nullptr; + std::coroutine_handle<> h; + capy::continuation cont; + capy::executor_ref ex; + std::error_code* ec_out = nullptr; + std::size_t* bytes_out = nullptr; /// True for receive/read ops (drives the zero-byte == EOF decision). - bool is_read = false; + bool is_read = false; /// True when the submitted buffer was zero-length (suppresses EOF). - bool empty_buffer = false; + bool empty_buffer = false; - std::atomic cancelled{false}; + std::atomic cancelled{false}; std::optional> stop_cb; /// Keeps the owning impl alive while the op is in flight (the kernel /// owns user buffers until completion). Dropped in the handler's resume /// tail (see coro_op_complete.hpp). - std::shared_ptr impl_ptr; + std::shared_ptr impl_ptr; /// Default-construct for virtual-dispatch backends (the reactors, which /// override operator()/destroy() and leave func_ null). @@ -126,7 +129,10 @@ struct coro_op : scheduler_op drive the kernel: io_uring submits an ASYNC_CANCEL SQE; IOCP calls its stored cancel_func_ (CancelIoEx / wait-reactor deregister). */ - virtual void on_cancel() noexcept { request_cancel(); } + virtual void on_cancel() noexcept + { + request_cancel(); + } }; } // namespace boost::corosio::detail diff --git a/include/boost/corosio/native/detail/coro_op_complete.hpp b/include/boost/corosio/native/detail/coro_op_complete.hpp index bd69d3fde..d9d09e9f1 100644 --- a/include/boost/corosio/native/detail/coro_op_complete.hpp +++ b/include/boost/corosio/native/detail/coro_op_complete.hpp @@ -69,11 +69,11 @@ namespace boost::corosio::detail { inline void decode_io_result( std::error_code* ec_out, - bool cancelled, - std::error_code err, - bool is_read, - std::size_t bytes, - bool empty_buffer) noexcept + bool cancelled, + std::error_code err, + bool is_read, + std::size_t bytes, + bool empty_buffer) noexcept { if (!ec_out) return; diff --git a/include/boost/corosio/native/detail/endpoint_convert.hpp b/include/boost/corosio/native/detail/endpoint_convert.hpp index 8988ac3f8..9220dee52 100644 --- a/include/boost/corosio/native/detail/endpoint_convert.hpp +++ b/include/boost/corosio/native/detail/endpoint_convert.hpp @@ -246,7 +246,11 @@ socket_family( #if BOOST_COROSIO_POSIX using un_sa_t = sockaddr_un; #else -struct un_sa_t { u_short sun_family; char sun_path[108]; }; +struct un_sa_t +{ + u_short sun_family; + char sun_path[108]; +}; #endif /** Convert a local_endpoint to sockaddr_storage. @@ -268,8 +272,7 @@ to_sockaddr(local_endpoint const& ep, sockaddr_storage& storage) noexcept std::memcpy(&storage, &sa, sizeof(sa)); if (ep.is_abstract()) - return static_cast( - offsetof(un_sa_t, sun_path) + copy_len); + return static_cast(offsetof(un_sa_t, sun_path) + copy_len); return static_cast(sizeof(sa)); } @@ -300,16 +303,14 @@ to_sockaddr( sockaddr_un, or an empty endpoint if the family is not AF_UNIX. */ inline local_endpoint -from_sockaddr_local( - sockaddr_storage const& storage, socklen_t len) noexcept +from_sockaddr_local(sockaddr_storage const& storage, socklen_t len) noexcept { if (storage.ss_family != AF_UNIX) return local_endpoint{}; un_sa_t sa{}; std::memcpy( - &sa, &storage, - (std::min)(static_cast(len), sizeof(sa))); + &sa, &storage, (std::min)(static_cast(len), sizeof(sa))); auto path_offset = offsetof(un_sa_t, sun_path); if (static_cast(len) <= path_offset) @@ -317,14 +318,14 @@ from_sockaddr_local( // Clamp to the buffer: a foreign len may overstate the payload, // and sun_path is the struct's last member. - auto path_len = (std::min)( - static_cast(len) - path_offset, sizeof(sa.sun_path)); + auto path_len = (std::min)(static_cast(len) - path_offset, + sizeof(sa.sun_path)); // Non-abstract paths may be null-terminated by the kernel if (path_len > 0 && sa.sun_path[0] != '\0') { - auto* end = static_cast( - std::memchr(sa.sun_path, '\0', path_len)); + auto* end = + static_cast(std::memchr(sa.sun_path, '\0', path_len)); if (end) path_len = static_cast(end - sa.sun_path); } @@ -350,7 +351,9 @@ from_sockaddr_local( */ inline endpoint from_sockaddr_as( - sockaddr_storage const& storage, socklen_t /*len*/, endpoint const&) noexcept + sockaddr_storage const& storage, + socklen_t /*len*/, + endpoint const&) noexcept { return from_sockaddr(storage); } diff --git a/include/boost/corosio/native/detail/epoll/epoll_scheduler.hpp b/include/boost/corosio/native/detail/epoll/epoll_scheduler.hpp index b3c33de0f..3e385a63e 100644 --- a/include/boost/corosio/native/detail/epoll/epoll_scheduler.hpp +++ b/include/boost/corosio/native/detail/epoll/epoll_scheduler.hpp @@ -127,16 +127,13 @@ class BOOST_COROSIO_DECL epoll_scheduler final : public reactor_scheduler void deregister_descriptor(int fd) const; /// Watch the read end of the POSIX signal self-pipe (see scheduler.hpp). - [[nodiscard]] std::error_code - register_signal_reader(int read_fd) override + [[nodiscard]] std::error_code register_signal_reader(int read_fd) override { return register_descriptor(read_fd, signal_pipe_reader_.arm()); } private: - void - run_task(lock_type& lock, context_type& ctx, - long timeout_us) override; + void run_task(lock_type& lock, context_type& ctx, long timeout_us) override; void interrupt_reactor() const override; void update_timerfd() const; @@ -258,7 +255,8 @@ epoll_scheduler::configure_reactor( } inline std::error_code -epoll_scheduler::register_descriptor(int fd, reactor_descriptor_state* desc) const +epoll_scheduler::register_descriptor( + int fd, reactor_descriptor_state* desc) const { epoll_event ev{}; ev.events = EPOLLIN | EPOLLOUT | EPOLLET | EPOLLERR | EPOLLHUP; @@ -346,8 +344,7 @@ epoll_scheduler::update_timerfd() const } inline void -epoll_scheduler::run_task( - lock_type& lock, context_type& ctx, long timeout_us) +epoll_scheduler::run_task(lock_type& lock, context_type& ctx, long timeout_us) { int timeout_ms; if (task_interrupted_) @@ -367,8 +364,8 @@ epoll_scheduler::run_task( update_timerfd(); int nfds = ::epoll_wait( - epoll_fd_, event_buffer_.data(), - static_cast(event_buffer_.size()), timeout_ms); + epoll_fd_, event_buffer_.data(), static_cast(event_buffer_.size()), + timeout_ms); if (nfds < 0 && errno != EINTR) detail::throw_system_error(make_err(errno), "epoll_wait"); diff --git a/include/boost/corosio/native/detail/epoll/epoll_traits.hpp b/include/boost/corosio/native/detail/epoll/epoll_traits.hpp index e8a88eac8..8b57e9b0d 100644 --- a/include/boost/corosio/native/detail/epoll/epoll_traits.hpp +++ b/include/boost/corosio/native/detail/epoll/epoll_traits.hpp @@ -37,8 +37,8 @@ class epoll_scheduler; struct epoll_traits { - using scheduler_type = epoll_scheduler; - using desc_state_type = reactor_descriptor_state; + using scheduler_type = epoll_scheduler; + using desc_state_type = reactor_descriptor_state; static constexpr bool needs_write_notification = false; @@ -46,12 +46,15 @@ struct epoll_traits struct stream_socket_hook { std::error_code on_set_option( - int fd, int level, int optname, - void const* data, std::size_t size) noexcept + int fd, + int level, + int optname, + void const* data, + std::size_t size) noexcept { if (::setsockopt( - fd, level, optname, data, - static_cast(size)) != 0) + fd, level, optname, data, static_cast(size)) != + 0) return make_err(errno); return {}; } @@ -76,8 +79,8 @@ struct epoll_traits return n; } - static ssize_t write_one( - int fd, void const* data, std::size_t size) noexcept + static ssize_t + write_one(int fd, void const* data, std::size_t size) noexcept { ssize_t n; do @@ -91,8 +94,8 @@ struct epoll_traits struct accept_policy { - static int do_accept( - int fd, sockaddr_storage& peer, socklen_t& addrlen) noexcept + static int + do_accept(int fd, sockaddr_storage& peer, socklen_t& addrlen) noexcept { addrlen = sizeof(peer); int new_fd; @@ -115,43 +118,39 @@ struct epoll_traits // Apply protocol-specific options after socket creation. // For IP sockets, sets IPV6_V6ONLY on AF_INET6 (best-effort). - static std::error_code - configure_ip_socket(int fd, int family) noexcept + static std::error_code configure_ip_socket(int fd, int family) noexcept { if (family == AF_INET6) { int one = 1; - std::ignore = ::setsockopt( - fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); + std::ignore = + ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); } return {}; } // Apply protocol-specific options for acceptor sockets. // For IP acceptors, sets IPV6_V6ONLY=0 (dual-stack, best-effort). - static std::error_code - configure_ip_acceptor(int fd, int family) noexcept + static std::error_code configure_ip_acceptor(int fd, int family) noexcept { if (family == AF_INET6) { int val = 0; - std::ignore = ::setsockopt( - fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); + std::ignore = + ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); } return {}; } // No extra configuration needed for local (unix) sockets on epoll. - static std::error_code - configure_local_socket(int /*fd*/) noexcept + static std::error_code configure_local_socket(int /*fd*/) noexcept { return {}; } // Non-mutating validation for fds adopted via assign(). Used when // the caller retains fd ownership responsibility. - static std::error_code - validate_assigned_fd(int /*fd*/) noexcept + static std::error_code validate_assigned_fd(int /*fd*/) noexcept { return {}; } diff --git a/include/boost/corosio/native/detail/epoll/epoll_types.hpp b/include/boost/corosio/native/detail/epoll/epoll_types.hpp index 264d9e356..5ea24afba 100644 --- a/include/boost/corosio/native/detail/epoll/epoll_types.hpp +++ b/include/boost/corosio/native/detail/epoll/epoll_types.hpp @@ -46,16 +46,26 @@ class epoll_local_datagram_service; class epoll_tcp_socket final : public reactor_stream_socket_impl< - epoll_tcp_socket, epoll_traits, epoll_tcp_service, - epoll_tcp_acceptor, tcp_socket::implementation, endpoint> + epoll_tcp_socket, + epoll_traits, + epoll_tcp_service, + epoll_tcp_acceptor, + tcp_socket::implementation, + endpoint> { using base_type = reactor_stream_socket_impl< - epoll_tcp_socket, epoll_traits, epoll_tcp_service, - epoll_tcp_acceptor, tcp_socket::implementation, endpoint>; + epoll_tcp_socket, + epoll_traits, + epoll_tcp_service, + epoll_tcp_acceptor, + tcp_socket::implementation, + endpoint>; friend epoll_tcp_service; + public: - explicit epoll_tcp_socket(epoll_tcp_service& svc) noexcept - : base_type(svc) {} + explicit epoll_tcp_socket(epoll_tcp_service& svc) noexcept : base_type(svc) + { + } native_handle_type release_socket() noexcept override { @@ -66,18 +76,27 @@ class epoll_tcp_socket final class epoll_local_stream_socket final : public reactor_stream_socket_impl< - epoll_local_stream_socket, epoll_traits, - epoll_local_stream_service, epoll_local_stream_acceptor, - local_stream_socket::implementation, corosio::local_endpoint> + epoll_local_stream_socket, + epoll_traits, + epoll_local_stream_service, + epoll_local_stream_acceptor, + local_stream_socket::implementation, + corosio::local_endpoint> { using base_type = reactor_stream_socket_impl< - epoll_local_stream_socket, epoll_traits, - epoll_local_stream_service, epoll_local_stream_acceptor, - local_stream_socket::implementation, corosio::local_endpoint>; + epoll_local_stream_socket, + epoll_traits, + epoll_local_stream_service, + epoll_local_stream_acceptor, + local_stream_socket::implementation, + corosio::local_endpoint>; friend epoll_local_stream_service; + public: explicit epoll_local_stream_socket(epoll_local_stream_service& svc) noexcept - : base_type(svc) {} + : base_type(svc) + { + } native_handle_type release_socket() noexcept override { @@ -90,16 +109,26 @@ class epoll_local_stream_socket final class epoll_udp_socket final : public reactor_dgram_socket_impl< - epoll_udp_socket, epoll_traits, epoll_udp_service, - epoll_tcp_acceptor, udp_socket::implementation, endpoint> + epoll_udp_socket, + epoll_traits, + epoll_udp_service, + epoll_tcp_acceptor, + udp_socket::implementation, + endpoint> { using base_type = reactor_dgram_socket_impl< - epoll_udp_socket, epoll_traits, epoll_udp_service, - epoll_tcp_acceptor, udp_socket::implementation, endpoint>; + epoll_udp_socket, + epoll_traits, + epoll_udp_service, + epoll_tcp_acceptor, + udp_socket::implementation, + endpoint>; friend epoll_udp_service; + public: - explicit epoll_udp_socket(epoll_udp_service& svc) noexcept - : base_type(svc) {} + explicit epoll_udp_socket(epoll_udp_service& svc) noexcept : base_type(svc) + { + } std::error_code shutdown(corosio::shutdown_type what) noexcept override { @@ -114,18 +143,28 @@ class epoll_udp_socket final class epoll_local_datagram_socket final : public reactor_dgram_socket_impl< - epoll_local_datagram_socket, epoll_traits, - epoll_local_datagram_service, epoll_tcp_acceptor, - local_datagram_socket::implementation, corosio::local_endpoint> + epoll_local_datagram_socket, + epoll_traits, + epoll_local_datagram_service, + epoll_tcp_acceptor, + local_datagram_socket::implementation, + corosio::local_endpoint> { using base_type = reactor_dgram_socket_impl< - epoll_local_datagram_socket, epoll_traits, - epoll_local_datagram_service, epoll_tcp_acceptor, - local_datagram_socket::implementation, corosio::local_endpoint>; + epoll_local_datagram_socket, + epoll_traits, + epoll_local_datagram_service, + epoll_tcp_acceptor, + local_datagram_socket::implementation, + corosio::local_endpoint>; friend epoll_local_datagram_service; + public: - explicit epoll_local_datagram_socket(epoll_local_datagram_service& svc) noexcept - : base_type(svc) {} + explicit epoll_local_datagram_socket( + epoll_local_datagram_service& svc) noexcept + : base_type(svc) + { + } std::error_code shutdown(corosio::shutdown_type what) noexcept override { @@ -147,119 +186,169 @@ class epoll_local_datagram_socket final class epoll_tcp_acceptor final : public reactor_acceptor_impl< - epoll_tcp_acceptor, epoll_traits, - epoll_tcp_acceptor_service, epoll_tcp_socket, - tcp_acceptor::implementation, endpoint> + epoll_tcp_acceptor, + epoll_traits, + epoll_tcp_acceptor_service, + epoll_tcp_socket, + tcp_acceptor::implementation, + endpoint> { using base_type = reactor_acceptor_impl< - epoll_tcp_acceptor, epoll_traits, - epoll_tcp_acceptor_service, epoll_tcp_socket, - tcp_acceptor::implementation, endpoint>; + epoll_tcp_acceptor, + epoll_traits, + epoll_tcp_acceptor_service, + epoll_tcp_socket, + tcp_acceptor::implementation, + endpoint>; friend epoll_tcp_acceptor_service; + public: explicit epoll_tcp_acceptor(epoll_tcp_acceptor_service& svc) noexcept - : base_type(svc) {} + : base_type(svc) + { + } }; class epoll_local_stream_acceptor final : public reactor_acceptor_impl< - epoll_local_stream_acceptor, epoll_traits, + epoll_local_stream_acceptor, + epoll_traits, epoll_local_stream_acceptor_service, epoll_local_stream_socket, - local_stream_acceptor::implementation, corosio::local_endpoint> + local_stream_acceptor::implementation, + corosio::local_endpoint> { using base_type = reactor_acceptor_impl< - epoll_local_stream_acceptor, epoll_traits, + epoll_local_stream_acceptor, + epoll_traits, epoll_local_stream_acceptor_service, epoll_local_stream_socket, - local_stream_acceptor::implementation, corosio::local_endpoint>; + local_stream_acceptor::implementation, + corosio::local_endpoint>; friend epoll_local_stream_acceptor_service; + public: explicit epoll_local_stream_acceptor( epoll_local_stream_acceptor_service& svc) noexcept - : base_type(svc) {} + : base_type(svc) + { + } }; // --- Services --- class BOOST_COROSIO_DECL epoll_tcp_service final : public reactor_tcp_service_impl< - epoll_tcp_service, epoll_traits, epoll_tcp_socket> + epoll_tcp_service, + epoll_traits, + epoll_tcp_socket> { using base_type = reactor_tcp_service_impl< - epoll_tcp_service, epoll_traits, epoll_tcp_socket>; + epoll_tcp_service, + epoll_traits, + epoll_tcp_socket>; + public: - explicit epoll_tcp_service(capy::execution_context& ctx) - : base_type(ctx) {} + explicit epoll_tcp_service(capy::execution_context& ctx) : base_type(ctx) {} }; class BOOST_COROSIO_DECL epoll_local_stream_service final : public reactor_local_stream_service_impl< - epoll_local_stream_service, epoll_traits, + epoll_local_stream_service, + epoll_traits, epoll_local_stream_socket> { using base_type = reactor_local_stream_service_impl< - epoll_local_stream_service, epoll_traits, + epoll_local_stream_service, + epoll_traits, epoll_local_stream_socket>; + public: explicit epoll_local_stream_service(capy::execution_context& ctx) - : base_type(ctx) {} + : base_type(ctx) + { + } }; class BOOST_COROSIO_DECL epoll_udp_service final : public reactor_udp_service_impl< - epoll_udp_service, epoll_traits, epoll_udp_socket> + epoll_udp_service, + epoll_traits, + epoll_udp_socket> { using base_type = reactor_udp_service_impl< - epoll_udp_service, epoll_traits, epoll_udp_socket>; + epoll_udp_service, + epoll_traits, + epoll_udp_socket>; + public: - explicit epoll_udp_service(capy::execution_context& ctx) - : base_type(ctx) {} + explicit epoll_udp_service(capy::execution_context& ctx) : base_type(ctx) {} }; class BOOST_COROSIO_DECL epoll_local_datagram_service final : public reactor_local_dgram_service_impl< - epoll_local_datagram_service, epoll_traits, + epoll_local_datagram_service, + epoll_traits, epoll_local_datagram_socket> { using base_type = reactor_local_dgram_service_impl< - epoll_local_datagram_service, epoll_traits, + epoll_local_datagram_service, + epoll_traits, epoll_local_datagram_socket>; + public: explicit epoll_local_datagram_service(capy::execution_context& ctx) - : base_type(ctx) {} + : base_type(ctx) + { + } }; class BOOST_COROSIO_DECL epoll_tcp_acceptor_service final : public reactor_acceptor_service_impl< - epoll_tcp_acceptor_service, epoll_traits, - tcp_acceptor_service, epoll_tcp_acceptor, - epoll_tcp_service, endpoint> + epoll_tcp_acceptor_service, + epoll_traits, + tcp_acceptor_service, + epoll_tcp_acceptor, + epoll_tcp_service, + endpoint> { using base_type = reactor_acceptor_service_impl< - epoll_tcp_acceptor_service, epoll_traits, - tcp_acceptor_service, epoll_tcp_acceptor, - epoll_tcp_service, endpoint>; + epoll_tcp_acceptor_service, + epoll_traits, + tcp_acceptor_service, + epoll_tcp_acceptor, + epoll_tcp_service, + endpoint>; + public: explicit epoll_tcp_acceptor_service(capy::execution_context& ctx) - : base_type(ctx) {} + : base_type(ctx) + { + } }; class BOOST_COROSIO_DECL epoll_local_stream_acceptor_service final : public reactor_acceptor_service_impl< - epoll_local_stream_acceptor_service, epoll_traits, + epoll_local_stream_acceptor_service, + epoll_traits, local_stream_acceptor_service, epoll_local_stream_acceptor, - epoll_local_stream_service, corosio::local_endpoint> + epoll_local_stream_service, + corosio::local_endpoint> { using base_type = reactor_acceptor_service_impl< - epoll_local_stream_acceptor_service, epoll_traits, + epoll_local_stream_acceptor_service, + epoll_traits, local_stream_acceptor_service, epoll_local_stream_acceptor, - epoll_local_stream_service, corosio::local_endpoint>; + epoll_local_stream_service, + corosio::local_endpoint>; + public: explicit epoll_local_stream_acceptor_service(capy::execution_context& ctx) - : base_type(ctx) {} + : base_type(ctx) + { + } }; } // namespace boost::corosio::detail diff --git a/include/boost/corosio/native/detail/iocp/win_dissociate.hpp b/include/boost/corosio/native/detail/iocp/win_dissociate.hpp index 92f79eed9..bc4f1dcfe 100644 --- a/include/boost/corosio/native/detail/iocp/win_dissociate.hpp +++ b/include/boost/corosio/native/detail/iocp/win_dissociate.hpp @@ -57,8 +57,7 @@ dissociate_from_iocp(SOCKET s) noexcept // class FileReplaceCompletionInformation (61). ULONG_PTR iosb[2] = {0, 0}; void* info[2] = {nullptr, nullptr}; - return fn(reinterpret_cast(s), iosb, &info, sizeof(info), 61) == - 0; + return fn(reinterpret_cast(s), iosb, &info, sizeof(info), 61) == 0; } } // namespace boost::corosio::detail diff --git a/include/boost/corosio/native/detail/iocp/win_file_service.hpp b/include/boost/corosio/native/detail/iocp/win_file_service.hpp index b4875830e..736fb7b93 100644 --- a/include/boost/corosio/native/detail/iocp/win_file_service.hpp +++ b/include/boost/corosio/native/detail/iocp/win_file_service.hpp @@ -40,8 +40,7 @@ namespace boost::corosio::detail { @par Thread Safety All public member functions are thread-safe. */ -class BOOST_COROSIO_DECL win_file_service final - : public file_service +class BOOST_COROSIO_DECL win_file_service final : public file_service { public: using key_type = win_file_service; @@ -84,14 +83,21 @@ class BOOST_COROSIO_DECL win_file_service final // NtFlushBuffersFileEx support for data-only sync struct io_status_block { - union { LONG Status; void* Pointer; }; + union + { + LONG Status; + void* Pointer; + }; ULONG_PTR Information; }; - enum { flush_flags_file_data_sync_only = 4 }; + enum + { + flush_flags_file_data_sync_only = 4 + }; - using nt_flush_fn = LONG(NTAPI*)( - HANDLE, ULONG, void*, ULONG, io_status_block*); + using nt_flush_fn = + LONG(NTAPI*)(HANDLE, ULONG, void*, ULONG, io_status_block*); win_scheduler& sched_; BOOST_COROSIO_MSVC_WARNING_PUSH @@ -207,8 +213,7 @@ file_write_op::do_complete( // win_stream_file_internal // --------------------------------------------------------------------------- -inline -win_stream_file_internal::win_stream_file_internal( +inline win_stream_file_internal::win_stream_file_internal( win_file_service& svc) noexcept : svc_(svc) , rd_(*this) @@ -216,8 +221,7 @@ win_stream_file_internal::win_stream_file_internal( { } -inline -win_stream_file_internal::~win_stream_file_internal() +inline win_stream_file_internal::~win_stream_file_internal() { svc_.unregister_impl(*this); } @@ -300,8 +304,8 @@ inline native_handle_type win_stream_file_internal::release() { HANDLE h = handle_; - handle_ = INVALID_HANDLE_VALUE; - offset_ = 0; + handle_ = INVALID_HANDLE_VALUE; + offset_ = 0; return reinterpret_cast(h); } @@ -367,7 +371,7 @@ win_stream_file_internal::read_some( auto& op = rd_; op.reset(); - op.is_read = true; + op.is_read = true; op.h = h; op.ex = ex; op.ec_out = ec; @@ -404,7 +408,7 @@ win_stream_file_internal::read_some( op.Offset = static_cast(offset_ & 0xFFFFFFFF); op.OffsetHigh = static_cast(offset_ >> 32); - BOOL ok = ::ReadFile(handle_, op.buf, op.buf_len, nullptr, &op); + BOOL ok = ::ReadFile(handle_, op.buf, op.buf_len, nullptr, &op); DWORD err = ok ? 0 : ::GetLastError(); if (err != 0 && err != ERROR_IO_PENDING) @@ -473,7 +477,7 @@ win_stream_file_internal::write_some( op.Offset = static_cast(offset_ & 0xFFFFFFFF); op.OffsetHigh = static_cast(offset_ >> 32); - BOOL ok = ::WriteFile(handle_, op.buf, op.buf_len, nullptr, &op); + BOOL ok = ::WriteFile(handle_, op.buf, op.buf_len, nullptr, &op); DWORD err = ok ? 0 : ::GetLastError(); if (err != 0 && err != ERROR_IO_PENDING) @@ -495,8 +499,7 @@ win_stream_file_internal::write_some( // win_stream_file wrapper // --------------------------------------------------------------------------- -inline -win_stream_file::win_stream_file( +inline win_stream_file::win_stream_file( std::shared_ptr internal) noexcept : internal_(std::move(internal)) { @@ -585,7 +588,8 @@ win_stream_file::assign(native_handle_type handle) noexcept } inline capy::io_result -win_stream_file::seek(std::int64_t offset, file_base::seek_basis origin) noexcept +win_stream_file::seek( + std::int64_t offset, file_base::seek_basis origin) noexcept { return internal_->seek(offset, origin); } @@ -600,8 +604,7 @@ win_stream_file::get_internal() const noexcept // win_file_service // --------------------------------------------------------------------------- -inline -win_file_service::win_file_service(capy::execution_context& ctx) +inline win_file_service::win_file_service(capy::execution_context& ctx) : sched_(ctx.use_service()) , iocp_(sched_.native_handle()) , nt_flush_buffers_file_ex_(nullptr) @@ -609,13 +612,12 @@ win_file_service::win_file_service(capy::execution_context& ctx) if (FARPROC p = ::GetProcAddress( ::GetModuleHandleA("NTDLL"), "NtFlushBuffersFileEx")) { - nt_flush_buffers_file_ex_ = reinterpret_cast( - reinterpret_cast(p)); + nt_flush_buffers_file_ex_ = + reinterpret_cast(reinterpret_cast(p)); } } -inline -win_file_service::~win_file_service() +inline win_file_service::~win_file_service() { for (auto* w = wrapper_list_.pop_front(); w != nullptr; w = wrapper_list_.pop_front()) @@ -700,27 +702,20 @@ win_file_service::open_file( disposition = TRUNCATE_EXISTING; // Build flags — FILE_FLAG_OVERLAPPED is required for IOCP - DWORD flags = FILE_ATTRIBUTE_NORMAL - | FILE_FLAG_OVERLAPPED - | FILE_FLAG_SEQUENTIAL_SCAN; + DWORD flags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | + FILE_FLAG_SEQUENTIAL_SCAN; if (mode & file_base::sync_all_on_write) flags |= FILE_FLAG_WRITE_THROUGH; HANDLE h = ::CreateFileW( - path.c_str(), - access, - FILE_SHARE_READ | FILE_SHARE_WRITE, - nullptr, - disposition, - flags, - nullptr); + path.c_str(), access, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, + disposition, flags, nullptr); if (h == INVALID_HANDLE_VALUE) return make_err(::GetLastError()); // Register with IOCP - if (!::CreateIoCompletionPort( - h, static_cast(iocp_), key_io, 0)) + if (!::CreateIoCompletionPort(h, static_cast(iocp_), key_io, 0)) { DWORD err = ::GetLastError(); ::CloseHandle(h); @@ -728,8 +723,8 @@ win_file_service::open_file( } // Handle truncation for create|truncate combo - if ((mode & file_base::create) && (mode & file_base::truncate) - && disposition == OPEN_ALWAYS) + if ((mode & file_base::create) && (mode & file_base::truncate) && + disposition == OPEN_ALWAYS) { if (!::SetEndOfFile(h)) { @@ -739,7 +734,7 @@ win_file_service::open_file( } } - auto& internal = *static_cast(impl).get_internal(); + auto& internal = *static_cast(impl).get_internal(); internal.handle_ = h; internal.offset_ = 0; @@ -749,7 +744,7 @@ win_file_service::open_file( LARGE_INTEGER sz; if (!::GetFileSizeEx(h, &sz)) { - DWORD err = ::GetLastError(); + DWORD err = ::GetLastError(); internal.handle_ = INVALID_HANDLE_VALUE; ::CloseHandle(h); return make_err(err); @@ -821,8 +816,7 @@ win_file_service::try_flush_data(HANDLE h) noexcept { io_status_block status = {}; if (nt_flush_buffers_file_ex_( - h, flush_flags_file_data_sync_only, - nullptr, 0, &status) == 0) + h, flush_flags_file_data_sync_only, nullptr, 0, &status) == 0) return true; } return false; diff --git a/include/boost/corosio/native/detail/iocp/win_local_stream_acceptor.hpp b/include/boost/corosio/native/detail/iocp/win_local_stream_acceptor.hpp index 9ea82001e..ccbec449f 100644 --- a/include/boost/corosio/native/detail/iocp/win_local_stream_acceptor.hpp +++ b/include/boost/corosio/native/detail/iocp/win_local_stream_acceptor.hpp @@ -41,7 +41,7 @@ class win_local_stream_acceptor_internal; */ struct local_stream_accept_op : overlapped_op { - SOCKET accepted_socket = INVALID_SOCKET; + SOCKET accepted_socket = INVALID_SOCKET; win_local_stream_socket* peer_wrapper = nullptr; std::shared_ptr acceptor_ptr; SOCKET listen_socket = INVALID_SOCKET; diff --git a/include/boost/corosio/native/detail/iocp/win_local_stream_acceptor_service.hpp b/include/boost/corosio/native/detail/iocp/win_local_stream_acceptor_service.hpp index 179cb1ad0..fc5ad9119 100644 --- a/include/boost/corosio/native/detail/iocp/win_local_stream_acceptor_service.hpp +++ b/include/boost/corosio/native/detail/iocp/win_local_stream_acceptor_service.hpp @@ -54,19 +54,19 @@ class BOOST_COROSIO_DECL win_local_stream_acceptor_service final std::error_code open_acceptor_socket( local_stream_acceptor::implementation& impl, - int family, int type, int protocol) override; + int family, + int type, + int protocol) override; std::error_code assign_socket( local_stream_acceptor::implementation& impl, native_handle_type fd) override; - std::error_code - bind_acceptor( + std::error_code bind_acceptor( local_stream_acceptor::implementation& impl, corosio::local_endpoint ep) override; - std::error_code - listen_acceptor( + std::error_code listen_acceptor( local_stream_acceptor::implementation& impl, int backlog) override; void shutdown() override; @@ -112,8 +112,7 @@ local_stream_acceptor_wait_op::do_cancel_impl(overlapped_op* base) noexcept } if (op->acceptor_ptr) { - op->acceptor_ptr->socket_service().scheduler() - .cancel_wait(op); + op->acceptor_ptr->socket_service().scheduler().cancel_wait(op); } } @@ -386,8 +385,8 @@ win_local_stream_acceptor_internal::accept( auto& peer_wrapper = static_cast(*peer_ptr); // Always AF_UNIX for local sockets - SOCKET accepted = ::WSASocketW( - AF_UNIX, SOCK_STREAM, 0, nullptr, 0, WSA_FLAG_OVERLAPPED); + SOCKET accepted = + ::WSASocketW(AF_UNIX, SOCK_STREAM, 0, nullptr, 0, WSA_FLAG_OVERLAPPED); if (accepted == INVALID_SOCKET) { @@ -424,8 +423,7 @@ win_local_stream_acceptor_internal::accept( } // AcceptEx address buffer sized for sockaddr_un - DWORD addr_size = - static_cast(sizeof(un_sa_t) + 16); + DWORD addr_size = static_cast(sizeof(un_sa_t) + 16); DWORD bytes_received = 0; BOOL ok = accept_ex( @@ -534,7 +532,7 @@ win_local_stream_acceptor::release_socket() noexcept { internal_->cancel(); dissociate_from_iocp(s); - internal_->socket_ = INVALID_SOCKET; + internal_->socket_ = INVALID_SOCKET; internal_->local_endpoint_ = corosio::local_endpoint{}; } return static_cast(s); @@ -587,12 +585,11 @@ inline win_local_stream_acceptor_service::win_local_stream_acceptor_service( inline io_object::implementation* win_local_stream_acceptor_service::construct() { - auto internal = - std::make_shared(svc_); + auto internal = std::make_shared(svc_); // Allocate wrapper before mutating lists so a throw from // new doesn't leave a dangling pointer in acceptor_list_. - auto* raw = internal.get(); + auto* raw = internal.get(); auto* wrapper = new win_local_stream_acceptor(std::move(internal)); { @@ -625,7 +622,9 @@ win_local_stream_acceptor_service::close(io_object::handle& h) inline std::error_code win_local_stream_acceptor_service::open_acceptor_socket( local_stream_acceptor::implementation& impl, - int family, int type, int protocol) + int family, + int type, + int protocol) { auto* internal = static_cast(impl).get_internal(); @@ -643,8 +642,7 @@ win_local_stream_acceptor_service::assign_socket( inline std::error_code win_local_stream_acceptor_service::bind_acceptor( - local_stream_acceptor::implementation& impl, - corosio::local_endpoint ep) + local_stream_acceptor::implementation& impl, corosio::local_endpoint ep) { auto* internal = static_cast(impl).get_internal(); diff --git a/include/boost/corosio/native/detail/iocp/win_local_stream_service.hpp b/include/boost/corosio/native/detail/iocp/win_local_stream_service.hpp index 84b0cd5cb..707105e87 100644 --- a/include/boost/corosio/native/detail/iocp/win_local_stream_service.hpp +++ b/include/boost/corosio/native/detail/iocp/win_local_stream_service.hpp @@ -60,14 +60,17 @@ class BOOST_COROSIO_DECL win_local_stream_service final ~win_local_stream_service(); - win_local_stream_service(win_local_stream_service const&) = delete; - win_local_stream_service& operator=(win_local_stream_service const&) = delete; + win_local_stream_service(win_local_stream_service const&) = delete; + win_local_stream_service& + operator=(win_local_stream_service const&) = delete; void shutdown() override; std::error_code open_socket( local_stream_socket::implementation& impl, - int family, int type, int protocol) override; + int family, + int type, + int protocol) override; std::error_code assign_socket( local_stream_socket::implementation& impl, @@ -79,7 +82,9 @@ class BOOST_COROSIO_DECL win_local_stream_service final std::error_code open_socket_internal( win_local_stream_socket_internal& impl, - int family, int type, int protocol); + int family, + int type, + int protocol); void destroy_acceptor_impl(win_local_stream_acceptor& impl); @@ -87,18 +92,18 @@ class BOOST_COROSIO_DECL win_local_stream_service final std::error_code open_acceptor_socket( win_local_stream_acceptor_internal& impl, - int family, int type, int protocol); + int family, + int type, + int protocol); std::error_code assign_acceptor_socket( - win_local_stream_acceptor_internal& impl, - native_handle_type fd); + win_local_stream_acceptor_internal& impl, native_handle_type fd); std::error_code bind_acceptor( - win_local_stream_acceptor_internal& impl, - corosio::local_endpoint ep); + win_local_stream_acceptor_internal& impl, corosio::local_endpoint ep); - std::error_code listen_acceptor( - win_local_stream_acceptor_internal& impl, int backlog); + std::error_code + listen_acceptor(win_local_stream_acceptor_internal& impl, int backlog); void* native_handle() const noexcept; LPFN_CONNECTEX connect_ex() const noexcept; @@ -388,8 +393,7 @@ win_local_stream_socket_internal::set_socket(SOCKET s) noexcept inline void win_local_stream_socket_internal::set_endpoints( - corosio::local_endpoint local, - corosio::local_endpoint remote) noexcept + corosio::local_endpoint local, corosio::local_endpoint remote) noexcept { local_endpoint_ = local; remote_endpoint_ = remote; @@ -424,9 +428,8 @@ win_local_stream_socket_internal::connect( socklen_t bind_len = static_cast(offsetof(un_sa_t, sun_path)); - if (::bind( - socket_, reinterpret_cast(&bind_sa), - bind_len) == SOCKET_ERROR) + if (::bind(socket_, reinterpret_cast(&bind_sa), bind_len) == + SOCKET_ERROR) { svc_.on_completion(&op, ::WSAGetLastError(), 0); return std::noop_coroutine(); @@ -479,7 +482,7 @@ win_local_stream_socket_internal::read_some( auto& op = rd_; op.reset(); - op.is_read = true; + op.is_read = true; op.h = h; op.ex = d; op.ec_out = ec; @@ -497,8 +500,8 @@ win_local_stream_socket_internal::read_some( } capy::mutable_buffer bufs[local_stream_read_op::max_buffers]; - op.wsabuf_count = - static_cast(param.copy_to(bufs, local_stream_read_op::max_buffers)); + op.wsabuf_count = static_cast( + param.copy_to(bufs, local_stream_read_op::max_buffers)); if (op.wsabuf_count == 0) { @@ -566,8 +569,8 @@ win_local_stream_socket_internal::write_some( } capy::mutable_buffer bufs[local_stream_write_op::max_buffers]; - op.wsabuf_count = - static_cast(param.copy_to(bufs, local_stream_write_op::max_buffers)); + op.wsabuf_count = static_cast( + param.copy_to(bufs, local_stream_write_op::max_buffers)); if (op.wsabuf_count == 0) { @@ -638,8 +641,8 @@ win_local_stream_socket_internal::wait( op.wsabuf = WSABUF{0, nullptr}; op.flags = 0; - int result = ::WSARecv( - socket_, &op.wsabuf, 1, nullptr, &op.flags, &op, nullptr); + int result = + ::WSARecv(socket_, &op.wsabuf, 1, nullptr, &op.flags, &op, nullptr); if (result == SOCKET_ERROR) { @@ -812,7 +815,7 @@ win_local_stream_socket::release_socket() noexcept // adopted again; best-effort, the caller keeps a working // socket either way. dissociate_from_iocp(s); - internal_->socket_ = INVALID_SOCKET; + internal_->socket_ = INVALID_SOCKET; internal_->local_endpoint_ = corosio::local_endpoint{}; internal_->remote_endpoint_ = corosio::local_endpoint{}; } @@ -967,17 +970,20 @@ win_local_stream_service::unregister_impl( inline std::error_code win_local_stream_service::open_socket( local_stream_socket::implementation& impl, - int family, int type, int protocol) + int family, + int type, + int protocol) { auto& wrapper = static_cast(impl); - return open_socket_internal(*wrapper.get_internal(), family, type, protocol); + return open_socket_internal( + *wrapper.get_internal(), family, type, protocol); } inline std::error_code win_local_stream_service::assign_socket( local_stream_socket::implementation& impl, native_handle_type fd) { - auto& wrapper = static_cast(impl); + auto& wrapper = static_cast(impl); auto& internal = *wrapper.get_internal(); SOCKET sock = static_cast(fd); @@ -991,7 +997,8 @@ win_local_stream_service::assign_socket( // a socket that reached connected state without an explicit bind. WSAPROTOCOL_INFOW proto_info{}; int proto_len = sizeof(proto_info); - if (::getsockopt(sock, SOL_SOCKET, SO_PROTOCOL_INFOW, + if (::getsockopt( + sock, SOL_SOCKET, SO_PROTOCOL_INFOW, reinterpret_cast(&proto_info), &proto_len) != 0) return make_err(::WSAGetLastError()); if (proto_info.iAddressFamily != AF_UNIX) @@ -1003,8 +1010,7 @@ win_local_stream_service::assign_socket( // shares descriptor state the way the reactor path does, so a // failed association must not cost the caller their old socket. HANDLE result = ::CreateIoCompletionPort( - reinterpret_cast(sock), - static_cast(iocp_), key_io, 0); + reinterpret_cast(sock), static_cast(iocp_), key_io, 0); if (result == nullptr) return make_err(::GetLastError()); @@ -1014,13 +1020,13 @@ win_local_stream_service::assign_socket( sockaddr_storage local{}; int local_len = sizeof(local); corosio::local_endpoint lep{}, rep{}; - if (::getsockname(sock, - reinterpret_cast(&local), &local_len) == 0) + if (::getsockname(sock, reinterpret_cast(&local), &local_len) == + 0) lep = from_sockaddr_local(local, static_cast(local_len)); sockaddr_storage remote{}; int remote_len = sizeof(remote); - if (::getpeername(sock, - reinterpret_cast(&remote), &remote_len) == 0) + if (::getpeername( + sock, reinterpret_cast(&remote), &remote_len) == 0) rep = from_sockaddr_local(remote, static_cast(remote_len)); internal.local_endpoint_ = lep; internal.remote_endpoint_ = rep; @@ -1029,8 +1035,7 @@ win_local_stream_service::assign_socket( inline std::error_code win_local_stream_service::open_socket_internal( - win_local_stream_socket_internal& impl, - int family, int type, int protocol) + win_local_stream_socket_internal& impl, int family, int type, int protocol) { impl.close_socket(); @@ -1106,8 +1111,7 @@ win_local_stream_service::work_finished() noexcept } inline void -win_local_stream_service::destroy_acceptor_impl( - win_local_stream_acceptor& impl) +win_local_stream_service::destroy_acceptor_impl(win_local_stream_acceptor& impl) { { std::lock_guard lock(mutex_); @@ -1127,7 +1131,9 @@ win_local_stream_service::unregister_acceptor_impl( inline std::error_code win_local_stream_service::open_acceptor_socket( win_local_stream_acceptor_internal& impl, - int family, int type, int protocol) + int family, + int type, + int protocol) { impl.close_socket(); @@ -1165,7 +1171,8 @@ win_local_stream_service::assign_acceptor_socket( // (WSAEINVAL until bind names it). WSAPROTOCOL_INFOW proto_info{}; int proto_len = sizeof(proto_info); - if (::getsockopt(sock, SOL_SOCKET, SO_PROTOCOL_INFOW, + if (::getsockopt( + sock, SOL_SOCKET, SO_PROTOCOL_INFOW, reinterpret_cast(&proto_info), &proto_len) != 0) return make_err(::WSAGetLastError()); if (proto_info.iAddressFamily != AF_UNIX) @@ -1187,8 +1194,8 @@ win_local_stream_service::assign_acceptor_socket( sockaddr_storage local{}; int local_len = sizeof(local); corosio::local_endpoint lep{}; - if (::getsockname( - sock, reinterpret_cast(&local), &local_len) == 0) + if (::getsockname(sock, reinterpret_cast(&local), &local_len) == + 0) lep = from_sockaddr_local(local, static_cast(local_len)); impl.set_local_endpoint(lep); @@ -1197,8 +1204,7 @@ win_local_stream_service::assign_acceptor_socket( inline std::error_code win_local_stream_service::bind_acceptor( - win_local_stream_acceptor_internal& impl, - corosio::local_endpoint ep) + win_local_stream_acceptor_internal& impl, corosio::local_endpoint ep) { // Reject abstract sockets on Windows if (ep.is_abstract()) diff --git a/include/boost/corosio/native/detail/iocp/win_local_stream_socket.hpp b/include/boost/corosio/native/detail/iocp/win_local_stream_socket.hpp index 0a91eefb5..f8ade9eb0 100644 --- a/include/boost/corosio/native/detail/iocp/win_local_stream_socket.hpp +++ b/include/boost/corosio/native/detail/iocp/win_local_stream_socket.hpp @@ -178,8 +178,7 @@ class win_local_stream_socket_internal void close_socket() noexcept; void set_socket(SOCKET s) noexcept; void set_endpoints( - corosio::local_endpoint local, - corosio::local_endpoint remote) noexcept; + corosio::local_endpoint local, corosio::local_endpoint remote) noexcept; private: corosio::local_endpoint local_endpoint_; @@ -234,8 +233,8 @@ class win_local_stream_socket final std::stop_token token, std::error_code* ec) override; - std::error_code shutdown( - local_stream_socket::shutdown_type what) noexcept override; + std::error_code + shutdown(local_stream_socket::shutdown_type what) noexcept override; native_handle_type native_handle() const noexcept override; diff --git a/include/boost/corosio/native/detail/iocp/win_mutex.hpp b/include/boost/corosio/native/detail/iocp/win_mutex.hpp index 650493fa7..85d41cd8a 100644 --- a/include/boost/corosio/native/detail/iocp/win_mutex.hpp +++ b/include/boost/corosio/native/detail/iocp/win_mutex.hpp @@ -50,8 +50,14 @@ class win_mutex win_mutex(win_mutex const&) = delete; win_mutex& operator=(win_mutex const&) = delete; - void set_enabled(bool v) noexcept { enabled_ = v; } - bool enabled() const noexcept { return enabled_; } + void set_enabled(bool v) noexcept + { + enabled_ = v; + } + bool enabled() const noexcept + { + return enabled_; + } void lock() noexcept { diff --git a/include/boost/corosio/native/detail/iocp/win_overlapped_op.hpp b/include/boost/corosio/native/detail/iocp/win_overlapped_op.hpp index 86cc33d8d..aa2ab2d4b 100644 --- a/include/boost/corosio/native/detail/iocp/win_overlapped_op.hpp +++ b/include/boost/corosio/native/detail/iocp/win_overlapped_op.hpp @@ -75,28 +75,34 @@ iocp_make_err(DWORD dwError, bool accept_path) noexcept // A pending op hit by a remote RST completes with ERROR_NETNAME_DELETED; // its portable meaning depends on the operation (reset vs aborted). if (dwError == ERROR_NETNAME_DELETED) - return std::make_error_code(accept_path - ? std::errc::connection_aborted - : std::errc::connection_reset); + return std::make_error_code( + accept_path ? std::errc::connection_aborted + : std::errc::connection_reset); switch (dwError) { - case WSAECONNRESET: // 10054 + case WSAECONNRESET: // 10054 return std::make_error_code(std::errc::connection_reset); - case WSAECONNREFUSED: case ERROR_CONNECTION_REFUSED: // 10061 / 1225 + case WSAECONNREFUSED: + case ERROR_CONNECTION_REFUSED: // 10061 / 1225 return std::make_error_code(std::errc::connection_refused); - case WSAECONNABORTED: case ERROR_CONNECTION_ABORTED: // 10053 / 1236 + case WSAECONNABORTED: + case ERROR_CONNECTION_ABORTED: // 10053 / 1236 return std::make_error_code(std::errc::connection_aborted); - case WSAENETUNREACH: case ERROR_NETWORK_UNREACHABLE: // 10051 / 1231 + case WSAENETUNREACH: + case ERROR_NETWORK_UNREACHABLE: // 10051 / 1231 return std::make_error_code(std::errc::network_unreachable); - case WSAEHOSTUNREACH: case ERROR_HOST_UNREACHABLE: // 10065 / 1232 + case WSAEHOSTUNREACH: + case ERROR_HOST_UNREACHABLE: // 10065 / 1232 return std::make_error_code(std::errc::host_unreachable); - case WSAETIMEDOUT: case ERROR_SEM_TIMEOUT: // 10060 / 121 + case WSAETIMEDOUT: + case ERROR_SEM_TIMEOUT: // 10060 / 121 return std::make_error_code(std::errc::timed_out); // Closed-object contract: MSVC maps ERROR_INVALID_HANDLE to // invalid_argument and MinGW's WSAEBADF mapping is unreliable, so // normalize both spellings of "dead handle" here. - case WSAEBADF: case ERROR_INVALID_HANDLE: // 10009 / 6 + case WSAEBADF: + case ERROR_INVALID_HANDLE: // 10009 / 6 return std::make_error_code(std::errc::bad_file_descriptor); default: break; @@ -127,8 +133,8 @@ struct overlapped_op atomicity of their own. The CAS protocol lives at the access sites in win_scheduler.hpp. */ std::atomic ready_{0}; - DWORD dwError = 0; - DWORD bytes_transferred = 0; + DWORD dwError = 0; + DWORD bytes_transferred = 0; cancel_func_type cancel_func_ = nullptr; explicit overlapped_op(func_type func) noexcept : coro_op(func) @@ -191,12 +197,10 @@ struct overlapped_op stop_cb.reset(); decode_io_result( - ec_out, - cancelled.load(std::memory_order_acquire), + ec_out, cancelled.load(std::memory_order_acquire), dwError != 0 ? iocp_make_err(dwError, /*accept_path=*/false) : std::error_code{}, - is_read, static_cast(bytes_transferred), - empty_buffer); + is_read, static_cast(bytes_transferred), empty_buffer); if (bytes_out) *bytes_out = static_cast(bytes_transferred); diff --git a/include/boost/corosio/native/detail/iocp/win_random_access_file.hpp b/include/boost/corosio/native/detail/iocp/win_random_access_file.hpp index 5b17942a2..4e3c1c4d3 100644 --- a/include/boost/corosio/native/detail/iocp/win_random_access_file.hpp +++ b/include/boost/corosio/native/detail/iocp/win_random_access_file.hpp @@ -42,8 +42,8 @@ struct raf_concurrent_op : overlapped_op , intrusive_list::node { - void* buf = nullptr; - DWORD buf_len = 0; + void* buf = nullptr; + DWORD buf_len = 0; win_random_access_file_internal* file_ = nullptr; std::shared_ptr file_ref; @@ -54,8 +54,7 @@ struct raf_concurrent_op std::uint32_t error); static void do_cancel_impl(overlapped_op* op) noexcept; - explicit raf_concurrent_op( - win_random_access_file_internal& f) noexcept; + explicit raf_concurrent_op(win_random_access_file_internal& f) noexcept; }; /** Internal random-access file state for IOCP-based I/O. diff --git a/include/boost/corosio/native/detail/iocp/win_random_access_file_service.hpp b/include/boost/corosio/native/detail/iocp/win_random_access_file_service.hpp index 870c7ce38..a0e22e66c 100644 --- a/include/boost/corosio/native/detail/iocp/win_random_access_file_service.hpp +++ b/include/boost/corosio/native/detail/iocp/win_random_access_file_service.hpp @@ -49,10 +49,10 @@ class BOOST_COROSIO_DECL win_random_access_file_service final explicit win_random_access_file_service(capy::execution_context& ctx); ~win_random_access_file_service(); - win_random_access_file_service( - win_random_access_file_service const&) = delete; - win_random_access_file_service& operator=( - win_random_access_file_service const&) = delete; + win_random_access_file_service(win_random_access_file_service const&) = + delete; + win_random_access_file_service& + operator=(win_random_access_file_service const&) = delete; io_object::implementation* construct() override; void destroy(io_object::implementation* p) override; @@ -86,14 +86,21 @@ class BOOST_COROSIO_DECL win_random_access_file_service final // NtFlushBuffersFileEx support for data-only sync struct io_status_block { - union { LONG Status; void* Pointer; }; + union + { + LONG Status; + void* Pointer; + }; ULONG_PTR Information; }; - enum { flush_flags_file_data_sync_only = 4 }; + enum + { + flush_flags_file_data_sync_only = 4 + }; - using nt_flush_fn = LONG(NTAPI*)( - HANDLE, ULONG, void*, ULONG, io_status_block*); + using nt_flush_fn = + LONG(NTAPI*)(HANDLE, ULONG, void*, ULONG, io_status_block*); win_scheduler& sched_; BOOST_COROSIO_MSVC_WARNING_PUSH @@ -194,15 +201,13 @@ raf_concurrent_op::do_complete( // win_random_access_file_internal // --------------------------------------------------------------------------- -inline -win_random_access_file_internal::win_random_access_file_internal( +inline win_random_access_file_internal::win_random_access_file_internal( win_random_access_file_service& svc) noexcept : svc_(svc) { } -inline -win_random_access_file_internal::~win_random_access_file_internal() +inline win_random_access_file_internal::~win_random_access_file_internal() { svc_.unregister_impl(*this); } @@ -226,9 +231,8 @@ win_random_access_file_internal::cancel() noexcept ::CancelIoEx(handle_, nullptr); std::lock_guard lock(ops_mutex_); - outstanding_ops_.for_each([](raf_concurrent_op* op) { - op->request_cancel(); - }); + outstanding_ops_.for_each( + [](raf_concurrent_op* op) { op->request_cancel(); }); } inline void @@ -287,7 +291,7 @@ inline native_handle_type win_random_access_file_internal::release() { HANDLE h = handle_; - handle_ = INVALID_HANDLE_VALUE; + handle_ = INVALID_HANDLE_VALUE; return reinterpret_cast(h); } @@ -318,11 +322,11 @@ win_random_access_file_internal::read_some_at( { static constexpr std::size_t max_buffers = 16; - auto* op = new raf_concurrent_op(*this); + auto* op = new raf_concurrent_op(*this); op->file_ref = shared_from_this(); op->reset(); - op->is_read = true; + op->is_read = true; op->h = h; op->ex = ex; op->ec_out = ec; @@ -369,7 +373,7 @@ win_random_access_file_internal::read_some_at( outstanding_ops_.push_back(op); } - BOOL ok = ::ReadFile(handle_, op->buf, op->buf_len, nullptr, op); + BOOL ok = ::ReadFile(handle_, op->buf, op->buf_len, nullptr, op); DWORD err = ok ? 0 : ::GetLastError(); if (err != 0 && err != ERROR_IO_PENDING) @@ -399,11 +403,11 @@ win_random_access_file_internal::write_some_at( { static constexpr std::size_t max_buffers = 16; - auto* op = new raf_concurrent_op(*this); + auto* op = new raf_concurrent_op(*this); op->file_ref = shared_from_this(); op->reset(); - op->is_read = false; + op->is_read = false; op->h = h; op->ex = ex; op->ec_out = ec; @@ -449,7 +453,7 @@ win_random_access_file_internal::write_some_at( outstanding_ops_.push_back(op); } - BOOL ok = ::WriteFile(handle_, op->buf, op->buf_len, nullptr, op); + BOOL ok = ::WriteFile(handle_, op->buf, op->buf_len, nullptr, op); DWORD err = ok ? 0 : ::GetLastError(); if (err != 0 && err != ERROR_IO_PENDING) @@ -471,8 +475,7 @@ win_random_access_file_internal::write_some_at( // win_random_access_file wrapper // --------------------------------------------------------------------------- -inline -win_random_access_file::win_random_access_file( +inline win_random_access_file::win_random_access_file( std::shared_ptr internal) noexcept : internal_(std::move(internal)) { @@ -572,8 +575,7 @@ win_random_access_file::get_internal() const noexcept // win_random_access_file_service // --------------------------------------------------------------------------- -inline -win_random_access_file_service::win_random_access_file_service( +inline win_random_access_file_service::win_random_access_file_service( capy::execution_context& ctx) : sched_(ctx.use_service()) , iocp_(sched_.native_handle()) @@ -582,13 +584,12 @@ win_random_access_file_service::win_random_access_file_service( if (FARPROC p = ::GetProcAddress( ::GetModuleHandleA("NTDLL"), "NtFlushBuffersFileEx")) { - nt_flush_buffers_file_ex_ = reinterpret_cast( - reinterpret_cast(p)); + nt_flush_buffers_file_ex_ = + reinterpret_cast(reinterpret_cast(p)); } } -inline -win_random_access_file_service::~win_random_access_file_service() +inline win_random_access_file_service::~win_random_access_file_service() { for (auto* w = wrapper_list_.pop_front(); w != nullptr; w = wrapper_list_.pop_front()) @@ -598,8 +599,7 @@ win_random_access_file_service::~win_random_access_file_service() inline io_object::implementation* win_random_access_file_service::construct() { - auto internal = - std::make_shared(*this); + auto internal = std::make_shared(*this); { std::lock_guard lock(mutex_); @@ -674,27 +674,20 @@ win_random_access_file_service::open_file( disposition = TRUNCATE_EXISTING; // Build flags — FILE_FLAG_OVERLAPPED + FILE_FLAG_RANDOM_ACCESS - DWORD flags = FILE_ATTRIBUTE_NORMAL - | FILE_FLAG_OVERLAPPED - | FILE_FLAG_RANDOM_ACCESS; + DWORD flags = + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_RANDOM_ACCESS; if (mode & file_base::sync_all_on_write) flags |= FILE_FLAG_WRITE_THROUGH; HANDLE h = ::CreateFileW( - path.c_str(), - access, - FILE_SHARE_READ | FILE_SHARE_WRITE, - nullptr, - disposition, - flags, - nullptr); + path.c_str(), access, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, + disposition, flags, nullptr); if (h == INVALID_HANDLE_VALUE) return make_err(::GetLastError()); // Register with IOCP - if (!::CreateIoCompletionPort( - h, static_cast(iocp_), key_io, 0)) + if (!::CreateIoCompletionPort(h, static_cast(iocp_), key_io, 0)) { DWORD err = ::GetLastError(); ::CloseHandle(h); @@ -702,8 +695,8 @@ win_random_access_file_service::open_file( } // Handle truncation for create|truncate combo - if ((mode & file_base::create) && (mode & file_base::truncate) - && disposition == OPEN_ALWAYS) + if ((mode & file_base::create) && (mode & file_base::truncate) && + disposition == OPEN_ALWAYS) { if (!::SetEndOfFile(h)) { @@ -713,8 +706,7 @@ win_random_access_file_service::open_file( } } - auto& internal = - *static_cast(impl).get_internal(); + auto& internal = *static_cast(impl).get_internal(); internal.handle_ = h; return {}; @@ -782,8 +774,7 @@ win_random_access_file_service::try_flush_data(HANDLE h) noexcept { io_status_block status = {}; if (nt_flush_buffers_file_ex_( - h, flush_flags_file_data_sync_only, - nullptr, 0, &status) == 0) + h, flush_flags_file_data_sync_only, nullptr, 0, &status) == 0) return true; } return false; diff --git a/include/boost/corosio/native/detail/iocp/win_scheduler.hpp b/include/boost/corosio/native/detail/iocp/win_scheduler.hpp index 79fbf4c56..57cf6c03d 100644 --- a/include/boost/corosio/native/detail/iocp/win_scheduler.hpp +++ b/include/boost/corosio/native/detail/iocp/win_scheduler.hpp @@ -136,7 +136,8 @@ class BOOST_COROSIO_DECL win_scheduler final bool scheduler_locking_disabled_ = false; BOOST_COROSIO_MSVC_WARNING_PUSH - BOOST_COROSIO_MSVC_WARNING_DISABLE(4251) // std::/detail:: members, dll-interface + BOOST_COROSIO_MSVC_WARNING_DISABLE( + 4251) // std::/detail:: members, dll-interface mutable win_mutex dispatch_mutex_; mutable op_queue completed_ops_; std::unique_ptr timers_; @@ -345,8 +346,7 @@ win_scheduler::on_pending(overlapped_op* op) const // op memory itself — no packet, no count. long expected = 0; if (op->ready_.compare_exchange_strong( - expected, 1, - std::memory_order_acq_rel, std::memory_order_acquire)) + expected, 1, std::memory_order_acq_rel, std::memory_order_acquire)) { ::InterlockedIncrement(&pending_io_); } @@ -590,8 +590,7 @@ win_scheduler::do_one(unsigned long timeout_ms) // skip and let on_pending() re-post. long expected = 0; if (!ov_op->ready_.compare_exchange_strong( - expected, 1, - std::memory_order_acq_rel, + expected, 1, std::memory_order_acq_rel, std::memory_order_acquire)) { ::InterlockedDecrement(&pending_io_); @@ -621,8 +620,8 @@ win_scheduler::do_one(unsigned long timeout_ms) return 1; } - default: // LCOV_EXCL_LINE unreachable: closed key set - continue; // LCOV_EXCL_LINE unreachable: closed key set + default: // LCOV_EXCL_LINE unreachable: closed key set + continue; // LCOV_EXCL_LINE unreachable: closed key set } } @@ -651,8 +650,8 @@ win_scheduler::do_one(unsigned long timeout_ms) // A key outside the closed set reaches here only if a // third party posts to the port. - default: // LCOV_EXCL_LINE unreachable: closed key set - continue; // LCOV_EXCL_LINE unreachable: closed key set + default: // LCOV_EXCL_LINE unreachable: closed key set + continue; // LCOV_EXCL_LINE unreachable: closed key set } } @@ -801,8 +800,7 @@ win_scheduler::shutdown() ULONG_PTR key; LPOVERLAPPED overlapped; ::GetQueuedCompletionStatus( - iocp_, &bytes, &key, &overlapped, - iocp::shutdown_drain_timeout_ms); + iocp_, &bytes, &key, &overlapped, iocp::shutdown_drain_timeout_ms); if (overlapped) { if (key == key_posted) diff --git a/include/boost/corosio/native/detail/iocp/win_signals.hpp b/include/boost/corosio/native/detail/iocp/win_signals.hpp index 581d56164..90b4320ff 100644 --- a/include/boost/corosio/native/detail/iocp/win_signals.hpp +++ b/include/boost/corosio/native/detail/iocp/win_signals.hpp @@ -678,7 +678,7 @@ win_signals::start_wait(win_signal& impl, signal_op* op) { --reg->undelivered; op->signal_number = reg->signal_number; - op->svc = nullptr; // No extra work_finished needed + op->svc = nullptr; // No extra work_finished needed // Post for immediate completion - post() handles work tracking post(op); return; @@ -704,8 +704,10 @@ win_signals::start_wait(win_signal& impl, signal_op* op) inline void win_signals::deliver_signal(int signal_number) { - if (signal_number < 0 || signal_number >= max_signal_number) // LCOV_EXCL_LINE OS never delivers out-of-range - return; // LCOV_EXCL_LINE OS never delivers out-of-range + if (signal_number < 0 || + signal_number >= + max_signal_number) // LCOV_EXCL_LINE OS never delivers out-of-range + return; // LCOV_EXCL_LINE OS never delivers out-of-range signal_detail::signal_state* state = signal_detail::get_signal_state(); std::lock_guard lock(state->mutex); diff --git a/include/boost/corosio/native/detail/iocp/win_stream_file.hpp b/include/boost/corosio/native/detail/iocp/win_stream_file.hpp index 9f338a503..3cb3a9bc8 100644 --- a/include/boost/corosio/native/detail/iocp/win_stream_file.hpp +++ b/include/boost/corosio/native/detail/iocp/win_stream_file.hpp @@ -34,8 +34,8 @@ class win_stream_file_internal; /** Read operation state for stream file IOCP I/O. */ struct file_read_op : overlapped_op { - void* buf = nullptr; - DWORD buf_len = 0; + void* buf = nullptr; + DWORD buf_len = 0; win_stream_file_internal& file_; std::shared_ptr file_ptr; @@ -52,8 +52,8 @@ struct file_read_op : overlapped_op /** Write operation state for stream file IOCP I/O. */ struct file_write_op : overlapped_op { - void* buf = nullptr; - DWORD buf_len = 0; + void* buf = nullptr; + DWORD buf_len = 0; win_stream_file_internal& file_; std::shared_ptr file_ptr; @@ -86,7 +86,7 @@ class win_stream_file_internal win_file_service& svc_; file_read_op rd_; file_write_op wr_; - HANDLE handle_ = INVALID_HANDLE_VALUE; + HANDLE handle_ = INVALID_HANDLE_VALUE; std::uint64_t offset_ = 0; public: diff --git a/include/boost/corosio/native/detail/iocp/win_tcp_acceptor.hpp b/include/boost/corosio/native/detail/iocp/win_tcp_acceptor.hpp index 0acdb5cbc..7779005c8 100644 --- a/include/boost/corosio/native/detail/iocp/win_tcp_acceptor.hpp +++ b/include/boost/corosio/native/detail/iocp/win_tcp_acceptor.hpp @@ -38,7 +38,7 @@ class win_tcp_acceptor_internal; /** Accept operation state. */ struct accept_op : overlapped_op { - SOCKET accepted_socket = INVALID_SOCKET; + SOCKET accepted_socket = INVALID_SOCKET; win_tcp_socket* peer_wrapper = nullptr; std::shared_ptr acceptor_ptr; SOCKET listen_socket = INVALID_SOCKET; diff --git a/include/boost/corosio/native/detail/iocp/win_tcp_acceptor_service.hpp b/include/boost/corosio/native/detail/iocp/win_tcp_acceptor_service.hpp index a490328cf..700aa168f 100644 --- a/include/boost/corosio/native/detail/iocp/win_tcp_acceptor_service.hpp +++ b/include/boost/corosio/native/detail/iocp/win_tcp_acceptor_service.hpp @@ -47,7 +47,8 @@ class BOOST_COROSIO_DECL win_tcp_acceptor_service final public: using key_type = win_tcp_acceptor_service; - win_tcp_acceptor_service(capy::execution_context& ctx, win_tcp_service& svc); + win_tcp_acceptor_service( + capy::execution_context& ctx, win_tcp_service& svc); io_object::implementation* construct() override; @@ -60,8 +61,8 @@ class BOOST_COROSIO_DECL win_tcp_acceptor_service final tcp_acceptor::implementation& impl, int family, int type, int protocol); /** Adopt an existing listening socket. */ - std::error_code assign_socket( - tcp_acceptor::implementation& impl, native_handle_type fd); + std::error_code + assign_socket(tcp_acceptor::implementation& impl, native_handle_type fd); /** Bind an open acceptor to a local endpoint. */ std::error_code @@ -195,8 +196,7 @@ acceptor_wait_op::do_cancel_impl(overlapped_op* base) noexcept } if (op->acceptor_ptr) { - op->acceptor_ptr->socket_service().scheduler() - .cancel_wait(op); + op->acceptor_ptr->socket_service().scheduler().cancel_wait(op); } } @@ -430,7 +430,8 @@ wait_op::do_complete( // win_tcp_socket_internal -inline win_tcp_socket_internal::win_tcp_socket_internal(win_tcp_service& svc) noexcept +inline win_tcp_socket_internal::win_tcp_socket_internal( + win_tcp_service& svc) noexcept : svc_(svc) , conn_(*this) , rd_(*this) @@ -578,7 +579,7 @@ win_tcp_socket_internal::read_some( auto& op = rd_; op.reset(); - op.is_read = true; + op.is_read = true; op.h = h; op.ex = d; op.ec_out = ec; @@ -746,8 +747,8 @@ win_tcp_socket_internal::wait( op.wsabuf = WSABUF{0, nullptr}; op.flags = 0; - int result = ::WSARecv( - socket_, &op.wsabuf, 1, nullptr, &op.flags, &op, nullptr); + int result = + ::WSARecv(socket_, &op.wsabuf, 1, nullptr, &op.flags, &op, nullptr); if (result == SOCKET_ERROR) { @@ -1169,8 +1170,8 @@ win_tcp_service::assign_socket( sockaddr_storage remote_storage{}; int remote_len = sizeof(remote_storage); if (::getpeername( - sock, reinterpret_cast(&remote_storage), - &remote_len) == 0) + sock, reinterpret_cast(&remote_storage), &remote_len) == + 0) remote_ep = detail::from_sockaddr(remote_storage); impl.set_endpoints(local_ep, remote_ep); @@ -1218,7 +1219,8 @@ win_tcp_service::on_pending(overlapped_op* op) noexcept } inline void -win_tcp_service::on_completion(overlapped_op* op, DWORD error, DWORD bytes) noexcept +win_tcp_service::on_completion( + overlapped_op* op, DWORD error, DWORD bytes) noexcept { sched_.on_completion(op, error, bytes); } @@ -1393,7 +1395,8 @@ win_tcp_service::listen_acceptor(win_tcp_acceptor_internal& impl, int backlog) // win_tcp_acceptor_internal -inline win_tcp_acceptor_internal::win_tcp_acceptor_internal(win_tcp_service& svc) noexcept +inline win_tcp_acceptor_internal::win_tcp_acceptor_internal( + win_tcp_service& svc) noexcept : svc_(svc) { } diff --git a/include/boost/corosio/native/detail/iocp/win_tcp_service.hpp b/include/boost/corosio/native/detail/iocp/win_tcp_service.hpp index e01455da5..dfed1c803 100644 --- a/include/boost/corosio/native/detail/iocp/win_tcp_service.hpp +++ b/include/boost/corosio/native/detail/iocp/win_tcp_service.hpp @@ -95,8 +95,8 @@ class BOOST_COROSIO_DECL win_tcp_service final @param impl The socket implementation internal to initialize. @return Error code, or success. */ - std::error_code - open_socket(win_tcp_socket_internal& impl, int family, int type, int protocol); + std::error_code open_socket( + win_tcp_socket_internal& impl, int family, int type, int protocol); /** Adopt an existing socket handle into an implementation. @@ -118,8 +118,7 @@ class BOOST_COROSIO_DECL win_tcp_service final @param ep The local endpoint to bind to. @return Error code, or success. */ - std::error_code - bind_socket(win_tcp_socket_internal& impl, endpoint ep); + std::error_code bind_socket(win_tcp_socket_internal& impl, endpoint ep); /** Destroy an acceptor implementation wrapper. Removes from tracking list and deletes. @@ -174,7 +173,8 @@ class BOOST_COROSIO_DECL win_tcp_service final @param backlog The listen backlog. @return Error code, or success. */ - std::error_code listen_acceptor(win_tcp_acceptor_internal& impl, int backlog); + std::error_code + listen_acceptor(win_tcp_acceptor_internal& impl, int backlog); /** Return the IOCP handle. */ void* native_handle() const noexcept; diff --git a/include/boost/corosio/native/detail/iocp/win_tcp_socket.hpp b/include/boost/corosio/native/detail/iocp/win_tcp_socket.hpp index 6099c819a..0a3ddb687 100644 --- a/include/boost/corosio/native/detail/iocp/win_tcp_socket.hpp +++ b/include/boost/corosio/native/detail/iocp/win_tcp_socket.hpp @@ -204,7 +204,8 @@ class win_tcp_socket final std::shared_ptr internal_; public: - explicit win_tcp_socket(std::shared_ptr internal) noexcept; + explicit win_tcp_socket( + std::shared_ptr internal) noexcept; void close_internal() noexcept; diff --git a/include/boost/corosio/native/detail/iocp/win_udp_service.hpp b/include/boost/corosio/native/detail/iocp/win_udp_service.hpp index 9ac93efff..c867ae72c 100644 --- a/include/boost/corosio/native/detail/iocp/win_udp_service.hpp +++ b/include/boost/corosio/native/detail/iocp/win_udp_service.hpp @@ -65,8 +65,7 @@ class BOOST_COROSIO_DECL win_udp_service final int type, int protocol) override; std::error_code assign_socket( - udp_socket::implementation& impl, - native_handle_type fd) override; + udp_socket::implementation& impl, native_handle_type fd) override; std::error_code bind_datagram(udp_socket::implementation& impl, endpoint ep) override; @@ -1136,8 +1135,8 @@ win_udp_service::assign_socket( sockaddr_storage remote_storage{}; int remote_len = sizeof(remote_storage); if (::getpeername( - sock, reinterpret_cast(&remote_storage), - &remote_len) == 0) + sock, reinterpret_cast(&remote_storage), &remote_len) == + 0) remote_ep = detail::from_sockaddr(remote_storage); internal->local_endpoint_ = local_ep; internal->remote_endpoint_ = remote_ep; diff --git a/include/boost/corosio/native/detail/iocp/win_wait_reactor.hpp b/include/boost/corosio/native/detail/iocp/win_wait_reactor.hpp index ed35045d0..dc3ca8fd3 100644 --- a/include/boost/corosio/native/detail/iocp/win_wait_reactor.hpp +++ b/include/boost/corosio/native/detail/iocp/win_wait_reactor.hpp @@ -153,15 +153,18 @@ class win_wait_reactor : private win_wsa_init { switch (w) { - case wait_type::read: return POLLRDNORM; - case wait_type::write: return POLLWRNORM; + case wait_type::read: + return POLLRDNORM; + case wait_type::write: + return POLLWRNORM; // The Microsoft provider does not implement POLLPRI and // refuses the whole call when it is asked for, which would // take every other registration in the set with it. The band // it does implement carries the same out-of-band meaning, and // the error conditions an error wait is really after arrive in // revents whether or not they were asked for. - default: return POLLRDBAND; + default: + return POLLRDBAND; } } @@ -208,8 +211,7 @@ class win_wait_reactor : private win_wsa_init std::thread thread_; }; -inline win_wait_reactor::win_wait_reactor(win_scheduler& sched) - : sched_(sched) +inline win_wait_reactor::win_wait_reactor(win_scheduler& sched) : sched_(sched) { // The win_wsa_init base is what makes the sockets below legal, and // holding the reference rather than borrowing someone else's is @@ -268,8 +270,7 @@ win_wait_reactor::make_wakeup_pair() noexcept return err; } - if (::connect( - wakeup_write_, reinterpret_cast(&addr), len) == + if (::connect(wakeup_write_, reinterpret_cast(&addr), len) == SOCKET_ERROR) { DWORD const err = last_error(); @@ -341,8 +342,7 @@ win_wait_reactor::wake_self() noexcept } inline void -win_wait_reactor::register_wait( - SOCKET fd, wait_type w, overlapped_op* op) +win_wait_reactor::register_wait(SOCKET fd, wait_type w, overlapped_op* op) { // If the op was already cancelled (e.g. pre-cancelled stop_token // fired synchronously before this call), complete immediately @@ -538,8 +538,7 @@ win_wait_reactor::run() // its own send fails, so a lost wake costs the wakes already in // flight rather than every wake after it. int n = ::WSAPoll( - pollfds.data(), - static_cast(pollfds.size()), + pollfds.data(), static_cast(pollfds.size()), -1 /* infinite */); if (n == SOCKET_ERROR) { @@ -580,7 +579,7 @@ win_wait_reactor::run() if (!ready_for_wait(e.w, pfd.revents)) continue; - DWORD err = 0; + DWORD err = 0; constexpr SHORT err_bits = POLLERR | POLLHUP | POLLNVAL; if (pfd.revents & err_bits) { diff --git a/include/boost/corosio/native/detail/iocp/win_wsa_init.hpp b/include/boost/corosio/native/detail/iocp/win_wsa_init.hpp index 66267871b..18d6635ca 100644 --- a/include/boost/corosio/native/detail/iocp/win_wsa_init.hpp +++ b/include/boost/corosio/native/detail/iocp/win_wsa_init.hpp @@ -46,7 +46,8 @@ class BOOST_COROSIO_DECL win_wsa_init // so win_wsa_init can carry BOOST_COROSIO_DECL: an exported/imported static // data member defined in a header is rejected by MSVC and clang-cl // ("definition of dllimport static field not allowed"). -inline long& win_wsa_init_count() noexcept +inline long& +win_wsa_init_count() noexcept { static long count = 0; return count; diff --git a/include/boost/corosio/native/detail/kqueue/kqueue_scheduler.hpp b/include/boost/corosio/native/detail/kqueue/kqueue_scheduler.hpp index 153f1d551..bf02a605e 100644 --- a/include/boost/corosio/native/detail/kqueue/kqueue_scheduler.hpp +++ b/include/boost/corosio/native/detail/kqueue/kqueue_scheduler.hpp @@ -148,16 +148,13 @@ class BOOST_COROSIO_DECL kqueue_scheduler final : public reactor_scheduler void deregister_descriptor(int fd) const; /// Watch the read end of the POSIX signal self-pipe (see scheduler.hpp). - [[nodiscard]] std::error_code - register_signal_reader(int read_fd) override + [[nodiscard]] std::error_code register_signal_reader(int read_fd) override { return register_descriptor(read_fd, signal_pipe_reader_.arm()); } private: - void - run_task(lock_type& lock, context_type& ctx, - long timeout_us) override; + void run_task(lock_type& lock, context_type& ctx, long timeout_us) override; void interrupt_reactor() const override; long calculate_timeout(long requested_timeout_us) const; @@ -240,7 +237,8 @@ kqueue_scheduler::configure_reactor( } inline std::error_code -kqueue_scheduler::register_descriptor(int fd, reactor_descriptor_state* desc) const +kqueue_scheduler::register_descriptor( + int fd, reactor_descriptor_state* desc) const { struct kevent changes[2]; EV_SET( @@ -334,8 +332,7 @@ kqueue_scheduler::calculate_timeout(long requested_timeout_us) const } inline void -kqueue_scheduler::run_task( - lock_type& lock, context_type& ctx, long timeout_us) +kqueue_scheduler::run_task(lock_type& lock, context_type& ctx, long timeout_us) { long effective_timeout_us = task_interrupted_ ? 0 : calculate_timeout(timeout_us); diff --git a/include/boost/corosio/native/detail/kqueue/kqueue_traits.hpp b/include/boost/corosio/native/detail/kqueue/kqueue_traits.hpp index c858bfff5..cfbb163a4 100644 --- a/include/boost/corosio/native/detail/kqueue/kqueue_traits.hpp +++ b/include/boost/corosio/native/detail/kqueue/kqueue_traits.hpp @@ -42,8 +42,8 @@ class kqueue_scheduler; struct kqueue_traits { - using scheduler_type = kqueue_scheduler; - using desc_state_type = reactor_descriptor_state; + using scheduler_type = kqueue_scheduler; + using desc_state_type = reactor_descriptor_state; static constexpr bool needs_write_notification = false; @@ -58,12 +58,15 @@ struct kqueue_traits struct stream_socket_hook { std::error_code on_set_option( - int fd, int level, int optname, - void const* data, std::size_t size) noexcept + int fd, + int level, + int optname, + void const* data, + std::size_t size) noexcept { if (::setsockopt( - fd, level, optname, data, - static_cast(size)) != 0) + fd, level, optname, data, static_cast(size)) != + 0) return make_err(errno); return {}; } @@ -87,8 +90,8 @@ struct kqueue_traits // Single-buffer fast path. write() carries no flag to suppress // SIGPIPE; the mandatory SO_NOSIGPIPE set in accept_policy and // set_fd_options does it per descriptor instead. - static ssize_t write_one( - int fd, void const* data, std::size_t size) noexcept + static ssize_t + write_one(int fd, void const* data, std::size_t size) noexcept { ssize_t n; do @@ -102,15 +105,15 @@ struct kqueue_traits struct accept_policy { - static int do_accept( - int fd, sockaddr_storage& peer, socklen_t& addrlen) noexcept + static int + do_accept(int fd, sockaddr_storage& peer, socklen_t& addrlen) noexcept { int new_fd; do { addrlen = sizeof(peer); - new_fd = ::accept( - fd, reinterpret_cast(&peer), &addrlen); + new_fd = + ::accept(fd, reinterpret_cast(&peer), &addrlen); } while (new_fd < 0 && errno == EINTR); @@ -143,8 +146,7 @@ struct kqueue_traits // absent. int one = 1; if (::setsockopt( - new_fd, SOL_SOCKET, SO_NOSIGPIPE, - &one, sizeof(one)) == -1) + new_fd, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one)) == -1) { int err = errno; ::close(new_fd); @@ -187,8 +189,7 @@ struct kqueue_traits // Apply protocol-specific options after socket creation. // For IP sockets, sets IPV6_V6ONLY on AF_INET6 (best-effort). - static std::error_code - configure_ip_socket(int fd, int family) noexcept + static std::error_code configure_ip_socket(int fd, int family) noexcept { auto ec = set_fd_options(fd); if (ec) @@ -196,18 +197,16 @@ struct kqueue_traits if (family == AF_INET6) { - int v6only = 1; + int v6only = 1; std::ignore = ::setsockopt( - fd, IPPROTO_IPV6, IPV6_V6ONLY, - &v6only, sizeof(v6only)); + fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)); } return {}; } // Apply protocol-specific options for acceptor sockets. // For IP acceptors, sets IPV6_V6ONLY=0 (dual-stack, best-effort). - static std::error_code - configure_ip_acceptor(int fd, int family) noexcept + static std::error_code configure_ip_acceptor(int fd, int family) noexcept { auto ec = set_fd_options(fd); if (ec) @@ -216,23 +215,21 @@ struct kqueue_traits if (family == AF_INET6) { int val = 0; - std::ignore = ::setsockopt( - fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); + std::ignore = + ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); } return {}; } // Apply options for local (unix) sockets. - static std::error_code - configure_local_socket(int fd) noexcept + static std::error_code configure_local_socket(int fd) noexcept { return set_fd_options(fd); } // Non-mutating validation for fds adopted via assign(). Used when // the caller retains fd ownership responsibility. - static std::error_code - validate_assigned_fd(int /*fd*/) noexcept + static std::error_code validate_assigned_fd(int /*fd*/) noexcept { return {}; } diff --git a/include/boost/corosio/native/detail/kqueue/kqueue_types.hpp b/include/boost/corosio/native/detail/kqueue/kqueue_types.hpp index 049175105..071a2f128 100644 --- a/include/boost/corosio/native/detail/kqueue/kqueue_types.hpp +++ b/include/boost/corosio/native/detail/kqueue/kqueue_types.hpp @@ -46,16 +46,27 @@ class kqueue_local_datagram_service; class kqueue_tcp_socket final : public reactor_stream_socket_impl< - kqueue_tcp_socket, kqueue_traits, kqueue_tcp_service, - kqueue_tcp_acceptor, tcp_socket::implementation, endpoint> + kqueue_tcp_socket, + kqueue_traits, + kqueue_tcp_service, + kqueue_tcp_acceptor, + tcp_socket::implementation, + endpoint> { using base_type = reactor_stream_socket_impl< - kqueue_tcp_socket, kqueue_traits, kqueue_tcp_service, - kqueue_tcp_acceptor, tcp_socket::implementation, endpoint>; + kqueue_tcp_socket, + kqueue_traits, + kqueue_tcp_service, + kqueue_tcp_acceptor, + tcp_socket::implementation, + endpoint>; friend kqueue_tcp_service; + public: explicit kqueue_tcp_socket(kqueue_tcp_service& svc) noexcept - : base_type(svc) {} + : base_type(svc) + { + } native_handle_type release_socket() noexcept override { @@ -66,18 +77,28 @@ class kqueue_tcp_socket final class kqueue_local_stream_socket final : public reactor_stream_socket_impl< - kqueue_local_stream_socket, kqueue_traits, - kqueue_local_stream_service, kqueue_local_stream_acceptor, - local_stream_socket::implementation, corosio::local_endpoint> + kqueue_local_stream_socket, + kqueue_traits, + kqueue_local_stream_service, + kqueue_local_stream_acceptor, + local_stream_socket::implementation, + corosio::local_endpoint> { using base_type = reactor_stream_socket_impl< - kqueue_local_stream_socket, kqueue_traits, - kqueue_local_stream_service, kqueue_local_stream_acceptor, - local_stream_socket::implementation, corosio::local_endpoint>; + kqueue_local_stream_socket, + kqueue_traits, + kqueue_local_stream_service, + kqueue_local_stream_acceptor, + local_stream_socket::implementation, + corosio::local_endpoint>; friend kqueue_local_stream_service; + public: - explicit kqueue_local_stream_socket(kqueue_local_stream_service& svc) noexcept - : base_type(svc) {} + explicit kqueue_local_stream_socket( + kqueue_local_stream_service& svc) noexcept + : base_type(svc) + { + } native_handle_type release_socket() noexcept override { @@ -90,16 +111,27 @@ class kqueue_local_stream_socket final class kqueue_udp_socket final : public reactor_dgram_socket_impl< - kqueue_udp_socket, kqueue_traits, kqueue_udp_service, - kqueue_tcp_acceptor, udp_socket::implementation, endpoint> + kqueue_udp_socket, + kqueue_traits, + kqueue_udp_service, + kqueue_tcp_acceptor, + udp_socket::implementation, + endpoint> { using base_type = reactor_dgram_socket_impl< - kqueue_udp_socket, kqueue_traits, kqueue_udp_service, - kqueue_tcp_acceptor, udp_socket::implementation, endpoint>; + kqueue_udp_socket, + kqueue_traits, + kqueue_udp_service, + kqueue_tcp_acceptor, + udp_socket::implementation, + endpoint>; friend kqueue_udp_service; + public: explicit kqueue_udp_socket(kqueue_udp_service& svc) noexcept - : base_type(svc) {} + : base_type(svc) + { + } std::error_code shutdown(corosio::shutdown_type what) noexcept override { @@ -114,18 +146,28 @@ class kqueue_udp_socket final class kqueue_local_datagram_socket final : public reactor_dgram_socket_impl< - kqueue_local_datagram_socket, kqueue_traits, - kqueue_local_datagram_service, kqueue_tcp_acceptor, - local_datagram_socket::implementation, corosio::local_endpoint> + kqueue_local_datagram_socket, + kqueue_traits, + kqueue_local_datagram_service, + kqueue_tcp_acceptor, + local_datagram_socket::implementation, + corosio::local_endpoint> { using base_type = reactor_dgram_socket_impl< - kqueue_local_datagram_socket, kqueue_traits, - kqueue_local_datagram_service, kqueue_tcp_acceptor, - local_datagram_socket::implementation, corosio::local_endpoint>; + kqueue_local_datagram_socket, + kqueue_traits, + kqueue_local_datagram_service, + kqueue_tcp_acceptor, + local_datagram_socket::implementation, + corosio::local_endpoint>; friend kqueue_local_datagram_service; + public: - explicit kqueue_local_datagram_socket(kqueue_local_datagram_service& svc) noexcept - : base_type(svc) {} + explicit kqueue_local_datagram_socket( + kqueue_local_datagram_service& svc) noexcept + : base_type(svc) + { + } std::error_code shutdown(corosio::shutdown_type what) noexcept override { @@ -147,119 +189,173 @@ class kqueue_local_datagram_socket final class kqueue_tcp_acceptor final : public reactor_acceptor_impl< - kqueue_tcp_acceptor, kqueue_traits, - kqueue_tcp_acceptor_service, kqueue_tcp_socket, - tcp_acceptor::implementation, endpoint> + kqueue_tcp_acceptor, + kqueue_traits, + kqueue_tcp_acceptor_service, + kqueue_tcp_socket, + tcp_acceptor::implementation, + endpoint> { using base_type = reactor_acceptor_impl< - kqueue_tcp_acceptor, kqueue_traits, - kqueue_tcp_acceptor_service, kqueue_tcp_socket, - tcp_acceptor::implementation, endpoint>; + kqueue_tcp_acceptor, + kqueue_traits, + kqueue_tcp_acceptor_service, + kqueue_tcp_socket, + tcp_acceptor::implementation, + endpoint>; friend kqueue_tcp_acceptor_service; + public: explicit kqueue_tcp_acceptor(kqueue_tcp_acceptor_service& svc) noexcept - : base_type(svc) {} + : base_type(svc) + { + } }; class kqueue_local_stream_acceptor final : public reactor_acceptor_impl< - kqueue_local_stream_acceptor, kqueue_traits, + kqueue_local_stream_acceptor, + kqueue_traits, kqueue_local_stream_acceptor_service, kqueue_local_stream_socket, - local_stream_acceptor::implementation, corosio::local_endpoint> + local_stream_acceptor::implementation, + corosio::local_endpoint> { using base_type = reactor_acceptor_impl< - kqueue_local_stream_acceptor, kqueue_traits, + kqueue_local_stream_acceptor, + kqueue_traits, kqueue_local_stream_acceptor_service, kqueue_local_stream_socket, - local_stream_acceptor::implementation, corosio::local_endpoint>; + local_stream_acceptor::implementation, + corosio::local_endpoint>; friend kqueue_local_stream_acceptor_service; + public: explicit kqueue_local_stream_acceptor( kqueue_local_stream_acceptor_service& svc) noexcept - : base_type(svc) {} + : base_type(svc) + { + } }; // --- Services --- class BOOST_COROSIO_DECL kqueue_tcp_service final : public reactor_tcp_service_impl< - kqueue_tcp_service, kqueue_traits, kqueue_tcp_socket> + kqueue_tcp_service, + kqueue_traits, + kqueue_tcp_socket> { using base_type = reactor_tcp_service_impl< - kqueue_tcp_service, kqueue_traits, kqueue_tcp_socket>; + kqueue_tcp_service, + kqueue_traits, + kqueue_tcp_socket>; + public: - explicit kqueue_tcp_service(capy::execution_context& ctx) - : base_type(ctx) {} + explicit kqueue_tcp_service(capy::execution_context& ctx) : base_type(ctx) + { + } }; class BOOST_COROSIO_DECL kqueue_local_stream_service final : public reactor_local_stream_service_impl< - kqueue_local_stream_service, kqueue_traits, + kqueue_local_stream_service, + kqueue_traits, kqueue_local_stream_socket> { using base_type = reactor_local_stream_service_impl< - kqueue_local_stream_service, kqueue_traits, + kqueue_local_stream_service, + kqueue_traits, kqueue_local_stream_socket>; + public: explicit kqueue_local_stream_service(capy::execution_context& ctx) - : base_type(ctx) {} + : base_type(ctx) + { + } }; class BOOST_COROSIO_DECL kqueue_udp_service final : public reactor_udp_service_impl< - kqueue_udp_service, kqueue_traits, kqueue_udp_socket> + kqueue_udp_service, + kqueue_traits, + kqueue_udp_socket> { using base_type = reactor_udp_service_impl< - kqueue_udp_service, kqueue_traits, kqueue_udp_socket>; + kqueue_udp_service, + kqueue_traits, + kqueue_udp_socket>; + public: - explicit kqueue_udp_service(capy::execution_context& ctx) - : base_type(ctx) {} + explicit kqueue_udp_service(capy::execution_context& ctx) : base_type(ctx) + { + } }; class BOOST_COROSIO_DECL kqueue_local_datagram_service final : public reactor_local_dgram_service_impl< - kqueue_local_datagram_service, kqueue_traits, + kqueue_local_datagram_service, + kqueue_traits, kqueue_local_datagram_socket> { using base_type = reactor_local_dgram_service_impl< - kqueue_local_datagram_service, kqueue_traits, + kqueue_local_datagram_service, + kqueue_traits, kqueue_local_datagram_socket>; + public: explicit kqueue_local_datagram_service(capy::execution_context& ctx) - : base_type(ctx) {} + : base_type(ctx) + { + } }; class BOOST_COROSIO_DECL kqueue_tcp_acceptor_service final : public reactor_acceptor_service_impl< - kqueue_tcp_acceptor_service, kqueue_traits, - tcp_acceptor_service, kqueue_tcp_acceptor, - kqueue_tcp_service, endpoint> + kqueue_tcp_acceptor_service, + kqueue_traits, + tcp_acceptor_service, + kqueue_tcp_acceptor, + kqueue_tcp_service, + endpoint> { using base_type = reactor_acceptor_service_impl< - kqueue_tcp_acceptor_service, kqueue_traits, - tcp_acceptor_service, kqueue_tcp_acceptor, - kqueue_tcp_service, endpoint>; + kqueue_tcp_acceptor_service, + kqueue_traits, + tcp_acceptor_service, + kqueue_tcp_acceptor, + kqueue_tcp_service, + endpoint>; + public: explicit kqueue_tcp_acceptor_service(capy::execution_context& ctx) - : base_type(ctx) {} + : base_type(ctx) + { + } }; class BOOST_COROSIO_DECL kqueue_local_stream_acceptor_service final : public reactor_acceptor_service_impl< - kqueue_local_stream_acceptor_service, kqueue_traits, + kqueue_local_stream_acceptor_service, + kqueue_traits, local_stream_acceptor_service, kqueue_local_stream_acceptor, - kqueue_local_stream_service, corosio::local_endpoint> + kqueue_local_stream_service, + corosio::local_endpoint> { using base_type = reactor_acceptor_service_impl< - kqueue_local_stream_acceptor_service, kqueue_traits, + kqueue_local_stream_acceptor_service, + kqueue_traits, local_stream_acceptor_service, kqueue_local_stream_acceptor, - kqueue_local_stream_service, corosio::local_endpoint>; + kqueue_local_stream_service, + corosio::local_endpoint>; + public: explicit kqueue_local_stream_acceptor_service(capy::execution_context& ctx) - : base_type(ctx) {} + : base_type(ctx) + { + } }; } // namespace boost::corosio::detail diff --git a/include/boost/corosio/native/detail/make_err.hpp b/include/boost/corosio/native/detail/make_err.hpp index 61028ca5a..d22ba1390 100644 --- a/include/boost/corosio/native/detail/make_err.hpp +++ b/include/boost/corosio/native/detail/make_err.hpp @@ -92,8 +92,7 @@ make_err(unsigned long dwError) noexcept if (dwError == WSAENOTSOCK) return std::make_error_code(std::errc::not_a_socket); if (dwError == WSAEAFNOSUPPORT) - return std::make_error_code( - std::errc::address_family_not_supported); + return std::make_error_code(std::errc::address_family_not_supported); if (dwError == WSAEPROTOTYPE) return std::make_error_code(std::errc::wrong_protocol_type); if (dwError == WSAEADDRINUSE) @@ -106,8 +105,7 @@ make_err(unsigned long dwError) noexcept // condition POSIX spells EAGAIN, which is what the contract // promises; no toolchain maps the Win32 spelling to it. if (dwError == ERROR_MAX_THRDS_REACHED) - return std::make_error_code( - std::errc::resource_unavailable_try_again); + return std::make_error_code(std::errc::resource_unavailable_try_again); return std::error_code(static_cast(dwError), std::system_category()); } diff --git a/include/boost/corosio/native/detail/msg_flags.hpp b/include/boost/corosio/native/detail/msg_flags.hpp index e0ec1b75d..632bce58c 100644 --- a/include/boost/corosio/native/detail/msg_flags.hpp +++ b/include/boost/corosio/native/detail/msg_flags.hpp @@ -31,9 +31,12 @@ inline int to_native_msg_flags(int flags) noexcept { int native = 0; - if (flags & 1) native |= MSG_PEEK; - if (flags & 2) native |= MSG_OOB; - if (flags & 4) native |= MSG_DONTROUTE; + if (flags & 1) + native |= MSG_PEEK; + if (flags & 2) + native |= MSG_OOB; + if (flags & 4) + native |= MSG_DONTROUTE; return native; } diff --git a/include/boost/corosio/native/detail/native_socket_base.hpp b/include/boost/corosio/native/detail/native_socket_base.hpp index 0744971fc..803077787 100644 --- a/include/boost/corosio/native/detail/native_socket_base.hpp +++ b/include/boost/corosio/native/detail/native_socket_base.hpp @@ -60,9 +60,10 @@ class native_socket_base // (reactor_stream_socket -> reactor_basic_socket) that are not `Derived`, // so a private ctor would stop those intermediates from constructing it. // Protected is the correct access; suppress the private-only suggestion. - native_socket_base() = default; // NOLINT(bugprone-crtp-constructor-accessibility) + // NOLINTNEXTLINE(bugprone-crtp-constructor-accessibility) + native_socket_base() = default; - int fd_ = -1; + int fd_ = -1; // mutable so a derived const local_endpoint() override can lazily fill // it via getsockname() on first read (io_uring's lazy_pending state). mutable Endpoint local_endpoint_; @@ -90,8 +91,10 @@ class native_socket_base /// Set a socket option. std::error_code set_option( - int level, int optname, void const* data, std::size_t size) - noexcept override + int level, + int optname, + void const* data, + std::size_t size) noexcept override { if (::setsockopt( fd_, level, optname, data, static_cast(size)) != 0) @@ -100,8 +103,8 @@ class native_socket_base } /// Get a socket option. - std::error_code get_option( - int level, int optname, void* data, std::size_t* size) + std::error_code + get_option(int level, int optname, void* data, std::size_t* size) const noexcept override { socklen_t len = static_cast(*size); @@ -139,10 +142,10 @@ class native_socket_base return make_err(errno); sockaddr_storage local_storage{}; - socklen_t local_len = sizeof(local_storage); + socklen_t local_len = sizeof(local_storage); if (::getsockname( - fd_, reinterpret_cast(&local_storage), &local_len) - == 0) + fd_, reinterpret_cast(&local_storage), &local_len) == + 0) local_endpoint_ = from_sockaddr_as(local_storage, local_len, Endpoint{}); diff --git a/include/boost/corosio/native/detail/posix/posix_random_access_file.hpp b/include/boost/corosio/native/detail/posix/posix_random_access_file.hpp index 5dc2a961d..9a6d001d0 100644 --- a/include/boost/corosio/native/detail/posix/posix_random_access_file.hpp +++ b/include/boost/corosio/native/detail/posix/posix_random_access_file.hpp @@ -88,10 +88,10 @@ class posix_random_access_file final , intrusive_list::node { iovec iovecs[max_buffers]; - int iovec_count = 0; + int iovec_count = 0; std::uint64_t offset = 0; - int errn = 0; + int errn = 0; std::size_t bytes_transferred = 0; // Raw back-pointer for the typed work; `impl_ptr` is the keepalive. @@ -147,8 +147,8 @@ class posix_random_access_file final native_handle_type release() override; std::error_code assign(native_handle_type handle) noexcept override; - std::error_code open_file( - std::filesystem::path const& path, file_base::flags mode); + std::error_code + open_file(std::filesystem::path const& path, file_base::flags mode); void close_file() noexcept; private: @@ -162,8 +162,7 @@ class posix_random_access_file final // Inline implementation // --------------------------------------------------------------------------- -inline -posix_random_access_file::posix_random_access_file( +inline posix_random_access_file::posix_random_access_file( posix_random_access_file_service& svc) noexcept : svc_(svc) { @@ -243,7 +242,7 @@ posix_random_access_file::sync_data() noexcept { #if BOOST_COROSIO_HAS_POSIX_SYNCHRONIZED_IO if (::fdatasync(fd_) < 0) -#else // BOOST_COROSIO_HAS_POSIX_SYNCHRONIZED_IO +#else // BOOST_COROSIO_HAS_POSIX_SYNCHRONIZED_IO if (::fsync(fd_) < 0) #endif // BOOST_COROSIO_HAS_POSIX_SYNCHRONIZED_IO return make_err(errno); @@ -262,7 +261,7 @@ inline native_handle_type posix_random_access_file::release() { int fd = fd_; - fd_ = -1; + fd_ = -1; return fd; } diff --git a/include/boost/corosio/native/detail/posix/posix_random_access_file_service.hpp b/include/boost/corosio/native/detail/posix/posix_random_access_file_service.hpp index ab285a4dc..d980dcf42 100644 --- a/include/boost/corosio/native/detail/posix/posix_random_access_file_service.hpp +++ b/include/boost/corosio/native/detail/posix/posix_random_access_file_service.hpp @@ -39,10 +39,10 @@ class BOOST_COROSIO_DECL posix_random_access_file_service final ~posix_random_access_file_service() override = default; - posix_random_access_file_service( - posix_random_access_file_service const&) = delete; - posix_random_access_file_service& operator=( - posix_random_access_file_service const&) = delete; + posix_random_access_file_service(posix_random_access_file_service const&) = + delete; + posix_random_access_file_service& + operator=(posix_random_access_file_service const&) = delete; io_object::implementation* construct() override { @@ -191,7 +191,7 @@ posix_random_access_file::read_some_at( return h; } - auto* op = new raf_op(); + auto* op = new raf_op(); op->is_read = true; op->offset = offset; @@ -262,7 +262,7 @@ posix_random_access_file::write_some_at( return h; } - auto* op = new raf_op(); + auto* op = new raf_op(); op->is_read = false; op->offset = offset; @@ -318,8 +318,9 @@ posix_random_access_file::raf_op::do_work(pool_work_item* w) noexcept op->errn = ECANCELED; op->bytes_transferred = 0; } - else if (op->offset > - static_cast(std::numeric_limits::max())) + else if ( + op->offset > + static_cast(std::numeric_limits::max())) { op->errn = EOVERFLOW; op->bytes_transferred = 0; @@ -331,8 +332,9 @@ posix_random_access_file::raf_op::do_work(pool_work_item* w) noexcept { do { - n = ::preadv(self->fd_, op->iovecs, op->iovec_count, - static_cast(op->offset)); + n = ::preadv( + self->fd_, op->iovecs, op->iovec_count, + static_cast(op->offset)); } while (n < 0 && errno == EINTR); } @@ -340,8 +342,9 @@ posix_random_access_file::raf_op::do_work(pool_work_item* w) noexcept { do { - n = ::pwritev(self->fd_, op->iovecs, op->iovec_count, - static_cast(op->offset)); + n = ::pwritev( + self->fd_, op->iovecs, op->iovec_count, + static_cast(op->offset)); } while (n < 0 && errno == EINTR); } diff --git a/include/boost/corosio/native/detail/posix/posix_resolver_service.hpp b/include/boost/corosio/native/detail/posix/posix_resolver_service.hpp index faf735c3e..71147be15 100644 --- a/include/boost/corosio/native/detail/posix/posix_resolver_service.hpp +++ b/include/boost/corosio/native/detail/posix/posix_resolver_service.hpp @@ -374,7 +374,7 @@ posix_resolver::resolve( { if (svc_.resolver_unavailable()) { - *ec = std::make_error_code(std::errc::operation_not_supported); + *ec = std::make_error_code(std::errc::operation_not_supported); op_.cont.h = h; return dispatch_coro(ex, op_.cont); } diff --git a/include/boost/corosio/native/detail/posix/posix_signal_service.hpp b/include/boost/corosio/native/detail/posix/posix_signal_service.hpp index bd65c778d..1b2365374 100644 --- a/include/boost/corosio/native/detail/posix/posix_signal_service.hpp +++ b/include/boost/corosio/native/detail/posix/posix_signal_service.hpp @@ -363,8 +363,8 @@ open_signal_pipe(signal_state* state) inline void corosio_posix_signal_handler(int signal_number) { - int saved_errno = errno; - signal_state* state = get_signal_state(); + int saved_errno = errno; + signal_state* state = get_signal_state(); [[maybe_unused]] ssize_t r = ::write(state->write_fd, &signal_number, sizeof(int)); errno = saved_errno; diff --git a/include/boost/corosio/native/detail/posix/posix_stream_file.hpp b/include/boost/corosio/native/detail/posix/posix_stream_file.hpp index f827582e8..831fdc98c 100644 --- a/include/boost/corosio/native/detail/posix/posix_stream_file.hpp +++ b/include/boost/corosio/native/detail/posix/posix_stream_file.hpp @@ -103,7 +103,7 @@ class posix_stream_file final int iovec_count = 0; // Result storage (populated by worker thread) - int errn = 0; + int errn = 0; std::size_t bytes_transferred = 0; file_op() = default; @@ -177,15 +177,15 @@ class posix_stream_file final // -- Internal -- /** Open the file and store the fd. */ - std::error_code open_file( - std::filesystem::path const& path, file_base::flags mode); + std::error_code + open_file(std::filesystem::path const& path, file_base::flags mode); /** Close the file descriptor. */ void close_file() noexcept; private: posix_stream_file_service& svc_; - int fd_ = -1; + int fd_ = -1; std::uint64_t offset_ = 0; file_op read_op_; @@ -201,8 +201,8 @@ class posix_stream_file final // Inline implementation // --------------------------------------------------------------------------- -inline -posix_stream_file::posix_stream_file(posix_stream_file_service& svc) noexcept +inline posix_stream_file::posix_stream_file( + posix_stream_file_service& svc) noexcept : svc_(svc) { } @@ -300,7 +300,7 @@ posix_stream_file::sync_data() noexcept { #if BOOST_COROSIO_HAS_POSIX_SYNCHRONIZED_IO if (::fdatasync(fd_) < 0) -#else // BOOST_COROSIO_HAS_POSIX_SYNCHRONIZED_IO +#else // BOOST_COROSIO_HAS_POSIX_SYNCHRONIZED_IO if (::fsync(fd_) < 0) #endif // BOOST_COROSIO_HAS_POSIX_SYNCHRONIZED_IO return make_err(errno); @@ -318,8 +318,8 @@ posix_stream_file::sync_all() noexcept inline native_handle_type posix_stream_file::release() { - int fd = fd_; - fd_ = -1; + int fd = fd_; + fd_ = -1; offset_ = 0; return fd; } @@ -328,7 +328,7 @@ inline std::error_code posix_stream_file::assign(native_handle_type handle) noexcept { close_file(); - fd_ = handle; + fd_ = handle; offset_ = 0; return {}; } diff --git a/include/boost/corosio/native/detail/posix/posix_stream_file_service.hpp b/include/boost/corosio/native/detail/posix/posix_stream_file_service.hpp index 44045f9ae..2f0358463 100644 --- a/include/boost/corosio/native/detail/posix/posix_stream_file_service.hpp +++ b/include/boost/corosio/native/detail/posix/posix_stream_file_service.hpp @@ -29,12 +29,10 @@ namespace boost::corosio::detail { Owns all posix_stream_file instances. Thread lifecycle is managed by the thread_pool service (shared with resolver). */ -class BOOST_COROSIO_DECL posix_stream_file_service final - : public file_service +class BOOST_COROSIO_DECL posix_stream_file_service final : public file_service { public: - posix_stream_file_service( - capy::execution_context& ctx, scheduler& sched) + posix_stream_file_service(capy::execution_context& ctx, scheduler& sched) : sched_(&sched) , pool_(ctx) { @@ -42,8 +40,9 @@ class BOOST_COROSIO_DECL posix_stream_file_service final ~posix_stream_file_service() override = default; - posix_stream_file_service(posix_stream_file_service const&) = delete; - posix_stream_file_service& operator=(posix_stream_file_service const&) = delete; + posix_stream_file_service(posix_stream_file_service const&) = delete; + posix_stream_file_service& + operator=(posix_stream_file_service const&) = delete; io_object::implementation* construct() override { @@ -179,7 +178,7 @@ posix_stream_file::read_some( { *ec = make_error_code(std::errc::bad_file_descriptor); *bytes_out = 0; - op.cont.h = h; + op.cont.h = h; return dispatch_coro(ex, op.cont); } @@ -190,7 +189,7 @@ posix_stream_file::read_some( { *ec = {}; *bytes_out = 0; - op.cont.h = h; + op.cont.h = h; return dispatch_coro(ex, op.cont); } @@ -240,8 +239,9 @@ posix_stream_file::do_read_work(pool_work_item* w) noexcept ssize_t n; do { - n = ::preadv(self->fd_, op.iovecs, op.iovec_count, - static_cast(self->offset_)); + n = ::preadv( + self->fd_, op.iovecs, op.iovec_count, + static_cast(self->offset_)); } while (n < 0 && errno == EINTR); @@ -280,7 +280,7 @@ posix_stream_file::write_some( { *ec = make_error_code(std::errc::bad_file_descriptor); *bytes_out = 0; - op.cont.h = h; + op.cont.h = h; return dispatch_coro(ex, op.cont); } @@ -291,7 +291,7 @@ posix_stream_file::write_some( { *ec = {}; *bytes_out = 0; - op.cont.h = h; + op.cont.h = h; return dispatch_coro(ex, op.cont); } @@ -341,8 +341,9 @@ posix_stream_file::do_write_work(pool_work_item* w) noexcept ssize_t n; do { - n = ::pwritev(self->fd_, op.iovecs, op.iovec_count, - static_cast(self->offset_)); + n = ::pwritev( + self->fd_, op.iovecs, op.iovec_count, + static_cast(self->offset_)); } while (n < 0 && errno == EINTR); diff --git a/include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp b/include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp index 096fc8bee..5e1623ab6 100644 --- a/include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp +++ b/include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp @@ -148,7 +148,7 @@ class reactor_acceptor /// Assign the fd and initialize descriptor state for the acceptor. void init_acceptor_fd(int fd) noexcept { - fd_ = fd; + fd_ = fd; desc_state_.fd = fd; { std::lock_guard lock(desc_state_.mutex); @@ -191,10 +191,16 @@ class reactor_acceptor return svc_; } - void cancel() noexcept override { do_cancel(); } + void cancel() noexcept override + { + do_cancel(); + } /// Close the acceptor (non-virtual, called by the service). - void close_socket() noexcept { do_close_socket(); } + void close_socket() noexcept + { + do_close_socket(); + } std::coroutine_handle<> wait( std::coroutine_handle<> h, @@ -279,8 +285,15 @@ template< class ImplBase, class Endpoint> void -reactor_acceptor:: - cancel_single_op(Op& op) noexcept +reactor_acceptor< + Derived, + Service, + Op, + AcceptOp, + WaitOp, + DescState, + ImplBase, + Endpoint>::cancel_single_op(Op& op) noexcept { auto self = this->weak_from_this().lock(); if (!self) @@ -318,8 +331,15 @@ template< class ImplBase, class Endpoint> void -reactor_acceptor:: - do_cancel() noexcept +reactor_acceptor< + Derived, + Service, + Op, + AcceptOp, + WaitOp, + DescState, + ImplBase, + Endpoint>::do_cancel() noexcept { cancel_single_op(acc_); cancel_single_op(wait_rd_); @@ -337,8 +357,15 @@ template< class ImplBase, class Endpoint> void -reactor_acceptor:: - do_close_socket() noexcept +reactor_acceptor< + Derived, + Service, + Op, + AcceptOp, + WaitOp, + DescState, + ImplBase, + Endpoint>::do_close_socket() noexcept { auto self = this->weak_from_this().lock(); if (self) @@ -403,8 +430,15 @@ template< class ImplBase, class Endpoint> native_handle_type -reactor_acceptor:: - do_release_socket() noexcept +reactor_acceptor< + Derived, + Service, + Op, + AcceptOp, + WaitOp, + DescState, + ImplBase, + Endpoint>::do_release_socket() noexcept { auto self = this->weak_from_this().lock(); if (self) @@ -472,8 +506,15 @@ template< class ImplBase, class Endpoint> std::error_code -reactor_acceptor:: - do_bind(Endpoint const& ep) +reactor_acceptor< + Derived, + Service, + Op, + AcceptOp, + WaitOp, + DescState, + ImplBase, + Endpoint>::do_bind(Endpoint const& ep) { sockaddr_storage storage{}; socklen_t addrlen = to_sockaddr(ep, storage); @@ -500,8 +541,15 @@ template< class ImplBase, class Endpoint> std::error_code -reactor_acceptor:: - do_listen(int backlog) +reactor_acceptor< + Derived, + Service, + Op, + AcceptOp, + WaitOp, + DescState, + ImplBase, + Endpoint>::do_listen(int backlog) { if (::listen(fd_, backlog) < 0) return make_err(errno); @@ -524,7 +572,15 @@ template< class ImplBase, class Endpoint> std::coroutine_handle<> -reactor_acceptor:: +reactor_acceptor< + Derived, + Service, + Op, + AcceptOp, + WaitOp, + DescState, + ImplBase, + Endpoint>:: do_wait( std::coroutine_handle<> h, capy::executor_ref ex, @@ -545,7 +601,7 @@ reactor_acceptorfd_; op.start(token, static_cast(this)); - op.impl_ptr = this->shared_from_this(); + op.impl_ptr = this->shared_from_this(); op.complete(ENOTSUP, 0); svc_.post(&op); return std::noop_coroutine(); @@ -568,7 +624,7 @@ reactor_acceptorfd_; op.start(token, static_cast(this)); - op.impl_ptr = this->shared_from_this(); + op.impl_ptr = this->shared_from_this(); // A listener's readiness can predate the wait: an adopted or // shared descriptor has history the reactor never saw, and an diff --git a/include/boost/corosio/native/detail/reactor/reactor_acceptor_service.hpp b/include/boost/corosio/native/detail/reactor/reactor_acceptor_service.hpp index daf8a5ae2..5063161e0 100644 --- a/include/boost/corosio/native/detail/reactor/reactor_acceptor_service.hpp +++ b/include/boost/corosio/native/detail/reactor/reactor_acceptor_service.hpp @@ -125,8 +125,9 @@ class reactor_acceptor_service : public ServiceBase StreamService* stream_svc_ = nullptr; private: - reactor_acceptor_service(reactor_acceptor_service const&) = delete; - reactor_acceptor_service& operator=(reactor_acceptor_service const&) = delete; + reactor_acceptor_service(reactor_acceptor_service const&) = delete; + reactor_acceptor_service& + operator=(reactor_acceptor_service const&) = delete; }; } // namespace boost::corosio::detail diff --git a/include/boost/corosio/native/detail/reactor/reactor_backend.hpp b/include/boost/corosio/native/detail/reactor/reactor_backend.hpp index 16588e811..bf7b6ed9c 100644 --- a/include/boost/corosio/native/detail/reactor/reactor_backend.hpp +++ b/include/boost/corosio/native/detail/reactor/reactor_backend.hpp @@ -31,15 +31,27 @@ namespace boost::corosio::detail { // Acceptor accept() implementation // ============================================================ -template +template< + class Derived, + class Traits, + class Service, + class SocketFinal, + class AccImplBase, + class Endpoint> std::coroutine_handle<> -reactor_acceptor_impl::accept( - std::coroutine_handle<> h, - capy::executor_ref ex, - std::stop_token token, - std::error_code* ec, - io_object::implementation** impl_out) +reactor_acceptor_impl< + Derived, + Traits, + Service, + SocketFinal, + AccImplBase, + Endpoint>:: + accept( + std::coroutine_handle<> h, + capy::executor_ref ex, + std::stop_token token, + std::error_code* ec, + io_object::implementation** impl_out) { auto& op = this->acc_; op.reset(); @@ -53,8 +65,8 @@ reactor_acceptor_implfd_, peer_storage, peer_addrlen); + int accepted = + Traits::accept_policy::do_accept(this->fd_, peer_storage, peer_addrlen); if (accepted >= 0) { diff --git a/include/boost/corosio/native/detail/reactor/reactor_basic_socket.hpp b/include/boost/corosio/native/detail/reactor/reactor_basic_socket.hpp index 7acc671f1..b3165cb00 100644 --- a/include/boost/corosio/native/detail/reactor/reactor_basic_socket.hpp +++ b/include/boost/corosio/native/detail/reactor/reactor_basic_socket.hpp @@ -60,7 +60,18 @@ class reactor_basic_socket template friend class reactor_stream_socket; - template + template< + class, + class, + class, + class, + class, + class, + class, + class, + class, + class, + class> friend class reactor_datagram_socket; explicit reactor_basic_socket(Service& svc) noexcept : svc_(svc) {} @@ -95,7 +106,7 @@ class reactor_basic_socket */ std::error_code init_and_register(int fd) noexcept { - fd_ = fd; + fd_ = fd; desc_state_.fd = fd; { std::lock_guard lock(desc_state_.mutex); @@ -107,8 +118,8 @@ class reactor_basic_socket { // Undo the partial state so a failed adopt is // indistinguishable from a closed implementation. - fd_ = -1; - desc_state_.fd = -1; + fd_ = -1; + desc_state_.fd = -1; desc_state_.registered_events = 0; return ec; } @@ -165,14 +176,20 @@ class reactor_basic_socket native_handle_type do_release_socket() noexcept; }; -template +template< + class Derived, + class ImplBase, + class Service, + class DescState, + class Endpoint> template void -reactor_basic_socket::register_op( - Op& op, - reactor_op_base*& desc_slot, - bool& ready_flag, - bool is_write_direction) noexcept +reactor_basic_socket:: + register_op( + Op& op, + reactor_op_base*& desc_slot, + bool& ready_flag, + bool is_write_direction) noexcept { svc_.work_started(); @@ -187,7 +204,6 @@ reactor_basic_socket::register_ op.errn = 0; } - if (io_done || op.cancelled.load(std::memory_order_acquire)) { svc_.post(&op); @@ -211,11 +227,16 @@ reactor_basic_socket::register_ } } -template +template< + class Derived, + class ImplBase, + class Service, + class DescState, + class Endpoint> template void -reactor_basic_socket::cancel_single_op( - Op& op) noexcept +reactor_basic_socket:: + cancel_single_op(Op& op) noexcept { auto self = this->weak_from_this().lock(); if (!self) @@ -248,7 +269,12 @@ reactor_basic_socket::cancel_si } } -template +template< + class Derived, + class ImplBase, + class Service, + class DescState, + class Endpoint> void reactor_basic_socket:: do_cancel() noexcept @@ -291,7 +317,12 @@ reactor_basic_socket:: } } -template +template< + class Derived, + class ImplBase, + class Service, + class DescState, + class Endpoint> void reactor_basic_socket:: do_close_socket() noexcept @@ -321,8 +352,8 @@ reactor_basic_socket:: ++count; } }); - desc_state_.read_ready = false; - desc_state_.write_ready = false; + desc_state_.read_ready = false; + desc_state_.write_ready = false; if (desc_state_.is_enqueued_.load(std::memory_order_acquire)) desc_state_.impl_ref_ = self; @@ -350,7 +381,12 @@ reactor_basic_socket:: local_endpoint_ = Endpoint{}; } -template +template< + class Derived, + class ImplBase, + class Service, + class DescState, + class Endpoint> native_handle_type reactor_basic_socket:: do_release_socket() noexcept @@ -381,8 +417,8 @@ reactor_basic_socket:: ++count; } }); - desc_state_.read_ready = false; - desc_state_.write_ready = false; + desc_state_.read_ready = false; + desc_state_.write_ready = false; if (desc_state_.is_enqueued_.load(std::memory_order_acquire)) desc_state_.impl_ref_ = self; diff --git a/include/boost/corosio/native/detail/reactor/reactor_datagram_ops.hpp b/include/boost/corosio/native/detail/reactor/reactor_datagram_ops.hpp index a6ef1b288..25bd017aa 100644 --- a/include/boost/corosio/native/detail/reactor/reactor_datagram_ops.hpp +++ b/include/boost/corosio/native/detail/reactor/reactor_datagram_ops.hpp @@ -24,8 +24,7 @@ namespace boost::corosio::detail { */ template -struct reactor_dgram_base_op - : reactor_op +struct reactor_dgram_base_op : reactor_op { void operator()() override; void cancel() noexcept override; @@ -44,8 +43,7 @@ template struct reactor_dgram_send_to_op final : reactor_send_to_op< reactor_dgram_base_op> -{ -}; +{}; template struct reactor_dgram_recv_from_op final @@ -58,23 +56,19 @@ struct reactor_dgram_recv_from_op final template struct reactor_dgram_send_op final - : reactor_send_op< - reactor_dgram_base_op> -{ -}; + : reactor_send_op> +{}; template struct reactor_dgram_recv_op final - : reactor_recv_op< - reactor_dgram_base_op> + : reactor_recv_op> { void operator()() override; }; template struct reactor_dgram_wait_op final - : reactor_wait_op< - reactor_dgram_base_op> + : reactor_wait_op> { void operator()() override; }; diff --git a/include/boost/corosio/native/detail/reactor/reactor_datagram_socket.hpp b/include/boost/corosio/native/detail/reactor/reactor_datagram_socket.hpp index 6a29f18e6..b88afa9e9 100644 --- a/include/boost/corosio/native/detail/reactor/reactor_datagram_socket.hpp +++ b/include/boost/corosio/native/detail/reactor/reactor_datagram_socket.hpp @@ -68,15 +68,20 @@ class reactor_datagram_socket DescState, Endpoint> { - using base_type = reactor_basic_socket< + using base_type = + reactor_basic_socket; + using self_type = reactor_datagram_socket< Derived, - ImplBase, Service, + ConnOp, + SendToOp, + RecvFromOp, + SendOp, + RecvOp, + WaitOp, DescState, + ImplBase, Endpoint>; - using self_type = reactor_datagram_socket< - Derived, Service, ConnOp, SendToOp, RecvFromOp, SendOp, RecvOp, WaitOp, - DescState, ImplBase, Endpoint>; friend base_type; friend Derived; @@ -315,7 +320,7 @@ class reactor_datagram_socket native_handle_type do_release_socket() noexcept { - auto fd = base_type::do_release_socket(); + auto fd = base_type::do_release_socket(); remote_endpoint_ = Endpoint{}; return fd; } @@ -373,7 +378,6 @@ class reactor_datagram_socket return nullptr; } - template void for_each_op(Fn fn) noexcept { @@ -485,7 +489,7 @@ reactor_datagram_socket< { *ec = err ? make_err(err) : std::error_code{}; *bytes_out = bytes; - op.cont.h = h; + op.cont.h = h; return dispatch_coro(ex, op.cont); } op.h = h; @@ -606,9 +610,7 @@ reactor_datagram_socket< *bytes_out = bytes; if (source && !err && n >= 0) *source = from_sockaddr_as( - op.source_storage, - op.source_addrlen, - Endpoint{}); + op.source_storage, op.source_addrlen, Endpoint{}); op.cont.h = h; return dispatch_coro(ex, op.cont); } @@ -695,7 +697,7 @@ reactor_datagram_socket< int err = (result < 0) ? errno : 0; if (this->svc_.scheduler().try_consume_inline_budget()) { - *ec = err ? make_err(err) : std::error_code{}; + *ec = err ? make_err(err) : std::error_code{}; op.cont.h = h; return dispatch_coro(ex, op.cont); } @@ -790,7 +792,7 @@ reactor_datagram_socket< { *ec = err ? make_err(err) : std::error_code{}; *bytes_out = bytes; - op.cont.h = h; + op.cont.h = h; return dispatch_coro(ex, op.cont); } op.h = h; @@ -902,7 +904,7 @@ reactor_datagram_socket< { *ec = err ? make_err(err) : std::error_code{}; *bytes_out = bytes; - op.cont.h = h; + op.cont.h = h; return dispatch_coro(ex, op.cont); } op.h = h; @@ -969,21 +971,21 @@ reactor_datagram_socket< if (w == wait_type::read) { - op_ptr = &wait_rd_; - desc_slot_ptr = &this->desc_state_.wait_read_op; - event = reactor_event_read; + op_ptr = &wait_rd_; + desc_slot_ptr = &this->desc_state_.wait_read_op; + event = reactor_event_read; } else if (w == wait_type::write) { - op_ptr = &wait_wr_; - desc_slot_ptr = &this->desc_state_.wait_write_op; - event = reactor_event_write; + op_ptr = &wait_wr_; + desc_slot_ptr = &this->desc_state_.wait_write_op; + event = reactor_event_write; } else // wait_type::error { - op_ptr = &wait_er_; - desc_slot_ptr = &this->desc_state_.wait_error_op; - event = reactor_event_error; + op_ptr = &wait_er_; + desc_slot_ptr = &this->desc_state_.wait_error_op; + event = reactor_event_error; } auto& op = *op_ptr; @@ -1008,7 +1010,7 @@ reactor_datagram_socket< op.ec_out = ec; op.fd = this->fd_; op.start(token, static_cast(this)); - op.impl_ptr = this->shared_from_this(); + op.impl_ptr = this->shared_from_this(); op.complete(perr, 0); this->svc_.post(&op); return std::noop_coroutine(); @@ -1021,7 +1023,7 @@ reactor_datagram_socket< op.ec_out = ec; op.fd = this->fd_; op.start(token, static_cast(this)); - op.impl_ptr = this->shared_from_this(); + op.impl_ptr = this->shared_from_this(); // Force register_op's ready path so the wait op re-probes under // the descriptor mutex before parking. An edge consumed between @@ -1030,8 +1032,7 @@ reactor_datagram_socket< // otherwise leave the wait parked on a ready socket. bool force_probe = true; this->register_op( - op, *desc_slot_ptr, force_probe, - event == reactor_event_write); + op, *desc_slot_ptr, force_probe, event == reactor_event_write); return std::noop_coroutine(); } diff --git a/include/boost/corosio/native/detail/reactor/reactor_op.hpp b/include/boost/corosio/native/detail/reactor/reactor_op.hpp index 3ef5f975f..986e590f0 100644 --- a/include/boost/corosio/native/detail/reactor/reactor_op.hpp +++ b/include/boost/corosio/native/detail/reactor/reactor_op.hpp @@ -164,9 +164,7 @@ struct reactor_connect_op : Base { // EAGAIN must not escape: it is the stay-parked sentinel. this->complete( - (errno == EAGAIN || errno == EWOULDBLOCK) ? ENOMEM - : errno, - 0); + (errno == EAGAIN || errno == EWOULDBLOCK) ? ENOMEM : errno, 0); return; } @@ -254,9 +252,7 @@ struct reactor_wait_op : Base // EAGAIN must not escape here: callers treat it as the // stay-parked sentinel, and poll() can fail with it on // BSD/macOS under transient resource pressure. - err = (errno == EAGAIN || errno == EWOULDBLOCK) - ? ENOMEM - : errno; + err = (errno == EAGAIN || errno == EWOULDBLOCK) ? ENOMEM : errno; return true; } return r != 0; @@ -390,17 +386,17 @@ struct reactor_accept_op : Base void reset() noexcept { Base::reset(); - accepted_fd = -1; - peer_impl = nullptr; - impl_out = nullptr; - peer_storage = {}; - peer_addrlen = 0; + accepted_fd = -1; + peer_impl = nullptr; + impl_out = nullptr; + peer_storage = {}; + peer_addrlen = 0; } void perform_io() noexcept override { - int new_fd = AcceptPolicy::do_accept( - this->fd, peer_storage, peer_addrlen); + int new_fd = + AcceptPolicy::do_accept(this->fd, peer_storage, peer_addrlen); if (new_fd >= 0) { accepted_fd = new_fd; diff --git a/include/boost/corosio/native/detail/reactor/reactor_op_complete.hpp b/include/boost/corosio/native/detail/reactor/reactor_op_complete.hpp index 1728cafed..fc88788f3 100644 --- a/include/boost/corosio/native/detail/reactor/reactor_op_complete.hpp +++ b/include/boost/corosio/native/detail/reactor/reactor_op_complete.hpp @@ -51,8 +51,7 @@ complete_io_op(Op& op) // here and the shared EOF test reduces to the reactor's original // `is_read && bytes == 0`. decode_io_result( - op.ec_out, - op.cancelled.load(std::memory_order_acquire), + op.ec_out, op.cancelled.load(std::memory_order_acquire), op.errn != 0 ? make_err(op.errn) : std::error_code{}, op.is_read_operation(), op.bytes_transferred, /*empty_buffer=*/false); @@ -90,8 +89,7 @@ complete_wait_op(Op& op) // Wait reports only success/cancel/error — no bytes, no EOF. decode_io_result( - op.ec_out, - op.cancelled.load(std::memory_order_acquire), + op.ec_out, op.cancelled.load(std::memory_order_acquire), op.errn != 0 ? make_err(op.errn) : std::error_code{}, /*is_read=*/false, /*bytes=*/0, /*empty_buffer=*/false); @@ -126,14 +124,12 @@ complete_connect_op(Op& op) if (::getsockname( op.fd, reinterpret_cast(&local_storage), &local_len) == 0) - local_ep = - from_sockaddr_as(local_storage, local_len, ep_type{}); + local_ep = from_sockaddr_as(local_storage, local_len, ep_type{}); op.socket_impl_->set_endpoints(local_ep, op.target_endpoint); } decode_io_result( - op.ec_out, - op.cancelled.load(std::memory_order_acquire), + op.ec_out, op.cancelled.load(std::memory_order_acquire), op.errn != 0 ? make_err(op.errn) : std::error_code{}, /*is_read=*/false, /*bytes=*/0, /*empty_buffer=*/false); @@ -197,10 +193,7 @@ setup_accepted_socket( using ep_type = decltype(acceptor_impl->local_endpoint()); impl.set_endpoints( acceptor_impl->local_endpoint(), - from_sockaddr_as( - peer_storage, - peer_addrlen, - ep_type{})); + from_sockaddr_as(peer_storage, peer_addrlen, ep_type{})); if (impl_out) *impl_out = &impl; @@ -229,8 +222,7 @@ complete_accept_op(Op& op) (op.errn == 0 && !op.cancelled.load(std::memory_order_acquire)); decode_io_result( - op.ec_out, - op.cancelled.load(std::memory_order_acquire), + op.ec_out, op.cancelled.load(std::memory_order_acquire), op.errn != 0 ? make_err(op.errn) : std::error_code{}, /*is_read=*/false, /*bytes=*/0, /*empty_buffer=*/false); @@ -274,8 +266,7 @@ complete_datagram_op(Op& op) // No EOF: a zero-length datagram is valid (success with 0 bytes). decode_io_result( - op.ec_out, - op.cancelled.load(std::memory_order_acquire), + op.ec_out, op.cancelled.load(std::memory_order_acquire), op.errn != 0 ? make_err(op.errn) : std::error_code{}, /*is_read=*/false, /*bytes=*/0, /*empty_buffer=*/false); @@ -304,8 +295,7 @@ complete_datagram_op(Op& op, Endpoint* source_out) // No EOF: a zero-length datagram is valid (success with 0 bytes). decode_io_result( - op.ec_out, - op.cancelled.load(std::memory_order_acquire), + op.ec_out, op.cancelled.load(std::memory_order_acquire), op.errn != 0 ? make_err(op.errn) : std::error_code{}, /*is_read=*/false, /*bytes=*/0, /*empty_buffer=*/false); @@ -313,10 +303,8 @@ complete_datagram_op(Op& op, Endpoint* source_out) if (source_out && !op.cancelled.load(std::memory_order_acquire) && op.errn == 0) - *source_out = from_sockaddr_as( - op.source_storage, - op.source_addrlen, - Endpoint{}); + *source_out = + from_sockaddr_as(op.source_storage, op.source_addrlen, Endpoint{}); coro_resume(&op); } diff --git a/include/boost/corosio/native/detail/reactor/reactor_scheduler.hpp b/include/boost/corosio/native/detail/reactor/reactor_scheduler.hpp index 0413bb658..8a8db0b9f 100644 --- a/include/boost/corosio/native/detail/reactor/reactor_scheduler.hpp +++ b/include/boost/corosio/native/detail/reactor/reactor_scheduler.hpp @@ -67,8 +67,7 @@ struct BOOST_COROSIO_SYMBOL_VISIBLE reactor_scheduler_context /// Construct a context frame linked to @a n. reactor_scheduler_context( - reactor_scheduler const* k, - reactor_scheduler_context* n); + reactor_scheduler const* k, reactor_scheduler_context* n); }; /// Thread-local context stack for reactor schedulers. @@ -86,7 +85,6 @@ reactor_find_context(reactor_scheduler const* self) noexcept return nullptr; } - /** Non-template base for reactor-backed scheduler implementations. Provides the complete threading model shared by epoll, kqueue, @@ -114,9 +112,9 @@ class reactor_scheduler public: using key_type = scheduler; using context_type = reactor_scheduler_context; - using mutex_type = conditionally_enabled_mutex; - using lock_type = mutex_type::scoped_lock; - using event_type = conditionally_enabled_event; + using mutex_type = conditionally_enabled_mutex; + using lock_type = mutex_type::scoped_lock; + using event_type = conditionally_enabled_event; /// Post a coroutine for deferred execution. void post(std::coroutine_handle<> h) const override; @@ -181,7 +179,6 @@ class reactor_scheduler */ void compensating_work_started() const noexcept; - /** Post completed operations for deferred invocation. If called from a thread running this scheduler, operations @@ -236,10 +233,10 @@ class reactor_scheduler } protected: - timer_service* timer_svc_ = nullptr; + timer_service* timer_svc_ = nullptr; bool scheduler_locking_disabled_ = false; - bool reactor_io_locking_ = true; - bool one_thread_ = false; + bool reactor_io_locking_ = true; + bool one_thread_ = false; reactor_scheduler() = default; @@ -303,8 +300,7 @@ class reactor_scheduler errors it retries rather than reports. */ virtual void - run_task(lock_type& lock, context_type& ctx, - long timeout_us) = 0; + run_task(lock_type& lock, context_type& ctx, long timeout_us) = 0; /// Wake a blocked reactor (e.g. write to eventfd or pipe). virtual void interrupt_reactor() const = 0; @@ -318,16 +314,14 @@ class reactor_scheduler ~work_cleanup(); }; - std::size_t do_one( - lock_type& lock, long timeout_us, context_type& ctx); + std::size_t do_one(lock_type& lock, long timeout_us, context_type& ctx); void signal_all(lock_type& lock) const; bool maybe_unlock_and_signal_one(lock_type& lock) const; bool unlock_and_signal_one(lock_type& lock) const; void clear_signal() const; void wait_for_signal(lock_type& lock) const; - void wait_for_signal_for( - lock_type& lock, long timeout_us) const; + void wait_for_signal_for(lock_type& lock, long timeout_us) const; void wake_one_thread_and_unlock(lock_type& lock) const; }; @@ -364,16 +358,13 @@ struct reactor_thread_context_guard // ---- Inline implementations ------------------------------------------------ -inline -reactor_scheduler_context::reactor_scheduler_context( - reactor_scheduler const* k, - reactor_scheduler_context* n) +inline reactor_scheduler_context::reactor_scheduler_context( + reactor_scheduler const* k, reactor_scheduler_context* n) : key(k) , next(n) , private_outstanding_work(0) , inline_budget(0) - , inline_budget_max( - static_cast(k->inline_budget_initial())) + , inline_budget_max(static_cast(k->inline_budget_initial())) , unassisted(false) { } @@ -387,11 +378,9 @@ reactor_scheduler::configure_reactor( { if (max_events < 1 || max_events > static_cast(std::numeric_limits::max())) - throw std::out_of_range( - "max_events_per_poll must be in [1, INT_MAX]"); + throw std::out_of_range("max_events_per_poll must be in [1, INT_MAX]"); if (budget_max > static_cast(std::numeric_limits::max())) - throw std::out_of_range( - "inline_budget_max must be in [0, INT_MAX]"); + throw std::out_of_range("inline_budget_max must be in [0, INT_MAX]"); // Clamp initial and unassisted to budget_max. if (budget_init > budget_max) @@ -417,21 +406,18 @@ reactor_scheduler::reset_inline_budget() const noexcept // Cap when no other thread absorbed queued work if (ctx->unassisted) { - ctx->inline_budget_max = - static_cast(unassisted_budget_); - ctx->inline_budget = - static_cast(unassisted_budget_); + ctx->inline_budget_max = static_cast(unassisted_budget_); + ctx->inline_budget = static_cast(unassisted_budget_); return; } // Ramp up when previous cycle fully consumed budget. // max(1, ...) ensures the doubling escapes zero. if (ctx->inline_budget == 0) - ctx->inline_budget_max = (std::min)( - (std::max)(1, ctx->inline_budget_max) * 2, - static_cast(inline_budget_max_)); - else if (ctx->inline_budget < ctx->inline_budget_max) ctx->inline_budget_max = - static_cast(inline_budget_initial_); + (std::min)((std::max)(1, ctx->inline_budget_max) * 2, + static_cast(inline_budget_max_)); + else if (ctx->inline_budget < ctx->inline_budget_max) + ctx->inline_budget_max = static_cast(inline_budget_initial_); ctx->inline_budget = ctx->inline_budget_max; } } @@ -670,7 +656,6 @@ reactor_scheduler::compensating_work_started() const noexcept ++ctx->private_outstanding_work; } - inline void reactor_scheduler::post_deferred_completions(ready_queue& ops) const { @@ -724,8 +709,7 @@ reactor_scheduler::signal_all(lock_type&) const } inline bool -reactor_scheduler::maybe_unlock_and_signal_one( - lock_type& lock) const +reactor_scheduler::maybe_unlock_and_signal_one(lock_type& lock) const { state_ |= signaled_bit; if (state_ > signaled_bit) @@ -738,8 +722,7 @@ reactor_scheduler::maybe_unlock_and_signal_one( } inline bool -reactor_scheduler::unlock_and_signal_one( - lock_type& lock) const +reactor_scheduler::unlock_and_signal_one(lock_type& lock) const { state_ |= signaled_bit; bool have_waiters = state_ > signaled_bit; @@ -756,8 +739,7 @@ reactor_scheduler::clear_signal() const } inline void -reactor_scheduler::wait_for_signal( - lock_type& lock) const +reactor_scheduler::wait_for_signal(lock_type& lock) const { while ((state_ & signaled_bit) == 0) { @@ -768,8 +750,7 @@ reactor_scheduler::wait_for_signal( } inline void -reactor_scheduler::wait_for_signal_for( - lock_type& lock, long timeout_us) const +reactor_scheduler::wait_for_signal_for(lock_type& lock, long timeout_us) const { if ((state_ & signaled_bit) == 0) { @@ -780,8 +761,7 @@ reactor_scheduler::wait_for_signal_for( } inline void -reactor_scheduler::wake_one_thread_and_unlock( - lock_type& lock) const +reactor_scheduler::wake_one_thread_and_unlock(lock_type& lock) const { if (maybe_unlock_and_signal_one(lock)) return; @@ -833,8 +813,7 @@ inline reactor_scheduler::task_cleanup::~task_cleanup() } inline std::size_t -reactor_scheduler::do_one( - lock_type& lock, long timeout_us, context_type& ctx) +reactor_scheduler::do_one(lock_type& lock, long timeout_us, context_type& ctx) { for (;;) { @@ -858,7 +837,7 @@ reactor_scheduler::do_one( } long task_timeout_us = more_handlers ? 0 : timeout_us; - task_interrupted_ = task_timeout_us == 0; + task_interrupted_ = task_timeout_us == 0; task_running_.store(true, std::memory_order_release); // Wake a peer to take the pending handlers while this thread diff --git a/include/boost/corosio/native/detail/reactor/reactor_service_finals.hpp b/include/boost/corosio/native/detail/reactor/reactor_service_finals.hpp index 7180a7f87..32f3758a9 100644 --- a/include/boost/corosio/native/detail/reactor/reactor_service_finals.hpp +++ b/include/boost/corosio/native/detail/reactor/reactor_service_finals.hpp @@ -48,7 +48,9 @@ template std::error_code do_open_socket( SocketFinal* socket_impl, - int family, int type, int protocol, + int family, + int type, + int protocol, bool is_ip) noexcept { socket_impl->close_socket(); @@ -57,9 +59,8 @@ do_open_socket( if (fd < 0) return make_err(errno); - std::error_code ec = is_ip - ? Traits::configure_ip_socket(fd, family) - : Traits::configure_local_socket(fd); + std::error_code ec = is_ip ? Traits::configure_ip_socket(fd, family) + : Traits::configure_local_socket(fd); if (ec) { @@ -78,10 +79,7 @@ do_open_socket( template std::error_code do_assign_fd( - SocketFinal* socket_impl, - int fd, - int expected_type, - bool is_ip) noexcept + SocketFinal* socket_impl, int fd, int expected_type, bool is_ip) noexcept { // fd >= 0 guard: an unset socket_impl reports native_handle() == -1, // and a caller-supplied -1 must fail as a bad fd, not a self-assign. @@ -105,8 +103,8 @@ do_assign_fd( return ec; // Best-effort: refresh endpoint caches. - using endpoint_type = std::remove_cvref_t< - decltype(socket_impl->local_endpoint())>; + using endpoint_type = + std::remove_cvref_tlocal_endpoint())>; endpoint_type local_ep{}; sockaddr_storage local_storage{}; @@ -130,9 +128,7 @@ do_assign_fd( template std::error_code do_open_acceptor( - AccFinal* acc_impl, - int family, int type, int protocol, - bool is_ip) noexcept + AccFinal* acc_impl, int family, int type, int protocol, bool is_ip) noexcept { acc_impl->close_socket(); @@ -140,9 +136,8 @@ do_open_acceptor( if (fd < 0) return make_err(errno); - std::error_code ec = is_ip - ? Traits::configure_ip_acceptor(fd, family) - : Traits::configure_local_socket(fd); + std::error_code ec = is_ip ? Traits::configure_ip_acceptor(fd, family) + : Traits::configure_local_socket(fd); if (ec) { @@ -176,8 +171,8 @@ do_assign_acceptor_fd(AccFinal* acc_impl, int fd, bool is_ip) noexcept if (auto ec = acc_impl->init_and_register(fd)) return ec; - using endpoint_type = std::remove_cvref_t< - decltype(acc_impl->local_endpoint())>; + using endpoint_type = + std::remove_cvref_tlocal_endpoint())>; endpoint_type local_ep{}; sockaddr_storage local_storage{}; @@ -204,13 +199,17 @@ class reactor_tcp_service_impl SocketFinal> { using base_service = reactor_socket_service< - Derived, tcp_service, - typename Traits::scheduler_type, SocketFinal>; + Derived, + tcp_service, + typename Traits::scheduler_type, + SocketFinal>; friend Derived; friend base_service; explicit reactor_tcp_service_impl(capy::execution_context& ctx) - : base_service(ctx) {} + : base_service(ctx) + { + } public: static constexpr bool needs_write_notification = @@ -218,11 +217,12 @@ class reactor_tcp_service_impl std::error_code open_socket( tcp_socket::implementation& impl, - int family, int type, int protocol) override + int family, + int type, + int protocol) override { return do_open_socket( - static_cast(&impl), - family, type, protocol, true); + static_cast(&impl), family, type, protocol, true); } std::error_code assign_socket( @@ -232,8 +232,8 @@ class reactor_tcp_service_impl static_cast(&impl), fd, SOCK_STREAM, true); } - std::error_code bind_socket( - tcp_socket::implementation& impl, endpoint ep) override + std::error_code + bind_socket(tcp_socket::implementation& impl, endpoint ep) override { return static_cast(&impl)->do_bind(ep); } @@ -262,13 +262,17 @@ class reactor_local_stream_service_impl SocketFinal> { using base_service = reactor_socket_service< - Derived, local_stream_service, - typename Traits::scheduler_type, SocketFinal>; + Derived, + local_stream_service, + typename Traits::scheduler_type, + SocketFinal>; friend Derived; friend base_service; explicit reactor_local_stream_service_impl(capy::execution_context& ctx) - : base_service(ctx) {} + : base_service(ctx) + { + } public: static constexpr bool needs_write_notification = @@ -276,11 +280,12 @@ class reactor_local_stream_service_impl std::error_code open_socket( local_stream_socket::implementation& impl, - int family, int type, int protocol) override + int family, + int type, + int protocol) override { return do_open_socket( - static_cast(&impl), - family, type, protocol, false); + static_cast(&impl), family, type, protocol, false); } std::error_code assign_socket( @@ -305,13 +310,17 @@ class reactor_udp_service_impl SocketFinal> { using base_service = reactor_socket_service< - Derived, udp_service, - typename Traits::scheduler_type, SocketFinal>; + Derived, + udp_service, + typename Traits::scheduler_type, + SocketFinal>; friend Derived; friend base_service; explicit reactor_udp_service_impl(capy::execution_context& ctx) - : base_service(ctx) {} + : base_service(ctx) + { + } public: static constexpr bool needs_write_notification = @@ -319,11 +328,12 @@ class reactor_udp_service_impl std::error_code open_datagram_socket( udp_socket::implementation& impl, - int family, int type, int protocol) override + int family, + int type, + int protocol) override { return do_open_socket( - static_cast(&impl), - family, type, protocol, true); + static_cast(&impl), family, type, protocol, true); } std::error_code assign_socket( @@ -333,8 +343,8 @@ class reactor_udp_service_impl static_cast(&impl), fd, SOCK_DGRAM, true); } - std::error_code bind_datagram( - udp_socket::implementation& impl, endpoint ep) override + std::error_code + bind_datagram(udp_socket::implementation& impl, endpoint ep) override { return static_cast(&impl)->do_bind(ep); } @@ -353,13 +363,17 @@ class reactor_local_dgram_service_impl SocketFinal> { using base_service = reactor_socket_service< - Derived, local_datagram_service, - typename Traits::scheduler_type, SocketFinal>; + Derived, + local_datagram_service, + typename Traits::scheduler_type, + SocketFinal>; friend Derived; friend base_service; explicit reactor_local_dgram_service_impl(capy::execution_context& ctx) - : base_service(ctx) {} + : base_service(ctx) + { + } public: static constexpr bool needs_write_notification = @@ -367,11 +381,12 @@ class reactor_local_dgram_service_impl std::error_code open_socket( local_datagram_socket::implementation& impl, - int family, int type, int protocol) override + int family, + int type, + int protocol) override { return do_open_socket( - static_cast(&impl), - family, type, protocol, false); + static_cast(&impl), family, type, protocol, false); } std::error_code assign_socket( @@ -394,8 +409,13 @@ class reactor_local_dgram_service_impl // Acceptor service // ============================================================ -template +template< + class Derived, + class Traits, + class ServiceBase, + class AccFinal, + class StreamServiceFinal, + class Endpoint> class reactor_acceptor_service_impl : public reactor_acceptor_service< Derived, @@ -424,33 +444,31 @@ class reactor_acceptor_service_impl public: std::error_code open_acceptor_socket( typename AccFinal::impl_base_type& impl, - int family, int type, int protocol) override + int family, + int type, + int protocol) override { return do_open_acceptor( - static_cast(&impl), - family, type, protocol, + static_cast(&impl), family, type, protocol, std::is_same_v); } std::error_code assign_socket( - typename AccFinal::impl_base_type& impl, - native_handle_type fd) override + typename AccFinal::impl_base_type& impl, native_handle_type fd) override { return do_assign_acceptor_fd( static_cast(&impl), fd, std::is_same_v); } - std::error_code bind_acceptor( - typename AccFinal::impl_base_type& impl, - Endpoint ep) override + std::error_code + bind_acceptor(typename AccFinal::impl_base_type& impl, Endpoint ep) override { return static_cast(&impl)->do_bind(ep); } std::error_code listen_acceptor( - typename AccFinal::impl_base_type& impl, - int backlog) override + typename AccFinal::impl_base_type& impl, int backlog) override { return static_cast(&impl)->do_listen(backlog); } diff --git a/include/boost/corosio/native/detail/reactor/reactor_signal_pipe.hpp b/include/boost/corosio/native/detail/reactor/reactor_signal_pipe.hpp index 13eab0b30..dccfb29af 100644 --- a/include/boost/corosio/native/detail/reactor/reactor_signal_pipe.hpp +++ b/include/boost/corosio/native/detail/reactor/reactor_signal_pipe.hpp @@ -55,7 +55,7 @@ struct reactor_signal_pipe_reader }; reactor_descriptor_state desc; - drain_op op; + drain_op op; // Park the drain op and return the descriptor to hand to // scheduler::register_descriptor(read_fd, ...). diff --git a/include/boost/corosio/native/detail/reactor/reactor_socket_finals.hpp b/include/boost/corosio/native/detail/reactor/reactor_socket_finals.hpp index 9ad573a98..aa405ff5c 100644 --- a/include/boost/corosio/native/detail/reactor/reactor_socket_finals.hpp +++ b/include/boost/corosio/native/detail/reactor/reactor_socket_finals.hpp @@ -52,8 +52,13 @@ namespace boost::corosio::detail { @tparam ImplBase The public vtable base. @tparam Endpoint endpoint or local_endpoint. */ -template +template< + class Derived, + class Traits, + class Service, + class AcceptorType, + class ImplBase, + class Endpoint> class reactor_stream_socket_impl : public reactor_stream_socket< Derived, @@ -83,8 +88,10 @@ class reactor_stream_socket_impl ~reactor_stream_socket_impl() override = default; std::error_code set_option( - int level, int optname, - void const* data, std::size_t size) noexcept override + int level, + int optname, + void const* data, + std::size_t size) noexcept override { return hook_.on_set_option(this->fd_, level, optname, data, size); } @@ -111,8 +118,13 @@ class reactor_stream_socket_impl @tparam ImplBase The public vtable base. @tparam Endpoint endpoint or local_endpoint. */ -template +template< + class Derived, + class Traits, + class Service, + class AcceptorType, + class ImplBase, + class Endpoint> class reactor_dgram_socket_impl : public reactor_datagram_socket< Derived, @@ -154,8 +166,13 @@ class reactor_dgram_socket_impl @tparam AccImplBase The public vtable base. @tparam Endpoint endpoint or local_endpoint. */ -template +template< + class Derived, + class Traits, + class Service, + class SocketFinal, + class AccImplBase, + class Endpoint> class reactor_acceptor_impl : public reactor_acceptor< Derived, diff --git a/include/boost/corosio/native/detail/reactor/reactor_socket_service.hpp b/include/boost/corosio/native/detail/reactor/reactor_socket_service.hpp index 4c9bfbff8..292254075 100644 --- a/include/boost/corosio/native/detail/reactor/reactor_socket_service.hpp +++ b/include/boost/corosio/native/detail/reactor/reactor_socket_service.hpp @@ -119,7 +119,8 @@ class reactor_socket_service : public ServiceBase protected: // Override in derived to add pre-close logic. No backend currently needs // it; the hooks exist so a trait can run fd-level teardown before close. - void pre_shutdown(Impl*) noexcept {} // LCOV_EXCL_LINE optional CRTP hook; no backend overrides it today + void pre_shutdown(Impl*) noexcept { + } // LCOV_EXCL_LINE optional CRTP hook; no backend overrides it today void pre_destroy(Impl*) noexcept {} std::unique_ptr state_; diff --git a/include/boost/corosio/native/detail/reactor/reactor_stream_ops.hpp b/include/boost/corosio/native/detail/reactor/reactor_stream_ops.hpp index 8d70d0b02..63e73c43a 100644 --- a/include/boost/corosio/native/detail/reactor/reactor_stream_ops.hpp +++ b/include/boost/corosio/native/detail/reactor/reactor_stream_ops.hpp @@ -31,8 +31,7 @@ namespace boost::corosio::detail { */ template -struct reactor_stream_base_op - : reactor_op +struct reactor_stream_base_op : reactor_op { void operator()() override; void cancel() noexcept override; @@ -51,16 +50,14 @@ template struct reactor_stream_read_op final : reactor_read_op< reactor_stream_base_op> -{ -}; +{}; template struct reactor_stream_write_op final : reactor_write_op< reactor_stream_base_op, typename Traits::write_policy> -{ -}; +{}; template struct reactor_stream_accept_op final diff --git a/include/boost/corosio/native/detail/reactor/reactor_stream_socket.hpp b/include/boost/corosio/native/detail/reactor/reactor_stream_socket.hpp index 7706a9e6a..e010b2e34 100644 --- a/include/boost/corosio/native/detail/reactor/reactor_stream_socket.hpp +++ b/include/boost/corosio/native/detail/reactor/reactor_stream_socket.hpp @@ -62,15 +62,18 @@ class reactor_stream_socket DescState, Endpoint> { - using base_type = reactor_basic_socket< + using base_type = + reactor_basic_socket; + using self_type = reactor_stream_socket< Derived, - ImplBase, Service, + ConnOp, + ReadOp, + WriteOp, + WaitOp, DescState, + ImplBase, Endpoint>; - using self_type = reactor_stream_socket< - Derived, Service, ConnOp, ReadOp, WriteOp, WaitOp, - DescState, ImplBase, Endpoint>; friend base_type; friend Derived; @@ -152,8 +155,7 @@ class reactor_stream_socket return do_wait(h, ex, w, token, ec); } - std::error_code - shutdown(corosio::shutdown_type what) noexcept override + std::error_code shutdown(corosio::shutdown_type what) noexcept override { return do_shutdown(static_cast(what)); } @@ -275,7 +277,7 @@ class reactor_stream_socket /// Release ownership of the descriptor and drop the cached peer. native_handle_type do_release_socket() noexcept { - auto fd = base_type::do_release_socket(); + auto fd = base_type::do_release_socket(); remote_endpoint_ = Endpoint{}; return fd; } @@ -301,7 +303,6 @@ class reactor_stream_socket return nullptr; } - template void for_each_op(Fn fn) noexcept { @@ -336,7 +337,16 @@ template< class ImplBase, class Endpoint> std::coroutine_handle<> -reactor_stream_socket:: +reactor_stream_socket< + Derived, + Service, + ConnOp, + ReadOp, + WriteOp, + WaitOp, + DescState, + ImplBase, + Endpoint>:: do_connect( std::coroutine_handle<> h, capy::executor_ref ex, @@ -368,7 +378,7 @@ reactor_stream_socketsvc_.scheduler().try_consume_inline_budget()) { - *ec = err ? make_err(err) : std::error_code{}; + *ec = err ? make_err(err) : std::error_code{}; op.cont.h = h; return dispatch_coro(ex, op.cont); } @@ -411,7 +421,16 @@ template< class ImplBase, class Endpoint> std::coroutine_handle<> -reactor_stream_socket:: +reactor_stream_socket< + Derived, + Service, + ConnOp, + ReadOp, + WriteOp, + WaitOp, + DescState, + ImplBase, + Endpoint>:: do_read_some( std::coroutine_handle<> h, capy::executor_ref ex, @@ -495,7 +514,7 @@ reactor_stream_socket std::coroutine_handle<> -reactor_stream_socket:: +reactor_stream_socket< + Derived, + Service, + ConnOp, + ReadOp, + WriteOp, + WaitOp, + DescState, + ImplBase, + Endpoint>:: do_write_some( std::coroutine_handle<> h, capy::executor_ref ex, @@ -595,8 +623,7 @@ reactor_stream_socketfd_, op.iovecs, op.iovec_count); + n = WriteOp::write_policy::write(this->fd_, op.iovecs, op.iovec_count); } if (n >= 0 || (errno != EAGAIN && errno != EWOULDBLOCK)) @@ -608,7 +635,7 @@ reactor_stream_socket std::coroutine_handle<> -reactor_stream_socket:: +reactor_stream_socket< + Derived, + Service, + ConnOp, + ReadOp, + WriteOp, + WaitOp, + DescState, + ImplBase, + Endpoint>:: do_wait( std::coroutine_handle<> h, capy::executor_ref ex, @@ -662,21 +698,21 @@ reactor_stream_socketdesc_state_.wait_read_op; - event = reactor_event_read; + op_ptr = &wait_rd_; + desc_slot_ptr = &this->desc_state_.wait_read_op; + event = reactor_event_read; } else if (w == wait_type::write) { - op_ptr = &wait_wr_; - desc_slot_ptr = &this->desc_state_.wait_write_op; - event = reactor_event_write; + op_ptr = &wait_wr_; + desc_slot_ptr = &this->desc_state_.wait_write_op; + event = reactor_event_write; } else // wait_type::error { - op_ptr = &wait_er_; - desc_slot_ptr = &this->desc_state_.wait_error_op; - event = reactor_event_error; + op_ptr = &wait_er_; + desc_slot_ptr = &this->desc_state_.wait_error_op; + event = reactor_event_error; } auto& op = *op_ptr; @@ -722,8 +758,8 @@ reactor_stream_socketregister_op(op, *desc_slot_ptr, force_probe, - event == reactor_event_write); + this->register_op( + op, *desc_slot_ptr, force_probe, event == reactor_event_write); return std::noop_coroutine(); } diff --git a/include/boost/corosio/native/detail/select/select_scheduler.hpp b/include/boost/corosio/native/detail/select/select_scheduler.hpp index dc6f31564..a1505c661 100644 --- a/include/boost/corosio/native/detail/select/select_scheduler.hpp +++ b/include/boost/corosio/native/detail/select/select_scheduler.hpp @@ -132,16 +132,13 @@ class BOOST_COROSIO_DECL select_scheduler final : public reactor_scheduler void notify_reactor() const; /// Watch the read end of the POSIX signal self-pipe (see scheduler.hpp). - [[nodiscard]] std::error_code - register_signal_reader(int read_fd) override + [[nodiscard]] std::error_code register_signal_reader(int read_fd) override { return register_descriptor(read_fd, signal_pipe_reader_.arm()); } private: - void - run_task(lock_type& lock, context_type& ctx, - long timeout_us) override; + void run_task(lock_type& lock, context_type& ctx, long timeout_us) override; void interrupt_reactor() const override; long calculate_timeout(long requested_timeout_us) const; @@ -153,7 +150,8 @@ class BOOST_COROSIO_DECL select_scheduler final : public reactor_scheduler int pipe_fds_[2]; // [0]=read, [1]=write // Per-fd tracking for fd_set building - mutable std::unordered_map registered_descs_; + mutable std::unordered_map + registered_descs_; mutable int max_fd_ = -1; }; @@ -328,8 +326,7 @@ select_scheduler::calculate_timeout(long requested_timeout_us) const } inline void -select_scheduler::run_task( - lock_type& lock, context_type& ctx, long timeout_us) +select_scheduler::run_task(lock_type& lock, context_type& ctx, long timeout_us) { long effective_timeout_us = task_interrupted_ ? 0 : calculate_timeout(timeout_us); @@ -358,8 +355,7 @@ select_scheduler::run_task( snapshot[snapshot_count].fd = fd; snapshot[snapshot_count].desc = desc; snapshot[snapshot_count].needs_write = - (desc->write_op || desc->connect_op || - desc->wait_write_op); + (desc->write_op || desc->connect_op || desc->wait_write_op); ++snapshot_count; } } @@ -429,7 +425,7 @@ select_scheduler::run_task( for (int i = 0; i < snapshot_count; ++i) { - int fd = snapshot[i].fd; + int fd = snapshot[i].fd; reactor_descriptor_state* desc = snapshot[i].desc; std::uint32_t flags = 0; diff --git a/include/boost/corosio/native/detail/select/select_traits.hpp b/include/boost/corosio/native/detail/select/select_traits.hpp index b36e0274e..3b08f6faa 100644 --- a/include/boost/corosio/native/detail/select/select_traits.hpp +++ b/include/boost/corosio/native/detail/select/select_traits.hpp @@ -42,8 +42,8 @@ class select_scheduler; struct select_traits { - using scheduler_type = select_scheduler; - using desc_state_type = reactor_descriptor_state; + using scheduler_type = select_scheduler; + using desc_state_type = reactor_descriptor_state; static constexpr bool needs_write_notification = true; @@ -51,12 +51,15 @@ struct select_traits struct stream_socket_hook { std::error_code on_set_option( - int fd, int level, int optname, - void const* data, std::size_t size) noexcept + int fd, + int level, + int optname, + void const* data, + std::size_t size) noexcept { if (::setsockopt( - fd, level, optname, data, - static_cast(size)) != 0) + fd, level, optname, data, static_cast(size)) != + 0) return make_err(errno); return {}; } @@ -91,8 +94,8 @@ struct select_traits // send() to suppress SIGPIPE inline; otherwise fall back to // write() and rely on the SO_NOSIGPIPE set in accept_policy // and set_fd_options. - static ssize_t write_one( - int fd, void const* data, std::size_t size) noexcept + static ssize_t + write_one(int fd, void const* data, std::size_t size) noexcept { ssize_t n; do @@ -110,15 +113,15 @@ struct select_traits struct accept_policy { - static int do_accept( - int fd, sockaddr_storage& peer, socklen_t& addrlen) noexcept + static int + do_accept(int fd, sockaddr_storage& peer, socklen_t& addrlen) noexcept { addrlen = sizeof(peer); int new_fd; do { - new_fd = ::accept( - fd, reinterpret_cast(&peer), &addrlen); + new_fd = + ::accept(fd, reinterpret_cast(&peer), &addrlen); } while (new_fd < 0 && errno == EINTR); @@ -165,8 +168,7 @@ struct select_traits // as fatal, matching the kqueue backend. int one = 1; if (::setsockopt( - new_fd, SOL_SOCKET, SO_NOSIGPIPE, - &one, sizeof(one)) != 0) + new_fd, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one)) != 0) { int err = errno; ::close(new_fd); @@ -208,8 +210,8 @@ struct select_traits // matching the kqueue backend. Caller closes fd on error. { int one = 1; - if (::setsockopt( - fd, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one)) != 0) + if (::setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one)) != + 0) return make_err(errno); } #endif @@ -219,14 +221,13 @@ struct select_traits // Apply protocol-specific options after socket creation. // For IP sockets, sets IPV6_V6ONLY on AF_INET6 (best-effort). - static std::error_code - configure_ip_socket(int fd, int family) noexcept + static std::error_code configure_ip_socket(int fd, int family) noexcept { if (family == AF_INET6) { int one = 1; - std::ignore = ::setsockopt( - fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); + std::ignore = + ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); } return set_fd_options(fd); @@ -234,22 +235,20 @@ struct select_traits // Apply protocol-specific options for acceptor sockets. // For IP acceptors, sets IPV6_V6ONLY=0 (dual-stack, best-effort). - static std::error_code - configure_ip_acceptor(int fd, int family) noexcept + static std::error_code configure_ip_acceptor(int fd, int family) noexcept { if (family == AF_INET6) { int val = 0; - std::ignore = ::setsockopt( - fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); + std::ignore = + ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); } return set_fd_options(fd); } // Apply options for local (unix) sockets. - static std::error_code - configure_local_socket(int fd) noexcept + static std::error_code configure_local_socket(int fd) noexcept { return set_fd_options(fd); } @@ -257,8 +256,7 @@ struct select_traits // Non-mutating validation for fds adopted via assign(). Select's // reactor cannot handle fds above FD_SETSIZE, so reject them up // front instead of letting FD_SET clobber unrelated memory. - static std::error_code - validate_assigned_fd(int fd) noexcept + static std::error_code validate_assigned_fd(int fd) noexcept { if (fd >= FD_SETSIZE) return make_err(EMFILE); diff --git a/include/boost/corosio/native/detail/select/select_types.hpp b/include/boost/corosio/native/detail/select/select_types.hpp index 67994e2af..cb919a7a4 100644 --- a/include/boost/corosio/native/detail/select/select_types.hpp +++ b/include/boost/corosio/native/detail/select/select_types.hpp @@ -46,16 +46,27 @@ class select_local_datagram_service; class select_tcp_socket final : public reactor_stream_socket_impl< - select_tcp_socket, select_traits, select_tcp_service, - select_tcp_acceptor, tcp_socket::implementation, endpoint> + select_tcp_socket, + select_traits, + select_tcp_service, + select_tcp_acceptor, + tcp_socket::implementation, + endpoint> { using base_type = reactor_stream_socket_impl< - select_tcp_socket, select_traits, select_tcp_service, - select_tcp_acceptor, tcp_socket::implementation, endpoint>; + select_tcp_socket, + select_traits, + select_tcp_service, + select_tcp_acceptor, + tcp_socket::implementation, + endpoint>; friend select_tcp_service; + public: explicit select_tcp_socket(select_tcp_service& svc) noexcept - : base_type(svc) {} + : base_type(svc) + { + } native_handle_type release_socket() noexcept override { @@ -66,18 +77,28 @@ class select_tcp_socket final class select_local_stream_socket final : public reactor_stream_socket_impl< - select_local_stream_socket, select_traits, - select_local_stream_service, select_local_stream_acceptor, - local_stream_socket::implementation, corosio::local_endpoint> + select_local_stream_socket, + select_traits, + select_local_stream_service, + select_local_stream_acceptor, + local_stream_socket::implementation, + corosio::local_endpoint> { using base_type = reactor_stream_socket_impl< - select_local_stream_socket, select_traits, - select_local_stream_service, select_local_stream_acceptor, - local_stream_socket::implementation, corosio::local_endpoint>; + select_local_stream_socket, + select_traits, + select_local_stream_service, + select_local_stream_acceptor, + local_stream_socket::implementation, + corosio::local_endpoint>; friend select_local_stream_service; + public: - explicit select_local_stream_socket(select_local_stream_service& svc) noexcept - : base_type(svc) {} + explicit select_local_stream_socket( + select_local_stream_service& svc) noexcept + : base_type(svc) + { + } native_handle_type release_socket() noexcept override { @@ -90,16 +111,27 @@ class select_local_stream_socket final class select_udp_socket final : public reactor_dgram_socket_impl< - select_udp_socket, select_traits, select_udp_service, - select_tcp_acceptor, udp_socket::implementation, endpoint> + select_udp_socket, + select_traits, + select_udp_service, + select_tcp_acceptor, + udp_socket::implementation, + endpoint> { using base_type = reactor_dgram_socket_impl< - select_udp_socket, select_traits, select_udp_service, - select_tcp_acceptor, udp_socket::implementation, endpoint>; + select_udp_socket, + select_traits, + select_udp_service, + select_tcp_acceptor, + udp_socket::implementation, + endpoint>; friend select_udp_service; + public: explicit select_udp_socket(select_udp_service& svc) noexcept - : base_type(svc) {} + : base_type(svc) + { + } std::error_code shutdown(corosio::shutdown_type what) noexcept override { @@ -114,18 +146,28 @@ class select_udp_socket final class select_local_datagram_socket final : public reactor_dgram_socket_impl< - select_local_datagram_socket, select_traits, - select_local_datagram_service, select_tcp_acceptor, - local_datagram_socket::implementation, corosio::local_endpoint> + select_local_datagram_socket, + select_traits, + select_local_datagram_service, + select_tcp_acceptor, + local_datagram_socket::implementation, + corosio::local_endpoint> { using base_type = reactor_dgram_socket_impl< - select_local_datagram_socket, select_traits, - select_local_datagram_service, select_tcp_acceptor, - local_datagram_socket::implementation, corosio::local_endpoint>; + select_local_datagram_socket, + select_traits, + select_local_datagram_service, + select_tcp_acceptor, + local_datagram_socket::implementation, + corosio::local_endpoint>; friend select_local_datagram_service; + public: - explicit select_local_datagram_socket(select_local_datagram_service& svc) noexcept - : base_type(svc) {} + explicit select_local_datagram_socket( + select_local_datagram_service& svc) noexcept + : base_type(svc) + { + } std::error_code shutdown(corosio::shutdown_type what) noexcept override { @@ -147,119 +189,173 @@ class select_local_datagram_socket final class select_tcp_acceptor final : public reactor_acceptor_impl< - select_tcp_acceptor, select_traits, - select_tcp_acceptor_service, select_tcp_socket, - tcp_acceptor::implementation, endpoint> + select_tcp_acceptor, + select_traits, + select_tcp_acceptor_service, + select_tcp_socket, + tcp_acceptor::implementation, + endpoint> { using base_type = reactor_acceptor_impl< - select_tcp_acceptor, select_traits, - select_tcp_acceptor_service, select_tcp_socket, - tcp_acceptor::implementation, endpoint>; + select_tcp_acceptor, + select_traits, + select_tcp_acceptor_service, + select_tcp_socket, + tcp_acceptor::implementation, + endpoint>; friend select_tcp_acceptor_service; + public: explicit select_tcp_acceptor(select_tcp_acceptor_service& svc) noexcept - : base_type(svc) {} + : base_type(svc) + { + } }; class select_local_stream_acceptor final : public reactor_acceptor_impl< - select_local_stream_acceptor, select_traits, + select_local_stream_acceptor, + select_traits, select_local_stream_acceptor_service, select_local_stream_socket, - local_stream_acceptor::implementation, corosio::local_endpoint> + local_stream_acceptor::implementation, + corosio::local_endpoint> { using base_type = reactor_acceptor_impl< - select_local_stream_acceptor, select_traits, + select_local_stream_acceptor, + select_traits, select_local_stream_acceptor_service, select_local_stream_socket, - local_stream_acceptor::implementation, corosio::local_endpoint>; + local_stream_acceptor::implementation, + corosio::local_endpoint>; friend select_local_stream_acceptor_service; + public: explicit select_local_stream_acceptor( select_local_stream_acceptor_service& svc) noexcept - : base_type(svc) {} + : base_type(svc) + { + } }; // --- Services --- class BOOST_COROSIO_DECL select_tcp_service final : public reactor_tcp_service_impl< - select_tcp_service, select_traits, select_tcp_socket> + select_tcp_service, + select_traits, + select_tcp_socket> { using base_type = reactor_tcp_service_impl< - select_tcp_service, select_traits, select_tcp_socket>; + select_tcp_service, + select_traits, + select_tcp_socket>; + public: - explicit select_tcp_service(capy::execution_context& ctx) - : base_type(ctx) {} + explicit select_tcp_service(capy::execution_context& ctx) : base_type(ctx) + { + } }; class BOOST_COROSIO_DECL select_local_stream_service final : public reactor_local_stream_service_impl< - select_local_stream_service, select_traits, + select_local_stream_service, + select_traits, select_local_stream_socket> { using base_type = reactor_local_stream_service_impl< - select_local_stream_service, select_traits, + select_local_stream_service, + select_traits, select_local_stream_socket>; + public: explicit select_local_stream_service(capy::execution_context& ctx) - : base_type(ctx) {} + : base_type(ctx) + { + } }; class BOOST_COROSIO_DECL select_udp_service final : public reactor_udp_service_impl< - select_udp_service, select_traits, select_udp_socket> + select_udp_service, + select_traits, + select_udp_socket> { using base_type = reactor_udp_service_impl< - select_udp_service, select_traits, select_udp_socket>; + select_udp_service, + select_traits, + select_udp_socket>; + public: - explicit select_udp_service(capy::execution_context& ctx) - : base_type(ctx) {} + explicit select_udp_service(capy::execution_context& ctx) : base_type(ctx) + { + } }; class BOOST_COROSIO_DECL select_local_datagram_service final : public reactor_local_dgram_service_impl< - select_local_datagram_service, select_traits, + select_local_datagram_service, + select_traits, select_local_datagram_socket> { using base_type = reactor_local_dgram_service_impl< - select_local_datagram_service, select_traits, + select_local_datagram_service, + select_traits, select_local_datagram_socket>; + public: explicit select_local_datagram_service(capy::execution_context& ctx) - : base_type(ctx) {} + : base_type(ctx) + { + } }; class BOOST_COROSIO_DECL select_tcp_acceptor_service final : public reactor_acceptor_service_impl< - select_tcp_acceptor_service, select_traits, - tcp_acceptor_service, select_tcp_acceptor, - select_tcp_service, endpoint> + select_tcp_acceptor_service, + select_traits, + tcp_acceptor_service, + select_tcp_acceptor, + select_tcp_service, + endpoint> { using base_type = reactor_acceptor_service_impl< - select_tcp_acceptor_service, select_traits, - tcp_acceptor_service, select_tcp_acceptor, - select_tcp_service, endpoint>; + select_tcp_acceptor_service, + select_traits, + tcp_acceptor_service, + select_tcp_acceptor, + select_tcp_service, + endpoint>; + public: explicit select_tcp_acceptor_service(capy::execution_context& ctx) - : base_type(ctx) {} + : base_type(ctx) + { + } }; class BOOST_COROSIO_DECL select_local_stream_acceptor_service final : public reactor_acceptor_service_impl< - select_local_stream_acceptor_service, select_traits, + select_local_stream_acceptor_service, + select_traits, local_stream_acceptor_service, select_local_stream_acceptor, - select_local_stream_service, corosio::local_endpoint> + select_local_stream_service, + corosio::local_endpoint> { using base_type = reactor_acceptor_service_impl< - select_local_stream_acceptor_service, select_traits, + select_local_stream_acceptor_service, + select_traits, local_stream_acceptor_service, select_local_stream_acceptor, - select_local_stream_service, corosio::local_endpoint>; + select_local_stream_service, + corosio::local_endpoint>; + public: explicit select_local_stream_acceptor_service(capy::execution_context& ctx) - : base_type(ctx) {} + : base_type(ctx) + { + } }; } // namespace boost::corosio::detail diff --git a/include/boost/corosio/native/detail/speculative_state.hpp b/include/boost/corosio/native/detail/speculative_state.hpp index c1be04516..c29b8253b 100644 --- a/include/boost/corosio/native/detail/speculative_state.hpp +++ b/include/boost/corosio/native/detail/speculative_state.hpp @@ -31,8 +31,8 @@ namespace boost::corosio::detail { */ class speculative_state { - std::atomic< bool > try_read_ { true }; - std::atomic< bool > try_write_{ true }; + std::atomic try_read_{true}; + std::atomic try_write_{true}; // Failure-streak counter for the read path. Increments on every // speculative-read EAGAIN; resets to 0 whenever a speculative read @@ -47,21 +47,21 @@ class speculative_state // pattern" (e.g. fan_out:nested/16: every speculation EAGAINs -> // streak hits max_read_failures and we stop wasting syscalls). static constexpr int max_read_failures = 4; - std::atomic< int > read_eagain_streak_ { 0 }; - std::atomic< bool > perma_off_read_ { false }; + std::atomic read_eagain_streak_{0}; + std::atomic perma_off_read_{false}; public: /// Return true when speculative read is currently worth trying. bool may_speculate_read() const noexcept { - return try_read_.load( std::memory_order_relaxed ) - && !perma_off_read_.load( std::memory_order_relaxed ); + return try_read_.load(std::memory_order_relaxed) && + !perma_off_read_.load(std::memory_order_relaxed); } /// Return true when speculative write is currently worth trying. bool may_speculate_write() const noexcept { - return try_write_.load( std::memory_order_relaxed ); + return try_write_.load(std::memory_order_relaxed); } /// Disable speculative reads (kernel buffer is empty). @@ -69,14 +69,14 @@ class speculative_state /// for this socket once the streak hits max_read_failures. void on_read_exhausted() noexcept { - try_read_.store( false, std::memory_order_relaxed ); - int s = read_eagain_streak_.load( std::memory_order_relaxed ); - if ( s < max_read_failures ) + try_read_.store(false, std::memory_order_relaxed); + int s = read_eagain_streak_.load(std::memory_order_relaxed); + if (s < max_read_failures) { ++s; - read_eagain_streak_.store( s, std::memory_order_relaxed ); - if ( s >= max_read_failures ) - perma_off_read_.store( true, std::memory_order_relaxed ); + read_eagain_streak_.store(s, std::memory_order_relaxed); + if (s >= max_read_failures) + perma_off_read_.store(true, std::memory_order_relaxed); } } @@ -85,14 +85,14 @@ class speculative_state /// hit speculation often enough to be worth the occasional EAGAIN. void on_read_success() noexcept { - if ( read_eagain_streak_.load( std::memory_order_relaxed ) != 0 ) - read_eagain_streak_.store( 0, std::memory_order_relaxed ); + if (read_eagain_streak_.load(std::memory_order_relaxed) != 0) + read_eagain_streak_.store(0, std::memory_order_relaxed); } /// Disable speculative writes (kernel buffer is full). void on_write_exhausted() noexcept { - try_write_.store( false, std::memory_order_relaxed ); + try_write_.store(false, std::memory_order_relaxed); } /// Restore speculative reads (kernel signalled readiness via CQE). @@ -100,14 +100,14 @@ class speculative_state /// — the strike-counter / perma-off latch overrides this signal. void on_async_read_ready() noexcept { - if ( !perma_off_read_.load( std::memory_order_relaxed ) ) - try_read_.store( true, std::memory_order_relaxed ); + if (!perma_off_read_.load(std::memory_order_relaxed)) + try_read_.store(true, std::memory_order_relaxed); } /// Restore speculative writes (kernel signalled readiness via CQE). void on_async_write_ready() noexcept { - try_write_.store( true, std::memory_order_relaxed ); + try_write_.store(true, std::memory_order_relaxed); } }; diff --git a/include/boost/corosio/native/detail/io_uring/io_uring_acceptor_ops.hpp b/include/boost/corosio/native/detail/uring/uring_acceptor_ops.hpp similarity index 60% rename from include/boost/corosio/native/detail/io_uring/io_uring_acceptor_ops.hpp rename to include/boost/corosio/native/detail/uring/uring_acceptor_ops.hpp index a1adc0ed3..3473c2096 100644 --- a/include/boost/corosio/native/detail/io_uring/io_uring_acceptor_ops.hpp +++ b/include/boost/corosio/native/detail/uring/uring_acceptor_ops.hpp @@ -7,20 +7,20 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_ACCEPTOR_OPS_HPP -#define BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_ACCEPTOR_OPS_HPP +#ifndef BOOST_COROSIO_NATIVE_DETAIL_URING_URING_ACCEPTOR_OPS_HPP +#define BOOST_COROSIO_NATIVE_DETAIL_URING_URING_ACCEPTOR_OPS_HPP #include -#if BOOST_COROSIO_HAS_IO_URING +#if BOOST_COROSIO_HAS_URING #include #include #include #include -#include -#include +#include +#include #include #include @@ -41,16 +41,16 @@ namespace boost::corosio::detail { present) or park the fd (no waiter). The multishot op persists across CQEs; only `acceptor_impl` owns its lifetime. */ -struct uring_multi_accept_op : io_uring_op +struct uring_multi_accept_op : uring_op { /// Filled by the kernel for each accept. Address of this struct /// is registered with the SQE; kernel writes peer address here. - sockaddr_storage peer_storage{}; - socklen_t peer_len = sizeof(peer_storage); - int listen_fd = -1; + sockaddr_storage peer_storage{}; + socklen_t peer_len = sizeof(peer_storage); + int listen_fd = -1; /// Owning acceptor; raw because the op IS owned by the acceptor. - void* acceptor_impl = nullptr; + void* acceptor_impl = nullptr; /** Callback into the acceptor for each accept CQE. @@ -60,20 +60,19 @@ struct uring_multi_accept_op : io_uring_op @param more True unless this is the terminating CQE (e.g. kernel dropped multishot on -ENOMEM). */ - void (*on_cqe)(void* acceptor, int new_fd, int err, - bool more) noexcept = nullptr; + void (*on_cqe)(void* acceptor, int new_fd, int err, bool more) noexcept = + nullptr; - uring_multi_accept_op() noexcept - : io_uring_op(&do_handler, &do_cqe, &do_prep) - {} + uring_multi_accept_op() noexcept : uring_op(&do_handler, &do_cqe, &do_prep) + { + } - static void do_prep(io_uring_op* base, ::io_uring_sqe* sqe) noexcept + static void do_prep(uring_op* base, ::io_uring_sqe* sqe) noexcept { auto* self = static_cast(base); ::io_uring_prep_multishot_accept( sqe, self->listen_fd, - reinterpret_cast(&self->peer_storage), - &self->peer_len, + reinterpret_cast(&self->peer_storage), &self->peer_len, SOCK_NONBLOCK | SOCK_CLOEXEC); } @@ -85,20 +84,23 @@ struct uring_multi_accept_op : io_uring_op already installed in the process table — dropping the CQE without closing it leaks it for the life of the process. */ - static void do_retired_cqe( - io_uring_op* /*base*/, int res, unsigned /*flags*/) noexcept + static void + do_retired_cqe(uring_op* /*base*/, int res, unsigned /*flags*/) noexcept { - if (res >= 0) // LCOV_EXCL_LINE adopt-over-armed race leak guard - ::close(res); // LCOV_EXCL_LINE adopt-over-armed race leak guard + if (res >= 0) // LCOV_EXCL_LINE adopt-over-armed race leak guard + ::close(res); // LCOV_EXCL_LINE adopt-over-armed race leak guard } - static void do_cqe(io_uring_op* base, int res, unsigned flags, - ready_queue& /*local*/) noexcept + static void do_cqe( + uring_op* base, + int res, + unsigned flags, + ready_queue& /*local*/) noexcept { - auto* self = static_cast(base); - bool more = (flags & IORING_CQE_F_MORE) != 0; - int err = (res < 0) ? -res : 0; - int new_fd = (res >= 0) ? res : -1; + auto* self = static_cast(base); + bool more = (flags & IORING_CQE_F_MORE) != 0; + int err = (res < 0) ? -res : 0; + int new_fd = (res >= 0) ? res : -1; if (self->on_cqe) self->on_cqe(self->acceptor_impl, new_fd, err, more); // Intentionally NOT pushed into local: the acceptor decides @@ -109,8 +111,10 @@ struct uring_multi_accept_op : io_uring_op // the acceptor and never queued for handler dispatch. Provided so // the vtable is complete. static void do_handler( - void* /*owner*/, scheduler_op* /*base*/, - std::uint32_t /*bytes*/, std::uint32_t /*error*/) noexcept + void* /*owner*/, + scheduler_op* /*base*/, + std::uint32_t /*bytes*/, + std::uint32_t /*error*/) noexcept { } // LCOV_EXCL_STOP @@ -126,44 +130,42 @@ struct uring_multi_accept_op : io_uring_op `do_cqe` is unused (this op never receives a kernel CQE). */ -struct uring_accept_op : io_uring_op +struct uring_accept_op : uring_op { - int accepted_fd = -1; - int err = 0; - sockaddr_storage peer_storage{}; - socklen_t peer_len = 0; + int accepted_fd = -1; + int err = 0; + sockaddr_storage peer_storage{}; + socklen_t peer_len = 0; /// Set by the acceptor's `async_accept` entry point; filled by /// `do_handler` with the new socket impl. - io_object::implementation** impl_out = nullptr; + io_object::implementation** impl_out = nullptr; /// Optional output for the peer endpoint. - endpoint* peer_endpoint_out = nullptr; + endpoint* peer_endpoint_out = nullptr; /// The peer service used to wrap the accepted fd. - void* peer_service = nullptr; + void* peer_service = nullptr; /// Acceptor-supplied wrapper: adopts `fd` into the right impl type. - io_object::implementation* - (*adopt_fn)(void* peer_service, int fd, - sockaddr_storage const& peer, - socklen_t peer_len) noexcept = nullptr; + io_object::implementation* (*adopt_fn)( + void* peer_service, + int fd, + sockaddr_storage const& peer, + socklen_t peer_len) noexcept = nullptr; - uring_accept_op() noexcept - : io_uring_op(&do_handler, &do_cqe) - {} + uring_accept_op() noexcept : uring_op(&do_handler, &do_cqe) {} // LCOV_EXCL_START: never receives a CQE; present for vtable // completeness. - static void do_cqe(io_uring_op*, int, unsigned, - ready_queue&) noexcept - { - } + static void do_cqe(uring_op*, int, unsigned, ready_queue&) noexcept {} // LCOV_EXCL_STOP static void do_handler( - void* owner, scheduler_op* base, - std::uint32_t /*bytes*/, std::uint32_t /*error*/) noexcept + void* owner, + scheduler_op* base, + std::uint32_t /*bytes*/, + std::uint32_t /*error*/) noexcept { auto* self = static_cast(base); self->stop_cb.reset(); @@ -174,8 +176,7 @@ struct uring_accept_op : io_uring_op return; } - bool was_cancelled = - self->cancelled.load(std::memory_order_acquire); + bool was_cancelled = self->cancelled.load(std::memory_order_acquire); if (was_cancelled || self->err) { @@ -184,7 +185,7 @@ struct uring_accept_op : io_uring_op ? std::error_code(capy::error::canceled) : make_err(self->err); self->cont.h = self->h; - auto next = dispatch_coro(self->ex, self->cont); + auto next = dispatch_coro(self->ex, self->cont); delete self; next.resume(); return; @@ -192,21 +193,20 @@ struct uring_accept_op : io_uring_op if (self->adopt_fn && self->impl_out) *self->impl_out = self->adopt_fn( - self->peer_service, self->accepted_fd, - self->peer_storage, self->peer_len); + self->peer_service, self->accepted_fd, self->peer_storage, + self->peer_len); // LCOV_EXCL_START: no public accept overload reports the peer // endpoint on this backend yet. if (self->peer_endpoint_out) - *self->peer_endpoint_out = - sockaddr_to_endpoint(self->peer_storage); + *self->peer_endpoint_out = sockaddr_to_endpoint(self->peer_storage); // LCOV_EXCL_STOP if (self->ec_out) *self->ec_out = {}; self->cont.h = self->h; - auto next = dispatch_coro(self->ex, self->cont); + auto next = dispatch_coro(self->ex, self->cont); delete self; next.resume(); } @@ -214,6 +214,6 @@ struct uring_accept_op : io_uring_op } // namespace boost::corosio::detail -#endif // BOOST_COROSIO_HAS_IO_URING +#endif // BOOST_COROSIO_HAS_URING -#endif // BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_ACCEPTOR_OPS_HPP +#endif // BOOST_COROSIO_NATIVE_DETAIL_URING_URING_ACCEPTOR_OPS_HPP diff --git a/include/boost/corosio/native/detail/io_uring/io_uring_buffer.hpp b/include/boost/corosio/native/detail/uring/uring_buffer.hpp similarity index 79% rename from include/boost/corosio/native/detail/io_uring/io_uring_buffer.hpp rename to include/boost/corosio/native/detail/uring/uring_buffer.hpp index 4a074a937..06f2c4738 100644 --- a/include/boost/corosio/native/detail/io_uring/io_uring_buffer.hpp +++ b/include/boost/corosio/native/detail/uring/uring_buffer.hpp @@ -7,12 +7,12 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_BUFFER_HPP -#define BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_BUFFER_HPP +#ifndef BOOST_COROSIO_NATIVE_DETAIL_URING_URING_BUFFER_HPP +#define BOOST_COROSIO_NATIVE_DETAIL_URING_URING_BUFFER_HPP #include -#if BOOST_COROSIO_HAS_IO_URING +#if BOOST_COROSIO_HAS_URING #include #include @@ -37,7 +37,8 @@ endpoint_to_sockaddr(endpoint const& ep, sockaddr_storage& out) noexcept /// Convert a corosio::local_endpoint to a sockaddr_storage. inline socklen_t -endpoint_to_sockaddr(corosio::local_endpoint const& ep, sockaddr_storage& out) noexcept +endpoint_to_sockaddr( + corosio::local_endpoint const& ep, sockaddr_storage& out) noexcept { return to_sockaddr(ep, out); } @@ -58,14 +59,13 @@ sockaddr_to_endpoint(sockaddr_storage const& sa) noexcept /// Convert a sockaddr_storage to a corosio::local_endpoint. inline corosio::local_endpoint -sockaddr_to_local_endpoint( - sockaddr_storage const& sa, socklen_t len) noexcept +sockaddr_to_local_endpoint(sockaddr_storage const& sa, socklen_t len) noexcept { return from_sockaddr_local(sa, len); } } // namespace boost::corosio::detail -#endif // BOOST_COROSIO_HAS_IO_URING +#endif // BOOST_COROSIO_HAS_URING -#endif // BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_BUFFER_HPP +#endif // BOOST_COROSIO_NATIVE_DETAIL_URING_URING_BUFFER_HPP diff --git a/include/boost/corosio/native/detail/io_uring/io_uring_dgram_ops.hpp b/include/boost/corosio/native/detail/uring/uring_dgram_ops.hpp similarity index 64% rename from include/boost/corosio/native/detail/io_uring/io_uring_dgram_ops.hpp rename to include/boost/corosio/native/detail/uring/uring_dgram_ops.hpp index 04e26f608..3078896b7 100644 --- a/include/boost/corosio/native/detail/io_uring/io_uring_dgram_ops.hpp +++ b/include/boost/corosio/native/detail/uring/uring_dgram_ops.hpp @@ -8,20 +8,20 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_DGRAM_OPS_HPP -#define BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_DGRAM_OPS_HPP +#ifndef BOOST_COROSIO_NATIVE_DETAIL_URING_URING_DGRAM_OPS_HPP +#define BOOST_COROSIO_NATIVE_DETAIL_URING_URING_DGRAM_OPS_HPP #include -#if BOOST_COROSIO_HAS_IO_URING +#if BOOST_COROSIO_HAS_URING #include #include -#include +#include #include #include -#include +#include #include #include @@ -40,22 +40,21 @@ namespace boost::corosio::detail { and `msg.msg_name == nullptr`. In unconnected mode, `dest_storage` holds the destination and `msg.msg_name` points at it. - `iovec[io_uring_max_iov]` for scatter/gather: a single datagram + `iovec[uring_max_iov]` for scatter/gather: a single datagram can be assembled from N user buffers via `msg.msg_iov`. */ -struct uring_dgram_send_op : io_uring_op +struct uring_dgram_send_op : uring_op { - iovec iovecs[io_uring_max_iov]; - int iovec_count = 0; - msghdr msg{}; + iovec iovecs[uring_max_iov]; + int iovec_count = 0; + msghdr msg{}; sockaddr_storage dest_storage{}; - socklen_t dest_len = 0; - int fd = -1; - int msg_flags = 0; + socklen_t dest_len = 0; + int fd = -1; + int msg_flags = 0; detail::speculative_state* spec_state = nullptr; - uring_dgram_send_op() noexcept - : io_uring_op(&do_handler, &do_cqe, &do_prep) {} + uring_dgram_send_op() noexcept : uring_op(&do_handler, &do_cqe, &do_prep) {} /** Reset and initialize for a new submission. @@ -64,19 +63,19 @@ struct uring_dgram_send_op : io_uring_op `dest_addr_storage` with the destination address. */ void prepare( - std::coroutine_handle<> handle, - capy::executor_ref executor, - std::error_code* ec, - std::size_t* bytes, - int file_descriptor, - io_uring_scheduler* scheduler, - std::shared_ptr impl, + std::coroutine_handle<> handle, + capy::executor_ref executor, + std::error_code* ec, + std::size_t* bytes, + int file_descriptor, + uring_scheduler* scheduler, + std::shared_ptr impl, detail::speculative_state* spec, - buffer_param buffers, - socklen_t dest_addr_len, - sockaddr_storage const& dest_addr_storage, - int flags, - std::stop_token const& token) noexcept + buffer_param buffers, + socklen_t dest_addr_len, + sockaddr_storage const& dest_addr_storage, + int flags, + std::stop_token const& token) noexcept { h = handle; ex = executor; @@ -92,13 +91,13 @@ struct uring_dgram_send_op : io_uring_op iovec_count = copy_to_iovec(buffers, iovecs); - msg = {}; + msg = {}; msg.msg_iov = iovecs; msg.msg_iovlen = static_cast(iovec_count); if (dest_addr_len > 0) { - dest_storage = dest_addr_storage; - dest_len = dest_addr_len; + dest_storage = dest_addr_storage; + dest_len = dest_addr_len; msg.msg_name = &dest_storage; msg.msg_namelen = dest_addr_len; } @@ -109,26 +108,27 @@ struct uring_dgram_send_op : io_uring_op start(token); } - static void do_prep(io_uring_op* base, ::io_uring_sqe* sqe) noexcept + static void do_prep(uring_op* base, ::io_uring_sqe* sqe) noexcept { auto* self = static_cast(base); ::io_uring_prep_sendmsg( - sqe, self->fd, &self->msg, - self->msg_flags | MSG_NOSIGNAL); + sqe, self->fd, &self->msg, self->msg_flags | MSG_NOSIGNAL); } - static void do_cqe( - io_uring_op* base, int res, unsigned flags, ready_queue& local) noexcept + static void + do_cqe(uring_op* base, int res, unsigned flags, ready_queue& local) noexcept { - auto* self = static_cast(base); + auto* self = static_cast(base); self->res = res; self->cqe_flags = flags; local.push(self); } static void do_handler( - void* owner, scheduler_op* base, - std::uint32_t /*bytes*/, std::uint32_t /*error*/) noexcept + void* owner, + scheduler_op* base, + std::uint32_t /*bytes*/, + std::uint32_t /*error*/) noexcept { auto* self = static_cast(base); if (coro_drain_if_shutdown(owner, self)) @@ -139,13 +139,12 @@ struct uring_dgram_send_op : io_uring_op // Datagram send: no EOF (a 0-byte send is success). decode_io_result( - self->ec_out, - self->cancelled.load(std::memory_order_acquire), + self->ec_out, self->cancelled.load(std::memory_order_acquire), self->res < 0 ? make_err(-self->res) : std::error_code{}, /*is_read=*/false, /*bytes=*/0, /*empty_buffer=*/false); if (self->bytes_out) - *self->bytes_out = (self->res >= 0) - ? static_cast(self->res) : 0; + *self->bytes_out = + (self->res >= 0) ? static_cast(self->res) : 0; if (self->res > 0 && self->spec_state) { @@ -169,25 +168,24 @@ struct uring_dgram_send_op : io_uring_op translate `sockaddr_storage` into `endpoint*` or `local_endpoint*` without the op needing to know which family it is. */ -struct uring_dgram_recv_op : io_uring_op +struct uring_dgram_recv_op : uring_op { - iovec iovecs[io_uring_max_iov]; - int iovec_count = 0; - msghdr msg{}; + iovec iovecs[uring_max_iov]; + int iovec_count = 0; + msghdr msg{}; sockaddr_storage source_storage{}; - socklen_t source_len = 0; - int fd = -1; - int msg_flags = 0; + socklen_t source_len = 0; + int fd = -1; + int msg_flags = 0; detail::speculative_state* spec_state = nullptr; /// Type-erased translator: writes source_storage into the user's /// endpoint output via concrete-class-specific conversion. void* source_writer_ctx = nullptr; - void (*source_writer)( - void*, sockaddr_storage const&, socklen_t) noexcept = nullptr; + void (*source_writer)(void*, sockaddr_storage const&, socklen_t) noexcept = + nullptr; - uring_dgram_recv_op() noexcept - : io_uring_op(&do_handler, &do_cqe, &do_prep) {} + uring_dgram_recv_op() noexcept : uring_op(&do_handler, &do_cqe, &do_prep) {} /** Reset and initialize for a new submission. @@ -203,19 +201,19 @@ struct uring_dgram_recv_op : io_uring_op otherwise block forever. */ void prepare( - std::coroutine_handle<> handle, - capy::executor_ref executor, - std::error_code* ec, - std::size_t* bytes, - int file_descriptor, - io_uring_scheduler* scheduler, - std::shared_ptr impl, + std::coroutine_handle<> handle, + capy::executor_ref executor, + std::error_code* ec, + std::size_t* bytes, + int file_descriptor, + uring_scheduler* scheduler, + std::shared_ptr impl, detail::speculative_state* spec, - buffer_param buffers, - void* source_ctx, + buffer_param buffers, + void* source_ctx, void (*source_fn)(void*, sockaddr_storage const&, socklen_t) noexcept, - int flags, - std::stop_token const& token) noexcept + int flags, + std::stop_token const& token) noexcept { h = handle; ex = executor; @@ -240,11 +238,10 @@ struct uring_dgram_recv_op : io_uring_op if (iovec_count > 0 && source_fn) { msg.msg_iov = iovecs; - msg.msg_iovlen = static_cast( - iovec_count); - source_storage = {}; - source_len = sizeof(source_storage); - msg.msg_name = &source_storage; + msg.msg_iovlen = static_cast(iovec_count); + source_storage = {}; + source_len = sizeof(source_storage); + msg.msg_name = &source_storage; msg.msg_namelen = source_len; source_writer_ctx = source_ctx; source_writer = source_fn; @@ -253,9 +250,9 @@ struct uring_dgram_recv_op : io_uring_op { if (iovec_count > 0) { - msg.msg_iov = iovecs; - msg.msg_iovlen = static_cast( - iovec_count); + msg.msg_iov = iovecs; + msg.msg_iovlen = + static_cast(iovec_count); } source_len = 0; source_writer_ctx = nullptr; @@ -264,17 +261,16 @@ struct uring_dgram_recv_op : io_uring_op start(token); } - static void do_prep(io_uring_op* base, ::io_uring_sqe* sqe) noexcept + static void do_prep(uring_op* base, ::io_uring_sqe* sqe) noexcept { auto* self = static_cast(base); - ::io_uring_prep_recvmsg( - sqe, self->fd, &self->msg, self->msg_flags); + ::io_uring_prep_recvmsg(sqe, self->fd, &self->msg, self->msg_flags); } - static void do_cqe( - io_uring_op* base, int res, unsigned flags, ready_queue& local) noexcept + static void + do_cqe(uring_op* base, int res, unsigned flags, ready_queue& local) noexcept { - auto* self = static_cast(base); + auto* self = static_cast(base); self->res = res; self->cqe_flags = flags; // recvmsg writes the actual source addrlen back into msg.msg_namelen. @@ -283,8 +279,10 @@ struct uring_dgram_recv_op : io_uring_op } static void do_handler( - void* owner, scheduler_op* base, - std::uint32_t /*bytes*/, std::uint32_t /*error*/) noexcept + void* owner, + scheduler_op* base, + std::uint32_t /*bytes*/, + std::uint32_t /*error*/) noexcept { auto* self = static_cast(base); if (coro_drain_if_shutdown(owner, self)) @@ -296,13 +294,12 @@ struct uring_dgram_recv_op : io_uring_op // Datagram recv: a 0-byte datagram is success, not EOF — is_read // stays false so the shared decode never maps it to end_of_file. decode_io_result( - self->ec_out, - self->cancelled.load(std::memory_order_acquire), + self->ec_out, self->cancelled.load(std::memory_order_acquire), self->res < 0 ? make_err(-self->res) : std::error_code{}, /*is_read=*/false, /*bytes=*/0, /*empty_buffer=*/false); if (self->bytes_out) - *self->bytes_out = (self->res >= 0) - ? static_cast(self->res) : 0; + *self->bytes_out = + (self->res >= 0) ? static_cast(self->res) : 0; if (self->res > 0 && self->spec_state) { @@ -313,8 +310,9 @@ struct uring_dgram_recv_op : io_uring_op // Translate source storage into user's endpoint output (only on // success and only when the concrete socket type asked for it). if (self->source_writer && self->res >= 0) - self->source_writer(self->source_writer_ctx, - self->source_storage, self->source_len); + self->source_writer( + self->source_writer_ctx, self->source_storage, + self->source_len); coro_resume(self); } @@ -322,6 +320,6 @@ struct uring_dgram_recv_op : io_uring_op } // namespace boost::corosio::detail -#endif // BOOST_COROSIO_HAS_IO_URING +#endif // BOOST_COROSIO_HAS_URING -#endif // BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_DGRAM_OPS_HPP +#endif // BOOST_COROSIO_NATIVE_DETAIL_URING_URING_DGRAM_OPS_HPP diff --git a/include/boost/corosio/native/detail/io_uring/io_uring_file_ops.hpp b/include/boost/corosio/native/detail/uring/uring_file_ops.hpp similarity index 65% rename from include/boost/corosio/native/detail/io_uring/io_uring_file_ops.hpp rename to include/boost/corosio/native/detail/uring/uring_file_ops.hpp index 75e9fb407..e151a3ad5 100644 --- a/include/boost/corosio/native/detail/io_uring/io_uring_file_ops.hpp +++ b/include/boost/corosio/native/detail/uring/uring_file_ops.hpp @@ -8,15 +8,15 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_FILE_OPS_HPP -#define BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_FILE_OPS_HPP +#ifndef BOOST_COROSIO_NATIVE_DETAIL_URING_URING_FILE_OPS_HPP +#define BOOST_COROSIO_NATIVE_DETAIL_URING_URING_FILE_OPS_HPP #include -#if BOOST_COROSIO_HAS_IO_URING +#if BOOST_COROSIO_HAS_URING -#include -#include +#include +#include #include #include @@ -42,16 +42,16 @@ namespace boost::corosio::detail { /// `uring_random_access_read_op` for heap-allocated per-call ops /// (random_access_file, where concurrent reads at different offsets /// are legitimate). -struct uring_file_read_op_base : io_uring_op +struct uring_file_read_op_base : uring_op { - iovec iovecs[io_uring_max_iov]; - int iovec_count = 0; - int fd = -1; - std::int64_t offset = -1; // -1 means kernel f_pos + iovec iovecs[uring_max_iov]; + int iovec_count = 0; + int fd = -1; + std::int64_t offset = -1; // -1 means kernel f_pos protected: explicit uring_file_read_op_base(func_type handler) noexcept - : io_uring_op(handler, &do_cqe, &do_prep) + : uring_op(handler, &do_cqe, &do_prep) { is_read = true; } @@ -64,33 +64,33 @@ struct uring_file_read_op_base : io_uring_op offset for random-access files. */ void prepare( - std::coroutine_handle<> handle, - capy::executor_ref executor, - std::error_code* ec, - std::size_t* bytes, - int file_descriptor, - std::int64_t file_offset, - io_uring_scheduler* scheduler, - std::shared_ptr impl, - buffer_param buffers, - std::stop_token const& token) noexcept + std::coroutine_handle<> handle, + capy::executor_ref executor, + std::error_code* ec, + std::size_t* bytes, + int file_descriptor, + std::int64_t file_offset, + uring_scheduler* scheduler, + std::shared_ptr impl, + buffer_param buffers, + std::stop_token const& token) noexcept { - h = handle; - ex = executor; - ec_out = ec; - bytes_out = bytes; - fd = file_descriptor; - offset = file_offset; - sched_ = scheduler; - impl_ptr = std::move(impl); - res = 0; - cqe_flags = 0; - iovec_count = copy_to_iovec(buffers, iovecs); + h = handle; + ex = executor; + ec_out = ec; + bytes_out = bytes; + fd = file_descriptor; + offset = file_offset; + sched_ = scheduler; + impl_ptr = std::move(impl); + res = 0; + cqe_flags = 0; + iovec_count = copy_to_iovec(buffers, iovecs); empty_buffer = (iovec_count == 0); start(token); } - static void do_prep(io_uring_op* base, ::io_uring_sqe* sqe) noexcept + static void do_prep(uring_op* base, ::io_uring_sqe* sqe) noexcept { auto* self = static_cast(base); ::io_uring_prep_readv( @@ -98,9 +98,8 @@ struct uring_file_read_op_base : io_uring_op static_cast<__u64>(self->offset)); } - static void do_cqe( - io_uring_op* base, int res, unsigned flags, - ready_queue& local) noexcept + static void + do_cqe(uring_op* base, int res, unsigned flags, ready_queue& local) noexcept { auto* self = static_cast(base); self->res = res; @@ -127,12 +126,13 @@ struct uring_file_read_op_base : io_uring_op /// the impl owns this slot. struct uring_file_read_op : uring_file_read_op_base { - uring_file_read_op() noexcept - : uring_file_read_op_base(&do_handler) {} + uring_file_read_op() noexcept : uring_file_read_op_base(&do_handler) {} static void do_handler( - void* owner, scheduler_op* base, - std::uint32_t /*bytes*/, std::uint32_t /*error*/) noexcept + void* owner, + scheduler_op* base, + std::uint32_t /*bytes*/, + std::uint32_t /*error*/) noexcept { auto* self = static_cast(base); if (coro_drain_if_shutdown(owner, self)) @@ -155,11 +155,15 @@ struct uring_file_read_op : uring_file_read_op_base struct uring_random_access_read_op : uring_file_read_op_base { uring_random_access_read_op() noexcept - : uring_file_read_op_base(&do_handler) {} + : uring_file_read_op_base(&do_handler) + { + } static void do_handler( - void* owner, scheduler_op* base, - std::uint32_t /*bytes*/, std::uint32_t /*error*/) noexcept + void* owner, + scheduler_op* base, + std::uint32_t /*bytes*/, + std::uint32_t /*error*/) noexcept { auto* self = static_cast(base); self->stop_cb.reset(); @@ -187,16 +191,18 @@ struct uring_random_access_read_op : uring_file_read_op_base */ /// Shared state and submission logic for file write ops. Concrete /// subclasses pick a `do_handler` matching their storage model. -struct uring_file_write_op_base : io_uring_op +struct uring_file_write_op_base : uring_op { - iovec iovecs[io_uring_max_iov]; - int iovec_count = 0; - int fd = -1; - std::int64_t offset = -1; + iovec iovecs[uring_max_iov]; + int iovec_count = 0; + int fd = -1; + std::int64_t offset = -1; protected: explicit uring_file_write_op_base(func_type handler) noexcept - : io_uring_op(handler, &do_cqe, &do_prep) {} + : uring_op(handler, &do_cqe, &do_prep) + { + } public: /** Reset and initialize for a new submission. @@ -204,33 +210,33 @@ struct uring_file_write_op_base : io_uring_op See uring_file_read_op_base::prepare for the offset convention. */ void prepare( - std::coroutine_handle<> handle, - capy::executor_ref executor, - std::error_code* ec, - std::size_t* bytes, - int file_descriptor, - std::int64_t file_offset, - io_uring_scheduler* scheduler, - std::shared_ptr impl, - buffer_param buffers, - std::stop_token const& token) noexcept + std::coroutine_handle<> handle, + capy::executor_ref executor, + std::error_code* ec, + std::size_t* bytes, + int file_descriptor, + std::int64_t file_offset, + uring_scheduler* scheduler, + std::shared_ptr impl, + buffer_param buffers, + std::stop_token const& token) noexcept { - h = handle; - ex = executor; - ec_out = ec; - bytes_out = bytes; - fd = file_descriptor; - offset = file_offset; - sched_ = scheduler; - impl_ptr = std::move(impl); - res = 0; - cqe_flags = 0; - iovec_count = copy_to_iovec(buffers, iovecs); + h = handle; + ex = executor; + ec_out = ec; + bytes_out = bytes; + fd = file_descriptor; + offset = file_offset; + sched_ = scheduler; + impl_ptr = std::move(impl); + res = 0; + cqe_flags = 0; + iovec_count = copy_to_iovec(buffers, iovecs); empty_buffer = (iovec_count == 0); start(token); } - static void do_prep(io_uring_op* base, ::io_uring_sqe* sqe) noexcept + static void do_prep(uring_op* base, ::io_uring_sqe* sqe) noexcept { auto* self = static_cast(base); ::io_uring_prep_writev( @@ -238,9 +244,8 @@ struct uring_file_write_op_base : io_uring_op static_cast<__u64>(self->offset)); } - static void do_cqe( - io_uring_op* base, int res, unsigned flags, - ready_queue& local) noexcept + static void + do_cqe(uring_op* base, int res, unsigned flags, ready_queue& local) noexcept { auto* self = static_cast(base); self->res = res; @@ -263,12 +268,13 @@ struct uring_file_write_op_base : io_uring_op /// Embedded file write op for stream_file. struct uring_file_write_op : uring_file_write_op_base { - uring_file_write_op() noexcept - : uring_file_write_op_base(&do_handler) {} + uring_file_write_op() noexcept : uring_file_write_op_base(&do_handler) {} static void do_handler( - void* owner, scheduler_op* base, - std::uint32_t /*bytes*/, std::uint32_t /*error*/) noexcept + void* owner, + scheduler_op* base, + std::uint32_t /*bytes*/, + std::uint32_t /*error*/) noexcept { auto* self = static_cast(base); if (coro_drain_if_shutdown(owner, self)) @@ -289,11 +295,15 @@ struct uring_file_write_op : uring_file_write_op_base struct uring_random_access_write_op : uring_file_write_op_base { uring_random_access_write_op() noexcept - : uring_file_write_op_base(&do_handler) {} + : uring_file_write_op_base(&do_handler) + { + } static void do_handler( - void* owner, scheduler_op* base, - std::uint32_t /*bytes*/, std::uint32_t /*error*/) noexcept + void* owner, + scheduler_op* base, + std::uint32_t /*bytes*/, + std::uint32_t /*error*/) noexcept { auto* self = static_cast(base); self->stop_cb.reset(); @@ -312,6 +322,6 @@ struct uring_random_access_write_op : uring_file_write_op_base } // namespace boost::corosio::detail -#endif // BOOST_COROSIO_HAS_IO_URING +#endif // BOOST_COROSIO_HAS_URING -#endif // BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_FILE_OPS_HPP +#endif // BOOST_COROSIO_NATIVE_DETAIL_URING_URING_FILE_OPS_HPP diff --git a/include/boost/corosio/native/detail/io_uring/io_uring_file_service_base.hpp b/include/boost/corosio/native/detail/uring/uring_file_service_base.hpp similarity index 74% rename from include/boost/corosio/native/detail/io_uring/io_uring_file_service_base.hpp rename to include/boost/corosio/native/detail/uring/uring_file_service_base.hpp index e681f1a6c..2d9629839 100644 --- a/include/boost/corosio/native/detail/io_uring/io_uring_file_service_base.hpp +++ b/include/boost/corosio/native/detail/uring/uring_file_service_base.hpp @@ -7,16 +7,16 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_FILE_SERVICE_BASE_HPP -#define BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_FILE_SERVICE_BASE_HPP +#ifndef BOOST_COROSIO_NATIVE_DETAIL_URING_URING_FILE_SERVICE_BASE_HPP +#define BOOST_COROSIO_NATIVE_DETAIL_URING_URING_FILE_SERVICE_BASE_HPP #include -#if BOOST_COROSIO_HAS_IO_URING +#if BOOST_COROSIO_HAS_URING #include #include -#include +#include #include #include @@ -25,13 +25,13 @@ /* Shared lifecycle plumbing for io_uring file services. - io_uring_stream_file_service and io_uring_random_access_file_service were + uring_stream_file_service and uring_random_access_file_service were byte-for-byte identical apart from the impl type and open_file's parameter type: both make_shared the file impl from the scheduler, track it in an intrusive list + raw->shared_ptr map, and close every file on shutdown. This base factors that out; the concrete services add only open_file. - This is a separate base from io_uring_socket_service_base because file + This is a separate base from uring_socket_service_base because file services differ from socket services in three ways that match the reactor socket service instead: they track via an intrusive list + map (sockets: map only), they CLOSE files on shutdown (sockets: cancel only), and the @@ -39,7 +39,7 @@ tasks/proactor-dedup-decisions.md (#14). Requirements on File: derive from enable_shared_from_this and - intrusive_list::node, a `File(io_uring_scheduler&)` constructor, and + intrusive_list::node, a `File(uring_scheduler&)` constructor, and a `void close_file() noexcept` method (cancel in-flight ops + close fd). @tparam Derived The concrete service (CRTP; unused today but kept for @@ -52,24 +52,24 @@ namespace boost::corosio::detail { template -class io_uring_file_service_base : public ServiceBase +class uring_file_service_base : public ServiceBase { friend Derived; // Private CRTP ctor: only `Derived` (the concrete service, a friend) // constructs the base — prevents inheriting with the wrong Derived // (bugprone-crtp-constructor-accessibility). - explicit io_uring_file_service_base(io_uring_scheduler& sched) noexcept + explicit uring_file_service_base(uring_scheduler& sched) noexcept : sched_(&sched) { } public: - ~io_uring_file_service_base() override = default; + ~uring_file_service_base() override = default; io_object::implementation* construct() override { - auto ptr = std::make_shared(*sched_); + auto ptr = std::make_shared(*sched_); auto* impl = ptr.get(); { std::lock_guard lock(mutex_); @@ -107,22 +107,24 @@ class io_uring_file_service_base : public ServiceBase } /// Return the scheduler used by files created by this service. - io_uring_scheduler& scheduler() noexcept { return *sched_; } + uring_scheduler& scheduler() noexcept + { + return *sched_; + } protected: - io_uring_scheduler* sched_; - std::mutex mutex_; + uring_scheduler* sched_; + std::mutex mutex_; intrusive_list file_list_; std::unordered_map> file_ptrs_; private: - io_uring_file_service_base(io_uring_file_service_base const&) = delete; - io_uring_file_service_base& - operator=(io_uring_file_service_base const&) = delete; + uring_file_service_base(uring_file_service_base const&) = delete; + uring_file_service_base& operator=(uring_file_service_base const&) = delete; }; } // namespace boost::corosio::detail -#endif // BOOST_COROSIO_HAS_IO_URING +#endif // BOOST_COROSIO_HAS_URING -#endif // BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_FILE_SERVICE_BASE_HPP +#endif // BOOST_COROSIO_NATIVE_DETAIL_URING_URING_FILE_SERVICE_BASE_HPP diff --git a/include/boost/corosio/native/detail/io_uring/io_uring_multishot_acceptor.hpp b/include/boost/corosio/native/detail/uring/uring_multishot_acceptor.hpp similarity index 84% rename from include/boost/corosio/native/detail/io_uring/io_uring_multishot_acceptor.hpp rename to include/boost/corosio/native/detail/uring/uring_multishot_acceptor.hpp index 768b044c2..a0640e7b5 100644 --- a/include/boost/corosio/native/detail/io_uring/io_uring_multishot_acceptor.hpp +++ b/include/boost/corosio/native/detail/uring/uring_multishot_acceptor.hpp @@ -7,21 +7,21 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_MULTISHOT_ACCEPTOR_HPP -#define BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_MULTISHOT_ACCEPTOR_HPP +#ifndef BOOST_COROSIO_NATIVE_DETAIL_URING_URING_MULTISHOT_ACCEPTOR_HPP +#define BOOST_COROSIO_NATIVE_DETAIL_URING_URING_MULTISHOT_ACCEPTOR_HPP #include -#if BOOST_COROSIO_HAS_IO_URING +#if BOOST_COROSIO_HAS_URING #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include @@ -54,24 +54,24 @@ namespace boost::corosio::detail { inline bool fd_is_listening(int fd) noexcept { - int accepting = 0; - socklen_t alen = sizeof(accepting); + int accepting = 0; + socklen_t alen = sizeof(accepting); if (::getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &alen) != 0) return true; return accepting != 0; } template -class io_uring_multishot_acceptor_base +class uring_multishot_acceptor_base : public ImplBase , public std::enable_shared_from_this { protected: struct ready_fd_node : intrusive_list::node { - int fd = -1; - sockaddr_storage peer{}; - socklen_t peer_len = 0; + int fd = -1; + sockaddr_storage peer{}; + socklen_t peer_len = 0; }; struct waiter_node; @@ -84,42 +84,42 @@ class io_uring_multishot_acceptor_base struct waiter_node : intrusive_list::node { - std::coroutine_handle<> h; - capy::executor_ref ex; - std::error_code* ec_out = nullptr; - io_object::implementation** impl_out = nullptr; - Derived* owner = nullptr; - std::atomic cancelled{false}; + std::coroutine_handle<> h; + capy::executor_ref ex; + std::error_code* ec_out = nullptr; + io_object::implementation** impl_out = nullptr; + Derived* owner = nullptr; + std::atomic cancelled{false}; /// True once linked into `waiters_` (guarded by `mutex_`). /// The stop callback is armed before the node is queued, so /// cancel_waiter must not unlink a node it never queued. - bool queued = false; + bool queued = false; /// A readiness wait rather than an accept: completion /// observes a pending connection without consuming it. - bool peek = false; - std::optional> stop_cb; + bool peek = false; + std::optional> stop_cb; }; - int fd_ = -1; - io_uring_scheduler* sched_; - PeerService* peer_service_; - Endpoint local_endpoint_{}; - mutable std::mutex mutex_; - intrusive_list ready_fds_; - intrusive_list waiters_; + int fd_ = -1; + uring_scheduler* sched_; + PeerService* peer_service_; + Endpoint local_endpoint_{}; + mutable std::mutex mutex_; + intrusive_list ready_fds_; + intrusive_list waiters_; /// Single parked readiness wait (guarded by `mutex_`). Multishot /// accepting drains the kernel queue instantly, so a listener's /// readiness lives in `ready_fds_`, not in `poll()`; the wait is /// completed by the next delivery instead of a kernel poll. - waiter_node* read_wait_ = nullptr; - std::unique_ptr multi_op_; - bool closing_ = false; + waiter_node* read_wait_ = nullptr; + std::unique_ptr multi_op_; + bool closing_ = false; /// Non-zero once an arming failed to reach the kernel (guarded by /// `mutex_`). Nothing will ever deliver a connection through an /// SQE the ring never took, so an accept reports this instead of /// parking on a delivery that cannot come. Cleared by the next /// arming that does reach the kernel. - int arm_err_ = 0; + int arm_err_ = 0; /// Bumped whenever an arming is retired. A re-arm posted for an /// earlier generation must not resubmit: `multi_op_` now names a /// different op, and resubmitting a live one would alias a single @@ -127,22 +127,22 @@ class io_uring_multishot_acceptor_base /// not atomic with its submit — a retirement landing between them /// (concurrent `assign()` on another thread) can still double-arm; /// closing that needs a generation-aware submit. - std::atomic arm_generation_{0}; + std::atomic arm_generation_{0}; private: // CRTP ctor private + Derived friended so the base cannot be // constructed except as a CRTP base of Derived // (clang-tidy bugprone-crtp-constructor-accessibility). friend Derived; - io_uring_multishot_acceptor_base( - io_uring_scheduler& sched, PeerService& peer_svc) noexcept + uring_multishot_acceptor_base( + uring_scheduler& sched, PeerService& peer_svc) noexcept : sched_(&sched) , peer_service_(&peer_svc) - {} + { + } public: - - ~io_uring_multishot_acceptor_base() override + ~uring_multishot_acceptor_base() override { { std::lock_guard lk(mutex_); @@ -249,7 +249,7 @@ class io_uring_multishot_acceptor_base { w->stop_cb.reset(); // NOLINTNEXTLINE(bugprone-unhandled-exception-at-new) — noexcept destructor path: OOM => std::terminate is the intended behavior - auto* op = new uring_accept_op(); + auto* op = new uring_accept_op(); op->h = w->h; op->ex = w->ex; op->ec_out = w->ec_out; @@ -270,9 +270,9 @@ class io_uring_multishot_acceptor_base */ void park_read_wait( std::coroutine_handle<> h, - capy::executor_ref ex, - std::stop_token const& token, - std::error_code* ec) noexcept + capy::executor_ref ex, + std::stop_token const& token, + std::error_code* ec) noexcept { bool ready = false; bool aborted = false; @@ -316,7 +316,7 @@ class io_uring_multishot_acceptor_base w->stop_cb.emplace(token, waiter_canceller{w}); bool was_cancelled = false; - int arm_err = 0; + int arm_err = 0; { std::lock_guard lk(mutex_); if (w->cancelled.load(std::memory_order_acquire) || closing_) @@ -355,25 +355,29 @@ class io_uring_multishot_acceptor_base } std::error_code set_option( - int level, int optname, - void const* data, std::size_t size) noexcept override + int level, + int optname, + void const* data, + std::size_t size) noexcept override { - if (fd_ < 0) return make_err(EBADF); - if (::setsockopt(fd_, level, optname, - reinterpret_cast(data), + if (fd_ < 0) + return make_err(EBADF); + if (::setsockopt( + fd_, level, optname, reinterpret_cast(data), static_cast(size)) < 0) return make_err(errno); return {}; } - std::error_code get_option( - int level, int optname, - void* data, std::size_t* size) const noexcept override + std::error_code + get_option(int level, int optname, void* data, std::size_t* size) + const noexcept override { - if (fd_ < 0) return make_err(EBADF); + if (fd_ < 0) + return make_err(EBADF); socklen_t len = static_cast(*size); - if (::getsockopt(fd_, level, optname, - reinterpret_cast(data), &len) < 0) + if (::getsockopt( + fd_, level, optname, reinterpret_cast(data), &len) < 0) return make_err(errno); *size = static_cast(len); return {}; @@ -509,12 +513,11 @@ class io_uring_multishot_acceptor_base { if (!multi_op_) { - multi_op_ = std::make_unique(); - multi_op_->listen_fd = fd_; + multi_op_ = std::make_unique(); + multi_op_->listen_fd = fd_; multi_op_->acceptor_impl = this; - multi_op_->on_cqe = - &io_uring_multishot_acceptor_base::on_accept_cqe; - multi_op_->impl_ptr = this->shared_from_this(); + multi_op_->on_cqe = &uring_multishot_acceptor_base::on_accept_cqe; + multi_op_->impl_ptr = this->shared_from_this(); } else { @@ -538,7 +541,7 @@ class io_uring_multishot_acceptor_base // The try_ spelling is what says so: it keeps a failed submission // off the scheduler's completion queue, which spends a // work_finished() on everything it dispatches. - if (io_uring_try_submit_op(*sched_, op)) + if (uring_try_submit_op(*sched_, op)) { std::lock_guard lk(mutex_); arm_err_ = 0; @@ -599,7 +602,7 @@ class io_uring_multishot_acceptor_base op->err = err; delete w; sched_->post(op); - sched_->work_finished(); // balance the waiter's work_started + sched_->work_finished(); // balance the waiter's work_started } } @@ -607,20 +610,20 @@ class io_uring_multishot_acceptor_base /// Either case ends with the calling coroutine suspending; the /// caller returns `std::noop_coroutine()` unconditionally. void dispatch_or_queue( - std::coroutine_handle<> h, - capy::executor_ref ex, - std::stop_token const& token, - std::error_code* ec, + std::coroutine_handle<> h, + capy::executor_ref ex, + std::stop_token const& token, + std::error_code* ec, io_object::implementation** impl_out) { sockaddr_storage peer_storage{}; - socklen_t peer_len = sizeof(peer_storage); - int accepted_fd = ::accept4(fd_, - reinterpret_cast(&peer_storage), &peer_len, + socklen_t peer_len = sizeof(peer_storage); + int accepted_fd = ::accept4( + fd_, reinterpret_cast(&peer_storage), &peer_len, SOCK_NONBLOCK | SOCK_CLOEXEC); if (accepted_fd >= 0) { - auto* op = new uring_accept_op(); + auto* op = new uring_accept_op(); op->h = h; op->ex = ex; op->ec_out = ec; @@ -641,12 +644,12 @@ class io_uring_multishot_acceptor_base if (errno != EAGAIN && errno != EWOULDBLOCK) { int saved_errno = errno; - auto* op = new uring_accept_op(); - op->h = h; - op->ex = ex; - op->ec_out = ec; - op->impl_out = impl_out; - op->err = saved_errno; + auto* op = new uring_accept_op(); + op->h = h; + op->ex = ex; + op->ec_out = ec; + op->impl_out = impl_out; + op->err = saved_errno; sched_->post(op); return; } @@ -656,7 +659,7 @@ class io_uring_multishot_acceptor_base std::lock_guard lk(mutex_); if (auto* r = ready_fds_.pop_front()) { - ready_op = new uring_accept_op(); + ready_op = new uring_accept_op(); ready_op->h = h; ready_op->ex = ex; ready_op->ec_out = ec; @@ -706,7 +709,7 @@ class io_uring_multishot_acceptor_base { // A connection arrived while the callback was armed; // prefer it over parking the waiter behind it. - ready_op = new uring_accept_op(); + ready_op = new uring_accept_op(); ready_op->h = h; ready_op->ex = ex; ready_op->ec_out = ec; @@ -762,14 +765,15 @@ class io_uring_multishot_acceptor_base { { std::lock_guard lk(mutex_); - if (closing_) return; // on_accept_cqe_impl will drain with closing_ set + if (closing_) + return; // on_accept_cqe_impl will drain with closing_ set if (!w->queued) - return; // not queued yet; the parking path observes - // `cancelled` and completes the op + return; // not queued yet; the parking path observes + // `cancelled` and completes the op if (w->peek) { if (read_wait_ != w) - return; // already claimed by a delivery + return; // already claimed by a delivery read_wait_ = nullptr; } else @@ -778,7 +782,7 @@ class io_uring_multishot_acceptor_base } } // NOLINTNEXTLINE(bugprone-unhandled-exception-at-new) — stop-token callback: noexcept, OOM => std::terminate is the intended behavior - auto* op = new uring_accept_op(); + auto* op = new uring_accept_op(); op->h = w->h; op->ex = w->ex; op->ec_out = w->ec_out; @@ -788,22 +792,21 @@ class io_uring_multishot_acceptor_base // post() increments outstanding_work_; balances the work_started() // from accept() when the waiter was queued. sched_->post(op); - sched_->work_finished(); // balance the work_started() from accept() + sched_->work_finished(); // balance the work_started() from accept() } private: - static void on_accept_cqe( - void* self_ptr, int new_fd, int err, bool more) noexcept + static void + on_accept_cqe(void* self_ptr, int new_fd, int err, bool more) noexcept { - static_cast(self_ptr) - ->on_accept_cqe_impl(new_fd, err, more); + static_cast(self_ptr)->on_accept_cqe_impl(new_fd, err, more); } protected: void on_accept_cqe_impl(int new_fd, int err, bool more) noexcept { - bool was_closing = false; - waiter_node* matched = nullptr; + bool was_closing = false; + waiter_node* matched = nullptr; waiter_node* claimed_peek = nullptr; intrusive_list closing_waiters; { @@ -857,10 +860,10 @@ class io_uring_multishot_acceptor_base else if (new_fd >= 0) { // NOLINTNEXTLINE(bugprone-unhandled-exception-at-new) — CQE handler: noexcept, OOM => std::terminate is the intended behavior - auto* node = new ready_fd_node{}; - node->fd = new_fd; - node->peer = multi_op_->peer_storage; - node->peer_len = multi_op_->peer_len; + auto* node = new ready_fd_node{}; + node->fd = new_fd; + node->peer = multi_op_->peer_storage; + node->peer_len = multi_op_->peer_len; ready_fds_.push_back(node); } } @@ -875,7 +878,7 @@ class io_uring_multishot_acceptor_base op->ec_out = claimed_peek->ec_out; delete claimed_peek; sched_->post(op); - sched_->work_finished(); // balance the parking work_started + sched_->work_finished(); // balance the parking work_started } if (matched) @@ -901,14 +904,14 @@ class io_uring_multishot_acceptor_base } delete matched; sched_->post(op); - sched_->work_finished(); // balance waiter's work_started + sched_->work_finished(); // balance waiter's work_started } while (auto* w = closing_waiters.pop_front()) { w->stop_cb.reset(); // NOLINTNEXTLINE(bugprone-unhandled-exception-at-new) — CQE handler shutdown path: noexcept, OOM => std::terminate is the intended behavior - auto* op = new uring_accept_op(); + auto* op = new uring_accept_op(); op->h = w->h; op->ex = w->ex; op->ec_out = w->ec_out; @@ -916,7 +919,7 @@ class io_uring_multishot_acceptor_base op->cancelled.store(true, std::memory_order_release); delete w; sched_->post(op); - sched_->work_finished(); // balance waiter's work_started + sched_->work_finished(); // balance waiter's work_started } if (!more && !was_closing) @@ -925,12 +928,14 @@ class io_uring_multishot_acceptor_base struct rearm_op final : scheduler_op { std::shared_ptr self_; - std::uint64_t generation_; + std::uint64_t generation_; rearm_op( std::shared_ptr s, - std::uint64_t generation) noexcept + std::uint64_t generation) noexcept : self_(std::move(s)) - , generation_(generation) {} + , generation_(generation) + { + } void operator()() override { @@ -954,7 +959,10 @@ class io_uring_multishot_acceptor_base self->start_multishot(); } - void destroy() override { delete this; } + void destroy() override + { + delete this; + } }; // NOLINTNEXTLINE(bugprone-unhandled-exception-at-new) — CQE handler re-arm: noexcept, OOM => std::terminate is the intended behavior sched_->post(new rearm_op( @@ -966,8 +974,8 @@ class io_uring_multishot_acceptor_base template inline void -io_uring_multishot_acceptor_base - ::waiter_canceller::operator()() const noexcept +uring_multishot_acceptor_base:: + waiter_canceller::operator()() const noexcept { if (w->cancelled.exchange(true, std::memory_order_acq_rel)) return; @@ -976,6 +984,6 @@ io_uring_multishot_acceptor_base } // namespace boost::corosio::detail -#endif // BOOST_COROSIO_HAS_IO_URING +#endif // BOOST_COROSIO_HAS_URING -#endif // BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_MULTISHOT_ACCEPTOR_HPP +#endif // BOOST_COROSIO_NATIVE_DETAIL_URING_URING_MULTISHOT_ACCEPTOR_HPP diff --git a/include/boost/corosio/native/detail/io_uring/io_uring_op.hpp b/include/boost/corosio/native/detail/uring/uring_op.hpp similarity index 70% rename from include/boost/corosio/native/detail/io_uring/io_uring_op.hpp rename to include/boost/corosio/native/detail/uring/uring_op.hpp index 5f9e044ac..2128731de 100644 --- a/include/boost/corosio/native/detail/io_uring/io_uring_op.hpp +++ b/include/boost/corosio/native/detail/uring/uring_op.hpp @@ -7,18 +7,20 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_OP_HPP -#define BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_OP_HPP +#ifndef BOOST_COROSIO_NATIVE_DETAIL_URING_URING_OP_HPP +#define BOOST_COROSIO_NATIVE_DETAIL_URING_URING_OP_HPP #include -#if BOOST_COROSIO_HAS_IO_URING +#if BOOST_COROSIO_HAS_URING #include #include -// Forward declare to avoid circular include with io_uring_scheduler.hpp. -namespace boost::corosio::detail { class io_uring_scheduler; } +// Forward declare to avoid circular include with uring_scheduler.hpp. +namespace boost::corosio::detail { +class uring_scheduler; +} // namespace boost::corosio::detail #include @@ -36,70 +38,73 @@ namespace boost::corosio::detail { pointers the run loop uses to prep an SQE and dispatch a CQE without template instantiation. */ -struct io_uring_op : coro_op +struct uring_op : coro_op { /// CQE-side dispatcher type. Called once per completion event. /// Pushes self into `local` rather than dispatching inline so /// process_completions can splice the batch into completed_ops_ /// atomically and do_one dispatches one handler at a time. - using cqe_func_type = - void (*)(io_uring_op*, int res, unsigned flags, ready_queue& local) noexcept; + using cqe_func_type = void (*)( + uring_op*, int res, unsigned flags, ready_queue& local) noexcept; /// SQE-preparation dispatcher type. Called by the leader during /// its drain step to fill an SQE for this op. Concrete op types /// set this at construction so the new submit path is purely /// data-driven (no template instantiation, no allocation). - using prep_func_type = - void (*)(io_uring_op*, ::io_uring_sqe*) noexcept; + using prep_func_type = void (*)(uring_op*, ::io_uring_sqe*) noexcept; /// Retired-CQE dispatcher type. Called in place of `cqe_func` once /// the op is retired, so the op type can release whatever `res` /// owns (an accepted descriptor, a registered buffer) that no /// handler will now take delivery of. using retire_func_type = - void (*)(io_uring_op*, int res, unsigned flags) noexcept; + void (*)(uring_op*, int res, unsigned flags) noexcept; - explicit io_uring_op( - func_type post_func, - cqe_func_type cqe_fn, + explicit uring_op( + func_type post_func, + cqe_func_type cqe_fn, prep_func_type prep_fn = nullptr) noexcept : coro_op(post_func) , cqe_func(cqe_fn) , prep_func(prep_fn) - {} + { + } - int res = 0; - unsigned cqe_flags = 0; + int res = 0; + unsigned cqe_flags = 0; /// True after `io_uring_sqe_set_data` has linked an SQE to this op. /// Until then, on_cancel() has nothing for the kernel to find. - std::atomic sqe_set{false}; - cqe_func_type cqe_func; + std::atomic sqe_set{false}; + cqe_func_type cqe_func; /// SQE-preparation dispatcher. nullptr for ops still using the - /// old `io_uring_submit_op(prep)` template path + /// old `uring_submit_op(prep)` template path /// (UDP/local/file/dgram during plan 5a). Set non-null by ops /// migrated to the queue-based submit path. - prep_func_type prep_func; + prep_func_type prep_func; /// Scheduler reference for submitting cancel SQEs on stop_token. - io_uring_scheduler* sched_ = nullptr; + uring_scheduler* sched_ = nullptr; /// Set when the op's owner went away while the kernel still held - /// its user_data (see `io_uring_scheduler::retire_op`). A retired + /// its user_data (see `uring_scheduler::retire_op`). A retired /// op belongs to the scheduler: the run loop routes its CQEs to /// `retire_func` instead of `cqe_func` and frees the op on the /// terminal CQE. - bool retired = false; + bool retired = false; /// Disposal hook used while `retired` is set. May be null when the /// op's result owns nothing. - retire_func_type retire_func = nullptr; + retire_func_type retire_func = nullptr; /// Bridge virtual dispatch to func-pointer dispatch. Lets the run /// loop dispatch any scheduler_op via `(*op)()` — both reactor-style /// services posted into the queue and proactor-style io_uring ops. /// `owner` is non-null per scheduler_op's completion-vs-destroy /// convention (see scheduler_op.hpp). - void operator()() override { complete(this, 0, 0); } + void operator()() override + { + complete(this, 0, 0); + } /// Arm the stop-token callback. Must be called before the SQE submits. /// Extends coro_op::start to also clear the ring-cancel flag. @@ -116,6 +121,6 @@ struct io_uring_op : coro_op } // namespace boost::corosio::detail -#endif // BOOST_COROSIO_HAS_IO_URING +#endif // BOOST_COROSIO_HAS_URING -#endif // BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_OP_HPP +#endif // BOOST_COROSIO_NATIVE_DETAIL_URING_URING_OP_HPP diff --git a/include/boost/corosio/native/detail/io_uring/io_uring_random_access_file.hpp b/include/boost/corosio/native/detail/uring/uring_random_access_file.hpp similarity index 68% rename from include/boost/corosio/native/detail/io_uring/io_uring_random_access_file.hpp rename to include/boost/corosio/native/detail/uring/uring_random_access_file.hpp index 134a4560d..b5baaa446 100644 --- a/include/boost/corosio/native/detail/io_uring/io_uring_random_access_file.hpp +++ b/include/boost/corosio/native/detail/uring/uring_random_access_file.hpp @@ -7,18 +7,18 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_RANDOM_ACCESS_FILE_HPP -#define BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_RANDOM_ACCESS_FILE_HPP +#ifndef BOOST_COROSIO_NATIVE_DETAIL_URING_URING_RANDOM_ACCESS_FILE_HPP +#define BOOST_COROSIO_NATIVE_DETAIL_URING_URING_RANDOM_ACCESS_FILE_HPP #include -#if BOOST_COROSIO_HAS_IO_URING +#if BOOST_COROSIO_HAS_URING #include #include -#include -#include -#include +#include +#include +#include #include #include @@ -37,7 +37,7 @@ namespace boost::corosio::detail { -class io_uring_random_access_file_service; +class uring_random_access_file_service; /** Native io_uring random-access-file implementation. @@ -52,15 +52,15 @@ class io_uring_random_access_file_service; submissions at the same offset is unspecified at the kernel level (matches POSIX `pread(2)` / `pwrite(2)` semantics). */ -class BOOST_COROSIO_DECL io_uring_random_access_file final +class BOOST_COROSIO_DECL uring_random_access_file final : public random_access_file::implementation - , public std::enable_shared_from_this - , public intrusive_list::node + , public std::enable_shared_from_this + , public intrusive_list::node { - friend class io_uring_random_access_file_service; + friend class uring_random_access_file_service; - int fd_ = -1; - io_uring_scheduler* sched_ = nullptr; + int fd_ = -1; + uring_scheduler* sched_ = nullptr; // Random-access files legitimately support concurrent ops at // different offsets on the same fd (e.g. parallel reads in @@ -68,11 +68,12 @@ class BOOST_COROSIO_DECL io_uring_random_access_file final // state across calls; ops are heap-allocated per submission. public: - explicit io_uring_random_access_file(io_uring_scheduler& sched) noexcept + explicit uring_random_access_file(uring_scheduler& sched) noexcept : sched_(&sched) - {} + { + } - ~io_uring_random_access_file() override + ~uring_random_access_file() override { close_file(); } @@ -112,15 +113,14 @@ class BOOST_COROSIO_DECL io_uring_random_access_file final { struct stat st; if (::fstat(fd_, &st) < 0) - throw_system_error( - make_err(errno), "random_access_file::size"); + throw_system_error(make_err(errno), "random_access_file::size"); return static_cast(st.st_size); } std::error_code resize(std::uint64_t new_size) noexcept override { - if (new_size > static_cast( - (std::numeric_limits::max)())) + if (new_size > + static_cast((std::numeric_limits::max)())) return make_err(EOVERFLOW); if (::ftruncate(fd_, static_cast(new_size)) < 0) return make_err(errno); @@ -148,7 +148,7 @@ class BOOST_COROSIO_DECL io_uring_random_access_file final native_handle_type release() override { int fd = fd_; - fd_ = -1; + fd_ = -1; return fd; } @@ -162,12 +162,12 @@ class BOOST_COROSIO_DECL io_uring_random_access_file final // -- Internal -- /// Open the file. Synchronous; sets `fd_`. Caller is the service. - std::error_code open_file( - std::filesystem::path const& path, file_base::flags mode) + std::error_code + open_file(std::filesystem::path const& path, file_base::flags mode) { close_file(); - int oflags = 0; + int oflags = 0; unsigned access = static_cast(mode) & 3u; if (access == static_cast(file_base::read_write)) oflags |= O_RDWR; @@ -219,19 +219,19 @@ class BOOST_COROSIO_DECL io_uring_random_access_file final }; inline std::coroutine_handle<> -io_uring_random_access_file::read_some_at( - std::uint64_t user_offset, +uring_random_access_file::read_some_at( + std::uint64_t user_offset, std::coroutine_handle<> h, - capy::executor_ref ex, - buffer_param buffers, - std::stop_token token, - std::error_code* ec, - std::size_t* bytes) + capy::executor_ref ex, + buffer_param buffers, + std::stop_token token, + std::error_code* ec, + std::size_t* bytes) { auto op_guard = std::make_unique(); - op_guard->prepare(h, ex, ec, bytes, fd_, - static_cast(user_offset), - sched_, shared_from_this(), buffers, token); + op_guard->prepare( + h, ex, ec, bytes, fd_, static_cast(user_offset), sched_, + shared_from_this(), buffers, token); sched_->work_started(); // Closed-object contract outranks the zero-length no-op. @@ -239,7 +239,7 @@ io_uring_random_access_file::read_some_at( { op_guard->empty_buffer = false; op_guard->res = -EBADF; - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(op_guard.release()); return std::noop_coroutine(); } @@ -247,29 +247,29 @@ io_uring_random_access_file::read_some_at( if (op_guard->empty_buffer || op_guard->cancelled.load(std::memory_order_acquire)) { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(op_guard.release()); return std::noop_coroutine(); } - io_uring_submit_op(*sched_, op_guard.release()); + uring_submit_op(*sched_, op_guard.release()); return std::noop_coroutine(); } inline std::coroutine_handle<> -io_uring_random_access_file::write_some_at( - std::uint64_t user_offset, +uring_random_access_file::write_some_at( + std::uint64_t user_offset, std::coroutine_handle<> h, - capy::executor_ref ex, - buffer_param buffers, - std::stop_token token, - std::error_code* ec, - std::size_t* bytes) + capy::executor_ref ex, + buffer_param buffers, + std::stop_token token, + std::error_code* ec, + std::size_t* bytes) { auto op_guard = std::make_unique(); - op_guard->prepare(h, ex, ec, bytes, fd_, - static_cast(user_offset), - sched_, shared_from_this(), buffers, token); + op_guard->prepare( + h, ex, ec, bytes, fd_, static_cast(user_offset), sched_, + shared_from_this(), buffers, token); sched_->work_started(); // Closed-object contract outranks the zero-length no-op. @@ -277,7 +277,7 @@ io_uring_random_access_file::write_some_at( { op_guard->empty_buffer = false; op_guard->res = -EBADF; - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(op_guard.release()); return std::noop_coroutine(); } @@ -285,54 +285,55 @@ io_uring_random_access_file::write_some_at( if (op_guard->empty_buffer || op_guard->cancelled.load(std::memory_order_acquire)) { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(op_guard.release()); return std::noop_coroutine(); } - io_uring_submit_op(*sched_, op_guard.release()); + uring_submit_op(*sched_, op_guard.release()); return std::noop_coroutine(); } /** Native io_uring random-access-file service. - Owns all `io_uring_random_access_file` impls. Replaces + Owns all `uring_random_access_file` impls. Replaces `posix_random_access_file_service` for the io_uring backend; registered under the abstract `random_access_file_service` key - by `io_uring_t::construct`. + by `uring_t::construct`. */ -class BOOST_COROSIO_DECL io_uring_random_access_file_service final - : public io_uring_file_service_base< - io_uring_random_access_file_service, +class BOOST_COROSIO_DECL uring_random_access_file_service final + : public uring_file_service_base< + uring_random_access_file_service, random_access_file_service, - io_uring_random_access_file> + uring_random_access_file> { - using base_service = io_uring_file_service_base< - io_uring_random_access_file_service, + using base_service = uring_file_service_base< + uring_random_access_file_service, random_access_file_service, - io_uring_random_access_file>; + uring_random_access_file>; public: - explicit io_uring_random_access_file_service( - capy::execution_context& /*ctx*/, io_uring_scheduler& sched) + explicit uring_random_access_file_service( + capy::execution_context& /*ctx*/, uring_scheduler& sched) : base_service(sched) - {} + { + } // construct / destroy / close / shutdown / scheduler() are inherited - // from io_uring_file_service_base. + // from uring_file_service_base. std::error_code open_file( random_access_file::implementation& impl, std::filesystem::path const& path, file_base::flags mode) override { - return static_cast(impl).open_file( + return static_cast(impl).open_file( path, mode); } }; } // namespace boost::corosio::detail -#endif // BOOST_COROSIO_HAS_IO_URING +#endif // BOOST_COROSIO_HAS_URING -#endif // BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_RANDOM_ACCESS_FILE_HPP +#endif // BOOST_COROSIO_NATIVE_DETAIL_URING_URING_RANDOM_ACCESS_FILE_HPP diff --git a/include/boost/corosio/native/detail/io_uring/io_uring_scheduler.hpp b/include/boost/corosio/native/detail/uring/uring_scheduler.hpp similarity index 86% rename from include/boost/corosio/native/detail/io_uring/io_uring_scheduler.hpp rename to include/boost/corosio/native/detail/uring/uring_scheduler.hpp index 7bdb85bf0..8425d0dfe 100644 --- a/include/boost/corosio/native/detail/io_uring/io_uring_scheduler.hpp +++ b/include/boost/corosio/native/detail/uring/uring_scheduler.hpp @@ -8,15 +8,15 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_SCHEDULER_HPP -#define BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_SCHEDULER_HPP +#ifndef BOOST_COROSIO_NATIVE_DETAIL_URING_URING_SCHEDULER_HPP +#define BOOST_COROSIO_NATIVE_DETAIL_URING_URING_SCHEDULER_HPP #include -#if BOOST_COROSIO_HAS_IO_URING +#if BOOST_COROSIO_HAS_URING // Include before any project headers open a namespace — prevents the -// boost::corosio::io_uring tag variable from shadowing struct ::io_uring. +// boost::corosio::uring tag variable from shadowing struct ::io_uring. #include #include @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include @@ -105,8 +105,8 @@ class scoped_sigpipe_block // Forward-declared so the out-of-line inline definitions below the class // can reference the frame stack without a circular dependency. -struct io_uring_scheduler_frame; -extern thread_local io_uring_scheduler_frame* tl_running_scheduler_frame_; +struct uring_scheduler_frame; +extern thread_local uring_scheduler_frame* tl_running_scheduler_frame_; /** io_uring scheduler — proactor model on Linux 6.x+. @@ -117,7 +117,7 @@ extern thread_local io_uring_scheduler_frame* tl_running_scheduler_frame_; @par Thread Safety All public member functions are thread-safe. */ -class BOOST_COROSIO_DECL io_uring_scheduler final +class BOOST_COROSIO_DECL uring_scheduler final : public scheduler , public capy::execution_context::service { @@ -127,10 +127,10 @@ class BOOST_COROSIO_DECL io_uring_scheduler final using lock_type = mutex_type::scoped_lock; using event_type = conditionally_enabled_event; - io_uring_scheduler(capy::execution_context& ctx, int concurrency_hint = -1); - ~io_uring_scheduler() override; - io_uring_scheduler(io_uring_scheduler const&) = delete; - io_uring_scheduler& operator=(io_uring_scheduler const&) = delete; + uring_scheduler(capy::execution_context& ctx, int concurrency_hint = -1); + ~uring_scheduler() override; + uring_scheduler(uring_scheduler const&) = delete; + uring_scheduler& operator=(uring_scheduler const&) = delete; void shutdown() override; @@ -153,13 +153,12 @@ class BOOST_COROSIO_DECL io_uring_scheduler final /// Watch the read end of the POSIX signal self-pipe (see scheduler.hpp). /// Submits a multishot POLL on @p read_fd; on readiness the drain+deliver /// runs in dispatch context via signal_drain_op_. - [[nodiscard]] std::error_code - register_signal_reader(int read_fd) override; + [[nodiscard]] std::error_code register_signal_reader(int read_fd) override; /** Return the underlying liburing ring. Triggers lazy ring initialisation on first call. Used by - socket op submission helpers (e.g. `io_uring_submit_op`) and + socket op submission helpers (e.g. `uring_submit_op`) and any other code path that needs a live ring pointer. */ struct ::io_uring* ring() noexcept @@ -169,10 +168,16 @@ class BOOST_COROSIO_DECL io_uring_scheduler final } /// Return the dispatch mutex (protects completed_ops_ / cond_). - mutex_type& dispatch_mutex() const noexcept { return dispatch_mutex_; } + mutex_type& dispatch_mutex() const noexcept + { + return dispatch_mutex_; + } /// Return the ring mutex (serialises userspace SQ/CQ access). - mutex_type& ring_mutex() const noexcept { return ring_mutex_; } + mutex_type& ring_mutex() const noexcept + { + return ring_mutex_; + } /** Reset the calling thread's inline-budget for this scheduler. @@ -196,7 +201,7 @@ class BOOST_COROSIO_DECL io_uring_scheduler final /// and the mutex provides the read-modify-write atomicity. bool submit_op_posted_exchange(bool desired) const noexcept { - bool prev = submit_op_posted_; + bool prev = submit_op_posted_; submit_op_posted_ = desired; return prev; } @@ -213,12 +218,12 @@ class BOOST_COROSIO_DECL io_uring_scheduler final /// progress doesn't depend on userspace getevents. void inflight_inc() const noexcept { - io_uring_inflight_.fetch_add(1, std::memory_order_release); + uring_inflight_.fetch_add(1, std::memory_order_release); } /** Return the current io_uring in-flight counter. - Test-only helper: `io_uring_inflight_` is an internal accounting + Test-only helper: `uring_inflight_` is an internal accounting counter (it gates the `do_one` ring pump), with no bearing on the public API. It is exposed solely so tests can assert the counter stays balanced across op submission and teardown — in particular @@ -230,7 +235,7 @@ class BOOST_COROSIO_DECL io_uring_scheduler final */ std::int64_t inflight() const noexcept { - return io_uring_inflight_.load(std::memory_order_acquire); + return uring_inflight_.load(std::memory_order_acquire); } /// Initialize the io_uring ring on first access. Idempotent. @@ -272,7 +277,7 @@ class BOOST_COROSIO_DECL io_uring_scheduler final @param target The in-flight op to cancel. */ - void submit_cancel_by_user_data(io_uring_op* target) noexcept; + void submit_cancel_by_user_data(uring_op* target) noexcept; /** Submit `IORING_OP_ASYNC_CANCEL` with `IORING_ASYNC_CANCEL_FD` to cancel every in-flight op on the given fd in one SQE. @@ -383,7 +388,7 @@ class BOOST_COROSIO_DECL io_uring_scheduler final @param target The op pointer used as user_data on the SQE. */ - void drain_cqes_for(io_uring_op* target) noexcept; + void drain_cqes_for(uring_op* target) noexcept; /** Queue an already-counted op while the caller holds dispatch_mutex_. @@ -427,8 +432,7 @@ class BOOST_COROSIO_DECL io_uring_scheduler final @param cpu Pin the polling thread to this CPU; -1 to not pin. */ - void configure_sqpoll( - bool enable, unsigned idle_ms, int cpu) noexcept + void configure_sqpoll(bool enable, unsigned idle_ms, int cpu) noexcept { enable_sqpoll_ = enable; sq_thread_idle_ms_ = idle_ms; @@ -444,9 +448,9 @@ class BOOST_COROSIO_DECL io_uring_scheduler final private: // ring_ + wakeup_eventfd_ are mutable so lazy_init_ring() (called // from const contexts like post()) can populate them on first use. - mutable struct ::io_uring ring_{}; - mutable int wakeup_eventfd_ = -1; - timer_service* timer_svc_ = nullptr; + mutable struct ::io_uring ring_{}; + mutable int wakeup_eventfd_ = -1; + timer_service* timer_svc_ = nullptr; // dispatch_mutex_ protects completed_ops_, cond_, task_running_. // ring_mutex_ protects every userspace touch of ring_ (SQ tail, @@ -457,15 +461,15 @@ class BOOST_COROSIO_DECL io_uring_scheduler final // dispatch_mutex_ to splice into completed_ops_. The locks are // never held simultaneously for the full duration of any other // path's critical section, so no deadlock. - mutable mutex_type dispatch_mutex_{true}; - mutable mutex_type ring_mutex_{true}; - mutable event_type cond_{true}; - mutable ready_queue completed_ops_; - // outstanding_work_ and io_uring_inflight_ are both atomic + mutable mutex_type dispatch_mutex_{true}; + mutable mutex_type ring_mutex_{true}; + mutable event_type cond_{true}; + mutable ready_queue completed_ops_; + // outstanding_work_ and uring_inflight_ are both atomic // counters updated at high frequency on different paths: // - outstanding_work_ : every work_started / work_finished call, // including timers, posts, and SQE submits. - // - io_uring_inflight_ : only SQE submit + non-F_MORE CQE consume. + // - uring_inflight_ : only SQE submit + non-F_MORE CQE consume. // Under multi-thread workloads the threads tend to update these // from different code paths; placing them on the same cache line // would cause false sharing and unnecessary cache-line ping-pong. @@ -475,21 +479,21 @@ class BOOST_COROSIO_DECL io_uring_scheduler final // space to enter the kernel via IORING_ENTER_GETEVENTS for task // work to progress under IORING_SETUP_DEFER_TASKRUN. Excludes the // wakeup-eventfd multishot poll (registered in lazy_init_ring), and - // is updated by io_uring_submit_op and by process_completions on + // is updated by uring_submit_op and by process_completions on // each non-F_MORE, non-eventfd CQE. Used by do_one to skip the // ring pump when there is no io_uring work pending. - alignas(64) mutable std::atomic io_uring_inflight_{0}; - std::atomic stopped_{false}; + alignas(64) mutable std::atomic uring_inflight_{0}; + std::atomic stopped_{false}; // Leader-follower flag: true while a thread is blocked in // io_uring_submit_and_wait_timeout. Protected by dispatch_mutex_. - mutable bool task_running_ = false; - bool scheduler_locking_disabled_ = false; - bool reactor_io_locking_ = true; - bool enable_sqpoll_ = false; - unsigned sq_thread_idle_ms_ = 0; - int sq_thread_cpu_ = -1; + mutable bool task_running_ = false; + bool scheduler_locking_disabled_ = false; + bool reactor_io_locking_ = true; + bool enable_sqpoll_ = false; + unsigned sq_thread_idle_ms_ = 0; + int sq_thread_cpu_ = -1; - int cancel_sentinel_ = 0; + int cancel_sentinel_ = 0; // Ops adopted by retire_op, kept alive so the kernel never sees // their user_data reused. Declared before ring_ is exited only in @@ -499,11 +503,11 @@ class BOOST_COROSIO_DECL io_uring_scheduler final // A plain std::mutex (not the conditionally-enabled mutex_type): // retirement happens on user threads regardless of the threading // configuration. Leaf lock — nothing else is taken under it. - mutable std::mutex retired_mutex_; - std::vector> retired_ops_; + mutable std::mutex retired_mutex_; + std::vector> retired_ops_; /// Free a retired op once its terminal CQE has been consumed. - void release_retired_op(io_uring_op* op) noexcept; + void release_retired_op(uring_op* op) noexcept; // Signal self-pipe integration. The read end is watched via a multishot // POLL SQE tagged with &signal_pipe_sentinel_ (distinct from nullptr = @@ -511,8 +515,8 @@ class BOOST_COROSIO_DECL io_uring_scheduler final // needed and enqueue signal_drain_op_ so the drain+deliver runs in // dispatch context — never under ring_mutex_ — keeping deliver_signal's // mutex locking off the ring critical section. - int signal_pipe_read_fd_ = -1; - int signal_pipe_sentinel_ = 0; + int signal_pipe_read_fd_ = -1; + int signal_pipe_sentinel_ = 0; /// Dispatch-context op that drains the signal self-pipe and delivers each /// pending signal. Enqueued (once at a time, guarded by queued_) from @@ -532,7 +536,7 @@ class BOOST_COROSIO_DECL io_uring_scheduler final void destroy() override {} }; - mutable signal_drain_op signal_drain_op_; + mutable signal_drain_op signal_drain_op_; /// Flushes the SQ ring and drains CQEs in one mutex-held pass. /// One instance covers a whole batch; subsequent SQEs in the same @@ -540,44 +544,45 @@ class BOOST_COROSIO_DECL io_uring_scheduler final /// Mirrors Asio's `submit_sqes_op` (`io_uring_service.ipp:730-742`). struct submit_sqes_op final : scheduler_op { - io_uring_scheduler* sched_ = nullptr; + uring_scheduler* sched_ = nullptr; submit_sqes_op() noexcept : scheduler_op(&do_handler) {} static void do_handler( - void* owner, scheduler_op* base, - std::uint32_t /*bytes*/, std::uint32_t /*error*/) noexcept; + void* owner, + scheduler_op* base, + std::uint32_t /*bytes*/, + std::uint32_t /*error*/) noexcept; }; /// True between the first submitter of a batch posting `submit_op_` /// and the dispatched op clearing the flag inside its handler. Read /// and written only while holding `ring_mutex_`. - mutable bool submit_op_posted_ = false; + mutable bool submit_op_posted_ = false; /// Single embedded `submit_sqes_op` instance, owned by the scheduler. - mutable submit_sqes_op submit_op_; + mutable submit_sqes_op submit_op_; // drain_cqes_for tuning. The bound exists to avoid stalling a // destructor if the kernel never returns a cancel completion (best- // effort drain); 8 rounds * 1ms == 8ms worst case. - static constexpr int drain_cqes_max_rounds = 8; - static constexpr unsigned long drain_cqes_kick_ns = 1'000'000; + static constexpr int drain_cqes_max_rounds = 8; + static constexpr unsigned long drain_cqes_kick_ns = 1'000'000; // ring_inited_ goes true once the ring exists. The init is deferred // from the constructor so configure_threading() and configure_sqpoll() // can take effect before io_uring_queue_init_params chooses flags. - mutable std::once_flag ring_init_once_; - mutable bool ring_inited_ = false; + mutable std::once_flag ring_init_once_; + mutable bool ring_inited_ = false; std::size_t do_one(long timeout_us); - void process_completions(); - void drain_wakeup_eventfd() const noexcept; - bool prep_multishot_poll(int fd, void* data) noexcept; - void lazy_init_ring_unlocked() const; + void process_completions(); + void drain_wakeup_eventfd() const noexcept; + bool prep_multishot_poll(int fd, void* data) noexcept; + void lazy_init_ring_unlocked() const; }; -inline -io_uring_scheduler::io_uring_scheduler( +inline uring_scheduler::uring_scheduler( capy::execution_context& ctx, int /*concurrency_hint*/) { // sched_ cannot be set in the member initialiser — `this` is not @@ -589,7 +594,7 @@ io_uring_scheduler::io_uring_scheduler( timer_svc_ = &get_timer_service(ctx, *this); timer_svc_->set_on_earliest_changed( timer_service::callback(this, [](void* p) { - static_cast(p)->interrupt_reactor(); + static_cast(p)->interrupt_reactor(); })); get_resolver_service(ctx, *this); @@ -603,8 +608,7 @@ io_uring_scheduler::io_uring_scheduler( // scheduler used without one. } -inline -io_uring_scheduler::~io_uring_scheduler() +inline uring_scheduler::~uring_scheduler() { if (ring_inited_) { @@ -618,15 +622,13 @@ io_uring_scheduler::~io_uring_scheduler() } inline void -io_uring_scheduler::lazy_init_ring() const +uring_scheduler::lazy_init_ring() const { - std::call_once(ring_init_once_, [this] { - lazy_init_ring_unlocked(); - }); + std::call_once(ring_init_once_, [this] { lazy_init_ring_unlocked(); }); } inline void -io_uring_scheduler::lazy_init_ring_unlocked() const +uring_scheduler::lazy_init_ring_unlocked() const { io_uring_params params{}; // The unsafe_io and unsafe tiers guarantee a single ring submitter. @@ -684,8 +686,7 @@ io_uring_scheduler::lazy_init_ring_unlocked() const int rc = ::io_uring_queue_init_params(256, &ring_, ¶ms); if (rc < 0) - detail::throw_system_error( - make_err(-rc), "io_uring_queue_init_params"); + detail::throw_system_error(make_err(-rc), "io_uring_queue_init_params"); wakeup_eventfd_ = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); if (wakeup_eventfd_ < 0) @@ -734,7 +735,7 @@ io_uring_scheduler::lazy_init_ring_unlocked() const } inline void -io_uring_scheduler::shutdown() +uring_scheduler::shutdown() { stopped_.store(true, std::memory_order_release); @@ -772,7 +773,7 @@ io_uring_scheduler::shutdown() } inline void -io_uring_scheduler::stop() +uring_scheduler::stop() { stopped_.store(true, std::memory_order_release); { @@ -786,39 +787,38 @@ io_uring_scheduler::stop() // this write reliably produces a CQE. if (ring_inited_) { - std::uint64_t v = 1; - [[maybe_unused]] auto r = - ::write(wakeup_eventfd_, &v, sizeof(v)); + std::uint64_t v = 1; + [[maybe_unused]] auto r = ::write(wakeup_eventfd_, &v, sizeof(v)); } } inline bool -io_uring_scheduler::stopped() const noexcept +uring_scheduler::stopped() const noexcept { return stopped_.load(std::memory_order_acquire); } inline void -io_uring_scheduler::restart() +uring_scheduler::restart() { stopped_.store(false, std::memory_order_release); } inline void -io_uring_scheduler::work_started() noexcept +uring_scheduler::work_started() noexcept { outstanding_work_.fetch_add(1, std::memory_order_relaxed); } inline void -io_uring_scheduler::work_finished() noexcept +uring_scheduler::work_finished() noexcept { if (outstanding_work_.fetch_sub(1, std::memory_order_acq_rel) == 1) stop(); } inline void -io_uring_scheduler::interrupt_reactor() const noexcept +uring_scheduler::interrupt_reactor() const noexcept { // Skip if the ring hasn't been initialised yet — there's no leader // to wake and no eventfd to write. @@ -842,11 +842,11 @@ io_uring_scheduler::interrupt_reactor() const noexcept // (drained together by drain_wakeup_eventfd's single read of // the eventfd counter). std::uint64_t v = 1; - std::ignore = ::write(wakeup_eventfd_, &v, sizeof(v)); + std::ignore = ::write(wakeup_eventfd_, &v, sizeof(v)); } inline void -io_uring_scheduler::drain_wakeup_eventfd() const noexcept +uring_scheduler::drain_wakeup_eventfd() const noexcept { std::uint64_t v; std::ignore = ::read(wakeup_eventfd_, &v, sizeof(v)); @@ -857,7 +857,7 @@ io_uring_scheduler::drain_wakeup_eventfd() const noexcept } inline bool -io_uring_scheduler::prep_multishot_poll(int fd, void* data) noexcept +uring_scheduler::prep_multishot_poll(int fd, void* data) noexcept { // Prepare a multishot POLLIN SQE on `fd` tagged with `data`. Caller holds // ring_mutex_ and flushes separately (re-arm sites ride the batch submit; @@ -879,7 +879,7 @@ io_uring_scheduler::prep_multishot_poll(int fd, void* data) noexcept } inline std::error_code -io_uring_scheduler::register_signal_reader(int read_fd) +uring_scheduler::register_signal_reader(int read_fd) { // Called once per service from add_signal(), holding neither the // signal_state mutex nor the service mutex (see the call site). Submit a @@ -904,7 +904,7 @@ io_uring_scheduler::register_signal_reader(int read_fd) } inline void -io_uring_scheduler::post(std::coroutine_handle<> h) const +uring_scheduler::post(std::coroutine_handle<> h) const { struct post_handler final : scheduler_op { @@ -943,7 +943,7 @@ io_uring_scheduler::post(std::coroutine_handle<> h) const } inline void -io_uring_scheduler::post(scheduler_op* op) const +uring_scheduler::post(scheduler_op* op) const { lazy_init_ring(); outstanding_work_.fetch_add(1, std::memory_order_relaxed); @@ -960,7 +960,7 @@ io_uring_scheduler::post(scheduler_op* op) const } inline void -io_uring_scheduler::post(capy::continuation& c) const +uring_scheduler::post(capy::continuation& c) const { lazy_init_ring(); outstanding_work_.fetch_add(1, std::memory_order_relaxed); @@ -981,46 +981,47 @@ io_uring_scheduler::post(capy::continuation& c) const // running_in_this_thread reporting) and the inline completion budget // used by the speculative non-blocking I/O path (plan 5j). Nesting // stacks frames via prev_ so each scheduler gets its own budget. -struct io_uring_scheduler_frame +struct uring_scheduler_frame { - io_uring_scheduler const* sched; - io_uring_scheduler_frame* prev; - int inline_budget; - int inline_budget_max; + uring_scheduler const* sched; + uring_scheduler_frame* prev; + int inline_budget; + int inline_budget_max; }; -inline thread_local io_uring_scheduler_frame* tl_running_scheduler_frame_ = nullptr; +inline thread_local uring_scheduler_frame* tl_running_scheduler_frame_ = + nullptr; // Default inline budget. Matches reactor's initial budget (2). Adaptive // ramp-up to a max is intentionally NOT implemented yet — keep it simple // for plan 5j and revisit if benches show fairness issues. -inline constexpr int io_uring_inline_budget_initial = 2; -inline constexpr int io_uring_inline_budget_max = 16; +inline constexpr int uring_inline_budget_initial = 2; +inline constexpr int uring_inline_budget_max = 16; /// RAII guard: pushes a frame onto the thread's running-scheduler stack /// on construction, restores the previous on destruction. Used by /// run/run_one/wait_one/poll/poll_one to mark the running thread and /// hold a fresh inline budget for speculative completions. -struct io_uring_run_guard +struct uring_run_guard { - io_uring_scheduler_frame frame_; + uring_scheduler_frame frame_; - explicit io_uring_run_guard(io_uring_scheduler const* self) noexcept - : frame_{self, tl_running_scheduler_frame_, - io_uring_inline_budget_initial, - io_uring_inline_budget_max} + explicit uring_run_guard(uring_scheduler const* self) noexcept + : frame_{ + self, tl_running_scheduler_frame_, uring_inline_budget_initial, + uring_inline_budget_max} { tl_running_scheduler_frame_ = &frame_; } - ~io_uring_run_guard() noexcept + ~uring_run_guard() noexcept { tl_running_scheduler_frame_ = frame_.prev; } }; inline bool -io_uring_scheduler::running_in_this_thread() const noexcept +uring_scheduler::running_in_this_thread() const noexcept { for (auto* f = tl_running_scheduler_frame_; f != nullptr; f = f->prev) { @@ -1031,7 +1032,7 @@ io_uring_scheduler::running_in_this_thread() const noexcept } inline void -io_uring_scheduler::reset_inline_budget() const noexcept +uring_scheduler::reset_inline_budget() const noexcept { for (auto* f = tl_running_scheduler_frame_; f != nullptr; f = f->prev) { @@ -1044,7 +1045,7 @@ io_uring_scheduler::reset_inline_budget() const noexcept } inline bool -io_uring_scheduler::try_consume_inline_budget() const noexcept +uring_scheduler::try_consume_inline_budget() const noexcept { for (auto* f = tl_running_scheduler_frame_; f != nullptr; f = f->prev) { @@ -1062,7 +1063,7 @@ io_uring_scheduler::try_consume_inline_budget() const noexcept } inline std::size_t -io_uring_scheduler::run() +uring_scheduler::run() { lazy_init_ring(); if (outstanding_work_.load(std::memory_order_acquire) == 0) @@ -1071,7 +1072,7 @@ io_uring_scheduler::run() return 0; } - io_uring_run_guard guard(this); + uring_run_guard guard(this); std::size_t n = 0; for (;;) { @@ -1092,7 +1093,7 @@ io_uring_scheduler::run() } inline std::size_t -io_uring_scheduler::run_one() +uring_scheduler::run_one() { lazy_init_ring(); if (outstanding_work_.load(std::memory_order_acquire) == 0) @@ -1100,12 +1101,12 @@ io_uring_scheduler::run_one() stop(); return 0; } - io_uring_run_guard guard(this); + uring_run_guard guard(this); return do_one(-1); } inline std::size_t -io_uring_scheduler::wait_one(long usec) +uring_scheduler::wait_one(long usec) { lazy_init_ring(); if (outstanding_work_.load(std::memory_order_acquire) == 0) @@ -1113,12 +1114,12 @@ io_uring_scheduler::wait_one(long usec) stop(); return 0; } - io_uring_run_guard guard(this); + uring_run_guard guard(this); return do_one(usec); } inline std::size_t -io_uring_scheduler::poll() +uring_scheduler::poll() { lazy_init_ring(); if (outstanding_work_.load(std::memory_order_acquire) == 0) @@ -1126,7 +1127,7 @@ io_uring_scheduler::poll() stop(); return 0; } - io_uring_run_guard guard(this); + uring_run_guard guard(this); std::size_t n = 0; while (do_one(0)) { @@ -1137,7 +1138,7 @@ io_uring_scheduler::poll() } inline std::size_t -io_uring_scheduler::poll_one() +uring_scheduler::poll_one() { lazy_init_ring(); if (outstanding_work_.load(std::memory_order_acquire) == 0) @@ -1145,12 +1146,12 @@ io_uring_scheduler::poll_one() stop(); return 0; } - io_uring_run_guard guard(this); + uring_run_guard guard(this); return do_one(0); } inline std::size_t -io_uring_scheduler::do_one(long timeout_us) +uring_scheduler::do_one(long timeout_us) { // Leader-follower: only one thread at a time may call // io_uring_submit_and_wait_timeout on a shared ring (liburing's @@ -1171,7 +1172,7 @@ io_uring_scheduler::do_one(long timeout_us) // Gate the kernel pump on there being io_uring-specific work. The // check is performed under ring_mutex_ so a concurrent cross-thread // submitter cannot prep an SQE that we then race past — both this - // path and io_uring_submit_op acquire ring_mutex_ before touching + // path and uring_submit_op acquire ring_mutex_ before touching // the ring. When all three sources are empty (no io_uring ops in // flight needing DEFER_TASKRUN GETEVENTS, no userspace-pending // SQEs, no kernel-ready CQEs) a kernel entry would have no work — @@ -1184,9 +1185,9 @@ io_uring_scheduler::do_one(long timeout_us) if (ring_inited_) { lock_type ring_lock(ring_mutex_); - if (io_uring_inflight_.load(std::memory_order_acquire) != 0 - || ::io_uring_sq_ready(&ring_) != 0 - || ::io_uring_cq_ready(&ring_) != 0) + if (uring_inflight_.load(std::memory_order_acquire) != 0 || + ::io_uring_sq_ready(&ring_) != 0 || + ::io_uring_cq_ready(&ring_) != 0) { ::io_uring_submit_and_get_events(&ring_); process_completions(); @@ -1253,8 +1254,7 @@ io_uring_scheduler::do_one(long timeout_us) cond_.wait(lock); else { - cond_.wait_for( - lock, std::chrono::microseconds(timeout_us)); + cond_.wait_for(lock, std::chrono::microseconds(timeout_us)); // wait_one honoured its timeout; if nothing arrived, // return rather than re-arm. if (completed_ops_.empty() && @@ -1269,10 +1269,10 @@ io_uring_scheduler::do_one(long timeout_us) // for the blocking wait, then take it back to release // leadership and wake any follower that should pick up new // work. - __kernel_timespec ts{}; - __kernel_timespec* ts_ptr = nullptr; - auto next_expiry = timer_svc_->nearest_expiry(); - auto now = std::chrono::steady_clock::now(); + __kernel_timespec ts{}; + __kernel_timespec* ts_ptr = nullptr; + auto next_expiry = timer_svc_->nearest_expiry(); + auto now = std::chrono::steady_clock::now(); if (timeout_us == 0) { @@ -1286,7 +1286,8 @@ io_uring_scheduler::do_one(long timeout_us) std::chrono::duration_cast( next_expiry - now) .count(); - if (delta_ns < 0) delta_ns = 0; + if (delta_ns < 0) + delta_ns = 0; ts.tv_sec = delta_ns / 1'000'000'000; ts.tv_nsec = delta_ns % 1'000'000'000; ts_ptr = &ts; @@ -1317,7 +1318,7 @@ io_uring_scheduler::do_one(long timeout_us) // io_uring_service::run pattern. ring_mutex_ is held briefly // to push pending SQEs and to drain CQEs, but NOT during // the blocking io_uring_wait_cqe_timeout. Cross-thread - // submitters (io_uring_submit_op, cancel paths) can take + // submitters (uring_submit_op, cancel paths) can take // ring_mutex_ during the wait and prep new SQEs without // blocking on the leader; their wake eventfd write fires the // multishot poll and returns the leader from wait_cqe_timeout @@ -1335,7 +1336,7 @@ io_uring_scheduler::do_one(long timeout_us) // head advancement happens under the mutex in // process_completions below. ::io_uring_cqe* cqe = nullptr; - int rc = ::io_uring_wait_cqe_timeout(&ring_, &cqe, ts_ptr); + int rc = ::io_uring_wait_cqe_timeout(&ring_, &cqe, ts_ptr); // Phase 3 — drain CQEs under the mutex. { @@ -1372,7 +1373,7 @@ io_uring_scheduler::do_one(long timeout_us) } inline void -io_uring_scheduler::process_completions() +uring_scheduler::process_completions() { unsigned head; ::io_uring_cqe* cqe; @@ -1389,7 +1390,7 @@ io_uring_scheduler::process_completions() if (ud == nullptr) { // Wakeup eventfd CQE: drain the eventfd byte. Not counted - // by io_uring_inflight_; we never incremented for the + // by uring_inflight_; we never incremented for the // wakeup multishot SQE (its progress doesn't depend on // userspace getevents). drain_wakeup_eventfd(); @@ -1413,7 +1414,7 @@ io_uring_scheduler::process_completions() // Signal self-pipe readiness. Re-arm the multishot poll if it // terminated (F_MORE cleared), then enqueue signal_drain_op_ to // drain + deliver in dispatch context. Not counted in - // io_uring_inflight_ (like the wakeup eventfd poll): its progress + // uring_inflight_ (like the wakeup eventfd poll): its progress // does not gate DEFER_TASKRUN GETEVENTS. if ((cqe->flags & IORING_CQE_F_MORE) == 0) std::ignore = prep_multishot_poll( @@ -1430,7 +1431,7 @@ io_uring_scheduler::process_completions() } else { - auto* iop = static_cast(ud); + auto* iop = static_cast(ud); if (iop->retired) { // The owner handed this op to retire_op and is no @@ -1460,8 +1461,7 @@ io_uring_scheduler::process_completions() ++consumed; } if (inflight_dec) - io_uring_inflight_.fetch_sub( - inflight_dec, std::memory_order_acq_rel); + uring_inflight_.fetch_sub(inflight_dec, std::memory_order_acq_rel); if (consumed) io_uring_cq_advance(&ring_, consumed); @@ -1479,25 +1479,27 @@ io_uring_scheduler::process_completions() } inline void -io_uring_scheduler::submit_sqes_op::do_handler( - void* owner, scheduler_op* base, - std::uint32_t /*bytes*/, std::uint32_t /*error*/) noexcept +uring_scheduler::submit_sqes_op::do_handler( + void* owner, + scheduler_op* base, + std::uint32_t /*bytes*/, + std::uint32_t /*error*/) noexcept { if (owner == nullptr) - return; // shutdown drain — nothing to do; SQE storage is - // kernel-mapped and discarded by io_uring_queue_exit. + return; // shutdown drain — nothing to do; SQE storage is + // kernel-mapped and discarded by io_uring_queue_exit. auto* self = static_cast(base); auto* sched = self->sched_; - io_uring_scheduler::lock_type ring_lock(sched->ring_mutex_); + uring_scheduler::lock_type ring_lock(sched->ring_mutex_); sched->submit_op_posted_ = false; ::io_uring_submit_and_get_events(&sched->ring_); sched->process_completions(); } inline void -io_uring_scheduler::submit_cancel_by_user_data(io_uring_op* target) noexcept +uring_scheduler::submit_cancel_by_user_data(uring_op* target) noexcept { lazy_init_ring(); // Wake the leader (if any) so its submit_and_wait_timeout returns @@ -1522,7 +1524,7 @@ io_uring_scheduler::submit_cancel_by_user_data(io_uring_op* target) noexcept } inline void -io_uring_scheduler::submit_cancel_by_fd(int fd) noexcept +uring_scheduler::submit_cancel_by_fd(int fd) noexcept { lazy_init_ring(); interrupt_reactor(); @@ -1542,9 +1544,9 @@ io_uring_scheduler::submit_cancel_by_fd(int fd) noexcept } inline void -io_uring_op::on_cancel() noexcept +uring_op::on_cancel() noexcept { - request_cancel(); // coro_op: records the cancellation (sets the flag) + request_cancel(); // coro_op: records the cancellation (sets the flag) // Skip the cancel SQE if we never linked an SQE to this op — the // bypass path in the caller will see cancelled=true and complete // synchronously without a kernel round-trip. @@ -1553,7 +1555,7 @@ io_uring_op::on_cancel() noexcept } inline void -io_uring_scheduler::cancel_and_flush(int fd) noexcept +uring_scheduler::cancel_and_flush(int fd) noexcept { // The flush can execute a queued write on `fd` inline; when the // fd is a pipe whose reader has already closed — service @@ -1582,14 +1584,14 @@ io_uring_scheduler::cancel_and_flush(int fd) noexcept } inline void -io_uring_scheduler::release_retired_op(io_uring_op* op) noexcept +uring_scheduler::release_retired_op(uring_op* op) noexcept { // Called from the CQE loop with ring_mutex_ held; takes // retired_mutex_ under it, matching retire_op's order. Deleting // here is safe only because retire_op requires the op to hold no // reference back to its owner, so ~op cannot re-enter the // scheduler or touch a destroyed acceptor. - std::unique_ptr owned; + std::unique_ptr owned; { std::lock_guard lock(retired_mutex_); for (auto it = retired_ops_.begin(); it != retired_ops_.end(); ++it) @@ -1605,7 +1607,7 @@ io_uring_scheduler::release_retired_op(io_uring_op* op) noexcept } inline void -io_uring_scheduler::drain_cqes_for(io_uring_op* target) noexcept +uring_scheduler::drain_cqes_for(uring_op* target) noexcept { lazy_init_ring(); // Submit a cancel by user_data so the kernel returns CQEs for @@ -1633,15 +1635,15 @@ io_uring_scheduler::drain_cqes_for(io_uring_op* target) noexcept { lock_type lock(ring_mutex_); - unsigned head; + unsigned head; ::io_uring_cqe* cqe; - unsigned consumed = 0; - bool saw_target = false; - std::int64_t inflight_dec = 0; + unsigned consumed = 0; + bool saw_target = false; + std::int64_t inflight_dec = 0; io_uring_for_each_cqe(&ring_, head, cqe) { - // Mirror process_completions' io_uring_inflight_ accounting. + // Mirror process_completions' uring_inflight_ accounting. // That counter gates the do_one ring pump, so every CQE we // advance past here must adjust it exactly as the normal // drain would — otherwise it drifts upward (each teardown @@ -1659,8 +1661,7 @@ io_uring_scheduler::drain_cqes_for(io_uring_op* target) noexcept // does. Never incremented, so never decremented. drain_wakeup_eventfd(); if ((cqe->flags & IORING_CQE_F_MORE) == 0) - std::ignore = - prep_multishot_poll(wakeup_eventfd_, nullptr); + std::ignore = prep_multishot_poll(wakeup_eventfd_, nullptr); } else if (ud == &signal_pipe_sentinel_) { @@ -1668,7 +1669,7 @@ io_uring_scheduler::drain_cqes_for(io_uring_op* target) noexcept // terminated; the still-readable pipe re-fires on the next // kernel enter so process_completions delivers the signal — // we deliberately do NOT enqueue signal_drain_op_ from this - // teardown path. Not counted by io_uring_inflight_ (the poll + // teardown path. Not counted by uring_inflight_ (the poll // was armed via prep_multishot_poll, which never increments), // so it must NOT be decremented. if ((cqe->flags & IORING_CQE_F_MORE) == 0) @@ -1710,7 +1711,7 @@ io_uring_scheduler::drain_cqes_for(io_uring_op* target) noexcept { io_uring_cq_advance(&ring_, consumed); if (inflight_dec) - io_uring_inflight_.fetch_sub( + uring_inflight_.fetch_sub( inflight_dec, std::memory_order_acq_rel); if (saw_target) break; @@ -1720,11 +1721,10 @@ io_uring_scheduler::drain_cqes_for(io_uring_op* target) noexcept // Nothing in the CQ — kick the kernel briefly. Hold // ring_mutex_ across the wait so we don't race with the // run-loop leader. - __kernel_timespec ts{ - 0, static_cast(drain_cqes_kick_ns)}; + __kernel_timespec ts{0, static_cast(drain_cqes_kick_ns)}; ::io_uring_cqe* one = nullptr; - int rc = ::io_uring_submit_and_wait_timeout( - &ring_, &one, 1, &ts, nullptr); + int rc = + ::io_uring_submit_and_wait_timeout(&ring_, &one, 1, &ts, nullptr); if (rc < 0 && rc != -ETIME && rc != -EINTR) break; if (rc == -ETIME) @@ -1734,6 +1734,6 @@ io_uring_scheduler::drain_cqes_for(io_uring_op* target) noexcept } // namespace boost::corosio::detail -#endif // BOOST_COROSIO_HAS_IO_URING +#endif // BOOST_COROSIO_HAS_URING -#endif // BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_SCHEDULER_HPP +#endif // BOOST_COROSIO_NATIVE_DETAIL_URING_URING_SCHEDULER_HPP diff --git a/include/boost/corosio/native/detail/io_uring/io_uring_socket_ops.hpp b/include/boost/corosio/native/detail/uring/uring_socket_ops.hpp similarity index 66% rename from include/boost/corosio/native/detail/io_uring/io_uring_socket_ops.hpp rename to include/boost/corosio/native/detail/uring/uring_socket_ops.hpp index 00ced752d..531acd1aa 100644 --- a/include/boost/corosio/native/detail/io_uring/io_uring_socket_ops.hpp +++ b/include/boost/corosio/native/detail/uring/uring_socket_ops.hpp @@ -8,12 +8,12 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_SOCKET_OPS_HPP -#define BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_SOCKET_OPS_HPP +#ifndef BOOST_COROSIO_NATIVE_DETAIL_URING_URING_SOCKET_OPS_HPP +#define BOOST_COROSIO_NATIVE_DETAIL_URING_URING_SOCKET_OPS_HPP #include -#if BOOST_COROSIO_HAS_IO_URING +#if BOOST_COROSIO_HAS_URING #include @@ -22,9 +22,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include #include #include @@ -42,12 +42,12 @@ namespace boost::corosio::detail { /// Maximum scatter/gather segments per read/write/dgram op. /// /// Bounded well below `IOV_MAX` (1024 on Linux) so each op's -/// `iovec[io_uring_max_iov]` lives inside the io_uring_op object on +/// `iovec[uring_max_iov]` lives inside the uring_op object on /// the same allocation as the rest of its state. Plan 4's registered- /// buffer work will revisit; until then 16 covers typical scatter use /// cases (fragmented buffers from buffer_sequence) without bloating /// per-op memory. -inline constexpr std::size_t io_uring_max_iov = 16; +inline constexpr std::size_t uring_max_iov = 16; /** Fill an `iovec` array from a buffer sequence without type-punning. @@ -65,11 +65,10 @@ inline constexpr std::size_t io_uring_max_iov = 16; */ inline int copy_to_iovec( - buffer_param const& buffers, - iovec (&iovecs)[io_uring_max_iov]) noexcept + buffer_param const& buffers, iovec (&iovecs)[uring_max_iov]) noexcept { - capy::mutable_buffer bufs[io_uring_max_iov]; - std::size_t const n = buffers.copy_to(bufs, io_uring_max_iov); + capy::mutable_buffer bufs[uring_max_iov]; + std::size_t const n = buffers.copy_to(bufs, uring_max_iov); for (std::size_t i = 0; i < n; ++i) { iovecs[i].iov_base = bufs[i].data(); @@ -88,15 +87,12 @@ copy_to_iovec( @param empty_buf True if the submitted buffer was zero-length. */ inline void -uring_set_result(io_uring_op* self, bool is_read, bool empty_buf) noexcept +uring_set_result(uring_op* self, bool is_read, bool empty_buf) noexcept { decode_io_result( - self->ec_out, - self->cancelled.load(std::memory_order_acquire), - self->res < 0 ? make_err(-self->res) : std::error_code{}, - is_read, - self->res >= 0 ? static_cast(self->res) : 0u, - empty_buf); + self->ec_out, self->cancelled.load(std::memory_order_acquire), + self->res < 0 ? make_err(-self->res) : std::error_code{}, is_read, + self->res >= 0 ? static_cast(self->res) : 0u, empty_buf); } /** Scatter-gather read via `IORING_OP_READV`. @@ -105,15 +101,14 @@ uring_set_result(io_uring_op* self, bool is_read, bool empty_buf) noexcept do_cqe captures `res`/`cqe_flags` and queues self into `local`; do_handler runs from the scheduler queue and resumes the coroutine. */ -struct uring_read_op : io_uring_op +struct uring_read_op : uring_op { - iovec iovecs[io_uring_max_iov]; - int iovec_count = 0; - int fd = -1; + iovec iovecs[uring_max_iov]; + int iovec_count = 0; + int fd = -1; detail::speculative_state* spec_state = nullptr; - uring_read_op() noexcept - : io_uring_op(&do_handler, &do_cqe, &do_prep) + uring_read_op() noexcept : uring_op(&do_handler, &do_cqe, &do_prep) { is_read = true; } @@ -127,33 +122,33 @@ struct uring_read_op : io_uring_op @pre This slot has no in-flight op (its prior op completed). */ void prepare( - std::coroutine_handle<> handle, - capy::executor_ref executor, - std::error_code* ec, - std::size_t* bytes, - int file_descriptor, - io_uring_scheduler* scheduler, - std::shared_ptr impl, + std::coroutine_handle<> handle, + capy::executor_ref executor, + std::error_code* ec, + std::size_t* bytes, + int file_descriptor, + uring_scheduler* scheduler, + std::shared_ptr impl, detail::speculative_state* spec, - buffer_param buffers, - std::stop_token const& token) noexcept + buffer_param buffers, + std::stop_token const& token) noexcept { - h = handle; - ex = executor; - ec_out = ec; - bytes_out = bytes; - fd = file_descriptor; - sched_ = scheduler; - impl_ptr = std::move(impl); - spec_state = spec; - res = 0; - cqe_flags = 0; - iovec_count = copy_to_iovec(buffers, iovecs); + h = handle; + ex = executor; + ec_out = ec; + bytes_out = bytes; + fd = file_descriptor; + sched_ = scheduler; + impl_ptr = std::move(impl); + spec_state = spec; + res = 0; + cqe_flags = 0; + iovec_count = copy_to_iovec(buffers, iovecs); empty_buffer = (iovec_count == 0); start(token); } - static void do_prep(io_uring_op* base, ::io_uring_sqe* sqe) noexcept + static void do_prep(uring_op* base, ::io_uring_sqe* sqe) noexcept { auto* self = static_cast(base); // Single-buffer fast path: IORING_OP_RECV with a flat @@ -163,10 +158,8 @@ struct uring_read_op : io_uring_op if (self->iovec_count == 1) { ::io_uring_prep_recv( - sqe, self->fd, - self->iovecs[0].iov_base, - self->iovecs[0].iov_len, - 0); + sqe, self->fd, self->iovecs[0].iov_base, + self->iovecs[0].iov_len, 0); } else { @@ -175,9 +168,8 @@ struct uring_read_op : io_uring_op } } - static void do_cqe( - io_uring_op* base, int res, unsigned flags, - ready_queue& local) noexcept + static void + do_cqe(uring_op* base, int res, unsigned flags, ready_queue& local) noexcept { auto* self = static_cast(base); self->res = res; @@ -186,8 +178,10 @@ struct uring_read_op : io_uring_op } static void do_handler( - void* owner, scheduler_op* base, - std::uint32_t /*bytes*/, std::uint32_t /*error*/) noexcept + void* owner, + scheduler_op* base, + std::uint32_t /*bytes*/, + std::uint32_t /*error*/) noexcept { auto* self = static_cast(base); if (coro_drain_if_shutdown(owner, self)) @@ -218,53 +212,51 @@ struct uring_read_op : io_uring_op `MSG_NOSIGNAL` prevents `SIGPIPE` when the peer has closed the connection; the error is surfaced as `EPIPE` instead. */ -struct uring_write_op : io_uring_op +struct uring_write_op : uring_op { - iovec iovecs[io_uring_max_iov]; - int iovec_count = 0; - int fd = -1; + iovec iovecs[uring_max_iov]; + int iovec_count = 0; + int fd = -1; msghdr msg{}; detail::speculative_state* spec_state = nullptr; - uring_write_op() noexcept - : io_uring_op(&do_handler, &do_cqe, &do_prep) - {} + uring_write_op() noexcept : uring_op(&do_handler, &do_cqe, &do_prep) {} /** Reset and initialize for a new submission. See uring_read_op::prepare. */ void prepare( - std::coroutine_handle<> handle, - capy::executor_ref executor, - std::error_code* ec, - std::size_t* bytes, - int file_descriptor, - io_uring_scheduler* scheduler, - std::shared_ptr impl, + std::coroutine_handle<> handle, + capy::executor_ref executor, + std::error_code* ec, + std::size_t* bytes, + int file_descriptor, + uring_scheduler* scheduler, + std::shared_ptr impl, detail::speculative_state* spec, - buffer_param buffers, - std::stop_token const& token) noexcept + buffer_param buffers, + std::stop_token const& token) noexcept { - h = handle; - ex = executor; - ec_out = ec; - bytes_out = bytes; - fd = file_descriptor; - sched_ = scheduler; - impl_ptr = std::move(impl); - spec_state = spec; - res = 0; - cqe_flags = 0; - iovec_count = copy_to_iovec(buffers, iovecs); + h = handle; + ex = executor; + ec_out = ec; + bytes_out = bytes; + fd = file_descriptor; + sched_ = scheduler; + impl_ptr = std::move(impl); + spec_state = spec; + res = 0; + cqe_flags = 0; + iovec_count = copy_to_iovec(buffers, iovecs); empty_buffer = (iovec_count == 0); if (!empty_buffer) { - msg = {}; + msg = {}; msg.msg_iov = iovecs; msg.msg_iovlen = static_cast(iovec_count); } start(token); } - static void do_prep(io_uring_op* base, ::io_uring_sqe* sqe) noexcept + static void do_prep(uring_op* base, ::io_uring_sqe* sqe) noexcept { auto* self = static_cast(base); // Single-buffer fast path: IORING_OP_SEND with MSG_NOSIGNAL @@ -273,21 +265,17 @@ struct uring_write_op : io_uring_op if (self->iovec_count == 1) { ::io_uring_prep_send( - sqe, self->fd, - self->iovecs[0].iov_base, - self->iovecs[0].iov_len, - MSG_NOSIGNAL); + sqe, self->fd, self->iovecs[0].iov_base, + self->iovecs[0].iov_len, MSG_NOSIGNAL); } else { - ::io_uring_prep_sendmsg( - sqe, self->fd, &self->msg, MSG_NOSIGNAL); + ::io_uring_prep_sendmsg(sqe, self->fd, &self->msg, MSG_NOSIGNAL); } } - static void do_cqe( - io_uring_op* base, int res, unsigned flags, - ready_queue& local) noexcept + static void + do_cqe(uring_op* base, int res, unsigned flags, ready_queue& local) noexcept { auto* self = static_cast(base); self->res = res; @@ -296,8 +284,10 @@ struct uring_write_op : io_uring_op } static void do_handler( - void* owner, scheduler_op* base, - std::uint32_t /*bytes*/, std::uint32_t /*error*/) noexcept + void* owner, + scheduler_op* base, + std::uint32_t /*bytes*/, + std::uint32_t /*error*/) noexcept { auto* self = static_cast(base); if (coro_drain_if_shutdown(owner, self)) @@ -328,18 +318,16 @@ struct uring_write_op : io_uring_op `remote_endpoint_out` is written only on success so a failed connect does not corrupt the socket's cached remote endpoint. */ -struct uring_connect_op : io_uring_op +struct uring_connect_op : uring_op { sockaddr_storage addr{}; - socklen_t addrlen = 0; - int fd = -1; - endpoint target_endpoint{}; - endpoint* remote_endpoint_out = nullptr; - endpoint* local_endpoint_out = nullptr; + socklen_t addrlen = 0; + int fd = -1; + endpoint target_endpoint{}; + endpoint* remote_endpoint_out = nullptr; + endpoint* local_endpoint_out = nullptr; - uring_connect_op() noexcept - : io_uring_op(&do_handler, &do_cqe, &do_prep) - {} + uring_connect_op() noexcept : uring_op(&do_handler, &do_cqe, &do_prep) {} /** Reset and initialize for a new submission. @@ -350,26 +338,26 @@ struct uring_connect_op : io_uring_op caller, not the op. */ void prepare( - std::coroutine_handle<> handle, - capy::executor_ref executor, - std::error_code* ec, - int file_descriptor, - io_uring_scheduler* scheduler, - std::shared_ptr impl, - endpoint target, - endpoint* remote_out, - endpoint* local_out, - std::stop_token const& token) noexcept + std::coroutine_handle<> handle, + capy::executor_ref executor, + std::error_code* ec, + int file_descriptor, + uring_scheduler* scheduler, + std::shared_ptr impl, + endpoint target, + endpoint* remote_out, + endpoint* local_out, + std::stop_token const& token) noexcept { - h = handle; - ex = executor; - ec_out = ec; - bytes_out = nullptr; - fd = file_descriptor; - sched_ = scheduler; - impl_ptr = std::move(impl); - res = 0; - cqe_flags = 0; + h = handle; + ex = executor; + ec_out = ec; + bytes_out = nullptr; + fd = file_descriptor; + sched_ = scheduler; + impl_ptr = std::move(impl); + res = 0; + cqe_flags = 0; target_endpoint = target; remote_endpoint_out = remote_out; local_endpoint_out = local_out; @@ -377,18 +365,16 @@ struct uring_connect_op : io_uring_op start(token); } - static void do_prep(io_uring_op* base, ::io_uring_sqe* sqe) noexcept + static void do_prep(uring_op* base, ::io_uring_sqe* sqe) noexcept { auto* self = static_cast(base); ::io_uring_prep_connect( - sqe, self->fd, - reinterpret_cast(&self->addr), + sqe, self->fd, reinterpret_cast(&self->addr), self->addrlen); } - static void do_cqe( - io_uring_op* base, int res, unsigned flags, - ready_queue& local) noexcept + static void + do_cqe(uring_op* base, int res, unsigned flags, ready_queue& local) noexcept { auto* self = static_cast(base); self->res = res; @@ -397,8 +383,10 @@ struct uring_connect_op : io_uring_op } static void do_handler( - void* owner, scheduler_op* base, - std::uint32_t /*bytes*/, std::uint32_t /*error*/) noexcept + void* owner, + scheduler_op* base, + std::uint32_t /*bytes*/, + std::uint32_t /*error*/) noexcept { auto* self = static_cast(base); if (coro_drain_if_shutdown(owner, self)) @@ -418,8 +406,9 @@ struct uring_connect_op : io_uring_op { sockaddr_storage local{}; socklen_t len = sizeof(local); - if (::getsockname(self->fd, - reinterpret_cast(&local), &len) == 0) + if (::getsockname( + self->fd, reinterpret_cast(&local), &len) == + 0) *self->local_endpoint_out = sockaddr_to_endpoint(local); } } @@ -428,10 +417,10 @@ struct uring_connect_op : io_uring_op } }; -/** Submit an `io_uring_op`, reporting an SQ that stayed full. +/** Submit an `uring_op`, reporting an SQ that stayed full. - The body behind @ref io_uring_submit_op and - @ref io_uring_try_submit_op; `counted` selects which of the two + The body behind @ref uring_submit_op and + @ref uring_try_submit_op; `counted` selects which of the two answers an exhausted SQ ring gets. @pre `op->prep_func != nullptr`. @@ -448,14 +437,13 @@ struct uring_connect_op : io_uring_op caller to report; `true` otherwise. */ inline bool -io_uring_do_submit_op( - io_uring_scheduler& sched, io_uring_op* op, bool counted) noexcept +uring_do_submit_op(uring_scheduler& sched, uring_op* op, bool counted) noexcept { sched.lazy_init_ring(); bool need_post = false; { - typename io_uring_scheduler::lock_type ring_lock(sched.ring_mutex()); + typename uring_scheduler::lock_type ring_lock(sched.ring_mutex()); ::io_uring_sqe* sqe = ::io_uring_get_sqe(sched.ring()); if (!sqe) @@ -485,7 +473,7 @@ io_uring_do_submit_op( // The owner reports the failure instead. return false; } - typename io_uring_scheduler::lock_type lock(sched.dispatch_mutex()); + typename uring_scheduler::lock_type lock(sched.dispatch_mutex()); sched.push_completed_locked(op); return true; } @@ -496,7 +484,7 @@ io_uring_do_submit_op( // expects exactly one F_MORE-less CQE per submitted SQE // (multishot ops decrement only on the terminal CQE). sched.inflight_inc(); - // Release pairs with the acquire in io_uring_op::request_cancel: + // Release pairs with the acquire in uring_op::request_cancel: // a stop_token firing after we release the mutex will see // sqe_set==true and submit a cancel-by-user_data SQE. op->sqe_set.store(true, std::memory_order_release); @@ -515,7 +503,7 @@ io_uring_do_submit_op( return true; } -/** Submit an `io_uring_op` a `work_started()` already paid for. +/** Submit an `uring_op` a `work_started()` already paid for. Acquires the ring mutex, prepares the SQE, and (under the same mutex) CAS-sets `submit_op_posted_`. The first submitter of a @@ -541,17 +529,17 @@ io_uring_do_submit_op( @param sched The scheduler owning the ring. @param op The operation to submit. - @see io_uring_try_submit_op + @see uring_try_submit_op */ inline void -io_uring_submit_op(io_uring_scheduler& sched, io_uring_op* op) noexcept +uring_submit_op(uring_scheduler& sched, uring_op* op) noexcept { // The result is true by construction: a counted op's SQ-full path // queues the op and answers through its own completion. - io_uring_do_submit_op(sched, op, true); + uring_do_submit_op(sched, op, true); } -/** Submit an `io_uring_op` nothing counted, reporting a full SQ. +/** Submit an `uring_op` nothing counted, reporting a full SQ. The scheduler spends a `work_finished()` on everything it dispatches out of `completed_ops_`, so an op no `work_started()` @@ -572,12 +560,12 @@ io_uring_submit_op(io_uring_scheduler& sched, io_uring_op* op) noexcept @return True when the SQE was prepared; false when the SQ stayed full after one flush and the caller owns the failure. - @see io_uring_submit_op + @see uring_submit_op */ [[nodiscard]] inline bool -io_uring_try_submit_op(io_uring_scheduler& sched, io_uring_op* op) noexcept +uring_try_submit_op(uring_scheduler& sched, uring_op* op) noexcept { - return io_uring_do_submit_op(sched, op, false); + return uring_do_submit_op(sched, op, false); } /** Readiness wait via `IORING_OP_POLL_ADD`. @@ -591,25 +579,23 @@ io_uring_try_submit_op(io_uring_scheduler& sched, io_uring_op* op) noexcept success/cancel/error on `*ec_out` — callers of `wait()` just need a readiness signal, not the specific event mask. */ -struct uring_wait_op : io_uring_op +struct uring_wait_op : uring_op { int fd = -1; int poll_flags = 0; - uring_wait_op() noexcept - : io_uring_op(&do_handler, &do_cqe, &do_prep) - {} + uring_wait_op() noexcept : uring_op(&do_handler, &do_cqe, &do_prep) {} /** Reset and initialize for a new submission. */ void prepare( - std::coroutine_handle<> handle, - capy::executor_ref executor, - std::error_code* ec, - int file_descriptor, - io_uring_scheduler* scheduler, - std::shared_ptr impl, - int flags, - std::stop_token const& token) noexcept + std::coroutine_handle<> handle, + capy::executor_ref executor, + std::error_code* ec, + int file_descriptor, + uring_scheduler* scheduler, + std::shared_ptr impl, + int flags, + std::stop_token const& token) noexcept { h = handle; ex = executor; @@ -624,15 +610,14 @@ struct uring_wait_op : io_uring_op start(token); } - static void do_prep(io_uring_op* base, ::io_uring_sqe* sqe) noexcept + static void do_prep(uring_op* base, ::io_uring_sqe* sqe) noexcept { auto* self = static_cast(base); ::io_uring_prep_poll_add(sqe, self->fd, self->poll_flags); } - static void do_cqe( - io_uring_op* base, int res, unsigned flags, - ready_queue& local) noexcept + static void + do_cqe(uring_op* base, int res, unsigned flags, ready_queue& local) noexcept { auto* self = static_cast(base); self->res = res; @@ -641,8 +626,10 @@ struct uring_wait_op : io_uring_op } static void do_handler( - void* owner, scheduler_op* base, - std::uint32_t /*bytes*/, std::uint32_t /*error*/) noexcept + void* owner, + scheduler_op* base, + std::uint32_t /*bytes*/, + std::uint32_t /*error*/) noexcept { auto* self = static_cast(base); if (coro_drain_if_shutdown(owner, self)) @@ -663,7 +650,7 @@ struct uring_wait_op : io_uring_op } else if (self->res & (POLLERR | POLLHUP | POLLNVAL)) { - int so_err = 0; + int so_err = 0; socklen_t len = sizeof(so_err); if (::getsockopt(self->fd, SOL_SOCKET, SO_ERROR, &so_err, &len) < 0) so_err = errno; @@ -674,9 +661,7 @@ struct uring_wait_op : io_uring_op // Wait reports only success/cancel/error — no bytes, no EOF. decode_io_result( - self->ec_out, - self->cancelled.load(std::memory_order_acquire), - ec, + self->ec_out, self->cancelled.load(std::memory_order_acquire), ec, /*is_read=*/false, /*bytes=*/0, /*empty_buffer=*/false); coro_resume(self); @@ -689,62 +674,60 @@ struct uring_wait_op : io_uring_op and out-pointers, since `sockaddr_to_local_endpoint` returns `local_endpoint`, not `endpoint`. */ -struct uring_local_connect_op : io_uring_op +struct uring_local_connect_op : uring_op { - sockaddr_storage addr{}; - socklen_t addrlen = 0; - int fd = -1; - corosio::local_endpoint target_endpoint{}; - corosio::local_endpoint* remote_endpoint_out = nullptr; - corosio::local_endpoint* local_endpoint_out = nullptr; + sockaddr_storage addr{}; + socklen_t addrlen = 0; + int fd = -1; + corosio::local_endpoint target_endpoint{}; + corosio::local_endpoint* remote_endpoint_out = nullptr; + corosio::local_endpoint* local_endpoint_out = nullptr; - uring_local_connect_op() noexcept - : io_uring_op(&do_handler, &do_cqe, &do_prep) - {} + uring_local_connect_op() noexcept : uring_op(&do_handler, &do_cqe, &do_prep) + { + } /** Reset and initialize for a new submission. Caller pre-fills `addr` and `addrlen` (see uring_connect_op::prepare). */ void prepare( - std::coroutine_handle<> handle, - capy::executor_ref executor, - std::error_code* ec, - int file_descriptor, - io_uring_scheduler* scheduler, - std::shared_ptr impl, - corosio::local_endpoint target, - corosio::local_endpoint* remote_out, - corosio::local_endpoint* local_out, - std::stop_token const& token) noexcept + std::coroutine_handle<> handle, + capy::executor_ref executor, + std::error_code* ec, + int file_descriptor, + uring_scheduler* scheduler, + std::shared_ptr impl, + corosio::local_endpoint target, + corosio::local_endpoint* remote_out, + corosio::local_endpoint* local_out, + std::stop_token const& token) noexcept { - h = handle; - ex = executor; - ec_out = ec; - bytes_out = nullptr; - fd = file_descriptor; - sched_ = scheduler; - impl_ptr = std::move(impl); - res = 0; - cqe_flags = 0; + h = handle; + ex = executor; + ec_out = ec; + bytes_out = nullptr; + fd = file_descriptor; + sched_ = scheduler; + impl_ptr = std::move(impl); + res = 0; + cqe_flags = 0; target_endpoint = target; remote_endpoint_out = remote_out; local_endpoint_out = local_out; start(token); } - static void do_prep(io_uring_op* base, ::io_uring_sqe* sqe) noexcept + static void do_prep(uring_op* base, ::io_uring_sqe* sqe) noexcept { auto* self = static_cast(base); ::io_uring_prep_connect( - sqe, self->fd, - reinterpret_cast(&self->addr), + sqe, self->fd, reinterpret_cast(&self->addr), self->addrlen); } - static void do_cqe( - io_uring_op* base, int res, unsigned flags, - ready_queue& local) noexcept + static void + do_cqe(uring_op* base, int res, unsigned flags, ready_queue& local) noexcept { auto* self = static_cast(base); self->res = res; @@ -753,8 +736,10 @@ struct uring_local_connect_op : io_uring_op } static void do_handler( - void* owner, scheduler_op* base, - std::uint32_t /*bytes*/, std::uint32_t /*error*/) noexcept + void* owner, + scheduler_op* base, + std::uint32_t /*bytes*/, + std::uint32_t /*error*/) noexcept { auto* self = static_cast(base); if (coro_drain_if_shutdown(owner, self)) @@ -774,8 +759,9 @@ struct uring_local_connect_op : io_uring_op { sockaddr_storage local{}; socklen_t len = sizeof(local); - if (::getsockname(self->fd, - reinterpret_cast(&local), &len) == 0) + if (::getsockname( + self->fd, reinterpret_cast(&local), &len) == + 0) *self->local_endpoint_out = sockaddr_to_local_endpoint(local, len); } @@ -787,6 +773,6 @@ struct uring_local_connect_op : io_uring_op } // namespace boost::corosio::detail -#endif // BOOST_COROSIO_HAS_IO_URING +#endif // BOOST_COROSIO_HAS_URING -#endif // BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_SOCKET_OPS_HPP +#endif // BOOST_COROSIO_NATIVE_DETAIL_URING_URING_SOCKET_OPS_HPP diff --git a/include/boost/corosio/native/detail/io_uring/io_uring_socket_service_base.hpp b/include/boost/corosio/native/detail/uring/uring_socket_service_base.hpp similarity index 75% rename from include/boost/corosio/native/detail/io_uring/io_uring_socket_service_base.hpp rename to include/boost/corosio/native/detail/uring/uring_socket_service_base.hpp index 44e3d7faf..bf510575e 100644 --- a/include/boost/corosio/native/detail/io_uring/io_uring_socket_service_base.hpp +++ b/include/boost/corosio/native/detail/uring/uring_socket_service_base.hpp @@ -7,15 +7,15 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_SOCKET_SERVICE_BASE_HPP -#define BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_SOCKET_SERVICE_BASE_HPP +#ifndef BOOST_COROSIO_NATIVE_DETAIL_URING_URING_SOCKET_SERVICE_BASE_HPP +#define BOOST_COROSIO_NATIVE_DETAIL_URING_URING_SOCKET_SERVICE_BASE_HPP #include -#if BOOST_COROSIO_HAS_IO_URING +#if BOOST_COROSIO_HAS_URING #include -#include +#include #include #include @@ -27,8 +27,8 @@ Shared lifecycle plumbing for io_uring socket/datagram services. construct / destroy / shutdown / close / scheduler() are identical across - io_uring_tcp_service, io_uring_udp_service, io_uring_local_stream_service, - and io_uring_local_datagram_service — they all make_shared the impl, track + uring_tcp_service, uring_udp_service, uring_local_stream_service, + and uring_local_datagram_service — they all make_shared the impl, track it in a raw->shared_ptr map, cancel on shutdown, and close eagerly. This base factors that out; the concrete services add only the protocol- specific open/bind/adopt. @@ -42,7 +42,7 @@ teardown behavior change for marginal extra sharing. See tasks/proactor-dedup-decisions.md (#13). - Requirements on Socket: a `(Derived& service, io_uring_scheduler& sched)` + Requirements on Socket: a `(Derived& service, uring_scheduler& sched)` constructor and a `void close_socket() noexcept` method (cancel in-flight ops + close fd + reset cached endpoints). @@ -54,20 +54,20 @@ namespace boost::corosio::detail { template -class io_uring_socket_service_base : public ServiceBase +class uring_socket_service_base : public ServiceBase { friend Derived; // Private CRTP ctor: only `Derived` (the concrete service, a friend) // constructs the base — prevents inheriting with the wrong Derived // (bugprone-crtp-constructor-accessibility). - explicit io_uring_socket_service_base(capy::execution_context& ctx) - : sched_(&ctx.template use_service()) + explicit uring_socket_service_base(capy::execution_context& ctx) + : sched_(&ctx.template use_service()) { } public: - ~io_uring_socket_service_base() override = default; + ~uring_socket_service_base() override = default; void shutdown() override { @@ -88,8 +88,8 @@ class io_uring_socket_service_base : public ServiceBase io_object::implementation* construct() override { - auto p = std::make_shared( - static_cast(*this), *sched_); + auto p = + std::make_shared(static_cast(*this), *sched_); auto* raw = p.get(); std::lock_guard lk(mutex_); impls_.emplace(raw, std::move(p)); @@ -113,7 +113,10 @@ class io_uring_socket_service_base : public ServiceBase } /// Return the scheduler used by sockets created by this service. - io_uring_scheduler& scheduler() noexcept { return *sched_; } + uring_scheduler& scheduler() noexcept + { + return *sched_; + } protected: /// Register an externally-built impl (used by adopt_fd on stream @@ -126,18 +129,18 @@ class io_uring_socket_service_base : public ServiceBase return raw; } - io_uring_scheduler* sched_; - std::mutex mutex_; + uring_scheduler* sched_; + std::mutex mutex_; std::unordered_map> impls_; private: - io_uring_socket_service_base(io_uring_socket_service_base const&) = delete; - io_uring_socket_service_base& - operator=(io_uring_socket_service_base const&) = delete; + uring_socket_service_base(uring_socket_service_base const&) = delete; + uring_socket_service_base& + operator=(uring_socket_service_base const&) = delete; }; } // namespace boost::corosio::detail -#endif // BOOST_COROSIO_HAS_IO_URING +#endif // BOOST_COROSIO_HAS_URING -#endif // BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_SOCKET_SERVICE_BASE_HPP +#endif // BOOST_COROSIO_NATIVE_DETAIL_URING_URING_SOCKET_SERVICE_BASE_HPP diff --git a/include/boost/corosio/native/detail/io_uring/io_uring_stream_file.hpp b/include/boost/corosio/native/detail/uring/uring_stream_file.hpp similarity index 68% rename from include/boost/corosio/native/detail/io_uring/io_uring_stream_file.hpp rename to include/boost/corosio/native/detail/uring/uring_stream_file.hpp index 6431aa23c..e0e80ae72 100644 --- a/include/boost/corosio/native/detail/io_uring/io_uring_stream_file.hpp +++ b/include/boost/corosio/native/detail/uring/uring_stream_file.hpp @@ -7,18 +7,18 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_STREAM_FILE_HPP -#define BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_STREAM_FILE_HPP +#ifndef BOOST_COROSIO_NATIVE_DETAIL_URING_URING_STREAM_FILE_HPP +#define BOOST_COROSIO_NATIVE_DETAIL_URING_URING_STREAM_FILE_HPP #include -#if BOOST_COROSIO_HAS_IO_URING +#if BOOST_COROSIO_HAS_URING #include #include -#include -#include -#include +#include +#include +#include #include #include @@ -37,7 +37,7 @@ namespace boost::corosio::detail { -class io_uring_stream_file_service; +class uring_stream_file_service; /** Native io_uring stream-file implementation. @@ -60,27 +60,27 @@ class io_uring_stream_file_service; to size-at-open. Both behaviours are valid; documented for cross-backend symmetry. */ -class BOOST_COROSIO_DECL io_uring_stream_file final +class BOOST_COROSIO_DECL uring_stream_file final : public stream_file::implementation - , public std::enable_shared_from_this - , public intrusive_list::node + , public std::enable_shared_from_this + , public intrusive_list::node { - friend class io_uring_stream_file_service; + friend class uring_stream_file_service; - int fd_ = -1; - io_uring_scheduler* sched_ = nullptr; + int fd_ = -1; + uring_scheduler* sched_ = nullptr; // Per-fd op slots — embedded to eliminate per-call heap allocation. // Single-pending invariant per slot. - uring_file_read_op rd_; - uring_file_write_op wr_; + uring_file_read_op rd_; + uring_file_write_op wr_; public: - explicit io_uring_stream_file(io_uring_scheduler& sched) noexcept - : sched_(&sched) - {} + explicit uring_stream_file(uring_scheduler& sched) noexcept : sched_(&sched) + { + } - ~io_uring_stream_file() override + ~uring_stream_file() override { close_file(); } @@ -126,8 +126,8 @@ class BOOST_COROSIO_DECL io_uring_stream_file final std::error_code resize(std::uint64_t new_size) noexcept override { - if (new_size > static_cast( - (std::numeric_limits::max)())) + if (new_size > + static_cast((std::numeric_limits::max)())) return make_err(EOVERFLOW); if (::ftruncate(fd_, static_cast(new_size)) < 0) return make_err(errno); @@ -155,7 +155,7 @@ class BOOST_COROSIO_DECL io_uring_stream_file final native_handle_type release() override { int fd = fd_; - fd_ = -1; + fd_ = -1; return fd; } @@ -166,12 +166,14 @@ class BOOST_COROSIO_DECL io_uring_stream_file final return {}; } - capy::io_result seek( - std::int64_t offset, file_base::seek_basis origin) noexcept override + capy::io_result + seek(std::int64_t offset, file_base::seek_basis origin) noexcept override { int whence = SEEK_SET; - if (origin == file_base::seek_cur) whence = SEEK_CUR; - else if (origin == file_base::seek_end) whence = SEEK_END; + if (origin == file_base::seek_cur) + whence = SEEK_CUR; + else if (origin == file_base::seek_end) + whence = SEEK_END; off_t r = ::lseek(fd_, static_cast(offset), whence); if (r == static_cast(-1)) @@ -182,12 +184,12 @@ class BOOST_COROSIO_DECL io_uring_stream_file final // -- Internal -- /// Open the file. Synchronous; sets `fd_`. Caller is the service. - std::error_code open_file( - std::filesystem::path const& path, file_base::flags mode) + std::error_code + open_file(std::filesystem::path const& path, file_base::flags mode) { close_file(); - int oflags = 0; + int oflags = 0; unsigned access = static_cast(mode) & 3u; if (access == static_cast(file_base::read_write)) oflags |= O_RDWR; @@ -241,16 +243,17 @@ class BOOST_COROSIO_DECL io_uring_stream_file final }; inline std::coroutine_handle<> -io_uring_stream_file::read_some( +uring_stream_file::read_some( std::coroutine_handle<> h, - capy::executor_ref ex, - buffer_param buffers, - std::stop_token token, - std::error_code* ec, - std::size_t* bytes) + capy::executor_ref ex, + buffer_param buffers, + std::stop_token token, + std::error_code* ec, + std::size_t* bytes) { - rd_.prepare(h, ex, ec, bytes, fd_, /*file_offset=*/-1, sched_, - shared_from_this(), buffers, token); + rd_.prepare( + h, ex, ec, bytes, fd_, /*file_offset=*/-1, sched_, shared_from_this(), + buffers, token); sched_->work_started(); // Closed-object contract outranks the zero-length no-op. @@ -258,34 +261,34 @@ io_uring_stream_file::read_some( { rd_.empty_buffer = false; rd_.res = -EBADF; - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&rd_); return std::noop_coroutine(); } - if (rd_.empty_buffer || - rd_.cancelled.load(std::memory_order_acquire)) + if (rd_.empty_buffer || rd_.cancelled.load(std::memory_order_acquire)) { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&rd_); return std::noop_coroutine(); } - io_uring_submit_op(*sched_, &rd_); + uring_submit_op(*sched_, &rd_); return std::noop_coroutine(); } inline std::coroutine_handle<> -io_uring_stream_file::write_some( +uring_stream_file::write_some( std::coroutine_handle<> h, - capy::executor_ref ex, - buffer_param buffers, - std::stop_token token, - std::error_code* ec, - std::size_t* bytes) + capy::executor_ref ex, + buffer_param buffers, + std::stop_token token, + std::error_code* ec, + std::size_t* bytes) { - wr_.prepare(h, ex, ec, bytes, fd_, /*file_offset=*/-1, sched_, - shared_from_this(), buffers, token); + wr_.prepare( + h, ex, ec, bytes, fd_, /*file_offset=*/-1, sched_, shared_from_this(), + buffers, token); sched_->work_started(); // Closed-object contract outranks the zero-length no-op. @@ -293,57 +296,60 @@ io_uring_stream_file::write_some( { wr_.empty_buffer = false; wr_.res = -EBADF; - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&wr_); return std::noop_coroutine(); } - if (wr_.empty_buffer || - wr_.cancelled.load(std::memory_order_acquire)) + if (wr_.empty_buffer || wr_.cancelled.load(std::memory_order_acquire)) { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&wr_); return std::noop_coroutine(); } - io_uring_submit_op(*sched_, &wr_); + uring_submit_op(*sched_, &wr_); return std::noop_coroutine(); } /** Native io_uring stream-file service. - Owns all `io_uring_stream_file` impls. Replaces + Owns all `uring_stream_file` impls. Replaces `posix_stream_file_service` for the io_uring backend; registered - under the abstract `file_service` key by `io_uring_t::construct`. + under the abstract `file_service` key by `uring_t::construct`. */ -class BOOST_COROSIO_DECL io_uring_stream_file_service final - : public io_uring_file_service_base< - io_uring_stream_file_service, file_service, io_uring_stream_file> +class BOOST_COROSIO_DECL uring_stream_file_service final + : public uring_file_service_base< + uring_stream_file_service, + file_service, + uring_stream_file> { - using base_service = io_uring_file_service_base< - io_uring_stream_file_service, file_service, io_uring_stream_file>; + using base_service = uring_file_service_base< + uring_stream_file_service, + file_service, + uring_stream_file>; public: - explicit io_uring_stream_file_service( - capy::execution_context& /*ctx*/, io_uring_scheduler& sched) + explicit uring_stream_file_service( + capy::execution_context& /*ctx*/, uring_scheduler& sched) : base_service(sched) - {} + { + } // construct / destroy / close / shutdown / scheduler() are inherited - // from io_uring_file_service_base. + // from uring_file_service_base. std::error_code open_file( stream_file::implementation& impl, std::filesystem::path const& path, file_base::flags mode) override { - return static_cast(impl).open_file( - path, mode); + return static_cast(impl).open_file(path, mode); } }; } // namespace boost::corosio::detail -#endif // BOOST_COROSIO_HAS_IO_URING +#endif // BOOST_COROSIO_HAS_URING -#endif // BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_STREAM_FILE_HPP +#endif // BOOST_COROSIO_NATIVE_DETAIL_URING_URING_STREAM_FILE_HPP diff --git a/include/boost/corosio/native/detail/io_uring/io_uring_types.hpp b/include/boost/corosio/native/detail/uring/uring_types.hpp similarity index 67% rename from include/boost/corosio/native/detail/io_uring/io_uring_types.hpp rename to include/boost/corosio/native/detail/uring/uring_types.hpp index df9a9c35f..7e9361c89 100644 --- a/include/boost/corosio/native/detail/io_uring/io_uring_types.hpp +++ b/include/boost/corosio/native/detail/uring/uring_types.hpp @@ -8,22 +8,22 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_TYPES_HPP -#define BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_TYPES_HPP +#ifndef BOOST_COROSIO_NATIVE_DETAIL_URING_URING_TYPES_HPP +#define BOOST_COROSIO_NATIVE_DETAIL_URING_URING_TYPES_HPP #include -#if BOOST_COROSIO_HAS_IO_URING +#if BOOST_COROSIO_HAS_URING #include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -56,18 +56,18 @@ namespace boost::corosio::detail { -class io_uring_tcp_service; -class io_uring_tcp_acceptor_service; // Task 18 -class io_uring_local_stream_service; -class io_uring_local_stream_acceptor_service; -class io_uring_udp_service; -class io_uring_local_datagram_service; +class uring_tcp_service; +class uring_tcp_acceptor_service; // Task 18 +class uring_local_stream_service; +class uring_local_stream_acceptor_service; +class uring_udp_service; +class uring_local_datagram_service; /** TCP socket implementation for io_uring. Implements `tcp_socket::implementation` using a proactor model: read, write, and connect operations are submitted to the kernel - via `io_uring_submit_op` and complete through the ring's CQE path. + via `uring_submit_op` and complete through the ring's CQE path. The object is always owned by a `shared_ptr` managed by the service. In-flight ops hold an additional `shared_ptr` copy (`impl_ptr`) so @@ -78,15 +78,17 @@ class io_uring_local_datagram_service; Shared objects: Unsafe. A socket must not have two operations of the same type in flight simultaneously. */ -class BOOST_COROSIO_DECL io_uring_tcp_socket final +class BOOST_COROSIO_DECL uring_tcp_socket final : public native_socket_base< - io_uring_tcp_socket, tcp_socket::implementation, endpoint> + uring_tcp_socket, + tcp_socket::implementation, + endpoint> { - friend io_uring_tcp_service; + friend uring_tcp_service; - int family_ = AF_UNSPEC; // cached at open_socket - io_uring_scheduler* sched_ = nullptr; - [[maybe_unused]] io_uring_tcp_service* svc_ = nullptr; + int family_ = AF_UNSPEC; // cached at open_socket + uring_scheduler* sched_ = nullptr; + [[maybe_unused]] uring_tcp_service* svc_ = nullptr; // fd_ and local_endpoint_ are provided by native_socket_base (the // readiness/completion-agnostic socket base shared with the reactor @@ -102,19 +104,24 @@ class BOOST_COROSIO_DECL io_uring_tcp_socket final // first read // resolved — local_endpoint_ is authoritative; accessor // returns the cached value - enum class endpoint_state : int { unresolved, lazy_pending, resolved }; - mutable std::atomic local_endpoint_state_ - { endpoint_state::unresolved }; + enum class endpoint_state : int + { + unresolved, + lazy_pending, + resolved + }; + mutable std::atomic local_endpoint_state_{ + endpoint_state::unresolved}; endpoint remote_endpoint_; // Per-fd op slots — embedded to eliminate per-call heap allocation. // Single-pending invariant per slot: at most one read, write, or // connect in flight on this socket at any time (the awaitable // contract). - uring_read_op rd_; - uring_write_op wr_; + uring_read_op rd_; + uring_write_op wr_; uring_connect_op conn_; - uring_wait_op wait_op_; + uring_wait_op wait_op_; mutable detail::speculative_state spec_; @@ -128,17 +135,18 @@ class BOOST_COROSIO_DECL io_uring_tcp_socket final @param svc The owning service (Task 13). @param sched The io_uring scheduler owned by the context. */ - explicit io_uring_tcp_socket( - io_uring_tcp_service& svc, - io_uring_scheduler& sched) noexcept + explicit uring_tcp_socket( + uring_tcp_service& svc, uring_scheduler& sched) noexcept : sched_(&sched) , svc_(&svc) - {} + { + } - ~io_uring_tcp_socket() override + ~uring_tcp_socket() override { if (fd_ >= 0) - ::close(fd_); // LCOV_EXCL_LINE backstop: close_socket() clears fd_ before destroy + ::close( + fd_); // LCOV_EXCL_LINE backstop: close_socket() clears fd_ before destroy } // ---------------------------------------------------------------- @@ -147,28 +155,32 @@ class BOOST_COROSIO_DECL io_uring_tcp_socket final std::coroutine_handle<> read_some( std::coroutine_handle<> h, - capy::executor_ref ex, - buffer_param buffers, - std::stop_token token, - std::error_code* ec, - std::size_t* bytes) override - { - iovec iovecs[io_uring_max_iov]; - int iovec_count = copy_to_iovec(buffers, iovecs); - bool stop_now = token.stop_possible() && token.stop_requested(); - bool empty_buf = (iovec_count == 0); - - ssize_t n = 0; - int err = 0; - bool have_sync_res = stop_now || empty_buf; + capy::executor_ref ex, + buffer_param buffers, + std::stop_token token, + std::error_code* ec, + std::size_t* bytes) override + { + iovec iovecs[uring_max_iov]; + int iovec_count = copy_to_iovec(buffers, iovecs); + bool stop_now = token.stop_possible() && token.stop_requested(); + bool empty_buf = (iovec_count == 0); + + ssize_t n = 0; + int err = 0; + bool have_sync_res = stop_now || empty_buf; if (!have_sync_res && spec_.may_speculate_read()) { - do { n = ::readv(fd_, iovecs, iovec_count); } + do + { + n = ::readv(fd_, iovecs, iovec_count); + } while (n < 0 && errno == EINTR); if (n >= 0 || (errno != EAGAIN && errno != EWOULDBLOCK)) { have_sync_res = true; - if (n < 0) err = errno; + if (n < 0) + err = errno; // Speculative read produced a definitive answer (data // or non-EAGAIN error); reset the failure streak so a // burst of past EAGAINs doesn't latch perma-off when @@ -188,67 +200,73 @@ class BOOST_COROSIO_DECL io_uring_tcp_socket final { decode_io_result( ec, stop_now, err ? make_err(err) : std::error_code{}, - /*is_read=*/true, - n < 0 ? 0u : static_cast(n), empty_buf); + /*is_read=*/true, n < 0 ? 0u : static_cast(n), + empty_buf); if (bytes) *bytes = (n < 0) ? 0u : static_cast(n); rd_.cont.h = h; return dispatch_coro(ex, rd_.cont); } - rd_.prepare(h, ex, ec, bytes, fd_, sched_, - shared_from_this(), &spec_, buffers, token); + rd_.prepare( + h, ex, ec, bytes, fd_, sched_, shared_from_this(), &spec_, + buffers, token); if (stop_now) rd_.cancelled.store(true, std::memory_order_release); else rd_.res = (n < 0) ? -err : static_cast(n); sched_->work_started(); { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&rd_); } return std::noop_coroutine(); } - rd_.prepare(h, ex, ec, bytes, fd_, sched_, - shared_from_this(), &spec_, buffers, token); + rd_.prepare( + h, ex, ec, bytes, fd_, sched_, shared_from_this(), &spec_, buffers, + token); sched_->work_started(); if (rd_.cancelled.load(std::memory_order_acquire)) { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&rd_); return std::noop_coroutine(); } - io_uring_submit_op(*sched_, &rd_); + uring_submit_op(*sched_, &rd_); return std::noop_coroutine(); } std::coroutine_handle<> write_some( std::coroutine_handle<> h, - capy::executor_ref ex, - buffer_param buffers, - std::stop_token token, - std::error_code* ec, - std::size_t* bytes) override - { - iovec iovecs[io_uring_max_iov]; - int iovec_count = copy_to_iovec(buffers, iovecs); - bool stop_now = token.stop_possible() && token.stop_requested(); - bool empty_buf = (iovec_count == 0); - - ssize_t n = 0; - int err = 0; - bool have_sync_res = stop_now || empty_buf; + capy::executor_ref ex, + buffer_param buffers, + std::stop_token token, + std::error_code* ec, + std::size_t* bytes) override + { + iovec iovecs[uring_max_iov]; + int iovec_count = copy_to_iovec(buffers, iovecs); + bool stop_now = token.stop_possible() && token.stop_requested(); + bool empty_buf = (iovec_count == 0); + + ssize_t n = 0; + int err = 0; + bool have_sync_res = stop_now || empty_buf; if (!have_sync_res && spec_.may_speculate_write()) { msghdr msg{}; msg.msg_iov = iovecs; msg.msg_iovlen = static_cast(iovec_count); - do { n = ::sendmsg(fd_, &msg, MSG_NOSIGNAL); } + do + { + n = ::sendmsg(fd_, &msg, MSG_NOSIGNAL); + } while (n < 0 && errno == EINTR); if (n >= 0 || (errno != EAGAIN && errno != EWOULDBLOCK)) { have_sync_res = true; - if (n < 0) err = errno; + if (n < 0) + err = errno; } else { @@ -268,30 +286,32 @@ class BOOST_COROSIO_DECL io_uring_tcp_socket final wr_.cont.h = h; return dispatch_coro(ex, wr_.cont); } - wr_.prepare(h, ex, ec, bytes, fd_, sched_, - shared_from_this(), &spec_, buffers, token); + wr_.prepare( + h, ex, ec, bytes, fd_, sched_, shared_from_this(), &spec_, + buffers, token); if (stop_now) wr_.cancelled.store(true, std::memory_order_release); else wr_.res = (n < 0) ? -err : static_cast(n); sched_->work_started(); { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&wr_); } return std::noop_coroutine(); } - wr_.prepare(h, ex, ec, bytes, fd_, sched_, - shared_from_this(), &spec_, buffers, token); + wr_.prepare( + h, ex, ec, bytes, fd_, sched_, shared_from_this(), &spec_, buffers, + token); sched_->work_started(); if (wr_.cancelled.load(std::memory_order_acquire)) { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&wr_); return std::noop_coroutine(); } - io_uring_submit_op(*sched_, &wr_); + uring_submit_op(*sched_, &wr_); return std::noop_coroutine(); } @@ -301,27 +321,29 @@ class BOOST_COROSIO_DECL io_uring_tcp_socket final std::coroutine_handle<> connect( std::coroutine_handle<> h, - capy::executor_ref ex, - endpoint ep, - std::stop_token token, - std::error_code* ec) override + capy::executor_ref ex, + endpoint ep, + std::stop_token token, + std::error_code* ec) override { bool stop_now = token.stop_possible() && token.stop_requested(); if (stop_now) { if (sched_->try_consume_inline_budget()) { - if (ec) *ec = capy::error::canceled; + if (ec) + *ec = capy::error::canceled; conn_.cont.h = h; return dispatch_coro(ex, conn_.cont); } conn_.addrlen = to_sockaddr(ep, family_, conn_.addr); - conn_.prepare(h, ex, ec, fd_, sched_, shared_from_this(), - ep, &remote_endpoint_, &local_endpoint_, token); + conn_.prepare( + h, ex, ec, fd_, sched_, shared_from_this(), ep, + &remote_endpoint_, &local_endpoint_, token); conn_.cancelled.store(true, std::memory_order_release); sched_->work_started(); { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&conn_); } return std::noop_coroutine(); @@ -330,43 +352,50 @@ class BOOST_COROSIO_DECL io_uring_tcp_socket final // A speculative ::connect would leave the fd in EINPROGRESS and // a subsequent IORING_OP_CONNECT would see EALREADY — avoid. conn_.addrlen = to_sockaddr(ep, family_, conn_.addr); - conn_.prepare(h, ex, ec, fd_, sched_, shared_from_this(), - ep, &remote_endpoint_, &local_endpoint_, token); + conn_.prepare( + h, ex, ec, fd_, sched_, shared_from_this(), ep, &remote_endpoint_, + &local_endpoint_, token); sched_->work_started(); if (conn_.cancelled.load(std::memory_order_acquire)) { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&conn_); return std::noop_coroutine(); } - io_uring_submit_op(*sched_, &conn_); + uring_submit_op(*sched_, &conn_); return std::noop_coroutine(); } std::coroutine_handle<> wait( std::coroutine_handle<> h, - capy::executor_ref ex, - wait_type w, - std::stop_token token, - std::error_code* ec) override + capy::executor_ref ex, + wait_type w, + std::stop_token token, + std::error_code* ec) override { int poll_flags = 0; switch (w) { - case wait_type::read: poll_flags = POLLIN; break; - case wait_type::write: poll_flags = POLLOUT; break; - case wait_type::error: poll_flags = POLLPRI | POLLERR | POLLHUP; break; - } - wait_op_.prepare(h, ex, ec, fd_, sched_, - shared_from_this(), poll_flags, token); + case wait_type::read: + poll_flags = POLLIN; + break; + case wait_type::write: + poll_flags = POLLOUT; + break; + case wait_type::error: + poll_flags = POLLPRI | POLLERR | POLLHUP; + break; + } + wait_op_.prepare( + h, ex, ec, fd_, sched_, shared_from_this(), poll_flags, token); sched_->work_started(); if (wait_op_.cancelled.load(std::memory_order_acquire)) { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&wait_op_); return std::noop_coroutine(); } - io_uring_submit_op(*sched_, &wait_op_); + uring_submit_op(*sched_, &wait_op_); return std::noop_coroutine(); } @@ -387,8 +416,8 @@ class BOOST_COROSIO_DECL io_uring_tcp_socket final // number (same reasoning as close_socket). if (fd_ >= 0) sched_->cancel_and_flush(fd_); - int fd = fd_; - fd_ = -1; + int fd = fd_; + fd_ = -1; local_endpoint_ = endpoint{}; remote_endpoint_ = endpoint{}; local_endpoint_state_.store( @@ -429,15 +458,14 @@ class BOOST_COROSIO_DECL io_uring_tcp_socket final // syscall. The mutable update races benignly with concurrent // readers — both threads would compute the same value from // the same fd. - if (local_endpoint_state_.load(std::memory_order_acquire) - == endpoint_state::lazy_pending - && fd_ >= 0) + if (local_endpoint_state_.load(std::memory_order_acquire) == + endpoint_state::lazy_pending && + fd_ >= 0) { sockaddr_storage local{}; socklen_t len = sizeof(local); - if (::getsockname( - fd_, - reinterpret_cast(&local), &len) == 0) + if (::getsockname(fd_, reinterpret_cast(&local), &len) == + 0) local_endpoint_ = sockaddr_to_endpoint(local); local_endpoint_state_.store( endpoint_state::resolved, std::memory_order_release); @@ -453,7 +481,7 @@ class BOOST_COROSIO_DECL io_uring_tcp_socket final /** TCP socket service for io_uring. - Owns all `io_uring_tcp_socket` implementations for an `io_context`. + Owns all `uring_tcp_socket` implementations for an `io_context`. Satisfies the `tcp_service` interface so the generic `tcp_socket` front-end can call `open_socket` and `bind_socket` transparently. @@ -464,12 +492,16 @@ class BOOST_COROSIO_DECL io_uring_tcp_socket final @par Thread Safety All public member functions are thread-safe. */ -class BOOST_COROSIO_DECL io_uring_tcp_service final - : public io_uring_socket_service_base< - io_uring_tcp_service, tcp_service, io_uring_tcp_socket> +class BOOST_COROSIO_DECL uring_tcp_service final + : public uring_socket_service_base< + uring_tcp_service, + tcp_service, + uring_tcp_socket> { - using base_service = io_uring_socket_service_base< - io_uring_tcp_service, tcp_service, io_uring_tcp_socket>; + using base_service = uring_socket_service_base< + uring_tcp_service, + tcp_service, + uring_tcp_socket>; public: /// Identifies this service for `execution_context` lookup. @@ -480,12 +512,12 @@ class BOOST_COROSIO_DECL io_uring_tcp_service final @param ctx The owning execution context. The io_uring scheduler must already be registered. */ - explicit io_uring_tcp_service(capy::execution_context& ctx) - : base_service(ctx) - {} + explicit uring_tcp_service(capy::execution_context& ctx) : base_service(ctx) + { + } // construct / destroy / shutdown / close / scheduler() are inherited - // from io_uring_socket_service_base. The methods below are TCP-specific. + // from uring_socket_service_base. The methods below are TCP-specific. /** Open a socket fd and associate it with an impl. @@ -499,11 +531,13 @@ class BOOST_COROSIO_DECL io_uring_tcp_service final */ std::error_code open_socket( tcp_socket::implementation& impl, - int family, int type, int protocol) override + int family, + int type, + int protocol) override { - auto& sock = static_cast(impl); - int fd = ::socket( - family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); + auto& sock = static_cast(impl); + int fd = + ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); if (fd < 0) return make_err(errno); // LCOV_EXCL_START: dead — open() guards is_open(), so open_socket @@ -537,11 +571,10 @@ class BOOST_COROSIO_DECL io_uring_tcp_service final @return Error code on failure, empty on success. */ std::error_code assign_socket( - tcp_socket::implementation& impl, - native_handle_type fd) override + tcp_socket::implementation& impl, native_handle_type fd) override { - auto& sock = static_cast(impl); - int nfd = static_cast(fd); + auto& sock = static_cast(impl); + int nfd = static_cast(fd); if (nfd >= 0 && nfd == sock.fd_) return std::make_error_code(std::errc::invalid_argument); if (auto ec = validate_socket_fd(nfd, SOCK_STREAM, true)) @@ -559,20 +592,21 @@ class BOOST_COROSIO_DECL io_uring_tcp_service final sockaddr_storage local{}; socklen_t local_len = sizeof(local); - if (::getsockname(sock.fd_, - reinterpret_cast(&local), &local_len) == 0) + if (::getsockname( + sock.fd_, reinterpret_cast(&local), &local_len) == 0) { sock.local_endpoint_ = sockaddr_to_endpoint(local); sock.family_ = local.ss_family; } sock.local_endpoint_state_.store( - io_uring_tcp_socket::endpoint_state::resolved, + uring_tcp_socket::endpoint_state::resolved, std::memory_order_release); sockaddr_storage remote{}; socklen_t remote_len = sizeof(remote); - if (::getpeername(sock.fd_, - reinterpret_cast(&remote), &remote_len) == 0) + if (::getpeername( + sock.fd_, reinterpret_cast(&remote), &remote_len) == + 0) sock.remote_endpoint_ = sockaddr_to_endpoint(remote); return {}; @@ -584,25 +618,22 @@ class BOOST_COROSIO_DECL io_uring_tcp_service final @param ep The local endpoint to bind to. @return Error code on failure, empty on success. */ - std::error_code bind_socket( - tcp_socket::implementation& impl, endpoint ep) override + std::error_code + bind_socket(tcp_socket::implementation& impl, endpoint ep) override { - auto& sock = static_cast(impl); + auto& sock = static_cast(impl); sockaddr_storage addr{}; socklen_t len = endpoint_to_sockaddr(ep, addr); - if (::bind( - sock.fd_, - reinterpret_cast(&addr), len) < 0) + if (::bind(sock.fd_, reinterpret_cast(&addr), len) < 0) return make_err(errno); sockaddr_storage local{}; socklen_t local_len = sizeof(local); if (::getsockname( - sock.fd_, - reinterpret_cast(&local), &local_len) == 0) + sock.fd_, reinterpret_cast(&local), &local_len) == 0) sock.local_endpoint_ = sockaddr_to_endpoint(local); sock.local_endpoint_state_.store( - io_uring_tcp_socket::endpoint_state::resolved, + uring_tcp_socket::endpoint_state::resolved, std::memory_order_release); return {}; } @@ -617,17 +648,17 @@ class BOOST_COROSIO_DECL io_uring_tcp_service final @param peer Peer endpoint from `accept(2)`. @return Raw pointer to the registered impl. */ - io_uring_tcp_socket* adopt_fd(int fd, endpoint const& peer) + uring_tcp_socket* adopt_fd(int fd, endpoint const& peer) { - auto p = std::make_shared(*this, *sched_); - p->fd_ = fd; + auto p = std::make_shared(*this, *sched_); + p->fd_ = fd; p->remote_endpoint_ = peer; // Mark the local endpoint as authoritative-but-unresolved. // The accessor will fetch it via getsockname on first call. // Accept-heavy workloads that never query the local endpoint // skip the syscall entirely. p->local_endpoint_state_.store( - io_uring_tcp_socket::endpoint_state::lazy_pending, + uring_tcp_socket::endpoint_state::lazy_pending, std::memory_order_release); return this->register_impl(std::move(p)); @@ -637,26 +668,26 @@ class BOOST_COROSIO_DECL io_uring_tcp_service final /** TCP acceptor implementation for io_uring. Inherits the multishot machinery (parked-fd queue, waiter queue, - CQE drain on destruction) from `io_uring_multishot_acceptor_base`. + CQE drain on destruction) from `uring_multishot_acceptor_base`. This class adds only the `accept()` override (matching `tcp_acceptor::implementation`'s exact signature) and the `adopt_thunk` static that wraps an accepted fd via - `io_uring_tcp_service::adopt_fd`. + `uring_tcp_service::adopt_fd`. */ -class BOOST_COROSIO_DECL io_uring_tcp_acceptor final - : public io_uring_multishot_acceptor_base< - io_uring_tcp_acceptor, +class BOOST_COROSIO_DECL uring_tcp_acceptor final + : public uring_multishot_acceptor_base< + uring_tcp_acceptor, tcp_acceptor::implementation, endpoint, - io_uring_tcp_service> + uring_tcp_service> { - friend io_uring_tcp_acceptor_service; + friend uring_tcp_acceptor_service; - using base_type = io_uring_multishot_acceptor_base< - io_uring_tcp_acceptor, + using base_type = uring_multishot_acceptor_base< + uring_tcp_acceptor, tcp_acceptor::implementation, endpoint, - io_uring_tcp_service>; + uring_tcp_service>; // Readiness-wait slot. The multishot accept op delivers accepted // fds, but `wait()` reports raw poll readiness on the listening fd @@ -664,18 +695,19 @@ class BOOST_COROSIO_DECL io_uring_tcp_acceptor final uring_wait_op wait_op_; public: - explicit io_uring_tcp_acceptor( - io_uring_tcp_acceptor_service&, - io_uring_scheduler& sched, - io_uring_tcp_service& peer_svc) noexcept + explicit uring_tcp_acceptor( + uring_tcp_acceptor_service&, + uring_scheduler& sched, + uring_tcp_service& peer_svc) noexcept : base_type(sched, peer_svc) - {} + { + } std::coroutine_handle<> accept( - std::coroutine_handle<> h, - capy::executor_ref ex, - std::stop_token token, - std::error_code* ec, + std::coroutine_handle<> h, + capy::executor_ref ex, + std::stop_token token, + std::error_code* ec, io_object::implementation** impl_out) override { base_type::dispatch_or_queue(h, ex, token, ec, impl_out); @@ -684,10 +716,10 @@ class BOOST_COROSIO_DECL io_uring_tcp_acceptor final std::coroutine_handle<> wait( std::coroutine_handle<> h, - capy::executor_ref ex, - wait_type w, - std::stop_token token, - std::error_code* ec) override + capy::executor_ref ex, + wait_type w, + std::stop_token token, + std::error_code* ec) override { // Closed-object contract: complete with bad_file_descriptor // instead of parking a waiter no accept machinery will signal. @@ -725,31 +757,34 @@ class BOOST_COROSIO_DECL io_uring_tcp_acceptor final } // Errors are not consumed by the accept machinery, so the // error wait still polls the descriptor. - wait_op_.prepare(h, ex, ec, this->fd_, this->sched_, - this->shared_from_this(), POLLPRI | POLLERR | POLLHUP, token); + wait_op_.prepare( + h, ex, ec, this->fd_, this->sched_, this->shared_from_this(), + POLLPRI | POLLERR | POLLHUP, token); this->sched_->work_started(); if (wait_op_.cancelled.load(std::memory_order_acquire)) { - io_uring_scheduler::lock_type lock(this->sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(this->sched_->dispatch_mutex()); this->sched_->push_completed_locked(&wait_op_); return std::noop_coroutine(); } - io_uring_submit_op(*this->sched_, &wait_op_); + uring_submit_op(*this->sched_, &wait_op_); return std::noop_coroutine(); } static io_object::implementation* adopt_thunk( - void* peer_service, int fd, - sockaddr_storage const& peer, socklen_t /*peer_len*/) noexcept + void* peer_service, + int fd, + sockaddr_storage const& peer, + socklen_t /*peer_len*/) noexcept { - auto* svc = static_cast(peer_service); + auto* svc = static_cast(peer_service); return svc->adopt_fd(fd, sockaddr_to_endpoint(peer)); } }; /** TCP acceptor service for io_uring. - Owns all `io_uring_tcp_acceptor` implementations for an `io_context`. + Owns all `uring_tcp_acceptor` implementations for an `io_context`. Satisfies the `tcp_acceptor_service` interface so the generic `tcp_acceptor` front-end can call `open_acceptor_socket`, `bind_acceptor`, and `listen_acceptor` transparently. @@ -761,7 +796,7 @@ class BOOST_COROSIO_DECL io_uring_tcp_acceptor final @par Thread Safety All public member functions are thread-safe. */ -class BOOST_COROSIO_DECL io_uring_tcp_acceptor_service final +class BOOST_COROSIO_DECL uring_tcp_acceptor_service final : public tcp_acceptor_service { public: @@ -773,14 +808,15 @@ class BOOST_COROSIO_DECL io_uring_tcp_acceptor_service final @param ctx The owning execution context. Both the io_uring scheduler and the TCP socket service must already be registered. */ - explicit io_uring_tcp_acceptor_service(capy::execution_context& ctx) - : sched_(&ctx.use_service()) - , peer_svc_(&ctx.use_service()) - {} + explicit uring_tcp_acceptor_service(capy::execution_context& ctx) + : sched_(&ctx.use_service()) + , peer_svc_(&ctx.use_service()) + { + } void shutdown() override { - std::vector> live; + std::vector> live; { std::lock_guard lk(mutex_); live.reserve(impls_.size()); @@ -795,8 +831,8 @@ class BOOST_COROSIO_DECL io_uring_tcp_acceptor_service final io_object::implementation* construct() override { - auto p = std::make_shared( - *this, *sched_, *peer_svc_); + auto p = + std::make_shared(*this, *sched_, *peer_svc_); auto* raw = p.get(); std::lock_guard lk(mutex_); impls_.emplace(raw, std::move(p)); @@ -808,14 +844,14 @@ class BOOST_COROSIO_DECL io_uring_tcp_acceptor_service final if (!p) return; std::lock_guard lk(mutex_); - impls_.erase(static_cast(p)); + impls_.erase(static_cast(p)); } // Close the fd eagerly when tcp_acceptor::close() is called, before // destroy() drops the shared_ptr and the destructor runs. void close(io_object::handle& h) override { - auto* acc = static_cast(h.get()); + auto* acc = static_cast(h.get()); if (acc && acc->fd_ >= 0) { // Flush the cancel SQE before closing the fd so the kernel @@ -851,9 +887,9 @@ class BOOST_COROSIO_DECL io_uring_tcp_acceptor_service final int type, int protocol) override { - auto& acc = static_cast(impl); - int fd = ::socket( - family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); + auto& acc = static_cast(impl); + int fd = + ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); if (fd < 0) return make_err(errno); // LCOV_EXCL_START: dead — open() guards is_open(), so open_socket @@ -884,8 +920,8 @@ class BOOST_COROSIO_DECL io_uring_tcp_acceptor_service final std::error_code assign_socket( tcp_acceptor::implementation& impl, native_handle_type fd) override { - auto& acc = static_cast(impl); - int nfd = static_cast(fd); + auto& acc = static_cast(impl); + int nfd = static_cast(fd); if (nfd >= 0 && nfd == acc.fd_) return std::make_error_code(std::errc::invalid_argument); if (auto ec = validate_socket_fd(nfd, SOCK_STREAM, true)) @@ -907,7 +943,7 @@ class BOOST_COROSIO_DECL io_uring_tcp_acceptor_service final acc.local_endpoint_ = endpoint{}; sockaddr_storage local{}; - socklen_t local_len = sizeof(local); + socklen_t local_len = sizeof(local); if (::getsockname( nfd, reinterpret_cast(&local), &local_len) == 0) acc.local_endpoint_ = sockaddr_to_endpoint(local); @@ -923,22 +959,19 @@ class BOOST_COROSIO_DECL io_uring_tcp_acceptor_service final @param ep The local endpoint to bind to. @return Error code on failure, empty on success. */ - std::error_code bind_acceptor( - tcp_acceptor::implementation& impl, endpoint ep) override + std::error_code + bind_acceptor(tcp_acceptor::implementation& impl, endpoint ep) override { - auto& acc = static_cast(impl); + auto& acc = static_cast(impl); sockaddr_storage addr{}; socklen_t len = endpoint_to_sockaddr(ep, addr); - if (::bind( - acc.fd_, - reinterpret_cast(&addr), len) < 0) + if (::bind(acc.fd_, reinterpret_cast(&addr), len) < 0) return make_err(errno); sockaddr_storage local{}; socklen_t local_len = sizeof(local); if (::getsockname( - acc.fd_, - reinterpret_cast(&local), &local_len) == 0) + acc.fd_, reinterpret_cast(&local), &local_len) == 0) acc.local_endpoint_ = sockaddr_to_endpoint(local); return {}; } @@ -952,10 +985,10 @@ class BOOST_COROSIO_DECL io_uring_tcp_acceptor_service final @param backlog Maximum pending-connection queue length. @return Error code on failure, empty on success. */ - std::error_code listen_acceptor( - tcp_acceptor::implementation& impl, int backlog) override + std::error_code + listen_acceptor(tcp_acceptor::implementation& impl, int backlog) override { - auto& acc = static_cast(impl); + auto& acc = static_cast(impl); if (::listen(acc.fd_, backlog) < 0) return make_err(errno); if (acc.prepare_listen_arm()) @@ -964,21 +997,24 @@ class BOOST_COROSIO_DECL io_uring_tcp_acceptor_service final } /// Return the scheduler used by acceptors created by this service. - io_uring_scheduler& scheduler() noexcept { return *sched_; } + uring_scheduler& scheduler() noexcept + { + return *sched_; + } private: - io_uring_scheduler* sched_; - io_uring_tcp_service* peer_svc_; - std::mutex mutex_; - std::unordered_map> impls_; + uring_scheduler* sched_; + uring_tcp_service* peer_svc_; + std::mutex mutex_; + std::unordered_map> + impls_; }; /** Unix domain stream socket implementation for io_uring. Implements `local_stream_socket::implementation` using a proactor model: read, write, and connect operations are submitted to the - kernel via `io_uring_submit_op` and complete through the ring's + kernel via `uring_submit_op` and complete through the ring's CQE path. The object is always owned by a `shared_ptr` managed by the service. @@ -990,16 +1026,16 @@ class BOOST_COROSIO_DECL io_uring_tcp_acceptor_service final Shared objects: Unsafe. A socket must not have two operations of the same type in flight simultaneously. */ -class BOOST_COROSIO_DECL io_uring_local_stream_socket final +class BOOST_COROSIO_DECL uring_local_stream_socket final : public native_socket_base< - io_uring_local_stream_socket, + uring_local_stream_socket, local_stream_socket::implementation, corosio::local_endpoint> { - friend io_uring_local_stream_service; + friend uring_local_stream_service; - io_uring_scheduler* sched_ = nullptr; - [[maybe_unused]] io_uring_local_stream_service* svc_ = nullptr; + uring_scheduler* sched_ = nullptr; + [[maybe_unused]] uring_local_stream_service* svc_ = nullptr; // fd_ and local_endpoint_ live in native_socket_base, which also // provides native_handle/is_open/set_option/get_option/local_endpoint. @@ -1007,10 +1043,10 @@ class BOOST_COROSIO_DECL io_uring_local_stream_socket final // Per-fd op slots — embedded to eliminate per-call heap allocation. // Single-pending invariant per slot. - uring_read_op rd_; - uring_write_op wr_; + uring_read_op rd_; + uring_write_op wr_; uring_local_connect_op conn_; - uring_wait_op wait_op_; + uring_wait_op wait_op_; mutable detail::speculative_state spec_; @@ -1022,17 +1058,18 @@ class BOOST_COROSIO_DECL io_uring_local_stream_socket final @param svc The owning service. @param sched The io_uring scheduler owned by the context. */ - explicit io_uring_local_stream_socket( - io_uring_local_stream_service& svc, - io_uring_scheduler& sched) noexcept + explicit uring_local_stream_socket( + uring_local_stream_service& svc, uring_scheduler& sched) noexcept : sched_(&sched) , svc_(&svc) - {} + { + } - ~io_uring_local_stream_socket() override + ~uring_local_stream_socket() override { if (fd_ >= 0) - ::close(fd_); // LCOV_EXCL_LINE backstop: close_socket() clears fd_ before destroy + ::close( + fd_); // LCOV_EXCL_LINE backstop: close_socket() clears fd_ before destroy } // ---------------------------------------------------------------- @@ -1041,28 +1078,32 @@ class BOOST_COROSIO_DECL io_uring_local_stream_socket final std::coroutine_handle<> read_some( std::coroutine_handle<> h, - capy::executor_ref ex, - buffer_param buffers, - std::stop_token token, - std::error_code* ec, - std::size_t* bytes) override - { - iovec iovecs[io_uring_max_iov]; - int iovec_count = copy_to_iovec(buffers, iovecs); - bool stop_now = token.stop_possible() && token.stop_requested(); - bool empty_buf = (iovec_count == 0); - - ssize_t n = 0; - int err = 0; - bool have_sync_res = stop_now || empty_buf; + capy::executor_ref ex, + buffer_param buffers, + std::stop_token token, + std::error_code* ec, + std::size_t* bytes) override + { + iovec iovecs[uring_max_iov]; + int iovec_count = copy_to_iovec(buffers, iovecs); + bool stop_now = token.stop_possible() && token.stop_requested(); + bool empty_buf = (iovec_count == 0); + + ssize_t n = 0; + int err = 0; + bool have_sync_res = stop_now || empty_buf; if (!have_sync_res && spec_.may_speculate_read()) { - do { n = ::readv(fd_, iovecs, iovec_count); } + do + { + n = ::readv(fd_, iovecs, iovec_count); + } while (n < 0 && errno == EINTR); if (n >= 0 || (errno != EAGAIN && errno != EWOULDBLOCK)) { have_sync_res = true; - if (n < 0) err = errno; + if (n < 0) + err = errno; // Speculative read produced a definitive answer (data // or non-EAGAIN error); reset the failure streak so a // burst of past EAGAINs doesn't latch perma-off when @@ -1082,67 +1123,73 @@ class BOOST_COROSIO_DECL io_uring_local_stream_socket final { decode_io_result( ec, stop_now, err ? make_err(err) : std::error_code{}, - /*is_read=*/true, - n < 0 ? 0u : static_cast(n), empty_buf); + /*is_read=*/true, n < 0 ? 0u : static_cast(n), + empty_buf); if (bytes) *bytes = (n < 0) ? 0u : static_cast(n); rd_.cont.h = h; return dispatch_coro(ex, rd_.cont); } - rd_.prepare(h, ex, ec, bytes, fd_, sched_, - shared_from_this(), &spec_, buffers, token); + rd_.prepare( + h, ex, ec, bytes, fd_, sched_, shared_from_this(), &spec_, + buffers, token); if (stop_now) rd_.cancelled.store(true, std::memory_order_release); else rd_.res = (n < 0) ? -err : static_cast(n); sched_->work_started(); { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&rd_); } return std::noop_coroutine(); } - rd_.prepare(h, ex, ec, bytes, fd_, sched_, - shared_from_this(), &spec_, buffers, token); + rd_.prepare( + h, ex, ec, bytes, fd_, sched_, shared_from_this(), &spec_, buffers, + token); sched_->work_started(); if (rd_.cancelled.load(std::memory_order_acquire)) { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&rd_); return std::noop_coroutine(); } - io_uring_submit_op(*sched_, &rd_); + uring_submit_op(*sched_, &rd_); return std::noop_coroutine(); } std::coroutine_handle<> write_some( std::coroutine_handle<> h, - capy::executor_ref ex, - buffer_param buffers, - std::stop_token token, - std::error_code* ec, - std::size_t* bytes) override - { - iovec iovecs[io_uring_max_iov]; - int iovec_count = copy_to_iovec(buffers, iovecs); - bool stop_now = token.stop_possible() && token.stop_requested(); - bool empty_buf = (iovec_count == 0); - - ssize_t n = 0; - int err = 0; - bool have_sync_res = stop_now || empty_buf; + capy::executor_ref ex, + buffer_param buffers, + std::stop_token token, + std::error_code* ec, + std::size_t* bytes) override + { + iovec iovecs[uring_max_iov]; + int iovec_count = copy_to_iovec(buffers, iovecs); + bool stop_now = token.stop_possible() && token.stop_requested(); + bool empty_buf = (iovec_count == 0); + + ssize_t n = 0; + int err = 0; + bool have_sync_res = stop_now || empty_buf; if (!have_sync_res && spec_.may_speculate_write()) { msghdr msg{}; msg.msg_iov = iovecs; msg.msg_iovlen = static_cast(iovec_count); - do { n = ::sendmsg(fd_, &msg, MSG_NOSIGNAL); } + do + { + n = ::sendmsg(fd_, &msg, MSG_NOSIGNAL); + } while (n < 0 && errno == EINTR); if (n >= 0 || (errno != EAGAIN && errno != EWOULDBLOCK)) { have_sync_res = true; - if (n < 0) err = errno; + if (n < 0) + err = errno; } else { @@ -1162,30 +1209,32 @@ class BOOST_COROSIO_DECL io_uring_local_stream_socket final wr_.cont.h = h; return dispatch_coro(ex, wr_.cont); } - wr_.prepare(h, ex, ec, bytes, fd_, sched_, - shared_from_this(), &spec_, buffers, token); + wr_.prepare( + h, ex, ec, bytes, fd_, sched_, shared_from_this(), &spec_, + buffers, token); if (stop_now) wr_.cancelled.store(true, std::memory_order_release); else wr_.res = (n < 0) ? -err : static_cast(n); sched_->work_started(); { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&wr_); } return std::noop_coroutine(); } - wr_.prepare(h, ex, ec, bytes, fd_, sched_, - shared_from_this(), &spec_, buffers, token); + wr_.prepare( + h, ex, ec, bytes, fd_, sched_, shared_from_this(), &spec_, buffers, + token); sched_->work_started(); if (wr_.cancelled.load(std::memory_order_acquire)) { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&wr_); return std::noop_coroutine(); } - io_uring_submit_op(*sched_, &wr_); + uring_submit_op(*sched_, &wr_); return std::noop_coroutine(); } @@ -1194,28 +1243,30 @@ class BOOST_COROSIO_DECL io_uring_local_stream_socket final // ---------------------------------------------------------------- std::coroutine_handle<> connect( - std::coroutine_handle<> h, - capy::executor_ref ex, - corosio::local_endpoint ep, - std::stop_token token, - std::error_code* ec) override + std::coroutine_handle<> h, + capy::executor_ref ex, + corosio::local_endpoint ep, + std::stop_token token, + std::error_code* ec) override { bool stop_now = token.stop_possible() && token.stop_requested(); if (stop_now) { if (sched_->try_consume_inline_budget()) { - if (ec) *ec = capy::error::canceled; + if (ec) + *ec = capy::error::canceled; conn_.cont.h = h; return dispatch_coro(ex, conn_.cont); } conn_.addrlen = to_sockaddr(ep, conn_.addr); - conn_.prepare(h, ex, ec, fd_, sched_, shared_from_this(), - ep, &remote_endpoint_, &local_endpoint_, token); + conn_.prepare( + h, ex, ec, fd_, sched_, shared_from_this(), ep, + &remote_endpoint_, &local_endpoint_, token); conn_.cancelled.store(true, std::memory_order_release); sched_->work_started(); { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&conn_); } return std::noop_coroutine(); @@ -1224,47 +1275,55 @@ class BOOST_COROSIO_DECL io_uring_local_stream_socket final // A speculative ::connect would leave the fd in EINPROGRESS and // a subsequent IORING_OP_CONNECT would see EALREADY — avoid. conn_.addrlen = to_sockaddr(ep, conn_.addr); - conn_.prepare(h, ex, ec, fd_, sched_, shared_from_this(), - ep, &remote_endpoint_, &local_endpoint_, token); + conn_.prepare( + h, ex, ec, fd_, sched_, shared_from_this(), ep, &remote_endpoint_, + &local_endpoint_, token); sched_->work_started(); if (conn_.cancelled.load(std::memory_order_acquire)) { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&conn_); return std::noop_coroutine(); } - io_uring_submit_op(*sched_, &conn_); + uring_submit_op(*sched_, &conn_); return std::noop_coroutine(); } std::coroutine_handle<> wait( std::coroutine_handle<> h, - capy::executor_ref ex, - wait_type w, - std::stop_token token, - std::error_code* ec) override + capy::executor_ref ex, + wait_type w, + std::stop_token token, + std::error_code* ec) override { int poll_flags = 0; switch (w) { - case wait_type::read: poll_flags = POLLIN; break; - case wait_type::write: poll_flags = POLLOUT; break; - case wait_type::error: poll_flags = POLLPRI | POLLERR | POLLHUP; break; - } - wait_op_.prepare(h, ex, ec, fd_, sched_, - shared_from_this(), poll_flags, token); + case wait_type::read: + poll_flags = POLLIN; + break; + case wait_type::write: + poll_flags = POLLOUT; + break; + case wait_type::error: + poll_flags = POLLPRI | POLLERR | POLLHUP; + break; + } + wait_op_.prepare( + h, ex, ec, fd_, sched_, shared_from_this(), poll_flags, token); sched_->work_started(); if (wait_op_.cancelled.load(std::memory_order_acquire)) { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&wait_op_); return std::noop_coroutine(); } - io_uring_submit_op(*sched_, &wait_op_); + uring_submit_op(*sched_, &wait_op_); return std::noop_coroutine(); } - std::error_code shutdown(local_stream_socket::shutdown_type what) noexcept override + std::error_code + shutdown(local_stream_socket::shutdown_type what) noexcept override { if (::shutdown(fd_, static_cast(what)) != 0) return make_err(errno); @@ -1281,8 +1340,8 @@ class BOOST_COROSIO_DECL io_uring_local_stream_socket final // number (same reasoning as close_socket). if (fd_ >= 0) sched_->cancel_and_flush(fd_); - int fd = fd_; - fd_ = -1; + int fd = fd_; + fd_ = -1; local_endpoint_ = corosio::local_endpoint{}; remote_endpoint_ = corosio::local_endpoint{}; return fd; @@ -1316,7 +1375,7 @@ class BOOST_COROSIO_DECL io_uring_local_stream_socket final /** Unix domain stream socket service for io_uring. - Owns all `io_uring_local_stream_socket` implementations for an + Owns all `uring_local_stream_socket` implementations for an `io_context`. Satisfies the `local_stream_service` interface so the generic `local_stream_socket` front-end can call `open_socket` and `assign_socket` transparently. @@ -1328,14 +1387,16 @@ class BOOST_COROSIO_DECL io_uring_local_stream_socket final @par Thread Safety All public member functions are thread-safe. */ -class BOOST_COROSIO_DECL io_uring_local_stream_service final - : public io_uring_socket_service_base< - io_uring_local_stream_service, local_stream_service, - io_uring_local_stream_socket> +class BOOST_COROSIO_DECL uring_local_stream_service final + : public uring_socket_service_base< + uring_local_stream_service, + local_stream_service, + uring_local_stream_socket> { - using base_service = io_uring_socket_service_base< - io_uring_local_stream_service, local_stream_service, - io_uring_local_stream_socket>; + using base_service = uring_socket_service_base< + uring_local_stream_service, + local_stream_service, + uring_local_stream_socket>; public: /// Identifies this service for `execution_context` lookup. @@ -1346,12 +1407,13 @@ class BOOST_COROSIO_DECL io_uring_local_stream_service final @param ctx The owning execution context. The io_uring scheduler must already be registered. */ - explicit io_uring_local_stream_service(capy::execution_context& ctx) + explicit uring_local_stream_service(capy::execution_context& ctx) : base_service(ctx) - {} + { + } // construct / destroy / shutdown / close / scheduler() are inherited - // from io_uring_socket_service_base. + // from uring_socket_service_base. /** Open an AF_UNIX stream socket and associate it with an impl. @@ -1366,10 +1428,13 @@ class BOOST_COROSIO_DECL io_uring_local_stream_service final */ std::error_code open_socket( local_stream_socket::implementation& impl, - int family, int type, int protocol) override + int family, + int type, + int protocol) override { - auto& sock = static_cast(impl); - int fd = ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); + auto& sock = static_cast(impl); + int fd = + ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); if (fd < 0) return make_err(errno); // LCOV_EXCL_START: dead — open() guards is_open(), so open_socket @@ -1397,8 +1462,8 @@ class BOOST_COROSIO_DECL io_uring_local_stream_service final local_stream_socket::implementation& impl, native_handle_type fd) override { - auto& sock = static_cast(impl); - int nfd = static_cast(fd); + auto& sock = static_cast(impl); + int nfd = static_cast(fd); if (nfd >= 0 && nfd == sock.fd_) return std::make_error_code(std::errc::invalid_argument); if (auto ec = validate_socket_fd(nfd, SOCK_STREAM, false)) @@ -1413,15 +1478,17 @@ class BOOST_COROSIO_DECL io_uring_local_stream_service final sockaddr_storage local{}; socklen_t local_len = sizeof(local); - if (::getsockname(sock.fd_, - reinterpret_cast(&local), &local_len) == 0) + if (::getsockname( + sock.fd_, reinterpret_cast(&local), &local_len) == 0) sock.local_endpoint_ = sockaddr_to_local_endpoint(local, local_len); sockaddr_storage remote{}; socklen_t remote_len = sizeof(remote); - if (::getpeername(sock.fd_, - reinterpret_cast(&remote), &remote_len) == 0) - sock.remote_endpoint_ = sockaddr_to_local_endpoint(remote, remote_len); + if (::getpeername( + sock.fd_, reinterpret_cast(&remote), &remote_len) == + 0) + sock.remote_endpoint_ = + sockaddr_to_local_endpoint(remote, remote_len); return {}; } @@ -1436,11 +1503,11 @@ class BOOST_COROSIO_DECL io_uring_local_stream_service final @param peer Peer endpoint from `accept(2)`. @return Raw pointer to the registered impl. */ - io_uring_local_stream_socket* adopt_fd( - int fd, corosio::local_endpoint const& peer) + uring_local_stream_socket* + adopt_fd(int fd, corosio::local_endpoint const& peer) { - auto p = std::make_shared(*this, *sched_); - p->fd_ = fd; + auto p = std::make_shared(*this, *sched_); + p->fd_ = fd; p->remote_endpoint_ = peer; sockaddr_storage local{}; @@ -1456,41 +1523,42 @@ class BOOST_COROSIO_DECL io_uring_local_stream_service final Inherits all multishot machinery (parked-fd queue, waiter queue, descriptor release, CQE drain on destruction) from - `io_uring_multishot_acceptor_base`. Adds only the `accept()` + `uring_multishot_acceptor_base`. Adds only the `accept()` override and the `adopt_thunk` static that wraps an accepted fd - via `io_uring_local_stream_service::adopt_fd`. + via `uring_local_stream_service::adopt_fd`. */ -class BOOST_COROSIO_DECL io_uring_local_stream_acceptor final - : public io_uring_multishot_acceptor_base< - io_uring_local_stream_acceptor, +class BOOST_COROSIO_DECL uring_local_stream_acceptor final + : public uring_multishot_acceptor_base< + uring_local_stream_acceptor, local_stream_acceptor::implementation, corosio::local_endpoint, - io_uring_local_stream_service> + uring_local_stream_service> { - friend io_uring_local_stream_acceptor_service; + friend uring_local_stream_acceptor_service; - using base_type = io_uring_multishot_acceptor_base< - io_uring_local_stream_acceptor, + using base_type = uring_multishot_acceptor_base< + uring_local_stream_acceptor, local_stream_acceptor::implementation, corosio::local_endpoint, - io_uring_local_stream_service>; + uring_local_stream_service>; - // Readiness-wait slot. See io_uring_tcp_acceptor::wait_op_. + // Readiness-wait slot. See uring_tcp_acceptor::wait_op_. uring_wait_op wait_op_; public: - explicit io_uring_local_stream_acceptor( - io_uring_local_stream_acceptor_service&, - io_uring_scheduler& sched, - io_uring_local_stream_service& peer_svc) noexcept + explicit uring_local_stream_acceptor( + uring_local_stream_acceptor_service&, + uring_scheduler& sched, + uring_local_stream_service& peer_svc) noexcept : base_type(sched, peer_svc) - {} + { + } std::coroutine_handle<> accept( - std::coroutine_handle<> h, - capy::executor_ref ex, - std::stop_token token, - std::error_code* ec, + std::coroutine_handle<> h, + capy::executor_ref ex, + std::stop_token token, + std::error_code* ec, io_object::implementation** impl_out) override { base_type::dispatch_or_queue(h, ex, token, ec, impl_out); @@ -1499,10 +1567,10 @@ class BOOST_COROSIO_DECL io_uring_local_stream_acceptor final std::coroutine_handle<> wait( std::coroutine_handle<> h, - capy::executor_ref ex, - wait_type w, - std::stop_token token, - std::error_code* ec) override + capy::executor_ref ex, + wait_type w, + std::stop_token token, + std::error_code* ec) override { // Closed-object contract: complete with bad_file_descriptor // instead of parking a waiter no accept machinery will signal. @@ -1540,31 +1608,34 @@ class BOOST_COROSIO_DECL io_uring_local_stream_acceptor final } // Errors are not consumed by the accept machinery, so the // error wait still polls the descriptor. - wait_op_.prepare(h, ex, ec, this->fd_, this->sched_, - this->shared_from_this(), POLLPRI | POLLERR | POLLHUP, token); + wait_op_.prepare( + h, ex, ec, this->fd_, this->sched_, this->shared_from_this(), + POLLPRI | POLLERR | POLLHUP, token); this->sched_->work_started(); if (wait_op_.cancelled.load(std::memory_order_acquire)) { - io_uring_scheduler::lock_type lock(this->sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(this->sched_->dispatch_mutex()); this->sched_->push_completed_locked(&wait_op_); return std::noop_coroutine(); } - io_uring_submit_op(*this->sched_, &wait_op_); + uring_submit_op(*this->sched_, &wait_op_); return std::noop_coroutine(); } static io_object::implementation* adopt_thunk( - void* peer_service, int fd, - sockaddr_storage const& peer, socklen_t peer_len) noexcept + void* peer_service, + int fd, + sockaddr_storage const& peer, + socklen_t peer_len) noexcept { - auto* svc = static_cast(peer_service); + auto* svc = static_cast(peer_service); return svc->adopt_fd(fd, sockaddr_to_local_endpoint(peer, peer_len)); } }; /** Unix domain stream acceptor service for io_uring. - Owns all `io_uring_local_stream_acceptor` implementations for an + Owns all `uring_local_stream_acceptor` implementations for an `io_context`. Satisfies the `local_stream_acceptor_service` interface so the generic `local_stream_acceptor` front-end can call `open_acceptor_socket`, `bind_acceptor`, and `listen_acceptor` @@ -1577,7 +1648,7 @@ class BOOST_COROSIO_DECL io_uring_local_stream_acceptor final @par Thread Safety All public member functions are thread-safe. */ -class BOOST_COROSIO_DECL io_uring_local_stream_acceptor_service final +class BOOST_COROSIO_DECL uring_local_stream_acceptor_service final : public local_stream_acceptor_service { public: @@ -1589,14 +1660,15 @@ class BOOST_COROSIO_DECL io_uring_local_stream_acceptor_service final @param ctx The owning execution context. Both the io_uring scheduler and the local stream socket service must already be registered. */ - explicit io_uring_local_stream_acceptor_service(capy::execution_context& ctx) - : sched_(&ctx.use_service()) - , peer_svc_(&ctx.use_service()) - {} + explicit uring_local_stream_acceptor_service(capy::execution_context& ctx) + : sched_(&ctx.use_service()) + , peer_svc_(&ctx.use_service()) + { + } void shutdown() override { - std::vector> live; + std::vector> live; { std::lock_guard lk(mutex_); live.reserve(impls_.size()); @@ -1611,7 +1683,7 @@ class BOOST_COROSIO_DECL io_uring_local_stream_acceptor_service final io_object::implementation* construct() override { - auto p = std::make_shared( + auto p = std::make_shared( *this, *sched_, *peer_svc_); auto* raw = p.get(); std::lock_guard lk(mutex_); @@ -1624,14 +1696,14 @@ class BOOST_COROSIO_DECL io_uring_local_stream_acceptor_service final if (!p) return; std::lock_guard lk(mutex_); - impls_.erase(static_cast(p)); + impls_.erase(static_cast(p)); } // Close the fd eagerly when local_stream_acceptor::close() is called, // before destroy() drops the shared_ptr and the destructor runs. void close(io_object::handle& h) override { - auto* acc = static_cast(h.get()); + auto* acc = static_cast(h.get()); if (acc && acc->fd_ >= 0) { // cancel_and_flush submits cancel-by-fd; drain_waiters_only @@ -1643,7 +1715,7 @@ class BOOST_COROSIO_DECL io_uring_local_stream_acceptor_service final // Break the multi_op_ -> impl_ptr (shared_ptr) cycle // start_multishot established. See the symmetric comment - // in io_uring_tcp_acceptor_service::close. + // in uring_tcp_acceptor_service::close. if (acc->multi_op_) acc->multi_op_->impl_ptr.reset(); } @@ -1663,8 +1735,9 @@ class BOOST_COROSIO_DECL io_uring_local_stream_acceptor_service final int type, int protocol) override { - auto& acc = static_cast(impl); - int fd = ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); + auto& acc = static_cast(impl); + int fd = + ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); if (fd < 0) return make_err(errno); // LCOV_EXCL_START: dead — open() guards is_open(), so open_socket @@ -1689,8 +1762,8 @@ class BOOST_COROSIO_DECL io_uring_local_stream_acceptor_service final local_stream_acceptor::implementation& impl, native_handle_type fd) override { - auto& acc = static_cast(impl); - int nfd = static_cast(fd); + auto& acc = static_cast(impl); + int nfd = static_cast(fd); if (nfd >= 0 && nfd == acc.fd_) return std::make_error_code(std::errc::invalid_argument); if (auto ec = validate_socket_fd(nfd, SOCK_STREAM, false)) @@ -1712,7 +1785,7 @@ class BOOST_COROSIO_DECL io_uring_local_stream_acceptor_service final acc.local_endpoint_ = corosio::local_endpoint{}; sockaddr_storage local{}; - socklen_t local_len = sizeof(local); + socklen_t local_len = sizeof(local); if (::getsockname( nfd, reinterpret_cast(&local), &local_len) == 0) acc.local_endpoint_ = sockaddr_to_local_endpoint(local, local_len); @@ -1732,7 +1805,7 @@ class BOOST_COROSIO_DECL io_uring_local_stream_acceptor_service final local_stream_acceptor::implementation& impl, corosio::local_endpoint ep) override { - auto& acc = static_cast(impl); + auto& acc = static_cast(impl); sockaddr_storage addr{}; socklen_t len = endpoint_to_sockaddr(ep, addr); if (::bind(acc.fd_, reinterpret_cast(&addr), len) < 0) @@ -1741,8 +1814,7 @@ class BOOST_COROSIO_DECL io_uring_local_stream_acceptor_service final sockaddr_storage local{}; socklen_t local_len = sizeof(local); if (::getsockname( - acc.fd_, - reinterpret_cast(&local), &local_len) == 0) + acc.fd_, reinterpret_cast(&local), &local_len) == 0) acc.local_endpoint_ = sockaddr_to_local_endpoint(local, local_len); return {}; } @@ -1757,10 +1829,9 @@ class BOOST_COROSIO_DECL io_uring_local_stream_acceptor_service final @return Error code on failure, empty on success. */ std::error_code listen_acceptor( - local_stream_acceptor::implementation& impl, - int backlog) override + local_stream_acceptor::implementation& impl, int backlog) override { - auto& acc = static_cast(impl); + auto& acc = static_cast(impl); if (::listen(acc.fd_, backlog) < 0) return make_err(errno); if (acc.prepare_listen_arm()) @@ -1769,21 +1840,26 @@ class BOOST_COROSIO_DECL io_uring_local_stream_acceptor_service final } /// Return the scheduler used by acceptors created by this service. - io_uring_scheduler& scheduler() noexcept { return *sched_; } + uring_scheduler& scheduler() noexcept + { + return *sched_; + } private: - io_uring_scheduler* sched_; - io_uring_local_stream_service* peer_svc_; - std::mutex mutex_; - std::unordered_map> impls_; + uring_scheduler* sched_; + uring_local_stream_service* peer_svc_; + std::mutex mutex_; + std::unordered_map< + uring_local_stream_acceptor*, + std::shared_ptr> + impls_; }; /** UDP socket implementation for io_uring. Implements `udp_socket::implementation` using a proactor model: send_to, recv_from, send, recv, and connect operations are submitted - to the kernel via `io_uring_submit_op` and complete through the ring's + to the kernel via `uring_submit_op` and complete through the ring's CQE path. The object is always owned by a `shared_ptr` managed by the service. @@ -1795,15 +1871,17 @@ class BOOST_COROSIO_DECL io_uring_local_stream_acceptor_service final Shared objects: Unsafe. One send and one recv may be in flight simultaneously, but two sends or two recvs must not overlap. */ -class BOOST_COROSIO_DECL io_uring_udp_socket final +class BOOST_COROSIO_DECL uring_udp_socket final : public native_socket_base< - io_uring_udp_socket, udp_socket::implementation, corosio::endpoint> + uring_udp_socket, + udp_socket::implementation, + corosio::endpoint> { - friend io_uring_udp_service; + friend uring_udp_service; - int family_ = AF_UNSPEC; // cached at open_socket - io_uring_scheduler* sched_ = nullptr; - [[maybe_unused]] io_uring_udp_service* svc_ = nullptr; + int family_ = AF_UNSPEC; // cached at open_socket + uring_scheduler* sched_ = nullptr; + [[maybe_unused]] uring_udp_service* svc_ = nullptr; // fd_ and local_endpoint_ live in native_socket_base, which also // provides native_handle/is_open/set_option/get_option/local_endpoint. @@ -1811,10 +1889,10 @@ class BOOST_COROSIO_DECL io_uring_udp_socket final // Per-fd op slots — embedded to eliminate per-call heap allocation. // Single-pending invariant per slot. - uring_connect_op conn_; + uring_connect_op conn_; uring_dgram_send_op send_; uring_dgram_recv_op recv_; - uring_wait_op wait_op_; + uring_wait_op wait_op_; mutable detail::speculative_state spec_; @@ -1826,17 +1904,18 @@ class BOOST_COROSIO_DECL io_uring_udp_socket final @param svc The owning service. @param sched The io_uring scheduler owned by the context. */ - explicit io_uring_udp_socket( - io_uring_udp_service& svc, - io_uring_scheduler& sched) noexcept + explicit uring_udp_socket( + uring_udp_service& svc, uring_scheduler& sched) noexcept : sched_(&sched) , svc_(&svc) - {} + { + } - ~io_uring_udp_socket() override + ~uring_udp_socket() override { if (fd_ >= 0) - ::close(fd_); // LCOV_EXCL_LINE backstop: close_socket() clears fd_ before destroy + ::close( + fd_); // LCOV_EXCL_LINE backstop: close_socket() clears fd_ before destroy } // ---------------------------------------------------------------- @@ -1845,84 +1924,84 @@ class BOOST_COROSIO_DECL io_uring_udp_socket final std::coroutine_handle<> send_to( std::coroutine_handle<> h, - capy::executor_ref ex, - buffer_param buf, - endpoint dest, - int flags, - std::stop_token token, - std::error_code* ec, - std::size_t* bytes_out) override + capy::executor_ref ex, + buffer_param buf, + endpoint dest, + int flags, + std::stop_token token, + std::error_code* ec, + std::size_t* bytes_out) override { sockaddr_storage addr{}; socklen_t len = endpoint_to_sockaddr(dest, addr); - return submit_send(h, ex, buf, len, addr, flags, - token, ec, bytes_out); + return submit_send(h, ex, buf, len, addr, flags, token, ec, bytes_out); } std::coroutine_handle<> recv_from( std::coroutine_handle<> h, - capy::executor_ref ex, - buffer_param buf, - endpoint* source, - int flags, - std::stop_token token, - std::error_code* ec, - std::size_t* bytes_out) override + capy::executor_ref ex, + buffer_param buf, + endpoint* source, + int flags, + std::stop_token token, + std::error_code* ec, + std::size_t* bytes_out) override { - return submit_recv(h, ex, buf, source != nullptr, source, flags, - token, ec, bytes_out); + return submit_recv( + h, ex, buf, source != nullptr, source, flags, token, ec, bytes_out); } std::coroutine_handle<> send( std::coroutine_handle<> h, - capy::executor_ref ex, - buffer_param buf, - int flags, - std::stop_token token, - std::error_code* ec, - std::size_t* bytes_out) override + capy::executor_ref ex, + buffer_param buf, + int flags, + std::stop_token token, + std::error_code* ec, + std::size_t* bytes_out) override { sockaddr_storage empty{}; - return submit_send(h, ex, buf, 0, empty, flags, - token, ec, bytes_out); + return submit_send(h, ex, buf, 0, empty, flags, token, ec, bytes_out); } std::coroutine_handle<> recv( std::coroutine_handle<> h, - capy::executor_ref ex, - buffer_param buf, - int flags, - std::stop_token token, - std::error_code* ec, - std::size_t* bytes_out) override + capy::executor_ref ex, + buffer_param buf, + int flags, + std::stop_token token, + std::error_code* ec, + std::size_t* bytes_out) override { - return submit_recv(h, ex, buf, false, nullptr, flags, - token, ec, bytes_out); + return submit_recv( + h, ex, buf, false, nullptr, flags, token, ec, bytes_out); } std::coroutine_handle<> connect( std::coroutine_handle<> h, - capy::executor_ref ex, - endpoint ep, - std::stop_token token, - std::error_code* ec) override + capy::executor_ref ex, + endpoint ep, + std::stop_token token, + std::error_code* ec) override { bool stop_now = token.stop_possible() && token.stop_requested(); if (stop_now) { if (sched_->try_consume_inline_budget()) { - if (ec) *ec = capy::error::canceled; + if (ec) + *ec = capy::error::canceled; conn_.cont.h = h; return dispatch_coro(ex, conn_.cont); } conn_.addrlen = to_sockaddr(ep, family_, conn_.addr); - conn_.prepare(h, ex, ec, fd_, sched_, shared_from_this(), - ep, &remote_endpoint_, &local_endpoint_, token); + conn_.prepare( + h, ex, ec, fd_, sched_, shared_from_this(), ep, + &remote_endpoint_, &local_endpoint_, token); conn_.cancelled.store(true, std::memory_order_release); sched_->work_started(); { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&conn_); } return std::noop_coroutine(); @@ -1931,51 +2010,57 @@ class BOOST_COROSIO_DECL io_uring_udp_socket final // io_uring's IORING_OP_CONNECT re-invokes connect(2) internally; // a prior speculative ::connect would leave EINPROGRESS → EALREADY. conn_.addrlen = to_sockaddr(ep, family_, conn_.addr); - conn_.prepare(h, ex, ec, fd_, sched_, shared_from_this(), - ep, &remote_endpoint_, &local_endpoint_, token); + conn_.prepare( + h, ex, ec, fd_, sched_, shared_from_this(), ep, &remote_endpoint_, + &local_endpoint_, token); sched_->work_started(); if (conn_.cancelled.load(std::memory_order_acquire)) { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&conn_); return std::noop_coroutine(); } - io_uring_submit_op(*sched_, &conn_); + uring_submit_op(*sched_, &conn_); return std::noop_coroutine(); } std::coroutine_handle<> wait( std::coroutine_handle<> h, - capy::executor_ref ex, - wait_type w, - std::stop_token token, - std::error_code* ec) override + capy::executor_ref ex, + wait_type w, + std::stop_token token, + std::error_code* ec) override { int poll_flags = 0; switch (w) { - case wait_type::read: poll_flags = POLLIN; break; - case wait_type::write: poll_flags = POLLOUT; break; - case wait_type::error: poll_flags = POLLPRI | POLLERR | POLLHUP; break; - } - wait_op_.prepare(h, ex, ec, fd_, sched_, - shared_from_this(), poll_flags, token); + case wait_type::read: + poll_flags = POLLIN; + break; + case wait_type::write: + poll_flags = POLLOUT; + break; + case wait_type::error: + poll_flags = POLLPRI | POLLERR | POLLHUP; + break; + } + wait_op_.prepare( + h, ex, ec, fd_, sched_, shared_from_this(), poll_flags, token); sched_->work_started(); if (wait_op_.cancelled.load(std::memory_order_acquire)) { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&wait_op_); return std::noop_coroutine(); } - io_uring_submit_op(*sched_, &wait_op_); + uring_submit_op(*sched_, &wait_op_); return std::noop_coroutine(); } // native_handle / is_open / set_option / get_option / local_endpoint // are inherited from native_socket_base. - std::error_code shutdown( - udp_socket::shutdown_type what) noexcept override + std::error_code shutdown(udp_socket::shutdown_type what) noexcept override { if (::shutdown(fd_, static_cast(what)) != 0) return make_err(errno); @@ -1989,8 +2074,8 @@ class BOOST_COROSIO_DECL io_uring_udp_socket final // number (same reasoning as close_socket). if (fd_ >= 0) sched_->cancel_and_flush(fd_); - int fd = fd_; - fd_ = -1; + int fd = fd_; + fd_ = -1; local_endpoint_ = endpoint{}; remote_endpoint_ = endpoint{}; return fd; @@ -2023,24 +2108,24 @@ class BOOST_COROSIO_DECL io_uring_udp_socket final private: std::coroutine_handle<> submit_send( - std::coroutine_handle<> h, - capy::executor_ref ex, - buffer_param buffers, - socklen_t dest_len, - sockaddr_storage const& dest_storage, - int flags, - std::stop_token const& token, - std::error_code* ec, - std::size_t* bytes) - { - iovec iovecs[io_uring_max_iov]; - int iovec_count = copy_to_iovec(buffers, iovecs); - bool stop_now = token.stop_possible() && token.stop_requested(); - bool empty_buf = (iovec_count == 0); - - ssize_t n = 0; - int err = 0; - bool have_sync_res = stop_now || empty_buf; + std::coroutine_handle<> h, + capy::executor_ref ex, + buffer_param buffers, + socklen_t dest_len, + sockaddr_storage const& dest_storage, + int flags, + std::stop_token const& token, + std::error_code* ec, + std::size_t* bytes) + { + iovec iovecs[uring_max_iov]; + int iovec_count = copy_to_iovec(buffers, iovecs); + bool stop_now = token.stop_possible() && token.stop_requested(); + bool empty_buf = (iovec_count == 0); + + ssize_t n = 0; + int err = 0; + bool have_sync_res = stop_now || empty_buf; if (!have_sync_res && spec_.may_speculate_write()) { msghdr msg{}; @@ -2053,12 +2138,16 @@ class BOOST_COROSIO_DECL io_uring_udp_socket final msg.msg_namelen = dest_len; } int native_flags = to_native_msg_flags(flags) | MSG_NOSIGNAL; - do { n = ::sendmsg(fd_, &msg, native_flags); } + do + { + n = ::sendmsg(fd_, &msg, native_flags); + } while (n < 0 && errno == EINTR); if (n >= 0 || (errno != EAGAIN && errno != EWOULDBLOCK)) { have_sync_res = true; - if (n < 0) err = errno; + if (n < 0) + err = errno; } else { @@ -2078,56 +2167,57 @@ class BOOST_COROSIO_DECL io_uring_udp_socket final send_.cont.h = h; return dispatch_coro(ex, send_.cont); } - send_.prepare(h, ex, ec, bytes, fd_, sched_, - shared_from_this(), &spec_, buffers, dest_len, dest_storage, - to_native_msg_flags(flags), token); + send_.prepare( + h, ex, ec, bytes, fd_, sched_, shared_from_this(), &spec_, + buffers, dest_len, dest_storage, to_native_msg_flags(flags), + token); if (stop_now) send_.cancelled.store(true, std::memory_order_release); else send_.res = (n < 0) ? -err : static_cast(n); sched_->work_started(); { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&send_); } return std::noop_coroutine(); } - send_.prepare(h, ex, ec, bytes, fd_, sched_, shared_from_this(), - &spec_, buffers, dest_len, dest_storage, - to_native_msg_flags(flags), token); + send_.prepare( + h, ex, ec, bytes, fd_, sched_, shared_from_this(), &spec_, buffers, + dest_len, dest_storage, to_native_msg_flags(flags), token); sched_->work_started(); if (send_.cancelled.load(std::memory_order_acquire)) { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&send_); return std::noop_coroutine(); } - io_uring_submit_op(*sched_, &send_); + uring_submit_op(*sched_, &send_); return std::noop_coroutine(); } std::coroutine_handle<> submit_recv( - std::coroutine_handle<> h, - capy::executor_ref ex, - buffer_param buffers, - bool want_source, - corosio::endpoint* source_out, - int flags, - std::stop_token const& token, - std::error_code* ec, - std::size_t* bytes) - { - iovec iovecs[io_uring_max_iov]; - int iovec_count = copy_to_iovec(buffers, iovecs); - bool stop_now = token.stop_possible() && token.stop_requested(); - bool empty_buf = (iovec_count == 0); - - ssize_t n = 0; - int err = 0; - bool have_sync_res = stop_now || empty_buf; + std::coroutine_handle<> h, + capy::executor_ref ex, + buffer_param buffers, + bool want_source, + corosio::endpoint* source_out, + int flags, + std::stop_token const& token, + std::error_code* ec, + std::size_t* bytes) + { + iovec iovecs[uring_max_iov]; + int iovec_count = copy_to_iovec(buffers, iovecs); + bool stop_now = token.stop_possible() && token.stop_requested(); + bool empty_buf = (iovec_count == 0); + + ssize_t n = 0; + int err = 0; + bool have_sync_res = stop_now || empty_buf; sockaddr_storage src_storage{}; - socklen_t src_namelen = 0; + socklen_t src_namelen = 0; if (!have_sync_res && spec_.may_speculate_read()) { msghdr msg{}; @@ -2139,12 +2229,16 @@ class BOOST_COROSIO_DECL io_uring_udp_socket final msg.msg_namelen = sizeof(src_storage); } int native_flags = to_native_msg_flags(flags); - do { n = ::recvmsg(fd_, &msg, native_flags); } + do + { + n = ::recvmsg(fd_, &msg, native_flags); + } while (n < 0 && errno == EINTR); if (n >= 0 || (errno != EAGAIN && errno != EWOULDBLOCK)) { have_sync_res = true; - if (n < 0) err = errno; + if (n < 0) + err = errno; src_namelen = (n >= 0) ? msg.msg_namelen : 0; } else @@ -2167,9 +2261,9 @@ class BOOST_COROSIO_DECL io_uring_udp_socket final recv_.cont.h = h; return dispatch_coro(ex, recv_.cont); } - recv_.prepare(h, ex, ec, bytes, fd_, sched_, shared_from_this(), - &spec_, buffers, source_out, - want_source ? &write_ip_source : nullptr, + recv_.prepare( + h, ex, ec, bytes, fd_, sched_, shared_from_this(), &spec_, + buffers, source_out, want_source ? &write_ip_source : nullptr, to_native_msg_flags(flags), token); if (stop_now) recv_.cancelled.store(true, std::memory_order_release); @@ -2187,25 +2281,25 @@ class BOOST_COROSIO_DECL io_uring_udp_socket final } sched_->work_started(); { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&recv_); } return std::noop_coroutine(); } - recv_.prepare(h, ex, ec, bytes, fd_, sched_, shared_from_this(), - &spec_, buffers, source_out, - want_source ? &write_ip_source : nullptr, + recv_.prepare( + h, ex, ec, bytes, fd_, sched_, shared_from_this(), &spec_, buffers, + source_out, want_source ? &write_ip_source : nullptr, to_native_msg_flags(flags), token); sched_->work_started(); if (recv_.iovec_count == 0 || recv_.cancelled.load(std::memory_order_acquire)) { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&recv_); return std::noop_coroutine(); } - io_uring_submit_op(*sched_, &recv_); + uring_submit_op(*sched_, &recv_); return std::noop_coroutine(); } @@ -2219,7 +2313,7 @@ class BOOST_COROSIO_DECL io_uring_udp_socket final /** UDP socket service for io_uring. - Owns all `io_uring_udp_socket` implementations for an `io_context`. + Owns all `uring_udp_socket` implementations for an `io_context`. Satisfies the `udp_service` interface so the generic `udp_socket` front-end can call `open_datagram_socket` and `bind_datagram` transparently. @@ -2231,12 +2325,16 @@ class BOOST_COROSIO_DECL io_uring_udp_socket final @par Thread Safety All public member functions are thread-safe. */ -class BOOST_COROSIO_DECL io_uring_udp_service final - : public io_uring_socket_service_base< - io_uring_udp_service, udp_service, io_uring_udp_socket> +class BOOST_COROSIO_DECL uring_udp_service final + : public uring_socket_service_base< + uring_udp_service, + udp_service, + uring_udp_socket> { - using base_service = io_uring_socket_service_base< - io_uring_udp_service, udp_service, io_uring_udp_socket>; + using base_service = uring_socket_service_base< + uring_udp_service, + udp_service, + uring_udp_socket>; public: /// Identifies this service for `execution_context` lookup. @@ -2247,12 +2345,12 @@ class BOOST_COROSIO_DECL io_uring_udp_service final @param ctx The owning execution context. The io_uring scheduler must already be registered. */ - explicit io_uring_udp_service(capy::execution_context& ctx) - : base_service(ctx) - {} + explicit uring_udp_service(capy::execution_context& ctx) : base_service(ctx) + { + } // construct / destroy / shutdown / close / scheduler() are inherited - // from io_uring_socket_service_base. + // from uring_socket_service_base. /** Open a datagram socket and associate it with an impl. @@ -2266,11 +2364,13 @@ class BOOST_COROSIO_DECL io_uring_udp_service final */ std::error_code open_datagram_socket( udp_socket::implementation& impl, - int family, int type, int protocol) override + int family, + int type, + int protocol) override { - auto& sock = static_cast(impl); - int fd = ::socket( - family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); + auto& sock = static_cast(impl); + int fd = + ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); if (fd < 0) return make_err(errno); // LCOV_EXCL_START: dead — open() guards is_open(), so open_socket @@ -2301,11 +2401,10 @@ class BOOST_COROSIO_DECL io_uring_udp_service final @return Error code on failure, empty on success. */ std::error_code assign_socket( - udp_socket::implementation& impl, - native_handle_type fd) override + udp_socket::implementation& impl, native_handle_type fd) override { - auto& sock = static_cast(impl); - int nfd = static_cast(fd); + auto& sock = static_cast(impl); + int nfd = static_cast(fd); if (nfd >= 0 && nfd == sock.fd_) return std::make_error_code(std::errc::invalid_argument); if (auto ec = validate_socket_fd(nfd, SOCK_DGRAM, true)) @@ -2323,8 +2422,8 @@ class BOOST_COROSIO_DECL io_uring_udp_service final sockaddr_storage local{}; socklen_t local_len = sizeof(local); - if (::getsockname(sock.fd_, - reinterpret_cast(&local), &local_len) == 0) + if (::getsockname( + sock.fd_, reinterpret_cast(&local), &local_len) == 0) { sock.local_endpoint_ = sockaddr_to_endpoint(local); sock.family_ = local.ss_family; @@ -2332,8 +2431,9 @@ class BOOST_COROSIO_DECL io_uring_udp_service final sockaddr_storage remote{}; socklen_t remote_len = sizeof(remote); - if (::getpeername(sock.fd_, - reinterpret_cast(&remote), &remote_len) == 0) + if (::getpeername( + sock.fd_, reinterpret_cast(&remote), &remote_len) == + 0) sock.remote_endpoint_ = sockaddr_to_endpoint(remote); return {}; @@ -2345,22 +2445,19 @@ class BOOST_COROSIO_DECL io_uring_udp_service final @param ep The local endpoint to bind to. @return Error code on failure, empty on success. */ - std::error_code bind_datagram( - udp_socket::implementation& impl, endpoint ep) override + std::error_code + bind_datagram(udp_socket::implementation& impl, endpoint ep) override { - auto& sock = static_cast(impl); + auto& sock = static_cast(impl); sockaddr_storage addr{}; socklen_t len = endpoint_to_sockaddr(ep, addr); - if (::bind( - sock.fd_, - reinterpret_cast(&addr), len) < 0) + if (::bind(sock.fd_, reinterpret_cast(&addr), len) < 0) return make_err(errno); sockaddr_storage local{}; socklen_t local_len = sizeof(local); if (::getsockname( - sock.fd_, - reinterpret_cast(&local), &local_len) == 0) + sock.fd_, reinterpret_cast(&local), &local_len) == 0) sock.local_endpoint_ = sockaddr_to_endpoint(local); return {}; } @@ -2370,7 +2467,7 @@ class BOOST_COROSIO_DECL io_uring_udp_service final Implements `local_datagram_socket::implementation` using a proactor model: send_to, recv_from, send, recv, and connect operations are - submitted to the kernel via `io_uring_submit_op` and complete through + submitted to the kernel via `uring_submit_op` and complete through the ring's CQE path. The object is always owned by a `shared_ptr` managed by the service. @@ -2382,16 +2479,16 @@ class BOOST_COROSIO_DECL io_uring_udp_service final Shared objects: Unsafe. One send and one recv may be in flight simultaneously, but two sends or two recvs must not overlap. */ -class BOOST_COROSIO_DECL io_uring_local_datagram_socket final +class BOOST_COROSIO_DECL uring_local_datagram_socket final : public native_socket_base< - io_uring_local_datagram_socket, + uring_local_datagram_socket, local_datagram_socket::implementation, corosio::local_endpoint> { - friend io_uring_local_datagram_service; + friend uring_local_datagram_service; - io_uring_scheduler* sched_ = nullptr; - [[maybe_unused]] io_uring_local_datagram_service* svc_ = nullptr; + uring_scheduler* sched_ = nullptr; + [[maybe_unused]] uring_local_datagram_service* svc_ = nullptr; // fd_ and local_endpoint_ live in native_socket_base, which also // provides native_handle/is_open/set_option/get_option/local_endpoint. @@ -2400,9 +2497,9 @@ class BOOST_COROSIO_DECL io_uring_local_datagram_socket final // Per-fd op slots — embedded to eliminate per-call heap allocation. // Single-pending invariant per slot. uring_local_connect_op conn_; - uring_dgram_send_op send_; - uring_dgram_recv_op recv_; - uring_wait_op wait_op_; + uring_dgram_send_op send_; + uring_dgram_recv_op recv_; + uring_wait_op wait_op_; mutable detail::speculative_state spec_; @@ -2414,17 +2511,18 @@ class BOOST_COROSIO_DECL io_uring_local_datagram_socket final @param svc The owning service. @param sched The io_uring scheduler owned by the context. */ - explicit io_uring_local_datagram_socket( - io_uring_local_datagram_service& svc, - io_uring_scheduler& sched) noexcept + explicit uring_local_datagram_socket( + uring_local_datagram_service& svc, uring_scheduler& sched) noexcept : sched_(&sched) , svc_(&svc) - {} + { + } - ~io_uring_local_datagram_socket() override + ~uring_local_datagram_socket() override { if (fd_ >= 0) - ::close(fd_); // LCOV_EXCL_LINE backstop: close_socket() clears fd_ before destroy + ::close( + fd_); // LCOV_EXCL_LINE backstop: close_socket() clears fd_ before destroy } // ---------------------------------------------------------------- @@ -2432,85 +2530,85 @@ class BOOST_COROSIO_DECL io_uring_local_datagram_socket final // ---------------------------------------------------------------- std::coroutine_handle<> send_to( - std::coroutine_handle<> h, - capy::executor_ref ex, - buffer_param buf, - corosio::local_endpoint dest, - int flags, - std::stop_token token, - std::error_code* ec, - std::size_t* bytes_out) override + std::coroutine_handle<> h, + capy::executor_ref ex, + buffer_param buf, + corosio::local_endpoint dest, + int flags, + std::stop_token token, + std::error_code* ec, + std::size_t* bytes_out) override { sockaddr_storage addr{}; socklen_t len = endpoint_to_sockaddr(dest, addr); - return submit_send(h, ex, buf, len, addr, flags, - token, ec, bytes_out); + return submit_send(h, ex, buf, len, addr, flags, token, ec, bytes_out); } std::coroutine_handle<> recv_from( - std::coroutine_handle<> h, - capy::executor_ref ex, - buffer_param buf, - corosio::local_endpoint* source, - int flags, - std::stop_token token, - std::error_code* ec, - std::size_t* bytes_out) override + std::coroutine_handle<> h, + capy::executor_ref ex, + buffer_param buf, + corosio::local_endpoint* source, + int flags, + std::stop_token token, + std::error_code* ec, + std::size_t* bytes_out) override { - return submit_recv(h, ex, buf, source != nullptr, source, flags, - token, ec, bytes_out); + return submit_recv( + h, ex, buf, source != nullptr, source, flags, token, ec, bytes_out); } std::coroutine_handle<> send( std::coroutine_handle<> h, - capy::executor_ref ex, - buffer_param buf, - int flags, - std::stop_token token, - std::error_code* ec, - std::size_t* bytes_out) override + capy::executor_ref ex, + buffer_param buf, + int flags, + std::stop_token token, + std::error_code* ec, + std::size_t* bytes_out) override { sockaddr_storage empty{}; - return submit_send(h, ex, buf, 0, empty, flags, - token, ec, bytes_out); + return submit_send(h, ex, buf, 0, empty, flags, token, ec, bytes_out); } std::coroutine_handle<> recv( std::coroutine_handle<> h, - capy::executor_ref ex, - buffer_param buf, - int flags, - std::stop_token token, - std::error_code* ec, - std::size_t* bytes_out) override + capy::executor_ref ex, + buffer_param buf, + int flags, + std::stop_token token, + std::error_code* ec, + std::size_t* bytes_out) override { - return submit_recv(h, ex, buf, false, nullptr, flags, - token, ec, bytes_out); + return submit_recv( + h, ex, buf, false, nullptr, flags, token, ec, bytes_out); } std::coroutine_handle<> connect( - std::coroutine_handle<> h, - capy::executor_ref ex, - corosio::local_endpoint ep, - std::stop_token token, - std::error_code* ec) override + std::coroutine_handle<> h, + capy::executor_ref ex, + corosio::local_endpoint ep, + std::stop_token token, + std::error_code* ec) override { bool stop_now = token.stop_possible() && token.stop_requested(); if (stop_now) { if (sched_->try_consume_inline_budget()) { - if (ec) *ec = capy::error::canceled; + if (ec) + *ec = capy::error::canceled; conn_.cont.h = h; return dispatch_coro(ex, conn_.cont); } conn_.addrlen = to_sockaddr(ep, conn_.addr); - conn_.prepare(h, ex, ec, fd_, sched_, shared_from_this(), - ep, &remote_endpoint_, &local_endpoint_, token); + conn_.prepare( + h, ex, ec, fd_, sched_, shared_from_this(), ep, + &remote_endpoint_, &local_endpoint_, token); conn_.cancelled.store(true, std::memory_order_release); sched_->work_started(); { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&conn_); } return std::noop_coroutine(); @@ -2519,48 +2617,55 @@ class BOOST_COROSIO_DECL io_uring_local_datagram_socket final // io_uring's IORING_OP_CONNECT re-invokes connect(2) internally; // a prior speculative ::connect would leave EINPROGRESS → EALREADY. conn_.addrlen = to_sockaddr(ep, conn_.addr); - conn_.prepare(h, ex, ec, fd_, sched_, shared_from_this(), - ep, &remote_endpoint_, &local_endpoint_, token); + conn_.prepare( + h, ex, ec, fd_, sched_, shared_from_this(), ep, &remote_endpoint_, + &local_endpoint_, token); sched_->work_started(); if (conn_.cancelled.load(std::memory_order_acquire)) { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&conn_); return std::noop_coroutine(); } - io_uring_submit_op(*sched_, &conn_); + uring_submit_op(*sched_, &conn_); return std::noop_coroutine(); } std::coroutine_handle<> wait( std::coroutine_handle<> h, - capy::executor_ref ex, - wait_type w, - std::stop_token token, - std::error_code* ec) override + capy::executor_ref ex, + wait_type w, + std::stop_token token, + std::error_code* ec) override { int poll_flags = 0; switch (w) { - case wait_type::read: poll_flags = POLLIN; break; - case wait_type::write: poll_flags = POLLOUT; break; - case wait_type::error: poll_flags = POLLPRI | POLLERR | POLLHUP; break; - } - wait_op_.prepare(h, ex, ec, fd_, sched_, - shared_from_this(), poll_flags, token); + case wait_type::read: + poll_flags = POLLIN; + break; + case wait_type::write: + poll_flags = POLLOUT; + break; + case wait_type::error: + poll_flags = POLLPRI | POLLERR | POLLHUP; + break; + } + wait_op_.prepare( + h, ex, ec, fd_, sched_, shared_from_this(), poll_flags, token); sched_->work_started(); if (wait_op_.cancelled.load(std::memory_order_acquire)) { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&wait_op_); return std::noop_coroutine(); } - io_uring_submit_op(*sched_, &wait_op_); + uring_submit_op(*sched_, &wait_op_); return std::noop_coroutine(); } - std::error_code shutdown( - local_datagram_socket::shutdown_type what) noexcept override + std::error_code + shutdown(local_datagram_socket::shutdown_type what) noexcept override { if (::shutdown(fd_, static_cast(what)) != 0) return make_err(errno); @@ -2577,8 +2682,8 @@ class BOOST_COROSIO_DECL io_uring_local_datagram_socket final // number (same reasoning as close_socket). if (fd_ >= 0) sched_->cancel_and_flush(fd_); - int fd = fd_; - fd_ = -1; + int fd = fd_; + fd_ = -1; local_endpoint_ = corosio::local_endpoint{}; remote_endpoint_ = corosio::local_endpoint{}; return fd; @@ -2622,8 +2727,7 @@ class BOOST_COROSIO_DECL io_uring_local_datagram_socket final sockaddr_storage local{}; socklen_t local_len = sizeof(local); if (::getsockname( - fd_, - reinterpret_cast(&local), &local_len) == 0) + fd_, reinterpret_cast(&local), &local_len) == 0) local_endpoint_ = sockaddr_to_local_endpoint(local, local_len); return {}; } @@ -2631,24 +2735,24 @@ class BOOST_COROSIO_DECL io_uring_local_datagram_socket final private: std::coroutine_handle<> submit_send( - std::coroutine_handle<> h, - capy::executor_ref ex, - buffer_param buffers, - socklen_t dest_len, - sockaddr_storage const& dest_storage, - int flags, - std::stop_token const& token, - std::error_code* ec, - std::size_t* bytes) - { - iovec iovecs[io_uring_max_iov]; - int iovec_count = copy_to_iovec(buffers, iovecs); - bool stop_now = token.stop_possible() && token.stop_requested(); - bool empty_buf = (iovec_count == 0); - - ssize_t n = 0; - int err = 0; - bool have_sync_res = stop_now || empty_buf; + std::coroutine_handle<> h, + capy::executor_ref ex, + buffer_param buffers, + socklen_t dest_len, + sockaddr_storage const& dest_storage, + int flags, + std::stop_token const& token, + std::error_code* ec, + std::size_t* bytes) + { + iovec iovecs[uring_max_iov]; + int iovec_count = copy_to_iovec(buffers, iovecs); + bool stop_now = token.stop_possible() && token.stop_requested(); + bool empty_buf = (iovec_count == 0); + + ssize_t n = 0; + int err = 0; + bool have_sync_res = stop_now || empty_buf; if (!have_sync_res && spec_.may_speculate_write()) { msghdr msg{}; @@ -2661,12 +2765,16 @@ class BOOST_COROSIO_DECL io_uring_local_datagram_socket final msg.msg_namelen = dest_len; } int native_flags = to_native_msg_flags(flags) | MSG_NOSIGNAL; - do { n = ::sendmsg(fd_, &msg, native_flags); } + do + { + n = ::sendmsg(fd_, &msg, native_flags); + } while (n < 0 && errno == EINTR); if (n >= 0 || (errno != EAGAIN && errno != EWOULDBLOCK)) { have_sync_res = true; - if (n < 0) err = errno; + if (n < 0) + err = errno; } else { @@ -2686,56 +2794,57 @@ class BOOST_COROSIO_DECL io_uring_local_datagram_socket final send_.cont.h = h; return dispatch_coro(ex, send_.cont); } - send_.prepare(h, ex, ec, bytes, fd_, sched_, - shared_from_this(), &spec_, buffers, dest_len, dest_storage, - to_native_msg_flags(flags), token); + send_.prepare( + h, ex, ec, bytes, fd_, sched_, shared_from_this(), &spec_, + buffers, dest_len, dest_storage, to_native_msg_flags(flags), + token); if (stop_now) send_.cancelled.store(true, std::memory_order_release); else send_.res = (n < 0) ? -err : static_cast(n); sched_->work_started(); { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&send_); } return std::noop_coroutine(); } - send_.prepare(h, ex, ec, bytes, fd_, sched_, shared_from_this(), - &spec_, buffers, dest_len, dest_storage, - to_native_msg_flags(flags), token); + send_.prepare( + h, ex, ec, bytes, fd_, sched_, shared_from_this(), &spec_, buffers, + dest_len, dest_storage, to_native_msg_flags(flags), token); sched_->work_started(); if (send_.cancelled.load(std::memory_order_acquire)) { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&send_); return std::noop_coroutine(); } - io_uring_submit_op(*sched_, &send_); + uring_submit_op(*sched_, &send_); return std::noop_coroutine(); } std::coroutine_handle<> submit_recv( - std::coroutine_handle<> h, - capy::executor_ref ex, - buffer_param buffers, - bool want_source, - corosio::local_endpoint* source_out, - int flags, - std::stop_token const& token, - std::error_code* ec, - std::size_t* bytes) - { - iovec iovecs[io_uring_max_iov]; - int iovec_count = copy_to_iovec(buffers, iovecs); - bool stop_now = token.stop_possible() && token.stop_requested(); - bool empty_buf = (iovec_count == 0); - - ssize_t n = 0; - int err = 0; - bool have_sync_res = stop_now || empty_buf; + std::coroutine_handle<> h, + capy::executor_ref ex, + buffer_param buffers, + bool want_source, + corosio::local_endpoint* source_out, + int flags, + std::stop_token const& token, + std::error_code* ec, + std::size_t* bytes) + { + iovec iovecs[uring_max_iov]; + int iovec_count = copy_to_iovec(buffers, iovecs); + bool stop_now = token.stop_possible() && token.stop_requested(); + bool empty_buf = (iovec_count == 0); + + ssize_t n = 0; + int err = 0; + bool have_sync_res = stop_now || empty_buf; sockaddr_storage src_storage{}; - socklen_t src_namelen = 0; + socklen_t src_namelen = 0; if (!have_sync_res && spec_.may_speculate_read()) { msghdr msg{}; @@ -2747,12 +2856,16 @@ class BOOST_COROSIO_DECL io_uring_local_datagram_socket final msg.msg_namelen = sizeof(src_storage); } int native_flags = to_native_msg_flags(flags); - do { n = ::recvmsg(fd_, &msg, native_flags); } + do + { + n = ::recvmsg(fd_, &msg, native_flags); + } while (n < 0 && errno == EINTR); if (n >= 0 || (errno != EAGAIN && errno != EWOULDBLOCK)) { have_sync_res = true; - if (n < 0) err = errno; + if (n < 0) + err = errno; src_namelen = (n >= 0) ? msg.msg_namelen : 0; } else @@ -2771,12 +2884,14 @@ class BOOST_COROSIO_DECL io_uring_local_datagram_socket final if (bytes) *bytes = (n < 0) ? 0u : static_cast(n); if (n >= 0 && want_source && source_out && !empty_buf) - *source_out = sockaddr_to_local_endpoint(src_storage, src_namelen); + *source_out = + sockaddr_to_local_endpoint(src_storage, src_namelen); recv_.cont.h = h; return dispatch_coro(ex, recv_.cont); } - recv_.prepare(h, ex, ec, bytes, fd_, sched_, shared_from_this(), - &spec_, buffers, source_out, + recv_.prepare( + h, ex, ec, bytes, fd_, sched_, shared_from_this(), &spec_, + buffers, source_out, want_source ? &write_local_source : nullptr, to_native_msg_flags(flags), token); if (stop_now) @@ -2795,25 +2910,25 @@ class BOOST_COROSIO_DECL io_uring_local_datagram_socket final } sched_->work_started(); { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&recv_); } return std::noop_coroutine(); } - recv_.prepare(h, ex, ec, bytes, fd_, sched_, shared_from_this(), - &spec_, buffers, source_out, - want_source ? &write_local_source : nullptr, + recv_.prepare( + h, ex, ec, bytes, fd_, sched_, shared_from_this(), &spec_, buffers, + source_out, want_source ? &write_local_source : nullptr, to_native_msg_flags(flags), token); sched_->work_started(); if (recv_.iovec_count == 0 || recv_.cancelled.load(std::memory_order_acquire)) { - io_uring_scheduler::lock_type lock(sched_->dispatch_mutex()); + uring_scheduler::lock_type lock(sched_->dispatch_mutex()); sched_->push_completed_locked(&recv_); return std::noop_coroutine(); } - io_uring_submit_op(*sched_, &recv_); + uring_submit_op(*sched_, &recv_); return std::noop_coroutine(); } @@ -2827,7 +2942,7 @@ class BOOST_COROSIO_DECL io_uring_local_datagram_socket final /** Unix domain datagram socket service for io_uring. - Owns all `io_uring_local_datagram_socket` implementations for an + Owns all `uring_local_datagram_socket` implementations for an `io_context`. Satisfies the `local_datagram_service` interface so the generic `local_datagram_socket` front-end can call `open_socket` and `bind_socket` transparently. @@ -2839,14 +2954,16 @@ class BOOST_COROSIO_DECL io_uring_local_datagram_socket final @par Thread Safety All public member functions are thread-safe. */ -class BOOST_COROSIO_DECL io_uring_local_datagram_service final - : public io_uring_socket_service_base< - io_uring_local_datagram_service, local_datagram_service, - io_uring_local_datagram_socket> +class BOOST_COROSIO_DECL uring_local_datagram_service final + : public uring_socket_service_base< + uring_local_datagram_service, + local_datagram_service, + uring_local_datagram_socket> { - using base_service = io_uring_socket_service_base< - io_uring_local_datagram_service, local_datagram_service, - io_uring_local_datagram_socket>; + using base_service = uring_socket_service_base< + uring_local_datagram_service, + local_datagram_service, + uring_local_datagram_socket>; public: /// Identifies this service for `execution_context` lookup. @@ -2857,12 +2974,13 @@ class BOOST_COROSIO_DECL io_uring_local_datagram_service final @param ctx The owning execution context. The io_uring scheduler must already be registered. */ - explicit io_uring_local_datagram_service(capy::execution_context& ctx) + explicit uring_local_datagram_service(capy::execution_context& ctx) : base_service(ctx) - {} + { + } // construct / destroy / shutdown / close / scheduler() are inherited - // from io_uring_socket_service_base. + // from uring_socket_service_base. /** Open an AF_UNIX datagram socket and associate it with an impl. @@ -2877,10 +2995,13 @@ class BOOST_COROSIO_DECL io_uring_local_datagram_service final */ std::error_code open_socket( local_datagram_socket::implementation& impl, - int family, int type, int protocol) override + int family, + int type, + int protocol) override { - auto& sock = static_cast(impl); - int fd = ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); + auto& sock = static_cast(impl); + int fd = + ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); if (fd < 0) return make_err(errno); // LCOV_EXCL_START: dead — open() guards is_open(), so open_socket @@ -2908,8 +3029,8 @@ class BOOST_COROSIO_DECL io_uring_local_datagram_service final local_datagram_socket::implementation& impl, native_handle_type fd) override { - auto& sock = static_cast(impl); - int nfd = static_cast(fd); + auto& sock = static_cast(impl); + int nfd = static_cast(fd); if (nfd >= 0 && nfd == sock.fd_) return std::make_error_code(std::errc::invalid_argument); if (auto ec = validate_socket_fd(nfd, SOCK_DGRAM, false)) @@ -2924,15 +3045,17 @@ class BOOST_COROSIO_DECL io_uring_local_datagram_service final sockaddr_storage local{}; socklen_t local_len = sizeof(local); - if (::getsockname(sock.fd_, - reinterpret_cast(&local), &local_len) == 0) + if (::getsockname( + sock.fd_, reinterpret_cast(&local), &local_len) == 0) sock.local_endpoint_ = sockaddr_to_local_endpoint(local, local_len); sockaddr_storage remote{}; socklen_t remote_len = sizeof(remote); - if (::getpeername(sock.fd_, - reinterpret_cast(&remote), &remote_len) == 0) - sock.remote_endpoint_ = sockaddr_to_local_endpoint(remote, remote_len); + if (::getpeername( + sock.fd_, reinterpret_cast(&remote), &remote_len) == + 0) + sock.remote_endpoint_ = + sockaddr_to_local_endpoint(remote, remote_len); return {}; } @@ -2947,19 +3070,16 @@ class BOOST_COROSIO_DECL io_uring_local_datagram_service final local_datagram_socket::implementation& impl, corosio::local_endpoint ep) override { - auto& sock = static_cast(impl); + auto& sock = static_cast(impl); sockaddr_storage addr{}; socklen_t len = endpoint_to_sockaddr(ep, addr); - if (::bind( - sock.fd_, - reinterpret_cast(&addr), len) < 0) + if (::bind(sock.fd_, reinterpret_cast(&addr), len) < 0) return make_err(errno); sockaddr_storage local{}; socklen_t local_len = sizeof(local); if (::getsockname( - sock.fd_, - reinterpret_cast(&local), &local_len) == 0) + sock.fd_, reinterpret_cast(&local), &local_len) == 0) sock.local_endpoint_ = sockaddr_to_local_endpoint(local, local_len); return {}; } @@ -2967,6 +3087,6 @@ class BOOST_COROSIO_DECL io_uring_local_datagram_service final } // namespace boost::corosio::detail -#endif // BOOST_COROSIO_HAS_IO_URING +#endif // BOOST_COROSIO_HAS_URING -#endif // BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_TYPES_HPP +#endif // BOOST_COROSIO_NATIVE_DETAIL_URING_URING_TYPES_HPP diff --git a/include/boost/corosio/native/detail/validate_fd.hpp b/include/boost/corosio/native/detail/validate_fd.hpp index 243fdc8f3..39c4e0c61 100644 --- a/include/boost/corosio/native/detail/validate_fd.hpp +++ b/include/boost/corosio/native/detail/validate_fd.hpp @@ -55,10 +55,9 @@ validate_socket_fd(int fd, int expected_type, bool is_ip) noexcept return make_err(EAFNOSUPPORT); } - int sock_type = 0; + int sock_type = 0; socklen_t opt_len = sizeof(sock_type); - if (::getsockopt(fd, SOL_SOCKET, SO_TYPE, - &sock_type, &opt_len) != 0) + if (::getsockopt(fd, SOL_SOCKET, SO_TYPE, &sock_type, &opt_len) != 0) return make_err(errno); if (sock_type != expected_type) return make_err(EPROTOTYPE); diff --git a/include/boost/corosio/native/native_io_context.hpp b/include/boost/corosio/native/native_io_context.hpp index 58522a116..838253010 100644 --- a/include/boost/corosio/native/native_io_context.hpp +++ b/include/boost/corosio/native/native_io_context.hpp @@ -31,8 +31,8 @@ #include #endif -#if BOOST_COROSIO_HAS_IO_URING -#include +#if BOOST_COROSIO_HAS_URING +#include #endif #endif // !BOOST_COROSIO_MRDOCS @@ -193,7 +193,7 @@ class native_io_context : public io_context typename Clock::time_point now = Clock::now(); for (;;) { - auto rel_time = abs_time - now; + auto rel_time = abs_time - now; using rel_type = decltype(rel_time); if (rel_time < rel_type::zero()) rel_time = rel_type::zero(); diff --git a/include/boost/corosio/native/native_local_datagram_socket.hpp b/include/boost/corosio/native/native_local_datagram_socket.hpp index e1428fe61..437ab1760 100644 --- a/include/boost/corosio/native/native_local_datagram_socket.hpp +++ b/include/boost/corosio/native/native_local_datagram_socket.hpp @@ -31,8 +31,8 @@ #include #endif -#if BOOST_COROSIO_HAS_IO_URING -#include +#if BOOST_COROSIO_HAS_URING +#include #endif #endif // !BOOST_COROSIO_MRDOCS @@ -120,8 +120,8 @@ class native_local_datagram_socket : public local_datagram_socket { token_ = env->stop_token; return self_.get_impl().send_to( - h, env->executor, buffers_, dest_, flags_, - token_, &ec_, &bytes_transferred_); + h, env->executor, buffers_, dest_, flags_, token_, &ec_, + &bytes_transferred_); } }; @@ -167,8 +167,8 @@ class native_local_datagram_socket : public local_datagram_socket { token_ = env->stop_token; return self_.get_impl().recv_from( - h, env->executor, buffers_, &source_, flags_, - token_, &ec_, &bytes_transferred_); + h, env->executor, buffers_, &source_, flags_, token_, &ec_, + &bytes_transferred_); } }; @@ -204,8 +204,7 @@ class native_local_datagram_socket : public local_datagram_socket -> std::coroutine_handle<> { token_ = env->stop_token; - return self_.get_impl().wait( - h, env->executor, w_, token_, &ec_); + return self_.get_impl().wait(h, env->executor, w_, token_, &ec_); } }; @@ -286,8 +285,8 @@ class native_local_datagram_socket : public local_datagram_socket { token_ = env->stop_token; return self_.get_impl().send( - h, env->executor, buffers_, flags_, - token_, &ec_, &bytes_transferred_); + h, env->executor, buffers_, flags_, token_, &ec_, + &bytes_transferred_); } }; @@ -330,8 +329,8 @@ class native_local_datagram_socket : public local_datagram_socket { token_ = env->stop_token; return self_.get_impl().recv( - h, env->executor, buffers_, flags_, - token_, &ec_, &bytes_transferred_); + h, env->executor, buffers_, flags_, token_, &ec_, + &bytes_transferred_); } }; @@ -351,8 +350,8 @@ class native_local_datagram_socket : public local_datagram_socket */ template requires(!std::same_as< - std::remove_cvref_t, - native_local_datagram_socket>) && + std::remove_cvref_t, + native_local_datagram_socket>) && capy::Executor explicit native_local_datagram_socket(Ex const& ex) : native_local_datagram_socket(ex.context()) @@ -382,7 +381,8 @@ class native_local_datagram_socket : public local_datagram_socket corosio::local_endpoint dest, corosio::message_flags flags) { - native_send_to_awaitable aw(*this, buffers, dest, static_cast(flags)); + native_send_to_awaitable aw( + *this, buffers, dest, static_cast(flags)); if (!is_open()) aw.ec_ = make_error_code(std::errc::bad_file_descriptor); return aw; @@ -406,7 +406,8 @@ class native_local_datagram_socket : public local_datagram_socket corosio::local_endpoint& source, corosio::message_flags flags) { - native_recv_from_awaitable aw(*this, buffers, source, static_cast(flags)); + native_recv_from_awaitable aw( + *this, buffers, source, static_cast(flags)); if (!is_open()) aw.ec_ = make_error_code(std::errc::bad_file_descriptor); return aw; @@ -414,7 +415,8 @@ class native_local_datagram_socket : public local_datagram_socket /// @overload template - [[nodiscard]] auto recv_from(MB const& buffers, corosio::local_endpoint& source) + [[nodiscard]] auto + recv_from(MB const& buffers, corosio::local_endpoint& source) { return recv_from(buffers, source, corosio::message_flags::none); } diff --git a/include/boost/corosio/native/native_local_stream_acceptor.hpp b/include/boost/corosio/native/native_local_stream_acceptor.hpp index c0181c5c8..c9255177a 100644 --- a/include/boost/corosio/native/native_local_stream_acceptor.hpp +++ b/include/boost/corosio/native/native_local_stream_acceptor.hpp @@ -27,8 +27,8 @@ #include #endif -#if BOOST_COROSIO_HAS_IO_URING -#include +#if BOOST_COROSIO_HAS_URING +#include #endif #if BOOST_COROSIO_HAS_IOCP @@ -107,8 +107,7 @@ class native_local_stream_acceptor : public local_stream_acceptor -> std::coroutine_handle<> { token_ = env->stop_token; - return acc_.get_impl().wait( - h, env->executor, w_, token_, &ec_); + return acc_.get_impl().wait(h, env->executor, w_, token_, &ec_); } }; @@ -182,8 +181,7 @@ class native_local_stream_acceptor : public local_stream_acceptor native_local_stream_socket(acc_.context())}; if (ec_ || !peer_impl_) return { - ec_, - native_local_stream_socket(acc_.context())}; + ec_, native_local_stream_socket(acc_.context())}; native_local_stream_socket peer(acc_.context()); acc_.reset_peer_impl(peer, peer_impl_); @@ -215,8 +213,8 @@ class native_local_stream_acceptor : public local_stream_acceptor */ template requires(!std::same_as< - std::remove_cvref_t, - native_local_stream_acceptor>) && + std::remove_cvref_t, + native_local_stream_acceptor>) && capy::Executor explicit native_local_stream_acceptor(Ex const& ex) : native_local_stream_acceptor(ex.context()) diff --git a/include/boost/corosio/native/native_local_stream_socket.hpp b/include/boost/corosio/native/native_local_stream_socket.hpp index 1d1f87e0a..eb407a68c 100644 --- a/include/boost/corosio/native/native_local_stream_socket.hpp +++ b/include/boost/corosio/native/native_local_stream_socket.hpp @@ -27,8 +27,8 @@ #include #endif -#if BOOST_COROSIO_HAS_IO_URING -#include +#if BOOST_COROSIO_HAS_URING +#include #endif #if BOOST_COROSIO_HAS_IOCP @@ -189,8 +189,7 @@ class native_local_stream_socket : public local_stream_socket -> std::coroutine_handle<> { token_ = env->stop_token; - return self_.get_impl().wait( - h, env->executor, w_, token_, &ec_); + return self_.get_impl().wait(h, env->executor, w_, token_, &ec_); } }; @@ -248,8 +247,8 @@ class native_local_stream_socket : public local_stream_socket */ template requires(!std::same_as< - std::remove_cvref_t, - native_local_stream_socket>) && + std::remove_cvref_t, + native_local_stream_socket>) && capy::Executor explicit native_local_stream_socket(Ex const& ex) : native_local_stream_socket(ex.context()) diff --git a/include/boost/corosio/native/native_random_access_file.hpp b/include/boost/corosio/native/native_random_access_file.hpp index 833491ef3..f61bc74d6 100644 --- a/include/boost/corosio/native/native_random_access_file.hpp +++ b/include/boost/corosio/native/native_random_access_file.hpp @@ -20,8 +20,8 @@ #include #endif -#if BOOST_COROSIO_HAS_IO_URING -#include +#if BOOST_COROSIO_HAS_URING +#include #endif #if BOOST_COROSIO_HAS_IOCP @@ -69,8 +69,7 @@ class native_random_access_file : public random_access_file { using backend_type = decltype(Backend); using impl_type = typename backend_type::random_access_file_type; - using service_type = - typename backend_type::random_access_file_service_type; + using service_type = typename backend_type::random_access_file_service_type; impl_type& get_impl() noexcept { @@ -116,8 +115,8 @@ class native_random_access_file : public random_access_file { token_ = env->stop_token; return self_.get_impl().read_some_at( - offset_, h, env->executor, buffers_, - token_, &ec_, &bytes_transferred_); + offset_, h, env->executor, buffers_, token_, &ec_, + &bytes_transferred_); } }; @@ -160,8 +159,8 @@ class native_random_access_file : public random_access_file { token_ = env->stop_token; return self_.get_impl().write_some_at( - offset_, h, env->executor, buffers_, - token_, &ec_, &bytes_transferred_); + offset_, h, env->executor, buffers_, token_, &ec_, + &bytes_transferred_); } }; @@ -181,8 +180,8 @@ class native_random_access_file : public random_access_file */ template requires(!std::same_as< - std::remove_cvref_t, - native_random_access_file>) && + std::remove_cvref_t, + native_random_access_file>) && capy::Executor explicit native_random_access_file(Ex const& ex) : native_random_access_file(ex.context()) diff --git a/include/boost/corosio/native/native_resolver.hpp b/include/boost/corosio/native/native_resolver.hpp index fc311b418..372679b58 100644 --- a/include/boost/corosio/native/native_resolver.hpp +++ b/include/boost/corosio/native/native_resolver.hpp @@ -85,7 +85,8 @@ class native_resolver : public resolver return static_cast(ec_) || token_.stop_requested(); } - [[nodiscard]] capy::io_result await_resume() const noexcept + [[nodiscard]] capy::io_result + await_resume() const noexcept { if (token_.stop_requested()) return {make_error_code(std::errc::operation_canceled), {}}; @@ -126,7 +127,8 @@ class native_resolver : public resolver return static_cast(ec_) || token_.stop_requested(); } - [[nodiscard]] capy::io_result await_resume() const noexcept + [[nodiscard]] capy::io_result + await_resume() const noexcept { if (token_.stop_requested()) return {make_error_code(std::errc::operation_canceled), {}}; diff --git a/include/boost/corosio/native/native_socket_option.hpp b/include/boost/corosio/native/native_socket_option.hpp index 5ad1eacf8..f6e57ddd1 100644 --- a/include/boost/corosio/native/native_socket_option.hpp +++ b/include/boost/corosio/native/native_socket_option.hpp @@ -266,16 +266,40 @@ class byte_boolean return *this; } - bool value() const noexcept { return value_ != 0; } - explicit operator bool() const noexcept { return value_ != 0; } - bool operator!() const noexcept { return value_ == 0; } + bool value() const noexcept + { + return value_ != 0; + } + explicit operator bool() const noexcept + { + return value_ != 0; + } + bool operator!() const noexcept + { + return value_ == 0; + } - static constexpr int level() noexcept { return Level; } - static constexpr int name() noexcept { return Name; } + static constexpr int level() noexcept + { + return Level; + } + static constexpr int name() noexcept + { + return Name; + } - void* data() noexcept { return &value_; } - void const* data() const noexcept { return &value_; } - std::size_t size() const noexcept { return sizeof(value_); } + void* data() noexcept + { + return &value_; + } + void const* data() const noexcept + { + return &value_; + } + std::size_t size() const noexcept + { + return sizeof(value_); + } void resize(std::size_t) noexcept {} }; @@ -300,7 +324,8 @@ class byte_integer explicit byte_integer(int v) noexcept : value_(static_cast(v)) - {} + { + } byte_integer& operator=(int v) noexcept { @@ -308,14 +333,32 @@ class byte_integer return *this; } - int value() const noexcept { return value_; } + int value() const noexcept + { + return value_; + } - static constexpr int level() noexcept { return Level; } - static constexpr int name() noexcept { return Name; } + static constexpr int level() noexcept + { + return Level; + } + static constexpr int name() noexcept + { + return Name; + } - void* data() noexcept { return &value_; } - void const* data() const noexcept { return &value_; } - std::size_t size() const noexcept { return sizeof(value_); } + void* data() noexcept + { + return &value_; + } + void const* data() const noexcept + { + return &value_; + } + std::size_t size() const noexcept + { + return sizeof(value_); + } void resize(std::size_t) noexcept {} }; diff --git a/include/boost/corosio/native/native_stream_file.hpp b/include/boost/corosio/native/native_stream_file.hpp index 479a671d1..afc85f452 100644 --- a/include/boost/corosio/native/native_stream_file.hpp +++ b/include/boost/corosio/native/native_stream_file.hpp @@ -20,8 +20,8 @@ #include #endif -#if BOOST_COROSIO_HAS_IO_URING -#include +#if BOOST_COROSIO_HAS_URING +#include #endif #if BOOST_COROSIO_HAS_IOCP @@ -86,8 +86,7 @@ class native_stream_file : public stream_file mutable std::size_t bytes_transferred_ = 0; native_read_awaitable( - native_stream_file& self, - MutableBufferSequence buffers) noexcept + native_stream_file& self, MutableBufferSequence buffers) noexcept : self_(self) , buffers_(std::move(buffers)) { @@ -126,8 +125,7 @@ class native_stream_file : public stream_file mutable std::size_t bytes_transferred_ = 0; native_write_awaitable( - native_stream_file& self, - ConstBufferSequence buffers) noexcept + native_stream_file& self, ConstBufferSequence buffers) noexcept : self_(self) , buffers_(std::move(buffers)) { diff --git a/include/boost/corosio/native/native_tcp_acceptor.hpp b/include/boost/corosio/native/native_tcp_acceptor.hpp index 03ab1aba4..759fb2e2d 100644 --- a/include/boost/corosio/native/native_tcp_acceptor.hpp +++ b/include/boost/corosio/native/native_tcp_acceptor.hpp @@ -30,8 +30,8 @@ #include #endif -#if BOOST_COROSIO_HAS_IO_URING -#include +#if BOOST_COROSIO_HAS_URING +#include #endif #endif // !BOOST_COROSIO_MRDOCS @@ -100,8 +100,7 @@ class native_tcp_acceptor : public tcp_acceptor -> std::coroutine_handle<> { token_ = env->stop_token; - return acc_.get_impl().wait( - h, env->executor, w_, token_, &ec_); + return acc_.get_impl().wait(h, env->executor, w_, token_, &ec_); } }; @@ -169,8 +168,9 @@ class native_tcp_acceptor : public tcp_acceptor [[nodiscard]] capy::io_result await_resume() noexcept { if (token_.stop_requested()) - return {make_error_code(std::errc::operation_canceled), - std::move(peer_)}; + return { + make_error_code(std::errc::operation_canceled), + std::move(peer_)}; if (!ec_ && peer_impl_) acc_.reset_peer_impl(peer_, peer_impl_); return {ec_, std::move(peer_)}; diff --git a/include/boost/corosio/native/native_tcp_socket.hpp b/include/boost/corosio/native/native_tcp_socket.hpp index 9dc2548fe..3e7127e68 100644 --- a/include/boost/corosio/native/native_tcp_socket.hpp +++ b/include/boost/corosio/native/native_tcp_socket.hpp @@ -31,8 +31,8 @@ #include #endif -#if BOOST_COROSIO_HAS_IO_URING -#include +#if BOOST_COROSIO_HAS_URING +#include #endif #endif // !BOOST_COROSIO_MRDOCS @@ -185,8 +185,7 @@ class native_tcp_socket : public tcp_socket -> std::coroutine_handle<> { token_ = env->stop_token; - return self_.get_impl().wait( - h, env->executor, w_, token_, &ec_); + return self_.get_impl().wait(h, env->executor, w_, token_, &ec_); } }; diff --git a/include/boost/corosio/native/native_udp_socket.hpp b/include/boost/corosio/native/native_udp_socket.hpp index d3528386d..c8a73deb5 100644 --- a/include/boost/corosio/native/native_udp_socket.hpp +++ b/include/boost/corosio/native/native_udp_socket.hpp @@ -27,8 +27,8 @@ #include #endif -#if BOOST_COROSIO_HAS_IO_URING -#include +#if BOOST_COROSIO_HAS_URING +#include #endif #if BOOST_COROSIO_HAS_IOCP @@ -119,8 +119,8 @@ class native_udp_socket : public udp_socket { token_ = env->stop_token; return self_.get_impl().send_to( - h, env->executor, buffers_, dest_, flags_, - token_, &ec_, &bytes_transferred_); + h, env->executor, buffers_, dest_, flags_, token_, &ec_, + &bytes_transferred_); } }; @@ -166,8 +166,8 @@ class native_udp_socket : public udp_socket { token_ = env->stop_token; return self_.get_impl().recv_from( - h, env->executor, buffers_, &source_, flags_, - token_, &ec_, &bytes_transferred_); + h, env->executor, buffers_, &source_, flags_, token_, &ec_, + &bytes_transferred_); } }; @@ -202,8 +202,7 @@ class native_udp_socket : public udp_socket -> std::coroutine_handle<> { token_ = env->stop_token; - return self_.get_impl().wait( - h, env->executor, w_, token_, &ec_); + return self_.get_impl().wait(h, env->executor, w_, token_, &ec_); } }; @@ -282,8 +281,8 @@ class native_udp_socket : public udp_socket { token_ = env->stop_token; return self_.get_impl().send( - h, env->executor, buffers_, flags_, - token_, &ec_, &bytes_transferred_); + h, env->executor, buffers_, flags_, token_, &ec_, + &bytes_transferred_); } }; @@ -326,8 +325,8 @@ class native_udp_socket : public udp_socket { token_ = env->stop_token; return self_.get_impl().recv( - h, env->executor, buffers_, flags_, - token_, &ec_, &bytes_transferred_); + h, env->executor, buffers_, flags_, token_, &ec_, + &bytes_transferred_); } }; @@ -375,12 +374,11 @@ class native_udp_socket : public udp_socket A closed socket reports `errc::bad_file_descriptor`. */ template - [[nodiscard]] auto send_to( - CB const& buffers, - endpoint dest, - corosio::message_flags flags) + [[nodiscard]] auto + send_to(CB const& buffers, endpoint dest, corosio::message_flags flags) { - native_send_to_awaitable aw(*this, buffers, dest, static_cast(flags)); + native_send_to_awaitable aw( + *this, buffers, dest, static_cast(flags)); if (!is_open()) aw.ec_ = make_error_code(std::errc::bad_file_descriptor); return aw; @@ -408,12 +406,11 @@ class native_udp_socket : public udp_socket A closed socket reports `errc::bad_file_descriptor`. */ template - [[nodiscard]] auto recv_from( - MB const& buffers, - endpoint& source, - corosio::message_flags flags) + [[nodiscard]] auto + recv_from(MB const& buffers, endpoint& source, corosio::message_flags flags) { - native_recv_from_awaitable aw(*this, buffers, source, static_cast(flags)); + native_recv_from_awaitable aw( + *this, buffers, source, static_cast(flags)); if (!is_open()) aw.ec_ = make_error_code(std::errc::bad_file_descriptor); return aw; diff --git a/include/boost/corosio/openssl_stream.hpp b/include/boost/corosio/openssl_stream.hpp index 2d8da64e9..add61822e 100644 --- a/include/boost/corosio/openssl_stream.hpp +++ b/include/boost/corosio/openssl_stream.hpp @@ -205,13 +205,16 @@ class BOOST_COROSIO_DECL openssl_stream final : public tls_stream protected: capy::io_task do_read_some( - capy::detail::mutable_buffer_array buffers) override; + capy::detail::mutable_buffer_array buffers) + override; capy::io_task do_write_some( - capy::detail::const_buffer_array buffers) override; + capy::detail::const_buffer_array buffers) + override; private: - static implementation* make_implementation(capy::any_stream& stream, tls_context const& ctx); + static implementation* + make_implementation(capy::any_stream& stream, tls_context const& ctx); }; /** Return the error category for raw OpenSSL errors. @@ -229,8 +232,7 @@ class BOOST_COROSIO_DECL openssl_stream final : public tls_stream @return A reference to a static category object with name `"corosio.openssl"`. */ -BOOST_COROSIO_DECL std::error_category const& -openssl_category() noexcept; +BOOST_COROSIO_DECL std::error_category const& openssl_category() noexcept; } // namespace boost::corosio diff --git a/include/boost/corosio/random_access_file.hpp b/include/boost/corosio/random_access_file.hpp index 26e0a2ba4..bb18c70af 100644 --- a/include/boost/corosio/random_access_file.hpp +++ b/include/boost/corosio/random_access_file.hpp @@ -142,8 +142,10 @@ class BOOST_COROSIO_DECL random_access_file : public io_object read_some_at_awaitable( random_access_file& f, std::uint64_t offset, - MutableBufferSequence buffers) - noexcept(std::is_nothrow_move_constructible_v) + MutableBufferSequence + buffers) noexcept(std:: + is_nothrow_move_constructible_v< + MutableBufferSequence>) : f_(f) , offset_(offset) , buffers_(std::move(buffers)) @@ -187,8 +189,10 @@ class BOOST_COROSIO_DECL random_access_file : public io_object write_some_at_awaitable( random_access_file& f, std::uint64_t offset, - ConstBufferSequence buffers) - noexcept(std::is_nothrow_move_constructible_v) + ConstBufferSequence + buffers) noexcept(std:: + is_nothrow_move_constructible_v< + ConstBufferSequence>) : f_(f) , offset_(offset) , buffers_(std::move(buffers)) diff --git a/include/boost/corosio/resolver.hpp b/include/boost/corosio/resolver.hpp index 24b93f84f..8697262f5 100644 --- a/include/boost/corosio/resolver.hpp +++ b/include/boost/corosio/resolver.hpp @@ -196,8 +196,8 @@ class BOOST_COROSIO_DECL resolver : public io_object { } - std::coroutine_handle<> dispatch( - std::coroutine_handle<> h, capy::executor_ref ex) const + std::coroutine_handle<> + dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const { return r_.get().resolve( h, ex, host_, service_, flags_, token_, &ec_, &value_); @@ -205,7 +205,8 @@ class BOOST_COROSIO_DECL resolver : public io_object }; struct reverse_resolve_awaitable - : detail::value_op_base + : detail:: + value_op_base { resolver& r_; endpoint ep_; @@ -219,8 +220,8 @@ class BOOST_COROSIO_DECL resolver : public io_object { } - std::coroutine_handle<> dispatch( - std::coroutine_handle<> h, capy::executor_ref ex) const + std::coroutine_handle<> + dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const { return r_.get().reverse_resolve( h, ex, ep_, flags_, token_, &ec_, &value_); diff --git a/include/boost/corosio/socket_option.hpp b/include/boost/corosio/socket_option.hpp index 7e304b037..2a42d1c1d 100644 --- a/include/boost/corosio/socket_option.hpp +++ b/include/boost/corosio/socket_option.hpp @@ -261,7 +261,8 @@ class BOOST_COROSIO_DECL byte_integer_option */ explicit byte_integer_option(int v) noexcept : value_(static_cast(v)) - {} + { + } /// Assign a new value; truncated to one byte. byte_integer_option& operator=(int v) noexcept diff --git a/include/boost/corosio/stream_file.hpp b/include/boost/corosio/stream_file.hpp index 77cd111dd..ca0b48baf 100644 --- a/include/boost/corosio/stream_file.hpp +++ b/include/boost/corosio/stream_file.hpp @@ -270,9 +270,9 @@ class BOOST_COROSIO_DECL stream_file : public io_stream @return The error code and new absolute position. */ - [[nodiscard]] capy::io_result - seek(std::int64_t offset, - file_base::seek_basis origin = file_base::seek_set) noexcept; + [[nodiscard]] capy::io_result seek( + std::int64_t offset, + file_base::seek_basis origin = file_base::seek_set) noexcept; protected: /// Default-construct (for derived types that initialize io_object directly). diff --git a/include/boost/corosio/tcp_acceptor.hpp b/include/boost/corosio/tcp_acceptor.hpp index faed4e62b..0b0daba38 100644 --- a/include/boost/corosio/tcp_acceptor.hpp +++ b/include/boost/corosio/tcp_acceptor.hpp @@ -63,17 +63,19 @@ namespace boost::corosio { */ class BOOST_COROSIO_DECL tcp_acceptor : public io_object { - struct wait_awaitable - : detail::void_op_base + struct wait_awaitable : detail::void_op_base { tcp_acceptor& acc_; wait_type w_; wait_awaitable(tcp_acceptor& acc, wait_type w) noexcept - : acc_(acc), w_(w) {} + : acc_(acc) + , w_(w) + { + } - std::coroutine_handle<> dispatch( - std::coroutine_handle<> h, capy::executor_ref ex) const + std::coroutine_handle<> + dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const { return acc_.get().wait(h, ex, w_, token_, &ec_); } @@ -126,8 +128,7 @@ class BOOST_COROSIO_DECL tcp_acceptor : public io_object mutable std::error_code ec_; mutable io_object::implementation* peer_impl_ = nullptr; - explicit accept_value_awaitable(tcp_acceptor& acc) noexcept - : acc_(acc) + explicit accept_value_awaitable(tcp_acceptor& acc) noexcept : acc_(acc) { } @@ -143,8 +144,9 @@ class BOOST_COROSIO_DECL tcp_acceptor : public io_object // The peer is built only on success: error paths must not // touch acc_.context(), which a moved-from acceptor lacks. if (token_.stop_requested()) - return {make_error_code(std::errc::operation_canceled), - tcp_socket()}; + return { + make_error_code(std::errc::operation_canceled), + tcp_socket()}; if (ec_ || !peer_impl_) return {ec_, tcp_socket()}; diff --git a/include/boost/corosio/tcp_server.hpp b/include/boost/corosio/tcp_server.hpp index 1b2606af4..89e0b859d 100644 --- a/include/boost/corosio/tcp_server.hpp +++ b/include/boost/corosio/tcp_server.hpp @@ -325,7 +325,7 @@ class BOOST_COROSIO_DECL tcp_server auto* wait = self_.waiters_; self_.waiters_ = wait->next; wait->w = &w_; - wait->cont.h = wait->h; + wait->cont.h = wait->h; self_.ex_.post(wait->cont); } else @@ -380,9 +380,9 @@ class BOOST_COROSIO_DECL tcp_server active_remove(&w); if (waiters_) { - auto* wait = waiters_; - waiters_ = wait->next; - wait->w = &w; + auto* wait = waiters_; + waiters_ = wait->next; + wait->w = &w; wait->cont.h = wait->h; ex_.post(wait->cont); } diff --git a/include/boost/corosio/tcp_socket.hpp b/include/boost/corosio/tcp_socket.hpp index 330ca81e4..3019667cd 100644 --- a/include/boost/corosio/tcp_socket.hpp +++ b/include/boost/corosio/tcp_socket.hpp @@ -180,34 +180,34 @@ class BOOST_COROSIO_DECL tcp_socket : public io_stream }; /// Represent the awaitable returned by @ref connect. - struct connect_awaitable - : detail::void_op_base + struct connect_awaitable : detail::void_op_base { tcp_socket& s_; endpoint endpoint_; connect_awaitable(tcp_socket& s, endpoint ep) noexcept - : s_(s), endpoint_(ep) {} + : s_(s) + , endpoint_(ep) + { + } - std::coroutine_handle<> dispatch( - std::coroutine_handle<> h, capy::executor_ref ex) const + std::coroutine_handle<> + dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const { return s_.get().connect(h, ex, endpoint_, token_, &ec_); } }; /// Represent the awaitable returned by @ref wait. - struct wait_awaitable - : detail::void_op_base + struct wait_awaitable : detail::void_op_base { tcp_socket& s_; wait_type w_; - wait_awaitable(tcp_socket& s, wait_type w) noexcept - : s_(s), w_(w) {} + wait_awaitable(tcp_socket& s, wait_type w) noexcept : s_(s), w_(w) {} - std::coroutine_handle<> dispatch( - std::coroutine_handle<> h, capy::executor_ref ex) const + std::coroutine_handle<> + dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const { return s_.get().wait(h, ex, w_, token_, &ec_); } diff --git a/include/boost/corosio/test/socket_pair.hpp b/include/boost/corosio/test/socket_pair.hpp index 512f4ad52..87430803c 100644 --- a/include/boost/corosio/test/socket_pair.hpp +++ b/include/boost/corosio/test/socket_pair.hpp @@ -53,7 +53,8 @@ make_socket_pair(io_context& ctx) Acceptor acc(ctx); if (auto open_ec = acc.open()) - throw std::runtime_error("socket_pair open failed: " + open_ec.message()); + throw std::runtime_error( + "socket_pair open failed: " + open_ec.message()); acc.set_option(socket_option::reuse_address(true)); if (auto ec = acc.bind(endpoint(ipv4_address::loopback(), 0))) throw std::runtime_error("socket_pair bind failed: " + ec.message()); @@ -64,7 +65,8 @@ make_socket_pair(io_context& ctx) Socket s1(ctx); Socket s2(ctx); if (auto open_ec = s2.open()) - throw std::runtime_error("socket_pair open failed: " + open_ec.message()); + throw std::runtime_error( + "socket_pair open failed: " + open_ec.message()); capy::run_async(ex)( [](Acceptor& a, Socket& s, std::error_code& ec_out, diff --git a/include/boost/corosio/timeout.hpp b/include/boost/corosio/timeout.hpp index f4ab1ef69..c2d4f769c 100644 --- a/include/boost/corosio/timeout.hpp +++ b/include/boost/corosio/timeout.hpp @@ -60,20 +60,20 @@ namespace boost::corosio { */ template requires detail::is_io_result_v< - std::remove_cvref_t>> && - std::is_default_constructible_v< - std::remove_cvref_t>> -[[nodiscard]] auto timeout(A a, std::chrono::duration dur) + std::remove_cvref_t>> && + std::is_default_constructible_v< + std::remove_cvref_t>> +[[nodiscard]] auto +timeout(A a, std::chrono::duration dur) { using namespace std::chrono; // Narrow reps wrap if nanoseconds::max() is converted into them; // a double comparison clamps safely in both directions. using dsec = duration; - auto ns = dsec(dur) >= dsec((nanoseconds::max)()) - ? (nanoseconds::max)() + auto ns = dsec(dur) >= dsec((nanoseconds::max)()) ? (nanoseconds::max)() : dsec(dur) <= dsec((nanoseconds::min)()) - ? (nanoseconds::min)() - : duration_cast(dur); + ? (nanoseconds::min)() + : duration_cast(dur); return detail::timeout_awaitable(std::move(a), ns); } @@ -93,10 +93,11 @@ template */ template requires detail::is_io_result_v< - std::remove_cvref_t>> && - std::is_default_constructible_v< - std::remove_cvref_t>> -[[nodiscard]] auto timeout(A a, std::chrono::steady_clock::time_point tp) + std::remove_cvref_t>> && + std::is_default_constructible_v< + std::remove_cvref_t>> +[[nodiscard]] auto +timeout(A a, std::chrono::steady_clock::time_point tp) { return detail::timeout_awaitable(std::move(a), tp); } diff --git a/include/boost/corosio/tls_context.hpp b/include/boost/corosio/tls_context.hpp index 468ce100f..b8f3f3c49 100644 --- a/include/boost/corosio/tls_context.hpp +++ b/include/boost/corosio/tls_context.hpp @@ -153,7 +153,9 @@ class verify_context */ verify_context( void* handle, unsigned char const* der, std::size_t der_len) noexcept - : handle_(handle), der_(der), der_len_(der_len) + : handle_(handle) + , der_(der) + , der_len_(der_len) { } @@ -165,7 +167,10 @@ class verify_context @return The native handle, or `nullptr` if none is available. */ - void* native_handle() const noexcept { return handle_; } + void* native_handle() const noexcept + { + return handle_; + } /** Return the DER encoding of the certificate being verified. @@ -387,7 +392,8 @@ class BOOST_COROSIO_DECL tls_context @see use_certificate_chain */ - [[nodiscard]] std::error_code use_certificate_chain_file(std::string_view filename); + [[nodiscard]] std::error_code + use_certificate_chain_file(std::string_view filename); /** Load the private key from a memory buffer. @@ -509,7 +515,8 @@ class BOOST_COROSIO_DECL tls_context @see load_verify_file @see set_default_verify_paths */ - [[nodiscard]] std::error_code add_certificate_authority(std::string_view ca); + [[nodiscard]] std::error_code + add_certificate_authority(std::string_view ca); /** Load CA certificates from a file. @@ -669,7 +676,8 @@ class BOOST_COROSIO_DECL tls_context @see set_ciphersuites */ - [[nodiscard]] std::error_code set_ciphersuites_tls13(std::string_view ciphers); + [[nodiscard]] std::error_code + set_ciphersuites_tls13(std::string_view ciphers); /** Set the ALPN protocol list. @@ -693,7 +701,8 @@ class BOOST_COROSIO_DECL tls_context @par Example @par !example set_alpn */ - [[nodiscard]] std::error_code set_alpn(std::initializer_list protocols); + [[nodiscard]] std::error_code + set_alpn(std::initializer_list protocols); // // Certificate Verification diff --git a/include/boost/corosio/tls_stream.hpp b/include/boost/corosio/tls_stream.hpp index d59ecf208..e6203f957 100644 --- a/include/boost/corosio/tls_stream.hpp +++ b/include/boost/corosio/tls_stream.hpp @@ -266,7 +266,10 @@ class BOOST_COROSIO_DECL tls_stream Safe to call after the handshake completes; not safe to call concurrently with a handshake or reset. */ - virtual std::string_view alpn_protocol() const noexcept { return {}; } // LCOV_EXCL_LINE every concrete stream overrides this; the base default is never called + virtual std::string_view alpn_protocol() const noexcept + { + return {}; + } // LCOV_EXCL_LINE every concrete stream overrides this; the base default is never called protected: tls_stream() = default; @@ -281,7 +284,8 @@ class BOOST_COROSIO_DECL tls_stream @return An awaitable yielding `(error_code,std::size_t)`. */ virtual capy::io_task do_read_some( - capy::detail::mutable_buffer_array buffers) = 0; + capy::detail::mutable_buffer_array + buffers) = 0; /** Virtual write implementation. diff --git a/include/boost/corosio/udp_socket.hpp b/include/boost/corosio/udp_socket.hpp index c9ecce58f..f2e217cc8 100644 --- a/include/boost/corosio/udp_socket.hpp +++ b/include/boost/corosio/udp_socket.hpp @@ -267,8 +267,7 @@ class BOOST_COROSIO_DECL udp_socket : public io_object Captures the destination endpoint and buffer, then dispatches to the backend implementation on suspension. */ - struct send_to_awaitable - : detail::bytes_op_base + struct send_to_awaitable : detail::bytes_op_base { udp_socket& s_; buffer_param buf_; @@ -276,12 +275,19 @@ class BOOST_COROSIO_DECL udp_socket : public io_object int flags_; send_to_awaitable( - udp_socket& s, buffer_param buf, - endpoint dest, int flags = 0) noexcept - : s_(s), buf_(buf), dest_(dest), flags_(flags) {} + udp_socket& s, + buffer_param buf, + endpoint dest, + int flags = 0) noexcept + : s_(s) + , buf_(buf) + , dest_(dest) + , flags_(flags) + { + } - std::coroutine_handle<> dispatch( - std::coroutine_handle<> h, capy::executor_ref ex) const + std::coroutine_handle<> + dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const { return s_.get().send_to( h, ex, buf_, dest_, flags_, token_, &ec_, &bytes_); @@ -293,8 +299,7 @@ class BOOST_COROSIO_DECL udp_socket : public io_object Captures the source endpoint reference and buffer, then dispatches to the backend implementation on suspension. */ - struct recv_from_awaitable - : detail::bytes_op_base + struct recv_from_awaitable : detail::bytes_op_base { udp_socket& s_; buffer_param buf_; @@ -302,12 +307,19 @@ class BOOST_COROSIO_DECL udp_socket : public io_object int flags_; recv_from_awaitable( - udp_socket& s, buffer_param buf, - endpoint& source, int flags = 0) noexcept - : s_(s), buf_(buf), source_(source), flags_(flags) {} + udp_socket& s, + buffer_param buf, + endpoint& source, + int flags = 0) noexcept + : s_(s) + , buf_(buf) + , source_(source) + , flags_(flags) + { + } - std::coroutine_handle<> dispatch( - std::coroutine_handle<> h, capy::executor_ref ex) const + std::coroutine_handle<> + dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const { return s_.get().recv_from( h, ex, buf_, &source_, flags_, token_, &ec_, &bytes_); @@ -315,78 +327,78 @@ class BOOST_COROSIO_DECL udp_socket : public io_object }; /// Represent the awaitable returned by @ref connect. - struct connect_awaitable - : detail::void_op_base + struct connect_awaitable : detail::void_op_base { udp_socket& s_; endpoint endpoint_; connect_awaitable(udp_socket& s, endpoint ep) noexcept - : s_(s), endpoint_(ep) {} + : s_(s) + , endpoint_(ep) + { + } - std::coroutine_handle<> dispatch( - std::coroutine_handle<> h, capy::executor_ref ex) const + std::coroutine_handle<> + dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const { return s_.get().connect(h, ex, endpoint_, token_, &ec_); } }; /// Represent the awaitable returned by @ref wait. - struct wait_awaitable - : detail::void_op_base + struct wait_awaitable : detail::void_op_base { udp_socket& s_; wait_type w_; - wait_awaitable(udp_socket& s, wait_type w) noexcept - : s_(s), w_(w) {} + wait_awaitable(udp_socket& s, wait_type w) noexcept : s_(s), w_(w) {} - std::coroutine_handle<> dispatch( - std::coroutine_handle<> h, capy::executor_ref ex) const + std::coroutine_handle<> + dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const { return s_.get().wait(h, ex, w_, token_, &ec_); } }; /// Represent the awaitable returned by @ref send. - struct send_awaitable - : detail::bytes_op_base + struct send_awaitable : detail::bytes_op_base { udp_socket& s_; buffer_param buf_; int flags_; - send_awaitable( - udp_socket& s, buffer_param buf, - int flags = 0) noexcept - : s_(s), buf_(buf), flags_(flags) {} + send_awaitable(udp_socket& s, buffer_param buf, int flags = 0) noexcept + : s_(s) + , buf_(buf) + , flags_(flags) + { + } - std::coroutine_handle<> dispatch( - std::coroutine_handle<> h, capy::executor_ref ex) const + std::coroutine_handle<> + dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const { - return s_.get().send( - h, ex, buf_, flags_, token_, &ec_, &bytes_); + return s_.get().send(h, ex, buf_, flags_, token_, &ec_, &bytes_); } }; /// Represent the awaitable returned by @ref recv. - struct recv_awaitable - : detail::bytes_op_base + struct recv_awaitable : detail::bytes_op_base { udp_socket& s_; buffer_param buf_; int flags_; - recv_awaitable( - udp_socket& s, buffer_param buf, - int flags = 0) noexcept - : s_(s), buf_(buf), flags_(flags) {} + recv_awaitable(udp_socket& s, buffer_param buf, int flags = 0) noexcept + : s_(s) + , buf_(buf) + , flags_(flags) + { + } - std::coroutine_handle<> dispatch( - std::coroutine_handle<> h, capy::executor_ref ex) const + std::coroutine_handle<> + dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const { - return s_.get().recv( - h, ex, buf_, flags_, token_, &ec_, &bytes_); + return s_.get().recv(h, ex, buf_, flags_, token_, &ec_, &bytes_); } }; @@ -628,10 +640,8 @@ class BOOST_COROSIO_DECL udp_socket : public io_object A closed socket reports `errc::bad_file_descriptor`. */ template - [[nodiscard]] auto send_to( - Buffers const& buf, - endpoint dest, - corosio::message_flags flags) + [[nodiscard]] auto + send_to(Buffers const& buf, endpoint dest, corosio::message_flags flags) { send_to_awaitable aw(*this, buf, dest, static_cast(flags)); if (!is_open()) @@ -660,9 +670,7 @@ class BOOST_COROSIO_DECL udp_socket : public io_object */ template [[nodiscard]] auto recv_from( - Buffers const& buf, - endpoint& source, - corosio::message_flags flags) + Buffers const& buf, endpoint& source, corosio::message_flags flags) { recv_from_awaitable aw(*this, buf, source, static_cast(flags)); if (!is_open()) diff --git a/include/boost/corosio/wait_traits.hpp b/include/boost/corosio/wait_traits.hpp index 5d6c6f2d4..f0486f220 100644 --- a/include/boost/corosio/wait_traits.hpp +++ b/include/boost/corosio/wait_traits.hpp @@ -51,8 +51,7 @@ struct wait_traits @return The duration the next underlying wait may cover. */ - static typename Clock::duration - to_wait_duration(typename Clock::duration d) + static typename Clock::duration to_wait_duration(typename Clock::duration d) { return d; } @@ -65,10 +64,10 @@ struct wait_traits `Traits::to_wait_duration` must not throw. */ template -concept WaitTraits = requires(typename Clock::duration d) -{ - { Traits::to_wait_duration(d) } - -> std::convertible_to; +concept WaitTraits = requires(typename Clock::duration d) { + { + Traits::to_wait_duration(d) + } -> std::convertible_to; }; } // namespace boost::corosio diff --git a/include/boost/corosio/wolfssl_stream.hpp b/include/boost/corosio/wolfssl_stream.hpp index 127b05387..e8979b750 100644 --- a/include/boost/corosio/wolfssl_stream.hpp +++ b/include/boost/corosio/wolfssl_stream.hpp @@ -201,13 +201,16 @@ class BOOST_COROSIO_DECL wolfssl_stream final : public tls_stream protected: capy::io_task do_read_some( - capy::detail::mutable_buffer_array buffers) override; + capy::detail::mutable_buffer_array buffers) + override; capy::io_task do_write_some( - capy::detail::const_buffer_array buffers) override; + capy::detail::const_buffer_array buffers) + override; private: - static implementation* make_implementation(capy::any_stream& stream, tls_context const& ctx); + static implementation* + make_implementation(capy::any_stream& stream, tls_context const& ctx); }; /** Return the error category for raw WolfSSL errors. @@ -221,8 +224,7 @@ class BOOST_COROSIO_DECL wolfssl_stream final : public tls_stream @return A reference to a static category object with name `"corosio.wolfssl"`. */ -BOOST_COROSIO_DECL std::error_category const& -wolfssl_category() noexcept; +BOOST_COROSIO_DECL std::error_category const& wolfssl_category() noexcept; /** Report whether this build's WolfSSL can honor a verify callback. @@ -242,8 +244,7 @@ wolfssl_category() noexcept; @see tls_context::set_verify_callback */ -BOOST_COROSIO_DECL bool -wolfssl_supports_verify_callback() noexcept; +BOOST_COROSIO_DECL bool wolfssl_supports_verify_callback() noexcept; /** Report whether this WolfSSL build can negotiate ALPN. @@ -257,8 +258,7 @@ wolfssl_supports_verify_callback() noexcept; @see tls_context::set_alpn, tls_stream::alpn_protocol */ -BOOST_COROSIO_DECL bool -wolfssl_supports_alpn() noexcept; +BOOST_COROSIO_DECL bool wolfssl_supports_alpn() noexcept; /** Report whether this WolfSSL build can check certificate revocation. @@ -271,8 +271,7 @@ wolfssl_supports_alpn() noexcept; @see tls_context::add_crl, tls_context::set_revocation_policy */ -BOOST_COROSIO_DECL bool -wolfssl_supports_crl() noexcept; +BOOST_COROSIO_DECL bool wolfssl_supports_crl() noexcept; /** Report whether this WolfSSL build can verify IP-literal hostnames. @@ -290,8 +289,7 @@ wolfssl_supports_crl() noexcept; @see tls_stream::set_hostname */ -BOOST_COROSIO_DECL bool -wolfssl_supports_ip_alt_name() noexcept; +BOOST_COROSIO_DECL bool wolfssl_supports_ip_alt_name() noexcept; } // namespace boost::corosio diff --git a/perf/CMakeLists.txt b/perf/CMakeLists.txt deleted file mode 100644 index d56d45104..000000000 --- a/perf/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2026 Steve Gerbino -# -# Distributed under the Boost Software License, Version 1.0. (See accompanying -# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -# -# Official repository: https://github.com/cppalliance/corosio -# - -# Find Boost.Asio for comparison benchmarks (sibling or system-installed). -# This lives here (not in the root CMakeLists.txt) because the Boost -# superproject's dependency scanner greps Boost::* from the root file -# and would pull in Asio's full transitive dependency tree. -if(NOT TARGET Boost::asio) - find_package(Boost 1.84 QUIET COMPONENTS asio) - if(TARGET Boost::asio) - message(STATUS "Found system Boost.Asio -- comparison benchmarks enabled") - else() - message(STATUS "Boost.Asio not found -- comparison benchmarks disabled") - endif() -endif() - -# Corosio benchmarks -add_subdirectory(bench) - -# Profiler workloads (LTO disabled for call stack visibility) -add_subdirectory(profile) - diff --git a/perf/profile/CMakeLists.txt b/perf/profile/CMakeLists.txt deleted file mode 100644 index 8637df777..000000000 --- a/perf/profile/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -# -# Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com) -# -# Distributed under the Boost Software License, Version 1.0. (See accompanying -# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -# -# Official repository: https://github.com/cppalliance/corosio -# - -# Profiler workloads - LTO disabled to preserve call stacks for profiling - -function(corosio_add_profile_workload name source) - add_executable(${name} ${source}) - target_link_libraries(${name} - PRIVATE - Boost::corosio - Threads::Threads) - set_property(TARGET ${name} PROPERTY FOLDER "benchmarks/profile") - # Explicitly disable LTO for profiling - preserves function names in profiler output - set_property(TARGET ${name} PROPERTY INTERPROCEDURAL_OPTIMIZATION FALSE) - # Flatten source tree in VS - no nested "Sources" folder - source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX "" FILES ${source}) -endfunction() - -corosio_add_profile_workload(profile_coroutine_post coroutine_post_bench.cpp) -corosio_add_profile_workload(profile_scheduler_contention scheduler_contention_bench.cpp) -corosio_add_profile_workload(profile_small_io small_io_bench.cpp) -corosio_add_profile_workload(profile_queue_depth queue_depth_bench.cpp) -corosio_add_profile_workload(profile_concurrent_io concurrent_io_bench.cpp) diff --git a/perf/profile/concurrent_io_bench.cpp b/perf/profile/concurrent_io_bench.cpp deleted file mode 100644 index 0261b75a0..000000000 --- a/perf/profile/concurrent_io_bench.cpp +++ /dev/null @@ -1,370 +0,0 @@ -// -// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com) -// Copyright (c) 2026 Steve Gerbino -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// Official repository: https://github.com/cppalliance/corosio -// - -// Profiler workload: Concurrent I/O -// -// This program tests I/O completion handling under concurrent multi-threaded load. -// Run with a profiler (VTune, perf, VS Profiler) to identify hot spots in: -// - IOCP completion distribution across threads -// - ready_ flag CAS operations in overlapped_op -// - Completion handler scheduling fairness -// - Socket service contention -// -// Example command lines: -// profile_concurrent_io --pairs 16 --threads 4 # Standard concurrent I/O -// profile_concurrent_io --pairs 32 --threads 8 # High contention -// profile_concurrent_io --pairs 4 --threads 1 # Baseline comparison - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "../common/backend_selection.hpp" -#include "../common/perf.hpp" - -namespace corosio = boost::corosio; -namespace capy = boost::capy; - -// Ping-pong coroutine: alternately write then read on a socket pair -// Passed by IILE parameters to avoid capture use-after-free -capy::task<> -ping_pong( - corosio::tcp_socket& sock_write, - corosio::tcp_socket& sock_read, - std::size_t buf_size, - std::atomic& ops, - std::atomic& stop) -{ - std::vector write_buf(buf_size, 'X'); - std::vector read_buf(buf_size); - - while (!stop.load(std::memory_order_relaxed)) - { - // Write - auto [wec, wn] = co_await sock_write.write_some( - capy::const_buffer(write_buf.data(), write_buf.size())); - if (wec) - co_return; - - // Read - auto [rec, rn] = co_await sock_read.read_some( - capy::mutable_buffer(read_buf.data(), read_buf.size())); - if (rec) - co_return; - - ops.fetch_add(2, std::memory_order_relaxed); - } -} - -// Run the profiler workload for the specified duration -void -run_workload( - perf::context_factory factory, - int duration_seconds, - std::size_t buffer_size, - int num_pairs, - int num_threads) -{ - auto ioc = factory(); - std::atomic ops{0}; - std::atomic stop{false}; - - // Create socket pairs - std::vector> pairs; - pairs.reserve(num_pairs); - - for (int i = 0; i < num_pairs; ++i) - { - auto [a, b] = corosio::test::make_socket_pair(*ioc); - a.set_option(corosio::native_socket_option::no_delay(true)); - b.set_option(corosio::native_socket_option::no_delay(true)); - pairs.emplace_back(std::move(a), std::move(b)); - } - - // Launch ping-pong on each pair - for (auto& [a, b] : pairs) - { - capy::run_async(ioc->get_executor())( - ping_pong(a, b, buffer_size, ops, stop)); - } - - auto start = std::chrono::steady_clock::now(); - auto end_time = start + std::chrono::seconds(duration_seconds); - - std::cout << "Running for " << duration_seconds << " seconds...\n"; - std::cout << "Pairs: " << num_pairs << ", Threads: " << num_threads - << ", Buffer: " << buffer_size << " bytes\n\n"; - - std::uint64_t last_count = 0; - - // Launch worker threads - std::vector workers; - workers.reserve(num_threads); - - for (int t = 0; t < num_threads; ++t) - { - workers.emplace_back([&]() { - auto next_report = - std::chrono::steady_clock::now() + std::chrono::seconds(2); - - while (std::chrono::steady_clock::now() < end_time) - { - ioc->run_for(std::chrono::milliseconds(100)); - - // Only first thread reports progress - auto now = std::chrono::steady_clock::now(); - if (now >= next_report) - { - auto elapsed = - std::chrono::duration(now - start).count(); - std::uint64_t current = ops.load(std::memory_order_relaxed); - double rate = - static_cast(current - last_count) / 2.0; - - std::cout << " [" << std::fixed << std::setprecision(0) - << elapsed << "s] " << perf::format_rate(rate) - << " (" << current << " total)\n"; - - last_count = current; - next_report = now + std::chrono::seconds(2); - } - } - }); - } - - // Wait for workers - for (auto& w : workers) - w.join(); - - // Signal stop and cancel pending operations - stop.store(true, std::memory_order_relaxed); - for (auto& [a, b] : pairs) - { - a.cancel(); - b.cancel(); - } - - // Drain remaining work - ioc->run(); - - // Final stats - auto total_elapsed = - std::chrono::duration(std::chrono::steady_clock::now() - start) - .count(); - std::uint64_t total = ops.load(std::memory_order_relaxed); - double avg_rate = static_cast(total) / total_elapsed; - - std::cout << "\n=== Results ===\n"; - std::cout << " Duration: " << std::fixed << std::setprecision(2) - << total_elapsed << " s\n"; - std::cout << " Operations: " << total << "\n"; - std::cout << " Avg rate: " << perf::format_rate(avg_rate) << "\n"; -} - -void -run_profiler_workload( - perf::context_factory factory, - const char* backend_name, - int duration, - std::size_t buffer_size, - int num_pairs, - int num_threads) -{ - std::cout << "Corosio Profiler Workload: Concurrent I/O\n"; - std::cout << "==========================================\n"; - std::cout << "Backend: " << backend_name << "\n\n"; - - std::cout << "Profile targets:\n"; - std::cout << " - IOCP completion distribution across threads\n"; - std::cout << " - ready_ flag CAS operations in overlapped_op\n"; - std::cout << " - Completion handler scheduling fairness\n"; - std::cout << " - Socket service contention\n\n"; - - // Warmup - std::cout << "Warming up (1 second)...\n"; - { - auto ioc = factory(); - auto [a, b] = corosio::test::make_socket_pair(*ioc); - a.set_option(corosio::native_socket_option::no_delay(true)); - b.set_option(corosio::native_socket_option::no_delay(true)); - - std::atomic warmup_ops{0}; - std::atomic warmup_stop{false}; - - capy::run_async(ioc->get_executor())( - ping_pong(a, b, 64, warmup_ops, warmup_stop)); - - auto warmup_end = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (std::chrono::steady_clock::now() < warmup_end) - ioc->run_for(std::chrono::milliseconds(100)); - - warmup_stop.store(true, std::memory_order_relaxed); - a.cancel(); - b.cancel(); - ioc->run(); - } - - std::cout << "Warmup complete.\n\n"; - - // Main workload - run_workload(factory, duration, buffer_size, num_pairs, num_threads); - - std::cout << "\nWorkload complete.\n"; -} - -void -print_usage(const char* program_name) -{ - std::cout << "Usage: " << program_name << " [OPTIONS]\n\n"; - std::cout - << "Profiler workload for concurrent I/O completion analysis.\n\n"; - std::cout << "Options:\n"; - std::cout << " --backend Select I/O backend (default: platform " - "default)\n"; - std::cout - << " --duration Run duration in seconds (default: 10)\n"; - std::cout - << " --pairs Number of socket pairs (default: 16)\n"; - std::cout << " --threads Runner threads (default: 4)\n"; - std::cout - << " --buffer Buffer size in bytes (default: 1024)\n"; - std::cout << " --list List available backends\n"; - std::cout << " --help Show this help message\n"; - std::cout << "\n"; - std::cout << "Example:\n"; - std::cout << " " << program_name - << " --pairs 16 --threads 4 --buffer 1024\n"; - std::cout << "\n"; - perf::print_available_backends(); -} - -int -main(int argc, char* argv[]) -{ - const char* backend = nullptr; - int duration = 10; - int num_pairs = 16; - int num_threads = 4; - std::size_t buffer_size = 1024; - - // Parse command-line arguments - for (int i = 1; i < argc; ++i) - { - if (std::strcmp(argv[i], "--backend") == 0) - { - if (i + 1 < argc) - backend = argv[++i]; - else - { - std::cerr << "Error: --backend requires an argument\n"; - return 1; - } - } - else if (std::strcmp(argv[i], "--duration") == 0) - { - if (i + 1 < argc) - duration = std::atoi(argv[++i]); - else - { - std::cerr << "Error: --duration requires an argument\n"; - return 1; - } - } - else if (std::strcmp(argv[i], "--pairs") == 0) - { - if (i + 1 < argc) - num_pairs = std::atoi(argv[++i]); - else - { - std::cerr << "Error: --pairs requires an argument\n"; - return 1; - } - } - else if (std::strcmp(argv[i], "--threads") == 0) - { - if (i + 1 < argc) - num_threads = std::atoi(argv[++i]); - else - { - std::cerr << "Error: --threads requires an argument\n"; - return 1; - } - } - else if (std::strcmp(argv[i], "--buffer") == 0) - { - if (i + 1 < argc) - buffer_size = static_cast(std::atoi(argv[++i])); - else - { - std::cerr << "Error: --buffer requires an argument\n"; - return 1; - } - } - else if (std::strcmp(argv[i], "--list") == 0) - { - perf::print_available_backends(); - return 0; - } - else if ( - std::strcmp(argv[i], "--help") == 0 || - std::strcmp(argv[i], "-h") == 0) - { - print_usage(argv[0]); - return 0; - } - else - { - std::cerr << "Unknown option: " << argv[i] << "\n"; - print_usage(argv[0]); - return 1; - } - } - - // Validate arguments - if (num_pairs < 1) - { - std::cerr << "Error: --pairs must be >= 1\n"; - return 1; - } - if (num_threads < 1) - { - std::cerr << "Error: --threads must be >= 1\n"; - return 1; - } - if (buffer_size == 0) - { - std::cerr << "Error: --buffer must be > 0\n"; - return 1; - } - - // If no backend specified, use platform default - if (!backend) - backend = perf::default_backend_name(); - - // Dispatch to the selected backend - return perf::dispatch_backend( - backend, [=](perf::context_factory factory, auto, const char* name) { - run_profiler_workload( - factory, name, duration, buffer_size, num_pairs, num_threads); - }); -} diff --git a/perf/profile/coroutine_post_bench.cpp b/perf/profile/coroutine_post_bench.cpp deleted file mode 100644 index 85e96fd92..000000000 --- a/perf/profile/coroutine_post_bench.cpp +++ /dev/null @@ -1,299 +0,0 @@ -// -// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com) -// Copyright (c) 2026 Steve Gerbino -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// Official repository: https://github.com/cppalliance/corosio -// - -// Profiler workload: Coroutine Post/Resume Path -// -// This program hammers the coroutine post/resume path for profiling. -// Run with a profiler (VTune, perf, VS Profiler) to identify hot spots in: -// - run_async template instantiation -// - post_handler allocation (new post_handler) -// - PostQueuedCompletionStatus / IOCP posting -// - GetQueuedCompletionStatus / dispatch loop -// - coro.resume() cost - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "../common/backend_selection.hpp" -#include "../common/perf.hpp" - -namespace corosio = boost::corosio; -namespace capy = boost::capy; - -// Empty coroutine - minimal work, maximizes framework overhead visibility -capy::task<> -empty_task(std::atomic& counter) -{ - counter.fetch_add(1, std::memory_order_relaxed); - co_return; -} - -// Coroutine with captured state - tests frame allocation scaling -template -capy::task<> -capture_task(std::atomic& counter) -{ - // Force capture of N bytes - [[maybe_unused]] char payload[CaptureSize]; - std::memset(payload, 0, CaptureSize); - counter.fetch_add(1, std::memory_order_relaxed); - co_return; -} - -// Run the profiler workload for the specified duration -void -run_workload( - perf::context_factory factory, - int duration_seconds, - int batch_size, - std::size_t capture_size) -{ - auto ioc = factory(); - auto ex = ioc->get_executor(); - std::atomic counter{0}; - - auto start = std::chrono::steady_clock::now(); - auto end_time = start + std::chrono::seconds(duration_seconds); - auto next_report = start + std::chrono::seconds(2); - - std::cout << "Running for " << duration_seconds << " seconds...\n"; - std::cout << "Batch size: " << batch_size - << ", Capture size: " << capture_size << " bytes\n\n"; - - std::uint64_t last_count = 0; - - while (std::chrono::steady_clock::now() < end_time) - { - // Post a batch of coroutines - for (int i = 0; i < batch_size; ++i) - { - switch (capture_size) - { - case 0: - capy::run_async(ex)(empty_task(counter)); - break; - case 64: - capy::run_async(ex)(capture_task<64>(counter)); - break; - case 256: - capy::run_async(ex)(capture_task<256>(counter)); - break; - case 1024: - capy::run_async(ex)(capture_task<1024>(counter)); - break; - default: - capy::run_async(ex)(empty_task(counter)); - break; - } - } - - // Execute all pending work - ioc->poll(); - ioc->restart(); - - // Progress report every 2 seconds - auto now = std::chrono::steady_clock::now(); - if (now >= next_report) - { - auto elapsed = std::chrono::duration(now - start).count(); - std::uint64_t current = counter.load(std::memory_order_relaxed); - double rate = static_cast(current - last_count) / 2.0; - - std::cout << " [" << std::fixed << std::setprecision(0) << elapsed - << "s] " << perf::format_rate(rate) << " (" << current - << " total)\n"; - - last_count = current; - next_report = now + std::chrono::seconds(2); - } - } - - // Final stats - auto total_elapsed = - std::chrono::duration(std::chrono::steady_clock::now() - start) - .count(); - std::uint64_t total = counter.load(std::memory_order_relaxed); - double avg_rate = static_cast(total) / total_elapsed; - - std::cout << "\n=== Results ===\n"; - std::cout << " Duration: " << std::fixed << std::setprecision(2) - << total_elapsed << " s\n"; - std::cout << " Operations: " << total << "\n"; - std::cout << " Avg rate: " << perf::format_rate(avg_rate) << "\n"; -} - -void -run_profiler_workload( - perf::context_factory factory, - const char* backend_name, - int duration, - int batch_size, - std::size_t capture_size) -{ - std::cout << "Corosio Profiler Workload: Coroutine Post/Resume\n"; - std::cout << "================================================\n"; - std::cout << "Backend: " << backend_name << "\n\n"; - - std::cout << "Profile targets:\n"; - std::cout << " - run_async / task machinery\n"; - std::cout << " - post_handler allocation\n"; - std::cout << " - IOCP posting (PostQueuedCompletionStatus)\n"; - std::cout << " - Dispatch loop (GetQueuedCompletionStatus)\n"; - std::cout << " - coro.resume()\n\n"; - - // Warmup - std::cout << "Warming up (1 second)...\n"; - { - auto ioc = factory(); - auto ex = ioc->get_executor(); - std::atomic warmup_counter{0}; - - auto warmup_end = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (std::chrono::steady_clock::now() < warmup_end) - { - for (int i = 0; i < 1000; ++i) - capy::run_async(ex)(empty_task(warmup_counter)); - ioc->poll(); - ioc->restart(); - } - } - - std::cout << "Warmup complete.\n\n"; - - // Main workload - run_workload(factory, duration, batch_size, capture_size); - - std::cout << "\nWorkload complete.\n"; -} - -void -print_usage(const char* program_name) -{ - std::cout << "Usage: " << program_name << " [OPTIONS]\n\n"; - std::cout - << "Profiler workload for coroutine post/resume path analysis.\n\n"; - std::cout << "Options:\n"; - std::cout << " --backend Select I/O backend (default: platform " - "default)\n"; - std::cout - << " --duration Run duration in seconds (default: 10)\n"; - std::cout - << " --batch Coroutines per poll cycle (default: 1000)\n"; - std::cout << " --capture Captured state size: 0, 64, 256, 1024 " - "(default: 0)\n"; - std::cout << " --list List available backends\n"; - std::cout << " --help Show this help message\n"; - std::cout << "\n"; - std::cout << "Example:\n"; - std::cout << " " << program_name << " --duration 10 --batch 1000\n"; - std::cout << "\n"; - perf::print_available_backends(); -} - -int -main(int argc, char* argv[]) -{ - const char* backend = nullptr; - int duration = 10; - int batch_size = 1000; - std::size_t capture_size = 0; - - // Parse command-line arguments - for (int i = 1; i < argc; ++i) - { - if (std::strcmp(argv[i], "--backend") == 0) - { - if (i + 1 < argc) - backend = argv[++i]; - else - { - std::cerr << "Error: --backend requires an argument\n"; - return 1; - } - } - else if (std::strcmp(argv[i], "--duration") == 0) - { - if (i + 1 < argc) - duration = std::atoi(argv[++i]); - else - { - std::cerr << "Error: --duration requires an argument\n"; - return 1; - } - } - else if (std::strcmp(argv[i], "--batch") == 0) - { - if (i + 1 < argc) - batch_size = std::atoi(argv[++i]); - else - { - std::cerr << "Error: --batch requires an argument\n"; - return 1; - } - } - else if (std::strcmp(argv[i], "--capture") == 0) - { - if (i + 1 < argc) - capture_size = static_cast(std::atoi(argv[++i])); - else - { - std::cerr << "Error: --capture requires an argument\n"; - return 1; - } - } - else if (std::strcmp(argv[i], "--list") == 0) - { - perf::print_available_backends(); - return 0; - } - else if ( - std::strcmp(argv[i], "--help") == 0 || - std::strcmp(argv[i], "-h") == 0) - { - print_usage(argv[0]); - return 0; - } - else - { - std::cerr << "Unknown option: " << argv[i] << "\n"; - print_usage(argv[0]); - return 1; - } - } - - // Validate capture size - if (capture_size != 0 && capture_size != 64 && capture_size != 256 && - capture_size != 1024) - { - std::cerr << "Error: --capture must be 0, 64, 256, or 1024\n"; - return 1; - } - - // If no backend specified, use platform default - if (!backend) - backend = perf::default_backend_name(); - - // Dispatch to the selected backend - return perf::dispatch_backend( - backend, [=](perf::context_factory factory, auto, const char* name) { - run_profiler_workload( - factory, name, duration, batch_size, capture_size); - }); -} diff --git a/perf/profile/queue_depth_bench.cpp b/perf/profile/queue_depth_bench.cpp deleted file mode 100644 index 0e1d2d0f3..000000000 --- a/perf/profile/queue_depth_bench.cpp +++ /dev/null @@ -1,289 +0,0 @@ -// -// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com) -// Copyright (c) 2026 Steve Gerbino -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// Official repository: https://github.com/cppalliance/corosio -// - -// Profiler workload: Queue Depth / Large Pending Queue -// -// This program tests dispatch efficiency with a large pending queue. -// Run with a profiler (VTune, perf, VS Profiler) to identify hot spots in: -// - op_queue traversal cost -// - completed_ops_ handling in do_one -// - Memory access patterns (cache locality) -// - Per-dispatch overhead at scale -// -// Example command lines: -// profile_queue_depth --depth 100000 # Large queue, single thread -// profile_queue_depth --depth 10000 --threads 4 # Moderate queue, multi-thread dispatch - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "../common/backend_selection.hpp" -#include "../common/perf.hpp" - -namespace corosio = boost::corosio; -namespace capy = boost::capy; - -// Empty coroutine - minimal work, maximizes framework overhead visibility -capy::task<> -empty_task(std::atomic& counter) -{ - counter.fetch_add(1, std::memory_order_relaxed); - co_return; -} - -// Run the profiler workload for the specified duration -void -run_workload( - perf::context_factory factory, - int duration_seconds, - int queue_depth, - int num_threads) -{ - auto ioc = factory(); - auto ex = ioc->get_executor(); - std::atomic counter{0}; - - auto start = std::chrono::steady_clock::now(); - auto end_time = start + std::chrono::seconds(duration_seconds); - auto next_report = start + std::chrono::seconds(2); - - std::cout << "Running for " << duration_seconds << " seconds...\n"; - std::cout << "Queue depth: " << queue_depth << ", Threads: " << num_threads - << "\n\n"; - - std::uint64_t last_count = 0; - int iterations = 0; - - while (std::chrono::steady_clock::now() < end_time) - { - // Fill the queue - for (int i = 0; i < queue_depth; ++i) - capy::run_async(ex)(empty_task(counter)); - - // Dispatch with multiple threads if requested - if (num_threads > 1) - { - std::vector workers; - workers.reserve(num_threads); - for (int t = 0; t < num_threads; ++t) - workers.emplace_back([&]() { ioc->run(); }); - for (auto& w : workers) - w.join(); - } - else - { - ioc->run(); - } - - ioc->restart(); - ++iterations; - - // Progress report every 2 seconds - auto now = std::chrono::steady_clock::now(); - if (now >= next_report) - { - auto elapsed = std::chrono::duration(now - start).count(); - std::uint64_t current = counter.load(std::memory_order_relaxed); - double rate = static_cast(current - last_count) / 2.0; - - std::cout << " [" << std::fixed << std::setprecision(0) << elapsed - << "s] " << perf::format_rate(rate) << " (" << iterations - << " iterations)\n"; - - last_count = current; - next_report = now + std::chrono::seconds(2); - } - } - - // Final stats - auto total_elapsed = - std::chrono::duration(std::chrono::steady_clock::now() - start) - .count(); - std::uint64_t total = counter.load(std::memory_order_relaxed); - double avg_rate = static_cast(total) / total_elapsed; - - std::cout << "\n=== Results ===\n"; - std::cout << " Duration: " << std::fixed << std::setprecision(2) - << total_elapsed << " s\n"; - std::cout << " Operations: " << total << "\n"; - std::cout << " Iterations: " << iterations << "\n"; - std::cout << " Avg rate: " << perf::format_rate(avg_rate) << "\n"; -} - -void -run_profiler_workload( - perf::context_factory factory, - const char* backend_name, - int duration, - int queue_depth, - int num_threads) -{ - std::cout << "Corosio Profiler Workload: Queue Depth\n"; - std::cout << "======================================\n"; - std::cout << "Backend: " << backend_name << "\n\n"; - - std::cout << "Profile targets:\n"; - std::cout << " - op_queue traversal cost\n"; - std::cout << " - completed_ops_ handling in do_one\n"; - std::cout << " - Memory access patterns (cache locality)\n"; - std::cout << " - Per-dispatch overhead at scale\n\n"; - - // Warmup - std::cout << "Warming up (1 second)...\n"; - { - auto ioc = factory(); - auto ex = ioc->get_executor(); - std::atomic warmup_counter{0}; - - auto warmup_end = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (std::chrono::steady_clock::now() < warmup_end) - { - for (int i = 0; i < 1000; ++i) - capy::run_async(ex)(empty_task(warmup_counter)); - ioc->poll(); - ioc->restart(); - } - } - - std::cout << "Warmup complete.\n\n"; - - // Main workload - run_workload(factory, duration, queue_depth, num_threads); - - std::cout << "\nWorkload complete.\n"; -} - -void -print_usage(const char* program_name) -{ - std::cout << "Usage: " << program_name << " [OPTIONS]\n\n"; - std::cout - << "Profiler workload for large pending queue dispatch analysis.\n\n"; - std::cout << "Options:\n"; - std::cout << " --backend Select I/O backend (default: platform " - "default)\n"; - std::cout - << " --duration Run duration in seconds (default: 10)\n"; - std::cout << " --depth Queue depth per iteration (default: " - "100000)\n"; - std::cout << " --threads Dispatch threads (default: 1)\n"; - std::cout << " --list List available backends\n"; - std::cout << " --help Show this help message\n"; - std::cout << "\n"; - std::cout << "Example:\n"; - std::cout << " " << program_name << " --depth 100000 --threads 1\n"; - std::cout << "\n"; - perf::print_available_backends(); -} - -int -main(int argc, char* argv[]) -{ - const char* backend = nullptr; - int duration = 10; - int queue_depth = 100000; - int num_threads = 1; - - // Parse command-line arguments - for (int i = 1; i < argc; ++i) - { - if (std::strcmp(argv[i], "--backend") == 0) - { - if (i + 1 < argc) - backend = argv[++i]; - else - { - std::cerr << "Error: --backend requires an argument\n"; - return 1; - } - } - else if (std::strcmp(argv[i], "--duration") == 0) - { - if (i + 1 < argc) - duration = std::atoi(argv[++i]); - else - { - std::cerr << "Error: --duration requires an argument\n"; - return 1; - } - } - else if (std::strcmp(argv[i], "--depth") == 0) - { - if (i + 1 < argc) - queue_depth = std::atoi(argv[++i]); - else - { - std::cerr << "Error: --depth requires an argument\n"; - return 1; - } - } - else if (std::strcmp(argv[i], "--threads") == 0) - { - if (i + 1 < argc) - num_threads = std::atoi(argv[++i]); - else - { - std::cerr << "Error: --threads requires an argument\n"; - return 1; - } - } - else if (std::strcmp(argv[i], "--list") == 0) - { - perf::print_available_backends(); - return 0; - } - else if ( - std::strcmp(argv[i], "--help") == 0 || - std::strcmp(argv[i], "-h") == 0) - { - print_usage(argv[0]); - return 0; - } - else - { - std::cerr << "Unknown option: " << argv[i] << "\n"; - print_usage(argv[0]); - return 1; - } - } - - // Validate arguments - if (queue_depth < 1) - { - std::cerr << "Error: --depth must be >= 1\n"; - return 1; - } - if (num_threads < 1) - { - std::cerr << "Error: --threads must be >= 1\n"; - return 1; - } - - // If no backend specified, use platform default - if (!backend) - backend = perf::default_backend_name(); - - // Dispatch to the selected backend - return perf::dispatch_backend( - backend, [=](perf::context_factory factory, auto, const char* name) { - run_profiler_workload( - factory, name, duration, queue_depth, num_threads); - }); -} diff --git a/perf/profile/scheduler_contention_bench.cpp b/perf/profile/scheduler_contention_bench.cpp deleted file mode 100644 index 1ce25a402..000000000 --- a/perf/profile/scheduler_contention_bench.cpp +++ /dev/null @@ -1,634 +0,0 @@ -// -// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com) -// Copyright (c) 2026 Steve Gerbino -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// Official repository: https://github.com/cppalliance/corosio -// - -// Profiler workload: Multi-threaded Scheduler Contention -// -// This program hammers the scheduler with multiple threads posting and -// running coroutines concurrently. Run with a profiler to identify: -// - dispatch_mutex_ lock contention -// - InterlockedIncrement/Decrement on outstanding_work_ -// - Cache line bouncing between cores -// - Unfair work distribution across threads -// -// Usage: -// -// Balanced mode (default) - each thread posts and polls: -// profile_scheduler_contention --threads 8 --batch 100 -// -// Post-only mode - profiles posting path (half threads post, half run): -// profile_scheduler_contention --threads 8 --post-only -// -// Run-only mode - isolates dispatch/completion path contention: -// profile_scheduler_contention --threads 8 --run-only --batch 10000 -// -// Options: -// --threads N Number of worker threads (default: 8) -// --batch N Coroutines per batch (default: 100) -// --duration N Run duration in seconds (default: 10) -// --post-only Half threads post (main included), half run -// --run-only Main posts continuously, all threads run - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "../common/backend_selection.hpp" -#include "../common/perf.hpp" - -namespace corosio = boost::corosio; -namespace capy = boost::capy; - -enum class workload_mode -{ - balanced, // Each thread posts and polls (default) - post_only, // All threads post, one thread runs - run_only // Pre-fill queue, all threads run -}; - -// Empty coroutine - minimal work, maximizes framework overhead visibility -capy::task<> -empty_task(std::atomic& counter) -{ - counter.fetch_add(1, std::memory_order_relaxed); - co_return; -} - -// Worker thread for balanced mode - posts and polls -void -balanced_worker( - corosio::io_context& ioc, - std::atomic& stop, - std::atomic& counter, - int batch_size) -{ - auto ex = ioc.get_executor(); - while (!stop.load(std::memory_order_relaxed)) - { - for (int i = 0; i < batch_size; ++i) - capy::run_async(ex)(empty_task(counter)); - ioc.poll(); - } -} - -// Worker thread for post-only mode - only posts, never runs -void -post_only_worker( - corosio::io_context& ioc, - std::atomic& stop, - std::atomic& posted, - int batch_size) -{ - auto ex = ioc.get_executor(); - while (!stop.load(std::memory_order_relaxed)) - { - for (int i = 0; i < batch_size; ++i) - { - capy::run_async(ex)(empty_task(posted)); - } - // Yield to avoid spinning too hard - std::this_thread::yield(); - } -} - -// Runner thread for post-only mode - only runs, never posts -void -post_only_runner(corosio::io_context& ioc, std::atomic& stop) -{ - while (!stop.load(std::memory_order_relaxed)) - { - auto n = ioc.poll(); - if (n == 0) - std::this_thread::yield(); - } - // Drain remaining work - ioc.poll(); -} - -// Worker thread for run-only mode - only runs from pre-filled queue -void -run_only_worker(corosio::io_context& ioc, std::atomic& stop) -{ - while (!stop.load(std::memory_order_relaxed)) - { - ioc.poll(); - } -} - -void -run_balanced_workload( - perf::context_factory factory, - int duration_seconds, - int num_threads, - int batch_size) -{ - auto ioc = factory(); - std::atomic counter{0}; - std::atomic stop{false}; - - auto start = std::chrono::steady_clock::now(); - auto end_time = start + std::chrono::seconds(duration_seconds); - std::atomic next_report_sec{2}; - - std::cout << "Mode: balanced (each thread posts and polls)\n"; - std::cout << "Threads: " << num_threads - << " (including main), Batch size: " << batch_size << "\n\n"; - - std::atomic last_count{0}; - - // Launch N-1 worker threads (main thread will be the Nth worker) - std::vector workers; - workers.reserve(num_threads - 1); - for (int t = 0; t < num_threads - 1; ++t) - { - workers.emplace_back( - [&]() { balanced_worker(*ioc, stop, counter, batch_size); }); - } - - // Main thread works too - no sleeping! - auto ex = ioc->get_executor(); - std::uint64_t local_batches = 0; - while (!stop.load(std::memory_order_relaxed)) - { - for (int i = 0; i < batch_size; ++i) - capy::run_async(ex)(empty_task(counter)); - ioc->poll(); - ++local_batches; - - // Check time every 1000 batches to avoid syscall overhead - if ((local_batches & 0x3FF) == 0) - { - auto now = std::chrono::steady_clock::now(); - if (now >= end_time) - { - stop.store(true, std::memory_order_relaxed); - break; - } - - // Progress report (only main thread prints) - auto elapsed = std::chrono::duration(now - start).count(); - int elapsed_int = static_cast(elapsed); - int expected = next_report_sec.load(std::memory_order_relaxed); - if (elapsed_int >= expected && - next_report_sec.compare_exchange_strong(expected, expected + 2)) - { - std::uint64_t current = counter.load(std::memory_order_relaxed); - std::uint64_t last = - last_count.exchange(current, std::memory_order_relaxed); - double rate = static_cast(current - last) / 2.0; - - std::cout << " [" << std::fixed << std::setprecision(0) - << elapsed << "s] " << perf::format_rate(rate) << " (" - << current << " total)\n"; - } - } - } - - // Stop workers - for (auto& w : workers) - w.join(); - - // Final stats - auto total_elapsed = - std::chrono::duration(std::chrono::steady_clock::now() - start) - .count(); - std::uint64_t total = counter.load(std::memory_order_relaxed); - double avg_rate = static_cast(total) / total_elapsed; - - std::cout << "\n=== Results ===\n"; - std::cout << " Duration: " << std::fixed << std::setprecision(2) - << total_elapsed << " s\n"; - std::cout << " Operations: " << total << "\n"; - std::cout << " Avg rate: " << perf::format_rate(avg_rate) << "\n"; -} - -void -run_post_only_workload( - perf::context_factory factory, - int duration_seconds, - int num_threads, - int batch_size) -{ - auto ioc = factory(); - std::atomic counter{0}; - std::atomic stop{false}; - - auto start = std::chrono::steady_clock::now(); - auto end_time = start + std::chrono::seconds(duration_seconds); - std::atomic next_report_sec{2}; - - // Split threads: main + half post, other half run - int num_posters = (num_threads + 1) / 2; // Round up, main is also a poster - int num_runners = num_threads - num_posters; - if (num_runners < 1) - num_runners = 1; - - std::cout << "Mode: post-only (profile posting path contention)\n"; - std::cout << "Posters: " << num_posters - << " (including main), Runners: " << num_runners - << ", Batch size: " << batch_size << "\n" - << std::endl; - - std::atomic last_count{0}; - - // Launch posting threads (main will be one more) - std::vector posters; - posters.reserve(num_posters - 1); - for (int t = 0; t < num_posters - 1; ++t) - { - posters.emplace_back( - [&]() { post_only_worker(*ioc, stop, counter, batch_size); }); - } - - // Launch runner threads to consume work - std::vector runners; - runners.reserve(num_runners); - for (int t = 0; t < num_runners; ++t) - { - runners.emplace_back([&]() { - while (!stop.load(std::memory_order_relaxed)) - ioc->poll(); - ioc->poll(); // Drain - }); - } - - // Main thread posts - this is what we want to profile! - auto ex = ioc->get_executor(); - std::uint64_t local_batches = 0; - while (!stop.load(std::memory_order_relaxed)) - { - for (int i = 0; i < batch_size; ++i) - capy::run_async(ex)(empty_task(counter)); - ++local_batches; - - // Check time every 256 batches - if ((local_batches & 0xFF) == 0) - { - auto now = std::chrono::steady_clock::now(); - if (now >= end_time) - { - stop.store(true, std::memory_order_relaxed); - break; - } - - // Progress report - auto elapsed = std::chrono::duration(now - start).count(); - int elapsed_int = static_cast(elapsed); - int expected = next_report_sec.load(std::memory_order_relaxed); - if (elapsed_int >= expected && - next_report_sec.compare_exchange_strong(expected, expected + 2)) - { - std::uint64_t current = counter.load(std::memory_order_relaxed); - std::uint64_t last = - last_count.exchange(current, std::memory_order_relaxed); - double rate = static_cast(current - last) / 2.0; - - std::cout << " [" << std::fixed << std::setprecision(0) - << elapsed << "s] " << perf::format_rate(rate) << " (" - << current << " total)\n"; - } - } - } - - // Stop all threads - for (auto& p : posters) - p.join(); - for (auto& r : runners) - r.join(); - - // Final stats - auto total_elapsed = - std::chrono::duration(std::chrono::steady_clock::now() - start) - .count(); - std::uint64_t total = counter.load(std::memory_order_relaxed); - double avg_rate = static_cast(total) / total_elapsed; - - std::cout << "\n=== Results ===\n"; - std::cout << " Duration: " << std::fixed << std::setprecision(2) - << total_elapsed << " s\n"; - std::cout << " Operations: " << total << "\n"; - std::cout << " Avg rate: " << perf::format_rate(avg_rate) << "\n"; -} - -void -run_run_only_workload( - perf::context_factory factory, - int duration_seconds, - int num_threads, - int queue_depth) -{ - auto ioc = factory(); - std::atomic counter{0}; - std::atomic stop{false}; - - auto start = std::chrono::steady_clock::now(); - auto end_time = start + std::chrono::seconds(duration_seconds); - std::atomic next_report_sec{2}; - - std::cout << "Mode: run-only (main posts, all threads dispatch)\n"; - std::cout << "Runner threads: " << num_threads - << ", Queue depth: " << queue_depth << "\n\n"; - - std::atomic last_count{0}; - auto ex = ioc->get_executor(); - - // Pre-fill the queue - std::cout << "Pre-filling queue with " << queue_depth << " coroutines...\n"; - for (int i = 0; i < queue_depth; ++i) - capy::run_async(ex)(empty_task(counter)); - - // Launch runner threads - std::vector runners; - runners.reserve(num_threads); - for (int t = 0; t < num_threads; ++t) - { - runners.emplace_back([&]() { run_only_worker(*ioc, stop); }); - } - - // Main thread continuously refills - no sleeping! - std::uint64_t local_refills = 0; - while (!stop.load(std::memory_order_relaxed)) - { - // Refill queue - for (int i = 0; i < queue_depth; ++i) - capy::run_async(ex)(empty_task(counter)); - ++local_refills; - - // Check time every 100 refills - if ((local_refills & 0x3F) == 0) - { - auto now = std::chrono::steady_clock::now(); - if (now >= end_time) - { - stop.store(true, std::memory_order_relaxed); - break; - } - - // Progress report - auto elapsed = std::chrono::duration(now - start).count(); - int elapsed_int = static_cast(elapsed); - int expected = next_report_sec.load(std::memory_order_relaxed); - if (elapsed_int >= expected && - next_report_sec.compare_exchange_strong(expected, expected + 2)) - { - std::uint64_t current = counter.load(std::memory_order_relaxed); - std::uint64_t last = - last_count.exchange(current, std::memory_order_relaxed); - double rate = static_cast(current - last) / 2.0; - - std::cout << " [" << std::fixed << std::setprecision(0) - << elapsed << "s] " << perf::format_rate(rate) << " (" - << current << " total)\n"; - } - } - } - - // Stop runners - for (auto& r : runners) - r.join(); - - // Drain remaining - ioc->poll(); - - // Final stats - auto total_elapsed = - std::chrono::duration(std::chrono::steady_clock::now() - start) - .count(); - std::uint64_t total = counter.load(std::memory_order_relaxed); - double avg_rate = static_cast(total) / total_elapsed; - - std::cout << "\n=== Results ===\n"; - std::cout << " Duration: " << std::fixed << std::setprecision(2) - << total_elapsed << " s\n"; - std::cout << " Operations: " << total << "\n"; - std::cout << " Avg rate: " << perf::format_rate(avg_rate) << "\n"; -} - -void -run_profiler_workload( - perf::context_factory factory, - const char* backend_name, - int duration, - int num_threads, - int batch_size, - workload_mode mode) -{ - std::cout << "Corosio Profiler Workload: Scheduler Contention\n"; - std::cout << "================================================\n"; - std::cout << "Backend: " << backend_name << "\n\n"; - - std::cout << "Profile targets:\n"; - std::cout << " - dispatch_mutex_ lock contention\n"; - std::cout << " - outstanding_work_ atomic operations\n"; - std::cout << " - Cache line bouncing between cores\n"; - std::cout << " - Work distribution fairness\n" << std::endl; - - // Warmup - main thread participates, no sleeping - std::cout << "Warming up (1 second)...\n"; - { - auto ioc = factory(); - std::atomic warmup_counter{0}; - std::atomic stop{false}; - - auto warmup_end = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - - std::vector warmup_threads; - for (int t = 0; t < num_threads - 1; ++t) - { - warmup_threads.emplace_back( - [&]() { balanced_worker(*ioc, stop, warmup_counter, 100); }); - } - - // Main thread works during warmup too - auto ex = ioc->get_executor(); - std::uint64_t local_batches = 0; - while (!stop.load(std::memory_order_relaxed)) - { - for (int i = 0; i < 100; ++i) - capy::run_async(ex)(empty_task(warmup_counter)); - ioc->poll(); - ++local_batches; - - if ((local_batches & 0xFF) == 0) - { - if (std::chrono::steady_clock::now() >= warmup_end) - { - stop.store(true, std::memory_order_relaxed); - break; - } - } - } - - for (auto& t : warmup_threads) - t.join(); - } - std::cout << "Warmup complete.\n" << std::endl; - - std::cout << "Running for " << duration << " seconds..." << std::endl; - - // Main workload - switch (mode) - { - case workload_mode::balanced: - run_balanced_workload(factory, duration, num_threads, batch_size); - break; - case workload_mode::post_only: - run_post_only_workload(factory, duration, num_threads, batch_size); - break; - case workload_mode::run_only: - run_run_only_workload(factory, duration, num_threads, batch_size); - break; - } - - std::cout << "\nWorkload complete.\n"; -} - -void -print_usage(const char* program_name) -{ - std::cout << "Usage: " << program_name << " [OPTIONS]\n\n"; - std::cout << "Profiler workload for multi-threaded scheduler contention " - "analysis.\n\n"; - std::cout << "Options:\n"; - std::cout << " --backend Select I/O backend (default: platform " - "default)\n"; - std::cout - << " --duration Run duration in seconds (default: 10)\n"; - std::cout - << " --threads Number of worker threads (default: 8)\n"; - std::cout << " --batch Coroutines per thread per cycle " - "(default: 100)\n"; - std::cout << " --post-only Profile posting path (half post, half " - "run)\n"; - std::cout << " --run-only Profile dispatch path (main posts, " - "all run)\n"; - std::cout << " --list List available backends\n"; - std::cout << " --help Show this help message\n"; - std::cout << "\n"; - std::cout << "Modes:\n"; - std::cout - << " (default) Each thread posts and polls - mixed contention\n"; - std::cout << " --post-only Half threads post (including main), half run\n"; - std::cout - << " --run-only Main posts, all threads run - dispatch contention\n"; - std::cout << "\n"; - std::cout << "Example:\n"; - std::cout << " " << program_name << " --threads 8 --duration 10\n"; - std::cout << " " << program_name << " --threads 16 --post-only\n"; - std::cout << "\n"; - perf::print_available_backends(); -} - -int -main(int argc, char* argv[]) -{ - const char* backend = nullptr; - int duration = 10; - int num_threads = 8; - int batch_size = 100; - workload_mode mode = workload_mode::balanced; - - // Parse command-line arguments - for (int i = 1; i < argc; ++i) - { - if (std::strcmp(argv[i], "--backend") == 0) - { - if (i + 1 < argc) - backend = argv[++i]; - else - { - std::cerr << "Error: --backend requires an argument\n"; - return 1; - } - } - else if (std::strcmp(argv[i], "--duration") == 0) - { - if (i + 1 < argc) - duration = std::atoi(argv[++i]); - else - { - std::cerr << "Error: --duration requires an argument\n"; - return 1; - } - } - else if (std::strcmp(argv[i], "--threads") == 0) - { - if (i + 1 < argc) - num_threads = std::atoi(argv[++i]); - else - { - std::cerr << "Error: --threads requires an argument\n"; - return 1; - } - } - else if (std::strcmp(argv[i], "--batch") == 0) - { - if (i + 1 < argc) - batch_size = std::atoi(argv[++i]); - else - { - std::cerr << "Error: --batch requires an argument\n"; - return 1; - } - } - else if (std::strcmp(argv[i], "--post-only") == 0) - { - mode = workload_mode::post_only; - } - else if (std::strcmp(argv[i], "--run-only") == 0) - { - mode = workload_mode::run_only; - } - else if (std::strcmp(argv[i], "--list") == 0) - { - perf::print_available_backends(); - return 0; - } - else if ( - std::strcmp(argv[i], "--help") == 0 || - std::strcmp(argv[i], "-h") == 0) - { - print_usage(argv[0]); - return 0; - } - else - { - std::cerr << "Unknown option: " << argv[i] << "\n"; - print_usage(argv[0]); - return 1; - } - } - - // Validate thread count - if (num_threads < 1) - { - std::cerr << "Error: --threads must be at least 1\n"; - return 1; - } - - // If no backend specified, use platform default - if (!backend) - backend = perf::default_backend_name(); - - // Dispatch to the selected backend - return perf::dispatch_backend( - backend, [=](perf::context_factory factory, auto, const char* name) { - run_profiler_workload( - factory, name, duration, num_threads, batch_size, mode); - }); -} diff --git a/perf/profile/small_io_bench.cpp b/perf/profile/small_io_bench.cpp deleted file mode 100644 index a36d7c42a..000000000 --- a/perf/profile/small_io_bench.cpp +++ /dev/null @@ -1,336 +0,0 @@ -// -// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com) -// Copyright (c) 2026 Steve Gerbino -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// Official repository: https://github.com/cppalliance/corosio -// - -// Profiler workload: Small I/O Operations -// -// This program hammers the I/O completion path with small buffer operations -// for profiling. Run with a profiler (VTune, perf, VS Profiler) to identify -// hot spots in: -// - overlapped_op allocation/completion -// - IOCP completion handling -// - Coroutine state machine transitions -// - Per-operation framework overhead -// -// Example command lines: -// profile_small_io --buffer 64 --pairs 1 # Single pair, tiny buffers (max overhead visibility) -// profile_small_io --buffer 64 --pairs 8 # Multiple pairs, stress completion handling -// profile_small_io --buffer 1024 --pairs 1 # Larger buffers, compare overhead ratio - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "../common/backend_selection.hpp" -#include "../common/perf.hpp" - -namespace corosio = boost::corosio; -namespace capy = boost::capy; - -// Ping-pong coroutine: alternately write then read on a socket pair -// Passed by IILE parameters to avoid capture use-after-free -capy::task<> -ping_pong( - corosio::tcp_socket& sock_write, - corosio::tcp_socket& sock_read, - std::size_t buf_size, - std::atomic& ops, - std::atomic& stop) -{ - std::vector write_buf(buf_size, 'X'); - std::vector read_buf(buf_size); - - while (!stop.load(std::memory_order_relaxed)) - { - // Write - auto [wec, wn] = co_await sock_write.write_some( - capy::const_buffer(write_buf.data(), write_buf.size())); - if (wec) - co_return; - - // Read - auto [rec, rn] = co_await sock_read.read_some( - capy::mutable_buffer(read_buf.data(), read_buf.size())); - if (rec) - co_return; - - ops.fetch_add(2, std::memory_order_relaxed); - } -} - -// Run the profiler workload for the specified duration -void -run_workload( - perf::context_factory factory, - int duration_seconds, - std::size_t buffer_size, - int num_pairs) -{ - auto ioc = factory(); - std::atomic ops{0}; - std::atomic stop{false}; - - // Create socket pairs and launch ping-pong coroutines - std::vector> pairs; - pairs.reserve(num_pairs); - - for (int i = 0; i < num_pairs; ++i) - { - auto [a, b] = corosio::test::make_socket_pair(*ioc); - a.set_option(corosio::native_socket_option::no_delay(true)); - b.set_option(corosio::native_socket_option::no_delay(true)); - pairs.emplace_back(std::move(a), std::move(b)); - } - - // Launch ping-pong on each pair - for (auto& [a, b] : pairs) - { - capy::run_async(ioc->get_executor())( - ping_pong(a, b, buffer_size, ops, stop)); - } - - auto start = std::chrono::steady_clock::now(); - auto end_time = start + std::chrono::seconds(duration_seconds); - auto next_report = start + std::chrono::seconds(2); - - std::cout << "Running for " << duration_seconds << " seconds...\n"; - std::cout << "Buffer size: " << buffer_size - << " bytes, Pairs: " << num_pairs << "\n\n"; - - std::uint64_t last_count = 0; - - // Run with periodic progress reports - while (std::chrono::steady_clock::now() < end_time) - { - // Run for a short burst - ioc->run_for(std::chrono::milliseconds(100)); - - // Progress report every 2 seconds - auto now = std::chrono::steady_clock::now(); - if (now >= next_report) - { - auto elapsed = std::chrono::duration(now - start).count(); - std::uint64_t current = ops.load(std::memory_order_relaxed); - double rate = static_cast(current - last_count) / 2.0; - - std::cout << " [" << std::fixed << std::setprecision(0) << elapsed - << "s] " << perf::format_rate(rate) << " (" << current - << " total)\n"; - - last_count = current; - next_report = now + std::chrono::seconds(2); - } - } - - // Signal stop and let coroutines finish - stop.store(true, std::memory_order_relaxed); - - // Cancel pending operations to unblock coroutines - for (auto& [a, b] : pairs) - { - a.cancel(); - b.cancel(); - } - - // Drain remaining work - ioc->run(); - - // Final stats - auto total_elapsed = - std::chrono::duration(std::chrono::steady_clock::now() - start) - .count(); - std::uint64_t total = ops.load(std::memory_order_relaxed); - double avg_rate = static_cast(total) / total_elapsed; - - std::cout << "\n=== Results ===\n"; - std::cout << " Duration: " << std::fixed << std::setprecision(2) - << total_elapsed << " s\n"; - std::cout << " Operations: " << total << "\n"; - std::cout << " Avg rate: " << perf::format_rate(avg_rate) << "\n"; -} - -void -run_profiler_workload( - perf::context_factory factory, - const char* backend_name, - int duration, - std::size_t buffer_size, - int num_pairs) -{ - std::cout << "Corosio Profiler Workload: Small I/O Operations\n"; - std::cout << "================================================\n"; - std::cout << "Backend: " << backend_name << "\n\n"; - - std::cout << "Profile targets:\n"; - std::cout << " - overlapped_op allocation/completion\n"; - std::cout << " - IOCP completion handling path\n"; - std::cout << " - Coroutine state machine transitions\n"; - std::cout << " - Per-operation framework overhead\n\n"; - - // Warmup - std::cout << "Warming up (1 second)...\n"; - { - auto ioc = factory(); - auto [a, b] = corosio::test::make_socket_pair(*ioc); - a.set_option(corosio::native_socket_option::no_delay(true)); - b.set_option(corosio::native_socket_option::no_delay(true)); - - std::atomic warmup_ops{0}; - std::atomic warmup_stop{false}; - - capy::run_async(ioc->get_executor())( - ping_pong(a, b, 64, warmup_ops, warmup_stop)); - - auto warmup_end = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (std::chrono::steady_clock::now() < warmup_end) - ioc->run_for(std::chrono::milliseconds(100)); - - warmup_stop.store(true, std::memory_order_relaxed); - a.cancel(); - b.cancel(); - ioc->run(); - } - - std::cout << "Warmup complete.\n\n"; - - // Main workload - run_workload(factory, duration, buffer_size, num_pairs); - - std::cout << "\nWorkload complete.\n"; -} - -void -print_usage(const char* program_name) -{ - std::cout << "Usage: " << program_name << " [OPTIONS]\n\n"; - std::cout - << "Profiler workload for small I/O operation overhead analysis.\n\n"; - std::cout << "Options:\n"; - std::cout << " --backend Select I/O backend (default: platform " - "default)\n"; - std::cout - << " --duration Run duration in seconds (default: 10)\n"; - std::cout << " --buffer Buffer size in bytes (default: 64)\n"; - std::cout << " --pairs Number of socket pairs (default: 1)\n"; - std::cout << " --list List available backends\n"; - std::cout << " --help Show this help message\n"; - std::cout << "\n"; - std::cout << "Example:\n"; - std::cout << " " << program_name - << " --duration 10 --buffer 64 --pairs 4\n"; - std::cout << "\n"; - perf::print_available_backends(); -} - -int -main(int argc, char* argv[]) -{ - const char* backend = nullptr; - int duration = 10; - std::size_t buffer_size = 64; - int num_pairs = 1; - - // Parse command-line arguments - for (int i = 1; i < argc; ++i) - { - if (std::strcmp(argv[i], "--backend") == 0) - { - if (i + 1 < argc) - backend = argv[++i]; - else - { - std::cerr << "Error: --backend requires an argument\n"; - return 1; - } - } - else if (std::strcmp(argv[i], "--duration") == 0) - { - if (i + 1 < argc) - duration = std::atoi(argv[++i]); - else - { - std::cerr << "Error: --duration requires an argument\n"; - return 1; - } - } - else if (std::strcmp(argv[i], "--buffer") == 0) - { - if (i + 1 < argc) - buffer_size = static_cast(std::atoi(argv[++i])); - else - { - std::cerr << "Error: --buffer requires an argument\n"; - return 1; - } - } - else if (std::strcmp(argv[i], "--pairs") == 0) - { - if (i + 1 < argc) - num_pairs = std::atoi(argv[++i]); - else - { - std::cerr << "Error: --pairs requires an argument\n"; - return 1; - } - } - else if (std::strcmp(argv[i], "--list") == 0) - { - perf::print_available_backends(); - return 0; - } - else if ( - std::strcmp(argv[i], "--help") == 0 || - std::strcmp(argv[i], "-h") == 0) - { - print_usage(argv[0]); - return 0; - } - else - { - std::cerr << "Unknown option: " << argv[i] << "\n"; - print_usage(argv[0]); - return 1; - } - } - - // Validate arguments - if (buffer_size == 0) - { - std::cerr << "Error: --buffer must be > 0\n"; - return 1; - } - if (num_pairs < 1) - { - std::cerr << "Error: --pairs must be >= 1\n"; - return 1; - } - - // If no backend specified, use platform default - if (!backend) - backend = perf::default_backend_name(); - - // Dispatch to the selected backend - return perf::dispatch_backend( - backend, [=](perf::context_factory factory, auto, const char* name) { - run_profiler_workload( - factory, name, duration, buffer_size, num_pairs); - }); -} diff --git a/src/corosio/src/endpoint.cpp b/src/corosio/src/endpoint.cpp index 2b22dd8c9..f77f5f164 100644 --- a/src/corosio/src/endpoint.cpp +++ b/src/corosio/src/endpoint.cpp @@ -89,7 +89,9 @@ parse_endpoint_impl(std::string_view s, endpoint& ep) noexcept // Find the colon separating address and port auto colon_pos = s.rfind(':'); if (colon_pos == std::string_view::npos) - return std::make_error_code(std::errc::invalid_argument); // LCOV_EXCL_LINE detect_endpoint_format reports ipv4_with_port only when a colon is present + return std::make_error_code( + std::errc:: + invalid_argument); // LCOV_EXCL_LINE detect_endpoint_format reports ipv4_with_port only when a colon is present auto addr_str = s.substr(0, colon_pos); auto port_str = s.substr(colon_pos + 1); diff --git a/src/corosio/src/host_name.cpp b/src/corosio/src/host_name.cpp index 37ee623f0..e0886748d 100644 --- a/src/corosio/src/host_name.cpp +++ b/src/corosio/src/host_name.cpp @@ -50,9 +50,8 @@ host_name() // Size query: returns ERROR_MORE_DATA and writes the required // wide-char count (including the trailing NUL) into `size`. DWORD size = 0; - BOOL ok = ::GetComputerNameExW( - ComputerNameDnsHostname, nullptr, &size); - DWORD err = ::GetLastError(); + BOOL ok = ::GetComputerNameExW(ComputerNameDnsHostname, nullptr, &size); + DWORD err = ::GetLastError(); if (ok) { // Can't-happen guard: a zero-length size query succeeding @@ -60,39 +59,30 @@ host_name() return {make_error_code(std::errc::protocol_error), {}}; } if (err != ERROR_MORE_DATA) - return { - detail::make_err(static_cast(err)), - {}}; + return {detail::make_err(static_cast(err)), {}}; // On success, GetComputerNameExW rewrites `size` to the count // without the NUL, so resize(size) below trims to the hostname. std::wstring wide(size, L'\0'); - if (!::GetComputerNameExW( - ComputerNameDnsHostname, wide.data(), &size)) + if (!::GetComputerNameExW(ComputerNameDnsHostname, wide.data(), &size)) return { - detail::make_err( - static_cast(::GetLastError())), - {}}; + detail::make_err(static_cast(::GetLastError())), {}}; wide.resize(size); int needed = ::WideCharToMultiByte( - CP_UTF8, 0, wide.data(), static_cast(wide.size()), - nullptr, 0, nullptr, nullptr); + CP_UTF8, 0, wide.data(), static_cast(wide.size()), nullptr, 0, + nullptr, nullptr); if (needed <= 0) return { - detail::make_err( - static_cast(::GetLastError())), - {}}; + detail::make_err(static_cast(::GetLastError())), {}}; std::string out(static_cast(needed), '\0'); int written = ::WideCharToMultiByte( - CP_UTF8, 0, wide.data(), static_cast(wide.size()), - out.data(), needed, nullptr, nullptr); + CP_UTF8, 0, wide.data(), static_cast(wide.size()), out.data(), + needed, nullptr, nullptr); if (written != needed) return { - detail::make_err( - static_cast(::GetLastError())), - {}}; + detail::make_err(static_cast(::GetLastError())), {}}; return {std::error_code{}, std::move(out)}; } diff --git a/src/corosio/src/io_context.cpp b/src/corosio/src/io_context.cpp index 200635c05..1f9e9ace8 100644 --- a/src/corosio/src/io_context.cpp +++ b/src/corosio/src/io_context.cpp @@ -28,15 +28,15 @@ #include #endif -#if BOOST_COROSIO_HAS_IO_URING -#include -#include -#include -#include -#include -#include -#include -#include +#if BOOST_COROSIO_HAS_URING +#include +#include +#include +#include +#include +#include +#include +#include #endif #if BOOST_COROSIO_HAS_IOCP @@ -126,21 +126,21 @@ iocp_t::construct(capy::execution_context& ctx, unsigned concurrency_hint) } #endif -#if BOOST_COROSIO_HAS_IO_URING +#if BOOST_COROSIO_HAS_URING detail::scheduler& -io_uring_t::construct(capy::execution_context& ctx, unsigned concurrency_hint) +uring_t::construct(capy::execution_context& ctx, unsigned concurrency_hint) { - auto& sched = ctx.make_service( + auto& sched = ctx.make_service( static_cast(concurrency_hint)); - ctx.make_service(); - ctx.make_service(); - ctx.make_service(); - ctx.make_service(); - ctx.make_service(); - ctx.make_service(); - ctx.make_service(sched); - ctx.make_service(sched); + ctx.make_service(); + ctx.make_service(); + ctx.make_service(); + ctx.make_service(); + ctx.make_service(); + ctx.make_service(); + ctx.make_service(sched); + ctx.make_service(sched); return sched; } @@ -154,8 +154,7 @@ check_options([[maybe_unused]] io_context_options const& opts) { #if BOOST_COROSIO_POSIX if (opts.thread_pool_size < 1) - throw std::invalid_argument( - "thread_pool_size must be at least 1"); + throw std::invalid_argument("thread_pool_size must be at least 1"); #endif } @@ -209,11 +208,11 @@ apply_scheduler_options( { sched.configure_threading(make_threading_config(opts)); -#if BOOST_COROSIO_HAS_EPOLL || BOOST_COROSIO_HAS_KQUEUE || BOOST_COROSIO_HAS_SELECT +#if BOOST_COROSIO_HAS_EPOLL || BOOST_COROSIO_HAS_KQUEUE || \ + BOOST_COROSIO_HAS_SELECT // dynamic_cast — when io_uring is also linked, the runtime probe may - // have selected io_uring_scheduler instead of a reactor_scheduler. - if (auto* reactor = - dynamic_cast(&sched)) + // have selected uring_scheduler instead of a reactor_scheduler. + if (auto* reactor = dynamic_cast(&sched)) { // Detect "user kept the defaults" by comparing all three to the // io_context-options-defined struct defaults. @@ -235,24 +234,18 @@ apply_scheduler_options( ua = 0; } - reactor->configure_reactor( - opts.max_events_per_poll, - init, - max, - ua); + reactor->configure_reactor(opts.max_events_per_poll, init, max, ua); } #endif -#if BOOST_COROSIO_HAS_IO_URING - if (auto* uring_sched = - dynamic_cast(&sched)) +#if BOOST_COROSIO_HAS_URING + if (auto* uring_sched = dynamic_cast(&sched)) { if (opts.enable_sqpoll) uring_sched->configure_sqpoll( true, opts.sq_thread_idle_ms, opts.sq_thread_cpu); } #endif - } // Bring up backend infrastructure whose setup depends on the options @@ -262,9 +255,8 @@ apply_scheduler_options( void finish_construction([[maybe_unused]] detail::scheduler& sched) { -#if BOOST_COROSIO_HAS_IO_URING - if (auto* uring_sched = - dynamic_cast(&sched)) +#if BOOST_COROSIO_HAS_URING + if (auto* uring_sched = dynamic_cast(&sched)) uring_sched->init_ring(); #endif } @@ -300,8 +292,7 @@ io_context::io_context(unsigned concurrency_hint) } io_context::io_context( - io_context_options const& opts_in, - unsigned concurrency_hint) + io_context_options const& opts_in, unsigned concurrency_hint) : capy::execution_context(this) , sched_(nullptr) { @@ -322,8 +313,7 @@ io_context::apply_options_pre_(io_context_options const& opts) void io_context::apply_options_post_( - io_context_options const& opts_in, - unsigned concurrency_hint) + io_context_options const& opts_in, unsigned concurrency_hint) { create_thread_pool(*this, opts_in); apply_scheduler_options(*sched_, opts_in, concurrency_hint); diff --git a/src/corosio/src/ipv6_address.cpp b/src/corosio/src/ipv6_address.cpp index 7a46ab1fa..53e3f8035 100644 --- a/src/corosio/src/ipv6_address.cpp +++ b/src/corosio/src/ipv6_address.cpp @@ -243,8 +243,8 @@ parse_h16( unsigned char& hi, unsigned char& lo) noexcept { - if (it == end) // LCOV_EXCL_LINE callers pre-check end-of-input - return false; // LCOV_EXCL_LINE callers pre-check end-of-input + if (it == end) // LCOV_EXCL_LINE callers pre-check end-of-input + return false; // LCOV_EXCL_LINE callers pre-check end-of-input int d = hexdig_value(*it); if (d < 0) @@ -363,7 +363,7 @@ parse_ipv6_impl(std::string_view s, ipv6_address& addr) noexcept return std::make_error_code(std::errc::invalid_argument); } // rewind the h16 and parse it as IPv4 - it = prev; + it = prev; auto [v4ec, v4] = make_ipv4_address( std::string_view(it, static_cast(end - it))); if (v4ec) @@ -377,8 +377,8 @@ parse_ipv6_impl(std::string_view s, ipv6_address& addr) noexcept // Verify it parsed correctly by re-parsing the exact substring auto [ckec, v4_check] = make_ipv4_address( std::string_view(it, static_cast(v4_it - it))); - if (ckec) // LCOV_EXCL_LINE prefix of a parsed tail cannot fail - return ckec; // LCOV_EXCL_LINE prefix of a parsed tail cannot fail + if (ckec) // LCOV_EXCL_LINE prefix of a parsed tail cannot fail + return ckec; // LCOV_EXCL_LINE prefix of a parsed tail cannot fail it = v4_it; auto const b4 = v4_check.to_bytes(); bytes[2 * (7 - n) + 0] = b4[0]; diff --git a/src/corosio/src/local_connect_pair.cpp b/src/corosio/src/local_connect_pair.cpp index f156c0a85..202fd8a52 100644 --- a/src/corosio/src/local_connect_pair.cpp +++ b/src/corosio/src/local_connect_pair.cpp @@ -106,8 +106,7 @@ pick_pair_path(std::filesystem::path& dir_out) for (int attempt = 0; attempt < 16; ++attempt) { auto candidate = - fs::temp_directory_path() / - ("co_pair_" + std::to_string(gen())); + fs::temp_directory_path() / ("co_pair_" + std::to_string(gen())); std::error_code ec; if (fs::create_directory(candidate, ec)) { @@ -139,13 +138,13 @@ make_pair_sockets(SOCKET& a_sock, SOCKET& b_sock) noexcept a_sock = INVALID_SOCKET; b_sock = INVALID_SOCKET; - fs::path dir; + fs::path dir; std::string path = pick_pair_path(dir); if (path.empty()) return detail::make_err(ERROR_PATH_NOT_FOUND); - SOCKET listen_sock = ::WSASocketW( - AF_UNIX, SOCK_STREAM, 0, nullptr, 0, WSA_FLAG_OVERLAPPED); + SOCKET listen_sock = + ::WSASocketW(AF_UNIX, SOCK_STREAM, 0, nullptr, 0, WSA_FLAG_OVERLAPPED); if (listen_sock == INVALID_SOCKET) { auto ec = detail::make_err(::WSAGetLastError()); @@ -158,12 +157,11 @@ make_pair_sockets(SOCKET& a_sock, SOCKET& b_sock) noexcept std::memcpy( addr.sun_path, path.c_str(), (std::min)(path.size(), sizeof(addr.sun_path) - 1)); - int addr_len = static_cast( - offsetof(detail::un_sa_t, sun_path) + path.size() + 1); + int addr_len = + static_cast(offsetof(detail::un_sa_t, sun_path) + path.size() + 1); - if (::bind( - listen_sock, reinterpret_cast(&addr), addr_len) - == SOCKET_ERROR) + if (::bind(listen_sock, reinterpret_cast(&addr), addr_len) == + SOCKET_ERROR) { auto ec = detail::make_err(::WSAGetLastError()); ::closesocket(listen_sock); @@ -191,8 +189,8 @@ make_pair_sockets(SOCKET& a_sock, SOCKET& b_sock) noexcept return ec; } - SOCKET worker_sock = INVALID_SOCKET; - std::error_code worker_ec; + SOCKET worker_sock = INVALID_SOCKET; + std::error_code worker_ec; std::atomic worker_done{false}; // One exit, so worker_done is published on every path: the accept @@ -215,9 +213,8 @@ make_pair_sockets(SOCKET& a_sock, SOCKET& b_sock) noexcept offsetof(detail::un_sa_t, sun_path) + path.size() + 1); if (::connect( - worker_sock, - reinterpret_cast(&caddr), caddr_len) - == SOCKET_ERROR) + worker_sock, reinterpret_cast(&caddr), + caddr_len) == SOCKET_ERROR) { worker_ec = detail::make_err(::WSAGetLastError()); ::closesocket(worker_sock); @@ -228,7 +225,7 @@ make_pair_sockets(SOCKET& a_sock, SOCKET& b_sock) noexcept worker_done.store(true, std::memory_order_release); }); - SOCKET accept_sock = INVALID_SOCKET; + SOCKET accept_sock = INVALID_SOCKET; std::error_code accept_ec; for (;;) { @@ -253,8 +250,7 @@ make_pair_sockets(SOCKET& a_sock, SOCKET& b_sock) noexcept // corosio's own and has to compare equal on every toolchain. if ((pfd.revents & POLLRDNORM) == 0) { - accept_ec = - std::make_error_code(std::errc::connection_aborted); + accept_ec = std::make_error_code(std::errc::connection_aborted); break; } diff --git a/src/corosio/src/local_datagram_socket.cpp b/src/corosio/src/local_datagram_socket.cpp index 9d9cf734f..18b8d6c14 100644 --- a/src/corosio/src/local_datagram_socket.cpp +++ b/src/corosio/src/local_datagram_socket.cpp @@ -39,12 +39,13 @@ local_datagram_socket::open(local_datagram proto) noexcept } std::error_code -local_datagram_socket::open_for_family(int family, int type, int protocol) noexcept +local_datagram_socket::open_for_family( + int family, int type, int protocol) noexcept { auto& svc = static_cast(h_.service()); std::error_code ec = svc.open_socket( - static_cast(*h_.get()), - family, type, protocol); + static_cast(*h_.get()), family, + type, protocol); return ec; } @@ -63,8 +64,7 @@ local_datagram_socket::bind(corosio::local_endpoint ep) noexcept return make_error_code(std::errc::bad_file_descriptor); auto& svc = static_cast(h_.service()); return svc.bind_socket( - static_cast(*h_.get()), - ep); + static_cast(*h_.get()), ep); } void @@ -120,8 +120,7 @@ local_datagram_socket::available() const int value = 0; if (::ioctl(native_handle(), FIONREAD, &value) < 0) detail::throw_system_error( - detail::make_err(errno), - "local_datagram_socket::available"); + detail::make_err(errno), "local_datagram_socket::available"); return static_cast(value); } diff --git a/src/corosio/src/local_endpoint.cpp b/src/corosio/src/local_endpoint.cpp index 058f1042f..5e1c69dde 100644 --- a/src/corosio/src/local_endpoint.cpp +++ b/src/corosio/src/local_endpoint.cpp @@ -34,8 +34,7 @@ operator<<(std::ostream& os, local_endpoint const& ep) if (ep.is_abstract()) { // Skip the leading null byte; print the rest as the name - os << "[abstract:" - << std::string_view(ep.path_ + 1, ep.len_ - 1) + os << "[abstract:" << std::string_view(ep.path_ + 1, ep.len_ - 1) << ']'; } else diff --git a/src/corosio/src/local_stream_acceptor.cpp b/src/corosio/src/local_stream_acceptor.cpp index 1f575888c..d868f552c 100644 --- a/src/corosio/src/local_stream_acceptor.cpp +++ b/src/corosio/src/local_stream_acceptor.cpp @@ -89,13 +89,13 @@ local_stream_acceptor::native_handle() const noexcept } std::error_code -local_stream_acceptor::bind(corosio::local_endpoint ep, bind_option opt) noexcept +local_stream_acceptor::bind( + corosio::local_endpoint ep, bind_option opt) noexcept { if (!is_open()) return make_error_code(std::errc::bad_file_descriptor); - if (opt == bind_option::unlink_existing && - !ep.empty() && !ep.is_abstract()) + if (opt == bind_option::unlink_existing && !ep.empty() && !ep.is_abstract()) { // Best-effort removal; missing file is fine. auto p = ep.path(); @@ -112,8 +112,7 @@ local_stream_acceptor::bind(corosio::local_endpoint ep, bind_option opt) noexcep auto& svc = static_cast(h_.service()); return svc.bind_acceptor( - static_cast(*h_.get()), - ep); + static_cast(*h_.get()), ep); } std::error_code diff --git a/src/corosio/src/local_stream_socket.cpp b/src/corosio/src/local_stream_socket.cpp index a5feab293..99f698fbd 100644 --- a/src/corosio/src/local_stream_socket.cpp +++ b/src/corosio/src/local_stream_socket.cpp @@ -43,12 +43,13 @@ local_stream_socket::open(local_stream proto) noexcept } std::error_code -local_stream_socket::open_for_family(int family, int type, int protocol) noexcept +local_stream_socket::open_for_family( + int family, int type, int protocol) noexcept { auto& svc = static_cast(h_.service()); std::error_code ec = svc.open_socket( - static_cast(*h_.get()), - family, type, protocol); + static_cast(*h_.get()), family, + type, protocol); return ec; } @@ -116,19 +117,17 @@ local_stream_socket::available() const "local_stream_socket::available"); #if BOOST_COROSIO_HAS_IOCP u_long value = 0; - if (::ioctlsocket( - static_cast(native_handle()), FIONREAD, &value) != 0) + if (::ioctlsocket(static_cast(native_handle()), FIONREAD, &value) != + 0) detail::throw_system_error( - detail::make_err( - static_cast(::WSAGetLastError())), + detail::make_err(static_cast(::WSAGetLastError())), "local_stream_socket::available"); return static_cast(value); #else int value = 0; if (::ioctl(native_handle(), FIONREAD, &value) < 0) detail::throw_system_error( - detail::make_err(errno), - "local_stream_socket::available"); + detail::make_err(errno), "local_stream_socket::available"); return static_cast(value); #endif } diff --git a/src/corosio/src/tcp_acceptor.cpp b/src/corosio/src/tcp_acceptor.cpp index fdf60e598..4f6574421 100644 --- a/src/corosio/src/tcp_acceptor.cpp +++ b/src/corosio/src/tcp_acceptor.cpp @@ -33,10 +33,22 @@ struct exclusive_address_use { int value_ = 1; - static int level() noexcept { return SOL_SOCKET; } - static int name() noexcept { return SO_EXCLUSIVEADDRUSE; } - void const* data() const noexcept { return &value_; } - std::size_t size() const noexcept { return sizeof(value_); } + static int level() noexcept + { + return SOL_SOCKET; + } + static int name() noexcept + { + return SO_EXCLUSIVEADDRUSE; + } + void const* data() const noexcept + { + return &value_; + } + std::size_t size() const noexcept + { + return sizeof(value_); + } }; } // namespace diff --git a/src/corosio/src/tcp_socket.cpp b/src/corosio/src/tcp_socket.cpp index dfd00f4c5..803dc4111 100644 --- a/src/corosio/src/tcp_socket.cpp +++ b/src/corosio/src/tcp_socket.cpp @@ -49,8 +49,8 @@ tcp_socket::open_for_family(int family, int type, int protocol) noexcept auto& svc = static_cast(h_.service()); auto& wrapper = static_cast(*h_.get()); std::error_code ec = svc.open_socket( - *static_cast(wrapper).get_internal(), family, type, - protocol); + *static_cast(wrapper).get_internal(), family, + type, protocol); #else auto& svc = static_cast(h_.service()); std::error_code ec = svc.open_socket( diff --git a/src/corosio/src/timer.cpp b/src/corosio/src/timer.cpp index a2dbc6faf..d28e9389b 100644 --- a/src/corosio/src/timer.cpp +++ b/src/corosio/src/timer.cpp @@ -85,7 +85,7 @@ timer::rearm_wait(waiter_node& w, duration d) noexcept { impl.svc_->insert_waiter(impl, &w); } - catch(std::bad_alloc const&) + catch (std::bad_alloc const&) { // insert_waiter grows the heap before publishing anything, // so the waiter is untouched and the caller can complete diff --git a/src/corosio/src/tls/detail/engine_driver.hpp b/src/corosio/src/tls/detail/engine_driver.hpp index 83fd247ad..1b0dfc7d2 100644 --- a/src/corosio/src/tls/detail/engine_driver.hpp +++ b/src/corosio/src/tls/detail/engine_driver.hpp @@ -113,34 +113,31 @@ namespace detail { points without the driver knowing the backend's session model. */ template -concept tls_engine = - requires( - Engine& e, - Engine const& ce, - engine_op op, - void* buf, - unsigned char const* in, - unsigned char* out, - std::size_t n, - tls_context const& ctx, - tls_role role, - std::string const& hostname, - std::string& alpn) - { - { e.perform(op, buf, n) } -> std::same_as; - { e.put_input(in, n) } -> std::same_as; - { e.input_area() } - -> std::same_as>; - { e.input_committed(n) }; - { ce.pending_output() } -> std::same_as; - { e.get_output(out, n) } -> std::same_as; - { ce.received_shutdown() } -> std::same_as; - { ce.capture_alpn(alpn) }; - { e.reset() }; - { ce.check_context() } -> std::same_as; - { ce.check_session() } -> std::same_as; - { e.prepare(ctx, role, hostname) } -> std::same_as; - }; +concept tls_engine = requires( + Engine& e, + Engine const& ce, + engine_op op, + void* buf, + unsigned char const* in, + unsigned char* out, + std::size_t n, + tls_context const& ctx, + tls_role role, + std::string const& hostname, + std::string& alpn) { + { e.perform(op, buf, n) } -> std::same_as; + { e.put_input(in, n) } -> std::same_as; + { e.input_area() } -> std::same_as>; + { e.input_committed(n) }; + { ce.pending_output() } -> std::same_as; + { e.get_output(out, n) } -> std::same_as; + { ce.received_shutdown() } -> std::same_as; + { ce.capture_alpn(alpn) }; + { e.reset() }; + { ce.check_context() } -> std::same_as; + { ce.check_session() } -> std::same_as; + { e.prepare(ctx, role, hostname) } -> std::same_as; +}; /** Coroutine driver shared by every TLS backend. @@ -227,8 +224,10 @@ class engine_driver // The loop guard just confirmed pending bytes exist, so a // drain failure here is unreachable in practice; fail loudly // rather than silently drop already-accepted ciphertext. - if (n == 0) // LCOV_EXCL_LINE unreachable: pending bytes confirmed - co_return make_error_code(std::errc::no_buffer_space); // LCOV_EXCL_LINE unreachable: transport returned 0 with no error unreachable: pending bytes confirmed + if (n == 0) // LCOV_EXCL_LINE unreachable: pending bytes confirmed + co_return make_error_code( + std::errc:: + no_buffer_space); // LCOV_EXCL_LINE unreachable: transport returned 0 with no error unreachable: pending bytes confirmed auto [ec, wn] = co_await capy::write( *s_, capy::const_buffer(out_buf_.data(), n)); if (ec) @@ -236,8 +235,7 @@ class engine_driver // wn bytes already reached the peer; keep only the unsent // remainder so a post-cancellation flush retry resends // neither the delivered prefix nor loses the rest. - std::memmove( - out_buf_.data(), out_buf_.data() + wn, n - wn); + std::memmove(out_buf_.data(), out_buf_.data() + wn, n - wn); out_len_ = n - wn; co_return ec; } @@ -286,8 +284,7 @@ class engine_driver if (cap == 0) co_return std::error_code{}; - auto [ec, n] = - co_await s_->read_some(capy::mutable_buffer(dst, cap)); + auto [ec, n] = co_await s_->read_some(capy::mutable_buffer(dst, cap)); // ReadStream permits n>0 alongside ec (IOCP forwards // bytes_transferred on failed completions; a canceled read can @@ -307,7 +304,9 @@ class engine_driver // The transport delivered nothing without an error, so it cannot // make progress: fail loudly rather than spin the engine's input // retry against a staging that will never fill. - co_return make_error_code(std::errc::no_buffer_space); // LCOV_EXCL_LINE unreachable: staging cannot stay empty + co_return make_error_code( + std::errc:: + no_buffer_space); // LCOV_EXCL_LINE unreachable: staging cannot stay empty } // A prior read/write already reported its full transfer as success; @@ -336,36 +335,31 @@ class engine_driver } /// Return the engine for backend-specific setup. - Engine& - engine() noexcept + Engine& engine() noexcept { return eng_; } /// Return the TLS context this driver was constructed with. - tls_context const& - context() const noexcept + tls_context const& context() const noexcept { return ctx_; } /// Point the driver at the transport's post-move location. - void - rebind_stream(capy::any_stream& s) noexcept + void rebind_stream(capy::any_stream& s) noexcept { s_ = &s; } /// Set the hostname applied to the next client handshake. - void - set_hostname(std::string_view hostname) + void set_hostname(std::string_view hostname) { hostname_ = hostname; } /// Return the ALPN protocol negotiated by the last handshake. - std::string_view - alpn_protocol() const noexcept + std::string_view alpn_protocol() const noexcept { return alpn_selected_; } @@ -382,8 +376,7 @@ class engine_driver used_ = false; } - capy::io_task - do_read_some( + capy::io_task do_read_some( capy::detail::mutable_buffer_array buffers) { if (auto ec = take_pending_flush_ec()) @@ -406,8 +399,7 @@ class engine_driver { auto const gen = read_gen_; auto r = eng_.perform( - engine_op::read, dest, - static_cast(remaining)); + engine_op::read, dest, static_cast(remaining)); if (r.ec) { @@ -429,8 +421,7 @@ class engine_driver // report now rather than loop for more (another // engine call could park on input). out_len_ > 0 // covers a retained tail the engine cannot see. - if (r.want == engine_want::output_then_done || - out_len_ > 0) + if (r.want == engine_want::output_then_done || out_len_ > 0) ec = co_await flush_output(); if (ec && total_read == bufs_size) { @@ -472,8 +463,7 @@ class engine_driver co_return {std::error_code{}, total_read}; } - capy::io_task - do_write_some( + capy::io_task do_write_some( capy::detail::const_buffer_array buffers) { if (auto ec = take_pending_flush_ec()) @@ -499,8 +489,7 @@ class engine_driver { auto const gen = read_gen_; auto r = eng_.perform( - engine_op::write, src, - static_cast(remaining)); + engine_op::write, src, static_cast(remaining)); if (r.ec) { @@ -521,8 +510,7 @@ class engine_driver // least one byte transferred" success condition; // report now rather than loop for more. out_len_ > 0 // covers a retained tail the engine cannot see. - if (r.want == engine_want::output_then_done || - out_len_ > 0) + if (r.want == engine_want::output_then_done || out_len_ > 0) ec = co_await flush_output(); if (ec && total_written == bufs_size) { @@ -589,9 +577,8 @@ class engine_driver if (auto pec = eng_.prepare(ctx_, role, hostname_)) co_return {pec}; - auto const op = role == tls_role::client - ? engine_op::handshake_client - : engine_op::handshake_server; + auto const op = role == tls_role::client ? engine_op::handshake_client + : engine_op::handshake_server; std::error_code ec; @@ -652,7 +639,7 @@ class engine_driver while (true) { auto const gen = read_gen_; - auto r = eng_.perform(engine_op::shutdown, nullptr, 0); + auto r = eng_.perform(engine_op::shutdown, nullptr, 0); if (r.ec) { diff --git a/src/corosio/src/tls/detail/engine_types.hpp b/src/corosio/src/tls/detail/engine_types.hpp index 34b677a03..df1c4e518 100644 --- a/src/corosio/src/tls/detail/engine_types.hpp +++ b/src/corosio/src/tls/detail/engine_types.hpp @@ -123,8 +123,7 @@ map_fill_error( return ec; if (ec != capy::cond::eof && ec != std::errc::connection_reset && - ec != std::errc::connection_aborted && - ec != std::errc::broken_pipe) + ec != std::errc::connection_aborted && ec != std::errc::broken_pipe) return ec; if (received_shutdown) diff --git a/src/openssl/src/detail/engine.cpp b/src/openssl/src/detail/engine.cpp index c0af17210..ea84d58b4 100644 --- a/src/openssl/src/detail/engine.cpp +++ b/src/openssl/src/detail/engine.cpp @@ -84,8 +84,9 @@ build_alpn_wire(std::vector const& protocols) std::string wire; for (auto const& p : protocols) { - if (p.empty() || p.size() > 255) // LCOV_EXCL_LINE set_alpn validates eagerly - continue; // LCOV_EXCL_LINE set_alpn validates eagerly + if (p.empty() || + p.size() > 255) // LCOV_EXCL_LINE set_alpn validates eagerly + continue; // LCOV_EXCL_LINE set_alpn validates eagerly wire.push_back(static_cast(p.size())); wire.append(p); } @@ -94,14 +95,12 @@ build_alpn_wire(std::vector const& protocols) class openssl_category_impl final : public std::error_category { - char const* - name() const noexcept override + char const* name() const noexcept override { return "corosio.openssl"; } - std::string - message(int value) const override + std::string message(int value) const override { char buf[256]; ::ERR_error_string_n( @@ -158,8 +157,9 @@ static int password_callback(char* buf, int size, int rwflag, void* userdata) { auto* cd = static_cast(userdata); - if (!cd || !cd->password_callback) // LCOV_EXCL_LINE installed only with a callback - return 0; // LCOV_EXCL_LINE installed only with a callback + if (!cd || + !cd->password_callback) // LCOV_EXCL_LINE installed only with a callback + return 0; // LCOV_EXCL_LINE installed only with a callback tls_password_purpose purpose = (rwflag == 0) ? tls_password_purpose::for_reading @@ -186,13 +186,13 @@ verify_callback_trampoline(int preverified, X509_STORE_CTX* store_ctx) { SSL* ssl = static_cast(X509_STORE_CTX_get_ex_data( store_ctx, SSL_get_ex_data_X509_STORE_CTX_idx())); - if (!ssl) // LCOV_EXCL_LINE ex-data set before verify runs - return preverified; // LCOV_EXCL_LINE ex-data set before verify runs + if (!ssl) // LCOV_EXCL_LINE ex-data set before verify runs + return preverified; // LCOV_EXCL_LINE ex-data set before verify runs auto* cd = static_cast( SSL_CTX_get_ex_data(SSL_get_SSL_CTX(ssl), sni_ctx_data_index)); - if (!cd) // LCOV_EXCL_LINE set at context build - return preverified; // LCOV_EXCL_LINE set at context build + if (!cd) // LCOV_EXCL_LINE set at context build + return preverified; // LCOV_EXCL_LINE set at context build bool ok = preverified != 0; @@ -242,12 +242,17 @@ verify_callback_trampoline(int preverified, X509_STORE_CTX* store_ctx) // valid for the connection) rather than into a local buffer. static int alpn_select_cb( - SSL* /* ssl */, unsigned char const** out, unsigned char* outlen, - unsigned char const* in, unsigned int inlen, void* arg) + SSL* /* ssl */, + unsigned char const** out, + unsigned char* outlen, + unsigned char const* in, + unsigned int inlen, + void* arg) { auto const* prefs = static_cast const*>(arg); - if (!prefs || prefs->empty()) // LCOV_EXCL_LINE installed only with a non-empty list - return SSL_TLSEXT_ERR_NOACK; // LCOV_EXCL_LINE installed only with a non-empty list + if (!prefs || + prefs->empty()) // LCOV_EXCL_LINE installed only with a non-empty list + return SSL_TLSEXT_ERR_NOACK; // LCOV_EXCL_LINE installed only with a non-empty list // Server preference order wins: for each server protocol, look for a // matching entry in the client's offered list. @@ -371,8 +376,7 @@ class openssl_native_context : public native_context_base SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; // The trampoline runs the revocation soft-fail downgrade and the // user callback, so install it if either is configured. - bool const need_trampoline = - cd.verify_callback || + bool const need_trampoline = cd.verify_callback || cd.revocation != tls_revocation_policy::disabled; SSL_CTX_set_verify( ctx_, verify_mode_flag, @@ -389,8 +393,7 @@ class openssl_native_context : public native_context_base // verify_mode::peer server. Fail closed like every other setup // error. BIO* bio = BIO_new_mem_buf( - cd.pkcs12_data.data(), - static_cast(cd.pkcs12_data.size())); + cd.pkcs12_data.data(), static_cast(cd.pkcs12_data.size())); if (!bio) setup_failed_ = true; else @@ -707,8 +710,8 @@ engine::init(tls_context const& ctx) void engine::reset() { - if (!ssl_) // LCOV_EXCL_LINE reset() runs only on a used stream - return; // LCOV_EXCL_LINE reset() runs only on a used stream + if (!ssl_) // LCOV_EXCL_LINE reset() runs only on a used stream + return; // LCOV_EXCL_LINE reset() runs only on a used stream // Preserves SSL* and BIO pair, releases session state if (SSL_clear(ssl_) != 1) @@ -760,7 +763,8 @@ engine::check_session() const noexcept } std::error_code -engine::prepare(tls_context const& ctx, tls_role role, std::string const& hostname) +engine::prepare( + tls_context const& ctx, tls_role role, std::string const& hostname) { // Session creation is deferred from construction so a setup // failure reports through the handshake completion. @@ -835,7 +839,8 @@ engine::perform(engine_op op, void* data, std::size_t len) // report I/O attempted before then instead of crashing on a null // SSL handle. if (!ssl_) - return {engine_want::done, + return { + engine_want::done, std::make_error_code(std::errc::invalid_argument), 0}; ERR_clear_error(); @@ -868,13 +873,15 @@ engine::perform(engine_op op, void* data, std::size_t len) return { pending_output() > 0 ? engine_want::output_then_retry : engine_want::input, - {}, 0}; + {}, + 0}; if (transfer ? ret > 0 : ret == 1) return { pending_output() > 0 ? engine_want::output_then_done : engine_want::done, - {}, transfer ? static_cast(ret) : 0}; + {}, + transfer ? static_cast(ret) : 0}; int const err = SSL_get_error(ssl_, ret); @@ -885,7 +892,8 @@ engine::perform(engine_op op, void* data, std::size_t len) return { pending_output() > 0 ? engine_want::output_then_retry : engine_want::input, - {}, 0}; + {}, + 0}; if (transfer && err == SSL_ERROR_ZERO_RETURN) { @@ -913,9 +921,13 @@ engine::perform(engine_op op, void* data, std::size_t len) // and the driver's `map_fill_error` policy. // The driver's map_fill_error reports the truncation // before a BIO-pair engine can see SYSCALL. - ec = received_shutdown() // LCOV_EXCL_LINE driver maps truncation first - ? std::error_code{} // LCOV_EXCL_LINE driver maps truncation first - : make_error_code(capy::error::stream_truncated); // LCOV_EXCL_LINE driver maps truncation first + ec = + received_shutdown() // LCOV_EXCL_LINE driver maps truncation first + ? std::error_code{} + // LCOV_EXCL_LINE driver maps truncation first + : make_error_code( + capy::error:: + stream_truncated); // LCOV_EXCL_LINE driver maps truncation first } else { diff --git a/src/openssl/src/detail/engine.hpp b/src/openssl/src/detail/engine.hpp index 89ea7e111..cd6aff0c6 100644 --- a/src/openssl/src/detail/engine.hpp +++ b/src/openssl/src/detail/engine.hpp @@ -87,7 +87,7 @@ class BOOST_COROSIO_DECL engine /// Destroy the engine, releasing the session and BIO pair. ~engine(); - engine() = default; + engine() = default; engine(engine const&) = delete; engine& operator=(engine const&) = delete; @@ -116,8 +116,7 @@ class BOOST_COROSIO_DECL engine void reset(); /// Check whether a prior `reset()` left the session unusable. - bool - clear_failed() const noexcept + bool clear_failed() const noexcept { return clear_failed_; } @@ -164,8 +163,8 @@ class BOOST_COROSIO_DECL engine @return An error when a requested setting could not be applied. */ - std::error_code prepare( - tls_context const& ctx, tls_role role, std::string const& hostname); + std::error_code + prepare(tls_context const& ctx, tls_role role, std::string const& hostname); /** Apply SNI and hostname verification for the next handshake. @@ -261,8 +260,7 @@ class BOOST_COROSIO_DECL engine bool received_shutdown() const; /// Return the underlying session handle (tests only). - ssl_st* - native_handle() const noexcept + ssl_st* native_handle() const noexcept { return ssl_; } diff --git a/src/openssl/src/openssl_stream.cpp b/src/openssl/src/openssl_stream.cpp index 4342fd8ea..1dca999be 100644 --- a/src/openssl/src/openssl_stream.cpp +++ b/src/openssl/src/openssl_stream.cpp @@ -31,7 +31,8 @@ struct openssl_stream::implementation }; openssl_stream::implementation* -openssl_stream::make_implementation(capy::any_stream& stream, tls_context const& ctx) +openssl_stream::make_implementation( + capy::any_stream& stream, tls_context const& ctx) { // Session creation is deferred to handshake time (the engine's // prepare hook builds it lazily), so a session setup failure diff --git a/src/wolfssl/src/detail/engine.cpp b/src/wolfssl/src/detail/engine.cpp index b1940d2f8..27fcc90d9 100644 --- a/src/wolfssl/src/detail/engine.cpp +++ b/src/wolfssl/src/detail/engine.cpp @@ -44,14 +44,12 @@ is_zero_return_error(int err) noexcept class wolfssl_category_impl final : public std::error_category { - char const* - name() const noexcept override + char const* name() const noexcept override { return "corosio.wolfssl"; } - std::string - message(int value) const override + std::string message(int value) const override { char buf[WOLFSSL_MAX_ERROR_SZ]; wolfSSL_ERR_error_string_n( @@ -150,7 +148,9 @@ wolfssl_sni_callback(WOLFSSL* ssl, int* /* alert */, void* arg) // still reject "revoked". static int wolfssl_crl_soft_fail_cb( - int /*ret*/, WOLFSSL_CRL* /*crl*/, WOLFSSL_CERT_MANAGER* /*cm*/, + int /*ret*/, + WOLFSSL_CRL* /*crl*/, + WOLFSSL_CERT_MANAGER* /*cm*/, void* /*ctx*/) { return 1; // override missing/unknown-status CRL error -> accept @@ -186,9 +186,9 @@ wolfssl_verify_callback(int preverified, WOLFSSL_X509_STORE_CTX* store) return preverified; WOLFSSL_CTX* wctx = wolfSSL_get_SSL_CTX(ssl); - auto* cd = wctx ? static_cast( - wolfSSL_CTX_get_ex_data(wctx, verify_cd_ex_index)) - : nullptr; + auto* cd = wctx ? static_cast( + wolfSSL_CTX_get_ex_data(wctx, verify_cd_ex_index)) + : nullptr; if (!cd || !cd->verify_callback) return preverified; @@ -198,10 +198,10 @@ wolfssl_verify_callback(int preverified, WOLFSSL_X509_STORE_CTX* store) // pointer into the certificate's own storage (no allocation, valid for // the callback's duration). unsigned char const* der = nullptr; - std::size_t der_len = 0; + std::size_t der_len = 0; if (WOLFSSL_X509* cert = wolfSSL_X509_STORE_CTX_get_current_cert(store)) { - int sz = 0; + int sz = 0; unsigned char const* d = wolfSSL_X509_get_der(cert, &sz); if (d && sz > 0) { @@ -264,8 +264,7 @@ class wolfssl_native_context : public native_context_base // / server candidates); caching it avoids rebuilding per connection. std::string alpn_list_; - void - apply_common_settings(WOLFSSL_CTX* ctx, tls_context_data const& cd) + void apply_common_settings(WOLFSSL_CTX* ctx, tls_context_data const& cd) { if (!ctx) return; @@ -350,7 +349,8 @@ class wolfssl_native_context : public native_context_base std::vector chain(cert, cert + certSz); for (WC_DerCertList* n = ca; n; n = n->next) chain.insert( - chain.end(), n->buffer, n->buffer + n->bufferSz); + chain.end(), n->buffer, + n->buffer + n->bufferSz); if (wolfSSL_CTX_use_certificate_chain_buffer_format( ctx, chain.data(), static_cast(chain.size()), @@ -473,8 +473,8 @@ class wolfssl_native_context : public native_context_base ctx, reinterpret_cast( cd.private_key.data()), - static_cast(cd.private_key.size()), format) != - WOLFSSL_SUCCESS) + static_cast(cd.private_key.size()), + format) != WOLFSSL_SUCCESS) setup_error_ = setup_error_ ? setup_error_ : 1; } } @@ -553,7 +553,8 @@ class wolfssl_native_context : public native_context_base // DER. A supplied CRL that parses as neither must not be // silently dropped, so record it for a fail-closed handshake. if (wolfSSL_CTX_LoadCRLBuffer( - ctx, buf, sz, WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS && + ctx, buf, sz, WOLFSSL_FILETYPE_PEM) != + WOLFSSL_SUCCESS && wolfSSL_CTX_LoadCRLBuffer( ctx, buf, sz, WOLFSSL_FILETYPE_ASN1) != WOLFSSL_SUCCESS) setup_error_ = setup_error_ ? setup_error_ : 1; @@ -668,8 +669,7 @@ engine::recv_callback(WOLFSSL*, char* buf, int sz, void* ctx) if (available == 0) return WOLFSSL_CBIO_ERR_WANT_READ; - std::size_t to_copy = - (std::min)(available, static_cast(sz)); + std::size_t to_copy = (std::min)(available, static_cast(sz)); std::memcpy(buf, self->in_.data() + self->in_pos_, to_copy); self->in_pos_ += to_copy; @@ -690,8 +690,7 @@ engine::send_callback(WOLFSSL*, char* buf, int sz, void* ctx) if (available == 0) return WOLFSSL_CBIO_ERR_WANT_WRITE; - std::size_t to_copy = - (std::min)(available, static_cast(sz)); + std::size_t to_copy = (std::min)(available, static_cast(sz)); std::memcpy(self->out_.data() + self->out_len_, buf, to_copy); self->out_len_ += to_copy; @@ -724,9 +723,8 @@ engine::init(tls_context const& ctx, tls_role role, std::string const& hostname) ? std::error_code(native->setup_error_, wolfssl_category()) : std::make_error_code(std::errc::invalid_argument); - WOLFSSL_CTX* native_ctx = (role == tls_role::client) - ? native->client_ctx_ - : native->server_ctx_; + WOLFSSL_CTX* native_ctx = + (role == tls_role::client) ? native->client_ctx_ : native->server_ctx_; if (!native_ctx) { @@ -839,21 +837,19 @@ engine::init(tls_context const& ctx, tls_role role, std::string const& hostname) // rather than skip the check silently. WOLFSSL_X509_VERIFY_PARAM* vp = wolfSSL_get0_param(ssl_); if (!vp || - wolfSSL_X509_VERIFY_PARAM_set1_ip_asc( - vp, hostname.c_str()) != WOLFSSL_SUCCESS) + wolfSSL_X509_VERIFY_PARAM_set1_ip_asc(vp, hostname.c_str()) != + WOLFSSL_SUCCESS) { // Fail closed rather than handshake without the // requested name check. wolfSSL_free(ssl_); ssl_ = nullptr; - return std::make_error_code( - std::errc::invalid_argument); + return std::make_error_code(std::errc::invalid_argument); } #else wolfSSL_free(ssl_); ssl_ = nullptr; - return std::make_error_code( - std::errc::function_not_supported); + return std::make_error_code(std::errc::function_not_supported); #endif } else @@ -892,9 +888,9 @@ engine::reset() wolfSSL_free(ssl_); ssl_ = nullptr; } - in_pos_ = 0; - in_len_ = 0; - out_len_ = 0; + in_pos_ = 0; + in_len_ = 0; + out_len_ = 0; received_close_notify_ = false; } @@ -904,8 +900,8 @@ engine::capture_alpn([[maybe_unused]] std::string& out) const #if defined(HAVE_ALPN) char* name = nullptr; unsigned short sz = 0; - if (wolfSSL_ALPN_GetProtocol(ssl_, &name, &sz) == WOLFSSL_SUCCESS && - name && sz) + if (wolfSSL_ALPN_GetProtocol(ssl_, &name, &sz) == WOLFSSL_SUCCESS && name && + sz) out.assign(name, sz); #endif } @@ -946,7 +942,8 @@ engine::perform(engine_op op, void* data, std::size_t len) return { pending_output() > 0 ? engine_want::output_then_done : engine_want::done, - {}, 0}; + {}, + 0}; ret = wolfSSL_shutdown(ssl_); break; } @@ -967,7 +964,8 @@ engine::perform(engine_op op, void* data, std::size_t len) return { pending_output() > 0 ? engine_want::output_then_done : engine_want::done, - {}, 0}; + {}, + 0}; // Once the peer's close_notify is latched the bidirectional // close is complete, so never park for more input: some @@ -978,7 +976,8 @@ engine::perform(engine_op op, void* data, std::size_t len) return { pending_output() > 0 ? engine_want::output_then_done : engine_want::done, - {}, 0}; + {}, + 0}; // Our close_notify was queued but the peer's has not arrived // yet: flush it, then read for it. @@ -986,7 +985,8 @@ engine::perform(engine_op op, void* data, std::size_t len) return { pending_output() > 0 ? engine_want::output_then_retry : engine_want::input, - {}, 0}; + {}, + 0}; int const err = wolfSSL_get_error(ssl_, ret); @@ -1002,7 +1002,8 @@ engine::perform(engine_op op, void* data, std::size_t len) return { pending_output() > 0 ? engine_want::output_then_retry : engine_want::input, - {}, 0}; + {}, + 0}; // A close_notify that races a concurrently parked read // surfaces here (ret == WOLFSSL_FATAL_ERROR) rather than @@ -1012,7 +1013,8 @@ engine::perform(engine_op op, void* data, std::size_t len) return { pending_output() > 0 ? engine_want::output_then_done : engine_want::done, - {}, 0}; + {}, + 0}; return { pending_output() > 0 ? engine_want::output_then_done @@ -1026,7 +1028,8 @@ engine::perform(engine_op op, void* data, std::size_t len) return { pending_output() > 0 ? engine_want::output_then_done : engine_want::done, - {}, transfer ? static_cast(ret) : 0}; + {}, + transfer ? static_cast(ret) : 0}; int const err = wolfSSL_get_error(ssl_, ret); @@ -1044,8 +1047,7 @@ engine::perform(engine_op op, void* data, std::size_t len) // used here: some builds clear it on the very read that reaches // this branch, which is exactly why the latch exists. if (op == engine_op::read && received_close_notify_) - return { - engine_want::done, make_error_code(capy::error::eof), 0}; + return {engine_want::done, make_error_code(capy::error::eof), 0}; // A write cannot make progress once the peer's close_notify has // been latched: the connection is closed, so parking on transport @@ -1062,7 +1064,8 @@ engine::perform(engine_op op, void* data, std::size_t len) return { pending_output() > 0 ? engine_want::output_then_retry : engine_want::input, - {}, 0}; + {}, + 0}; } if (transfer && is_zero_return_error(err)) diff --git a/src/wolfssl/src/detail/engine.hpp b/src/wolfssl/src/detail/engine.hpp index 3bbbe25a0..ed1ea3bd0 100644 --- a/src/wolfssl/src/detail/engine.hpp +++ b/src/wolfssl/src/detail/engine.hpp @@ -130,15 +130,13 @@ class BOOST_COROSIO_DECL engine void reset(); /// Nothing can invalidate the cached contexts between handshakes. - std::error_code - check_context() const noexcept + std::error_code check_context() const noexcept { return {}; } /// Session teardown in `reset()` cannot fail. - std::error_code - check_session() const noexcept + std::error_code check_session() const noexcept { return {}; } @@ -233,8 +231,7 @@ class BOOST_COROSIO_DECL engine bool received_shutdown() const; /// Return the underlying session handle (tests only). - WOLFSSL* - native_handle() const noexcept + WOLFSSL* native_handle() const noexcept { return ssl_; } diff --git a/src/wolfssl/src/wolfssl_stream.cpp b/src/wolfssl/src/wolfssl_stream.cpp index d93c912e1..6cf25263e 100644 --- a/src/wolfssl/src/wolfssl_stream.cpp +++ b/src/wolfssl/src/wolfssl_stream.cpp @@ -31,7 +31,8 @@ struct wolfssl_stream::implementation }; wolfssl_stream::implementation* -wolfssl_stream::make_implementation(capy::any_stream& stream, tls_context const& ctx) +wolfssl_stream::make_implementation( + capy::any_stream& stream, tls_context const& ctx) { // Session creation is deferred to handshake time when the role is // known (the engine's prepare hook builds it from the role's diff --git a/test/doc/doc_warnings.hpp b/test/doc/doc_warnings.hpp index d343e8c97..4b191dfab 100644 --- a/test/doc/doc_warnings.hpp +++ b/test/doc/doc_warnings.hpp @@ -42,14 +42,14 @@ #pragma clang diagnostic ignored "-Wunused-private-field" #endif #if defined(_MSC_VER) -#pragma warning(disable: 4834) // discarding [[nodiscard]] return value -#pragma warning(disable: 4189) // local variable initialized but not referenced -#pragma warning(disable: 4100) // unreferenced formal parameter -#pragma warning(disable: 4101) // unreferenced local variable -#pragma warning(disable: 4456) // declaration hides previous local declaration -#pragma warning(disable: 4457) // declaration hides function parameter -#pragma warning(disable: 4458) // declaration hides class member -#pragma warning(disable: 4459) // declaration hides global declaration +#pragma warning(disable : 4834) // discarding [[nodiscard]] return value +#pragma warning(disable : 4189) // local variable initialized but not referenced +#pragma warning(disable : 4100) // unreferenced formal parameter +#pragma warning(disable : 4101) // unreferenced local variable +#pragma warning(disable : 4456) // declaration hides previous local declaration +#pragma warning(disable : 4457) // declaration hides function parameter +#pragma warning(disable : 4458) // declaration hides class member +#pragma warning(disable : 4459) // declaration hides global declaration #endif #endif diff --git a/test/doc/programs/4c_io_context_typical.cpp b/test/doc/programs/4c_io_context_typical.cpp index 9aa880a4e..cbb9e22af 100644 --- a/test/doc/programs/4c_io_context_typical.cpp +++ b/test/doc/programs/4c_io_context_typical.cpp @@ -16,17 +16,19 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; // The page focuses on the launch pattern; the coroutine body is a // placeholder so the program exits cleanly. -capy::task<> main_coroutine(corosio::tcp_socket&) +capy::task<> +main_coroutine(corosio::tcp_socket&) { co_return; } // tag::full[] -int main() +int +main() { corosio::io_context ioc; diff --git a/test/doc/programs/4k_tcp_server_echo.cpp b/test/doc/programs/4k_tcp_server_echo.cpp index 6e86cb78e..91355d425 100644 --- a/test/doc/programs/4k_tcp_server_echo.cpp +++ b/test/doc/programs/4k_tcp_server_echo.cpp @@ -23,7 +23,7 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; class echo_worker : public corosio::tcp_server::worker_base { @@ -32,14 +32,15 @@ class echo_worker : public corosio::tcp_server::worker_base std::string buf; public: - explicit echo_worker(corosio::io_context& ctx) - : ctx_(ctx) - , sock_(ctx) + explicit echo_worker(corosio::io_context& ctx) : ctx_(ctx), sock_(ctx) { buf.reserve(4096); } - corosio::tcp_socket& socket() override { return sock_; } + corosio::tcp_socket& socket() override + { + return sock_; + } void run(corosio::tcp_server::launcher launch) override { @@ -69,7 +70,8 @@ class echo_worker : public corosio::tcp_server::worker_base } }; -auto make_echo_workers(corosio::io_context& ctx, int n) +auto +make_echo_workers(corosio::io_context& ctx, int n) { std::vector> v; v.reserve(n); @@ -88,7 +90,8 @@ class echo_server : public corosio::tcp_server } }; -int main() +int +main() { corosio::io_context ioc; diff --git a/test/doc/programs/index_page_connect.cpp b/test/doc/programs/index_page_connect.cpp index 1e4c555a6..da2ad6725 100644 --- a/test/doc/programs/index_page_connect.cpp +++ b/test/doc/programs/index_page_connect.cpp @@ -18,9 +18,10 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; -capy::task connect_example(corosio::io_context& ioc) +capy::task +connect_example(corosio::io_context& ioc) { // connect() opens the socket automatically corosio::tcp_socket s(ioc); @@ -37,14 +38,15 @@ capy::task connect_example(corosio::io_context& ioc) // Read some data char buf[1024]; - auto [read_ec, n] = co_await s.read_some( - capy::mutable_buffer(buf, sizeof(buf))); + auto [read_ec, n] = + co_await s.read_some(capy::mutable_buffer(buf, sizeof(buf))); if (!read_ec) std::cout << "Received " << n << " bytes\n"; } -int main() +int +main() { corosio::io_context ioc; capy::run_async(ioc.get_executor())(connect_example(ioc)); diff --git a/test/doc/programs/quick_start_context.cpp b/test/doc/programs/quick_start_context.cpp index 2dd8b624f..81cd696e2 100644 --- a/test/doc/programs/quick_start_context.cpp +++ b/test/doc/programs/quick_start_context.cpp @@ -15,12 +15,13 @@ namespace corosio = boost::corosio; // tag::full[] -int main() +int +main() { corosio::io_context ioc; // ... create and start server ... - ioc.run(); // Process events until all work completes + ioc.run(); // Process events until all work completes } // end::full[] diff --git a/test/doc/programs/quick_start_echo.cpp b/test/doc/programs/quick_start_echo.cpp index 23f5a450f..b423d6d1d 100644 --- a/test/doc/programs/quick_start_echo.cpp +++ b/test/doc/programs/quick_start_echo.cpp @@ -19,7 +19,7 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; // end::assume[] #include @@ -35,14 +35,15 @@ class worker : public corosio::tcp_server::worker_base std::string buf_; public: - worker(corosio::io_context& ctx) - : ctx_(ctx) - , sock_(ctx) + worker(corosio::io_context& ctx) : ctx_(ctx), sock_(ctx) { buf_.reserve(4096); } - corosio::tcp_socket& socket() override { return sock_; } + corosio::tcp_socket& socket() override + { + return sock_; + } void run(corosio::tcp_server::launcher launch) override { @@ -75,7 +76,8 @@ class echo_server : public corosio::tcp_server // end::server_class[] // tag::session[] -capy::task<> worker::do_session() +capy::task<> +worker::do_session() { for (;;) { @@ -86,7 +88,7 @@ capy::task<> worker::do_session() capy::mutable_buffer(buf_.data(), buf_.size())); if (ec || n == 0) - break; // Connection closed or error + break; // Connection closed or error buf_.resize(n); @@ -95,7 +97,7 @@ capy::task<> worker::do_session() sock_, capy::const_buffer(buf_.data(), buf_.size())); if (wec) - break; // Write error + break; // Write error } sock_.close(); @@ -103,7 +105,8 @@ capy::task<> worker::do_session() // end::session[] // tag::main[] -int main() +int +main() { corosio::io_context ioc; diff --git a/test/doc/reference/connect.function.cpp b/test/doc/reference/connect.function.cpp index 5aca864db..6e174c0eb 100644 --- a/test/doc/reference/connect.function.cpp +++ b/test/doc/reference/connect.function.cpp @@ -26,14 +26,15 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { // Resolving and connecting to a public hostname needs the network; // compiled, never run. // tag::connect[] -capy::task<> connect_to_first_available(corosio::io_context& ioc) +capy::task<> +connect_to_first_available(corosio::io_context& ioc) { corosio::resolver r(ioc); auto [rec, results] = co_await r.resolve("www.boost.org", "80"); diff --git a/test/doc/reference/delay.function.cpp b/test/doc/reference/delay.function.cpp index 83003e434..542d61e8f 100644 --- a/test/doc/reference/delay.function.cpp +++ b/test/doc/reference/delay.function.cpp @@ -29,12 +29,13 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { // tag::duration[] -capy::task<> wait_briefly() +capy::task<> +wait_briefly() { auto [ec] = co_await corosio::delay(std::chrono::milliseconds(100)); if (ec == capy::cond::canceled) @@ -46,7 +47,8 @@ capy::task<> wait_briefly() // Waits a real wall-clock hour if ever launched; compiled, never run. // tag::system_clock_deadline[] -capy::task<> wait_one_hour_wall_clock() +capy::task<> +wait_one_hour_wall_clock() { auto [ec] = co_await corosio::delay( std::chrono::system_clock::now() + std::chrono::hours(1)); diff --git a/test/doc/reference/endpoint.record.cpp b/test/doc/reference/endpoint.record.cpp index 1fe9ef12c..fa2bb5646 100644 --- a/test/doc/reference/endpoint.record.cpp +++ b/test/doc/reference/endpoint.record.cpp @@ -23,7 +23,8 @@ namespace corosio = boost::corosio; namespace { // tag::endpoint[] -void construct_endpoints() +void +construct_endpoints() { // IPv4 endpoint corosio::endpoint ep4(corosio::ipv4_address::loopback(), 8080); diff --git a/test/doc/reference/host_name.function.cpp b/test/doc/reference/host_name.function.cpp index d43ac5d80..ede67d59a 100644 --- a/test/doc/reference/host_name.function.cpp +++ b/test/doc/reference/host_name.function.cpp @@ -23,7 +23,8 @@ namespace corosio = boost::corosio; namespace { // tag::host_name[] -void print_local_host_name() +void +print_local_host_name() { auto [ec, h] = corosio::host_name(); if (ec) diff --git a/test/doc/reference/io_context.record.cpp b/test/doc/reference/io_context.record.cpp index f18706293..a637d6924 100644 --- a/test/doc/reference/io_context.record.cpp +++ b/test/doc/reference/io_context.record.cpp @@ -30,10 +30,11 @@ namespace { #if BOOST_COROSIO_HAS_EPOLL // tag::construct[] -void construct_contexts() +void +construct_contexts() { - corosio::io_context ioc; // platform default (epoll on Linux) - corosio::io_context ioc2(corosio::epoll); // explicit backend + corosio::io_context ioc; // platform default (epoll on Linux) + corosio::io_context ioc2(corosio::epoll); // explicit backend } // end::construct[] #endif // BOOST_COROSIO_HAS_EPOLL diff --git a/test/doc/reference/io_context_options.record.cpp b/test/doc/reference/io_context_options.record.cpp index e654da649..a4a1d6cb8 100644 --- a/test/doc/reference/io_context_options.record.cpp +++ b/test/doc/reference/io_context_options.record.cpp @@ -21,7 +21,8 @@ namespace corosio = boost::corosio; namespace { // tag::configure[] -void configure_for_high_throughput() +void +configure_for_high_throughput() { corosio::io_context_options opts; diff --git a/test/doc/reference/io_stream.record.cpp b/test/doc/reference/io_stream.record.cpp index 280d59fa8..c93bd93e6 100644 --- a/test/doc/reference/io_stream.record.cpp +++ b/test/doc/reference/io_stream.record.cpp @@ -25,13 +25,14 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { // tag::io_stream[] // Read until buffer full or EOF -capy::task<> read_all(corosio::io_stream& stream, std::span buf) +capy::task<> +read_all(corosio::io_stream& stream, std::span buf) { std::size_t total = 0; while (total < buf.size()) diff --git a/test/doc/reference/ipv4_address__to_string.function.cpp b/test/doc/reference/ipv4_address__to_string.function.cpp index e22d72776..15c7a3883 100644 --- a/test/doc/reference/ipv4_address__to_string.function.cpp +++ b/test/doc/reference/ipv4_address__to_string.function.cpp @@ -23,7 +23,8 @@ namespace corosio = boost::corosio; namespace { // tag::to_string[] -void print_as_dotted_decimal() +void +print_as_dotted_decimal() { assert(corosio::ipv4_address(0x01020304).to_string() == "1.2.3.4"); } diff --git a/test/doc/reference/ipv6_address__to_string.function.cpp b/test/doc/reference/ipv6_address__to_string.function.cpp index f5dcec09a..fa437a6bf 100644 --- a/test/doc/reference/ipv6_address__to_string.function.cpp +++ b/test/doc/reference/ipv6_address__to_string.function.cpp @@ -23,11 +23,11 @@ namespace corosio = boost::corosio; namespace { // tag::to_string[] -void print_as_colon_hex() +void +print_as_colon_hex() { - corosio::ipv6_address::bytes_type b = {{ - 0, 1, 0, 2, 0, 3, 0, 4, - 0, 5, 0, 6, 0, 7, 0, 8 }}; + corosio::ipv6_address::bytes_type b = { + {0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8}}; corosio::ipv6_address a(b); assert(a.to_string() == "1:2:3:4:5:6:7:8"); } diff --git a/test/doc/reference/local_datagram_socket.record.cpp b/test/doc/reference/local_datagram_socket.record.cpp index 170ffb7f7..92732bd58 100644 --- a/test/doc/reference/local_datagram_socket.record.cpp +++ b/test/doc/reference/local_datagram_socket.record.cpp @@ -31,13 +31,14 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { #if BOOST_COROSIO_POSIX // tag::connectionless_and_connected[] -capy::task<> connectionless_and_connected(corosio::io_context& ioc) +capy::task<> +connectionless_and_connected(corosio::io_context& ioc) { // Connectionless corosio::local_datagram_socket sender(ioc); @@ -53,11 +54,11 @@ capy::task<> connectionless_and_connected(corosio::io_context& ioc) // Connected corosio::local_datagram_socket sock(ioc); - auto [cec] = co_await sock.connect(corosio::local_endpoint("/tmp/peer.sock")); + auto [cec] = + co_await sock.connect(corosio::local_endpoint("/tmp/peer.sock")); if (cec) co_return; - auto [ec2, n2] = co_await sock.send( - capy::const_buffer("hi", 2)); + auto [ec2, n2] = co_await sock.send(capy::const_buffer("hi", 2)); if (ec2) co_return; } diff --git a/test/doc/reference/local_stream.record.cpp b/test/doc/reference/local_stream.record.cpp index a78eb67b2..7d74b755d 100644 --- a/test/doc/reference/local_stream.record.cpp +++ b/test/doc/reference/local_stream.record.cpp @@ -29,7 +29,8 @@ namespace corosio = boost::corosio; namespace { // tag::open_with_protocol[] -void open_with_protocol(corosio::io_context& ctx) +void +open_with_protocol(corosio::io_context& ctx) { corosio::local_stream_socket sock(ctx); if (auto ec = sock.open(corosio::local_stream{})) diff --git a/test/doc/reference/local_stream_acceptor.record.cpp b/test/doc/reference/local_stream_acceptor.record.cpp index 61a243b5d..287902b0b 100644 --- a/test/doc/reference/local_stream_acceptor.record.cpp +++ b/test/doc/reference/local_stream_acceptor.record.cpp @@ -28,18 +28,20 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { // tag::bind_listen_accept[] -capy::task<> bind_listen_accept(corosio::io_context& ioc) +capy::task<> +bind_listen_accept(corosio::io_context& ioc) { corosio::local_stream_acceptor acc(ioc); if (auto ec = acc.open()) co_return; - if (auto ec = acc.bind(corosio::local_endpoint("/tmp/my_app.sock"), - corosio::bind_option::unlink_existing)) + if (auto ec = acc.bind( + corosio::local_endpoint("/tmp/my_app.sock"), + corosio::bind_option::unlink_existing)) co_return; if (auto ec = acc.listen()) co_return; diff --git a/test/doc/reference/local_stream_socket.record.cpp b/test/doc/reference/local_stream_socket.record.cpp index b0fd68e1e..c7d2ef759 100644 --- a/test/doc/reference/local_stream_socket.record.cpp +++ b/test/doc/reference/local_stream_socket.record.cpp @@ -27,12 +27,13 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { // tag::connect_and_read[] -capy::task<> connect_and_read(corosio::io_context& ioc) +capy::task<> +connect_and_read(corosio::io_context& ioc) { corosio::local_stream_socket s(ioc); @@ -41,8 +42,8 @@ capy::task<> connect_and_read(corosio::io_context& ioc) co_return; char buf[1024]; - auto [read_ec, n] = co_await s.read_some( - capy::mutable_buffer(buf, sizeof(buf))); + auto [read_ec, n] = + co_await s.read_some(capy::mutable_buffer(buf, sizeof(buf))); if (read_ec) co_return; } diff --git a/test/doc/reference/make_endpoint.function.cpp b/test/doc/reference/make_endpoint.function.cpp index 7a45cd7d1..8a7f9abe8 100644 --- a/test/doc/reference/make_endpoint.function.cpp +++ b/test/doc/reference/make_endpoint.function.cpp @@ -23,7 +23,8 @@ namespace corosio = boost::corosio; namespace { // tag::make_endpoint[] -void parse_v4_and_v6() +void +parse_v4_and_v6() { auto [ec, ep] = corosio::make_endpoint("192.168.1.1:8080"); if (ec) diff --git a/test/doc/reference/native_io_context.record.cpp b/test/doc/reference/native_io_context.record.cpp index 84b8a58a7..682c2ed43 100644 --- a/test/doc/reference/native_io_context.record.cpp +++ b/test/doc/reference/native_io_context.record.cpp @@ -17,7 +17,7 @@ // reference slug drops the template parameter, but the example must still // name a concrete backend tag. corosio::epoll is what this library actually // offers as a compile-time tag on Linux (see backend.hpp); other platforms -// get iocp_t/kqueue_t/select_t/io_uring_t instead, so the whole example is +// get iocp_t/kqueue_t/select_t/uring_t instead, so the whole example is // guarded on the tag it names actually existing. #include "../doc_warnings.hpp" @@ -31,10 +31,11 @@ namespace { #if BOOST_COROSIO_HAS_EPOLL // tag::poll[] -void poll_native_context() +void +poll_native_context() { corosio::native_io_context ctx; - ctx.poll(); // devirtualized call, no vtable dispatch + ctx.poll(); // devirtualized call, no vtable dispatch } // end::poll[] #endif // BOOST_COROSIO_HAS_EPOLL diff --git a/test/doc/reference/native_local_datagram_socket.record.cpp b/test/doc/reference/native_local_datagram_socket.record.cpp index fdb612b5d..67d7df381 100644 --- a/test/doc/reference/native_local_datagram_socket.record.cpp +++ b/test/doc/reference/native_local_datagram_socket.record.cpp @@ -33,13 +33,14 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { #if BOOST_COROSIO_HAS_EPOLL // tag::open_bind_recv[] -capy::task<> open_bind_recv() +capy::task<> +open_bind_recv() { corosio::native_io_context ctx; corosio::native_local_datagram_socket s(ctx); @@ -50,8 +51,8 @@ capy::task<> open_bind_recv() char buf[1024]; corosio::local_endpoint sender; - auto [ec, n] = co_await s.recv_from( - capy::mutable_buffer(buf, sizeof(buf)), sender); + auto [ec, n] = + co_await s.recv_from(capy::mutable_buffer(buf, sizeof(buf)), sender); if (ec) co_return; } diff --git a/test/doc/reference/native_local_stream_socket.record.cpp b/test/doc/reference/native_local_stream_socket.record.cpp index e0b5ec3e7..0849b2e95 100644 --- a/test/doc/reference/native_local_stream_socket.record.cpp +++ b/test/doc/reference/native_local_stream_socket.record.cpp @@ -32,13 +32,14 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { #if BOOST_COROSIO_HAS_EPOLL // tag::connect[] -capy::task<> connect_native() +capy::task<> +connect_native() { corosio::native_io_context ctx; corosio::native_local_stream_socket s(ctx); diff --git a/test/doc/reference/native_random_access_file.record.cpp b/test/doc/reference/native_random_access_file.record.cpp index 95cb26def..d6d615fc8 100644 --- a/test/doc/reference/native_random_access_file.record.cpp +++ b/test/doc/reference/native_random_access_file.record.cpp @@ -31,13 +31,14 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { #if BOOST_COROSIO_HAS_EPOLL // tag::native_random_access_file[] -capy::task<> open_and_read_at() +capy::task<> +open_and_read_at() { corosio::native_io_context ctx; corosio::native_random_access_file f(ctx); @@ -45,8 +46,8 @@ capy::task<> open_and_read_at() co_return; char buf[4096]; - auto [ec, n] = co_await f.read_some_at( - 0, capy::mutable_buffer(buf, sizeof(buf))); + auto [ec, n] = + co_await f.read_some_at(0, capy::mutable_buffer(buf, sizeof(buf))); if (ec) co_return; } diff --git a/test/doc/reference/native_socket_option__boolean.record.cpp b/test/doc/reference/native_socket_option__boolean.record.cpp index 7411f93d7..9e112d0e6 100644 --- a/test/doc/reference/native_socket_option__boolean.record.cpp +++ b/test/doc/reference/native_socket_option__boolean.record.cpp @@ -29,7 +29,8 @@ namespace corosio = boost::corosio; namespace { // tag::boolean[] -void receive_urgent_data_inline(corosio::tcp_socket& sock) +void +receive_urgent_data_inline(corosio::tcp_socket& sock) { // corosio has no dedicated type for SO_OOBINLINE; naming the level and // option as template arguments is what this class is for -- reaching an diff --git a/test/doc/reference/native_socket_option__integer.record.cpp b/test/doc/reference/native_socket_option__integer.record.cpp index 33c00f34d..51c92e69a 100644 --- a/test/doc/reference/native_socket_option__integer.record.cpp +++ b/test/doc/reference/native_socket_option__integer.record.cpp @@ -30,7 +30,8 @@ namespace corosio = boost::corosio; namespace { // tag::integer[] -void limit_how_far_outgoing_packets_can_travel(corosio::udp_socket& sock) +void +limit_how_far_outgoing_packets_can_travel(corosio::udp_socket& sock) { // Precondition: sock is open on udp::v4(). IPPROTO_IP options don't // apply to an AF_INET6 socket; set_option compiles either way and diff --git a/test/doc/reference/native_socket_option__join_group_v4.record.cpp b/test/doc/reference/native_socket_option__join_group_v4.record.cpp index 60e66430b..0109c3a30 100644 --- a/test/doc/reference/native_socket_option__join_group_v4.record.cpp +++ b/test/doc/reference/native_socket_option__join_group_v4.record.cpp @@ -27,11 +27,12 @@ namespace corosio = boost::corosio; namespace { // tag::join_group_v4[] -void receive_an_ipv4_multicast_group(corosio::io_context& ioc) +void +receive_an_ipv4_multicast_group(corosio::io_context& ioc) { corosio::udp_socket sock(ioc); if (auto ec = sock.open(corosio::udp::v4())) - return; // report the error + return; // report the error // Lets other listeners on this host bind the same port and receive the // same group. set_option reports failure by throwing, not by returning @@ -40,16 +41,17 @@ void receive_an_ipv4_multicast_group(corosio::io_context& ioc) // Bind before joining: a membership attaches to the socket's local port, // so there is nothing for the join to attach to until the bind succeeds. - if (auto ec = sock.bind( - corosio::endpoint(corosio::ipv4_address::any(), 9000))) - return; // report the error + if (auto ec = + sock.bind(corosio::endpoint(corosio::ipv4_address::any(), 9000))) + return; // report the error // 239.0.0.0/8 is the administratively scoped range, the IPv4 counterpart // of a private address range. The optional second argument names the // local interface to receive on; the default, 0.0.0.0, lets the kernel // choose one. - sock.set_option(corosio::native_socket_option::join_group_v4( - corosio::ipv4_address("239.255.0.1"))); + sock.set_option( + corosio::native_socket_option::join_group_v4( + corosio::ipv4_address("239.255.0.1"))); } // end::join_group_v4[] diff --git a/test/doc/reference/native_socket_option__join_group_v6.record.cpp b/test/doc/reference/native_socket_option__join_group_v6.record.cpp index b14cb9923..18f7ef49b 100644 --- a/test/doc/reference/native_socket_option__join_group_v6.record.cpp +++ b/test/doc/reference/native_socket_option__join_group_v6.record.cpp @@ -27,11 +27,12 @@ namespace corosio = boost::corosio; namespace { // tag::join_group_v6[] -void receive_an_ipv6_multicast_group(corosio::io_context& ioc) +void +receive_an_ipv6_multicast_group(corosio::io_context& ioc) { corosio::udp_socket sock(ioc); if (auto ec = sock.open(corosio::udp::v6())) - return; // report the error + return; // report the error // Lets other listeners on this host bind the same port and receive the // same group. set_option reports failure by throwing, not by returning @@ -40,16 +41,17 @@ void receive_an_ipv6_multicast_group(corosio::io_context& ioc) // Bind before joining: a membership attaches to the socket's local port, // so there is nothing for the join to attach to until the bind succeeds. - if (auto ec = sock.bind( - corosio::endpoint(corosio::ipv6_address::any(), 9000))) - return; // report the error + if (auto ec = + sock.bind(corosio::endpoint(corosio::ipv6_address::any(), 9000))) + return; // report the error // ff15::1234 is a transient, site-scoped group: the 1 marks it // non-permanent, the 5 sets the scope. The interface index selects which // link to join on; 0 lets the kernel choose, and if_nametoindex() maps a // name such as "eth0". - sock.set_option(corosio::native_socket_option::join_group_v6( - corosio::ipv6_address("ff15::1234"), 0)); + sock.set_option( + corosio::native_socket_option::join_group_v6( + corosio::ipv6_address("ff15::1234"), 0)); } // end::join_group_v6[] diff --git a/test/doc/reference/native_socket_option__leave_group_v4.record.cpp b/test/doc/reference/native_socket_option__leave_group_v4.record.cpp index 1769191ec..96101333a 100644 --- a/test/doc/reference/native_socket_option__leave_group_v4.record.cpp +++ b/test/doc/reference/native_socket_option__leave_group_v4.record.cpp @@ -24,7 +24,8 @@ namespace corosio = boost::corosio; namespace { // tag::leave_group_v4[] -void stop_receiving_an_ipv4_multicast_group(corosio::udp_socket& sock) +void +stop_receiving_an_ipv4_multicast_group(corosio::udp_socket& sock) { // Precondition: sock is open on udp::v4() and joined this group. // @@ -33,8 +34,9 @@ void stop_receiving_an_ipv4_multicast_group(corosio::udp_socket& sock) // attempting to leave a (group, interface) pair the kernel has no // membership for fails with EADDRNOTAVAIL, which set_option reports by // throwing. - sock.set_option(corosio::native_socket_option::leave_group_v4( - corosio::ipv4_address("239.255.0.1"))); + sock.set_option( + corosio::native_socket_option::leave_group_v4( + corosio::ipv4_address("239.255.0.1"))); } // end::leave_group_v4[] diff --git a/test/doc/reference/native_socket_option__leave_group_v6.record.cpp b/test/doc/reference/native_socket_option__leave_group_v6.record.cpp index 1531b8d66..630b9a32f 100644 --- a/test/doc/reference/native_socket_option__leave_group_v6.record.cpp +++ b/test/doc/reference/native_socket_option__leave_group_v6.record.cpp @@ -24,7 +24,8 @@ namespace corosio = boost::corosio; namespace { // tag::leave_group_v6[] -void stop_receiving_an_ipv6_multicast_group(corosio::udp_socket& sock) +void +stop_receiving_an_ipv6_multicast_group(corosio::udp_socket& sock) { // Precondition: sock is open on udp::v6() and joined this group. // @@ -33,8 +34,9 @@ void stop_receiving_an_ipv6_multicast_group(corosio::udp_socket& sock) // attempting to leave a (group, interface) pair the kernel has no // membership for fails with EADDRNOTAVAIL, which set_option reports by // throwing. - sock.set_option(corosio::native_socket_option::leave_group_v6( - corosio::ipv6_address("ff15::1234"), 0)); + sock.set_option( + corosio::native_socket_option::leave_group_v6( + corosio::ipv6_address("ff15::1234"), 0)); } // end::leave_group_v6[] diff --git a/test/doc/reference/native_socket_option__linger.record.cpp b/test/doc/reference/native_socket_option__linger.record.cpp index 3511774bb..c41e691a7 100644 --- a/test/doc/reference/native_socket_option__linger.record.cpp +++ b/test/doc/reference/native_socket_option__linger.record.cpp @@ -23,7 +23,8 @@ namespace corosio = boost::corosio; namespace { // tag::linger[] -void control_what_close_does_with_queued_data(corosio::tcp_socket& sock) +void +control_what_close_does_with_queued_data(corosio::tcp_socket& sock) { // A non-zero timeout can make close() block the calling thread for up // to that many seconds. close() also runs from the destructor and from @@ -37,8 +38,8 @@ void control_what_close_does_with_queued_data(corosio::tcp_socket& sock) // storage -- an implementation detail invisible at this call site. sock.set_option(corosio::native_socket_option::linger(true, 5)); - auto opt = sock.get_option(); - bool waits = opt.enabled(); + auto opt = sock.get_option(); + bool waits = opt.enabled(); int seconds = opt.timeout(); } // end::linger[] diff --git a/test/doc/reference/native_socket_option__multicast_interface_v4.record.cpp b/test/doc/reference/native_socket_option__multicast_interface_v4.record.cpp index ef205ffe4..7a02659bc 100644 --- a/test/doc/reference/native_socket_option__multicast_interface_v4.record.cpp +++ b/test/doc/reference/native_socket_option__multicast_interface_v4.record.cpp @@ -24,7 +24,8 @@ namespace corosio = boost::corosio; namespace { // tag::multicast_interface_v4[] -void choose_the_outgoing_interface_v4(corosio::udp_socket& sock) +void +choose_the_outgoing_interface_v4(corosio::udp_socket& sock) { // Precondition: sock is open on udp::v4(). // @@ -32,8 +33,9 @@ void choose_the_outgoing_interface_v4(corosio::udp_socket& sock) // multicast_interface_v6 takes an interface index. The default, // 0.0.0.0, leaves the choice to the routing table -- which on a // multi-homed host is rarely the interface you meant. - sock.set_option(corosio::native_socket_option::multicast_interface_v4( - corosio::ipv4_address("192.168.1.1"))); + sock.set_option( + corosio::native_socket_option::multicast_interface_v4( + corosio::ipv4_address("192.168.1.1"))); } // end::multicast_interface_v4[] diff --git a/test/doc/reference/native_stream_file.record.cpp b/test/doc/reference/native_stream_file.record.cpp index 4a495c5cd..2ba779611 100644 --- a/test/doc/reference/native_stream_file.record.cpp +++ b/test/doc/reference/native_stream_file.record.cpp @@ -30,13 +30,14 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { #if BOOST_COROSIO_HAS_EPOLL // tag::native_stream_file[] -capy::task<> open_and_read() +capy::task<> +open_and_read() { corosio::native_io_context ctx; corosio::native_stream_file f(ctx); @@ -44,8 +45,7 @@ capy::task<> open_and_read() co_return; char buf[4096]; - auto [ec, n] = co_await f.read_some( - capy::mutable_buffer(buf, sizeof(buf))); + auto [ec, n] = co_await f.read_some(capy::mutable_buffer(buf, sizeof(buf))); if (ec) co_return; } diff --git a/test/doc/reference/native_tcp_socket.record.cpp b/test/doc/reference/native_tcp_socket.record.cpp index e34fca9da..5fdee5edc 100644 --- a/test/doc/reference/native_tcp_socket.record.cpp +++ b/test/doc/reference/native_tcp_socket.record.cpp @@ -31,13 +31,14 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { #if BOOST_COROSIO_HAS_EPOLL // tag::native_tcp_socket[] -capy::task<> connect_and_read() +capy::task<> +connect_and_read() { corosio::native_io_context ctx; corosio::native_tcp_socket s(ctx); @@ -47,8 +48,8 @@ capy::task<> connect_and_read() co_return; char buf[1024]; - auto [ec2, n] = co_await s.read_some( - capy::mutable_buffer(buf, sizeof(buf))); + auto [ec2, n] = + co_await s.read_some(capy::mutable_buffer(buf, sizeof(buf))); if (ec2) co_return; } diff --git a/test/doc/reference/native_udp_socket.record.cpp b/test/doc/reference/native_udp_socket.record.cpp index 0c8ae4fa1..60e6f0f09 100644 --- a/test/doc/reference/native_udp_socket.record.cpp +++ b/test/doc/reference/native_udp_socket.record.cpp @@ -31,26 +31,26 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { #if BOOST_COROSIO_HAS_EPOLL // tag::native_udp_socket[] -capy::task<> open_bind_recv() +capy::task<> +open_bind_recv() { corosio::native_io_context ctx; corosio::native_udp_socket s(ctx); if (auto ec = s.open()) co_return; - if (auto ec = s.bind( - corosio::endpoint(corosio::ipv4_address::any(), 9000))) + if (auto ec = s.bind(corosio::endpoint(corosio::ipv4_address::any(), 9000))) co_return; char buf[1024]; corosio::endpoint sender; - auto [ec, n] = co_await s.recv_from( - capy::mutable_buffer(buf, sizeof(buf)), sender); + auto [ec, n] = + co_await s.recv_from(capy::mutable_buffer(buf, sizeof(buf)), sender); if (ec) co_return; } diff --git a/test/doc/reference/openssl_stream.record.cpp b/test/doc/reference/openssl_stream.record.cpp index f8d801d83..41511d792 100644 --- a/test/doc/reference/openssl_stream.record.cpp +++ b/test/doc/reference/openssl_stream.record.cpp @@ -31,7 +31,7 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { @@ -40,11 +40,12 @@ namespace { // modes; reusing one socket for both would leave tls pointing at sock // after it was gutted by the move into tls2 (use-after-move), not a // dangling reference -- sock itself stays in scope. -capy::task<> reference_and_owning_construction( +capy::task<> +reference_and_owning_construction( corosio::io_context& ioc, corosio::endpoint ep) { corosio::tls_context ctx; - if (auto ec = ctx.set_default_verify_paths()) // trust the system CAs + if (auto ec = ctx.set_default_verify_paths()) // trust the system CAs co_return; if (auto ec = ctx.set_verify_mode(corosio::tls_verify_mode::peer)) co_return; diff --git a/test/doc/reference/random_access_file.record.cpp b/test/doc/reference/random_access_file.record.cpp index 28748883c..3c350d78d 100644 --- a/test/doc/reference/random_access_file.record.cpp +++ b/test/doc/reference/random_access_file.record.cpp @@ -23,22 +23,23 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { // tag::random_access_file[] // Every read/write names an explicit byte offset; there is no implicit // position to advance, unlike stream_file. -capy::task<> read_a_file_at_an_offset(corosio::io_context& ioc) +capy::task<> +read_a_file_at_an_offset(corosio::io_context& ioc) { corosio::random_access_file f(ioc); if (auto ec = f.open("data.bin", corosio::file_base::read_only)) - co_return; // report the error + co_return; // report the error char buf[4096]; - auto [ec, n] = co_await f.read_some_at( - 0, capy::mutable_buffer(buf, sizeof(buf))); + auto [ec, n] = + co_await f.read_some_at(0, capy::mutable_buffer(buf, sizeof(buf))); if (ec) co_return; } diff --git a/test/doc/reference/resolver.record.cpp b/test/doc/reference/resolver.record.cpp index d252a1a8f..c7c86b17f 100644 --- a/test/doc/reference/resolver.record.cpp +++ b/test/doc/reference/resolver.record.cpp @@ -23,13 +23,14 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { // Resolving a public hostname needs the network; compiled, never run. // tag::resolver[] -capy::task<> resolve_and_print(corosio::io_context& ioc) +capy::task<> +resolve_and_print(corosio::io_context& ioc) { corosio::resolver r(ioc); diff --git a/test/doc/reference/resolver__resolve.function.cpp b/test/doc/reference/resolver__resolve.function.cpp index 4798d8e7b..18f499357 100644 --- a/test/doc/reference/resolver__resolve.function.cpp +++ b/test/doc/reference/resolver__resolve.function.cpp @@ -31,13 +31,14 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { // Resolving a public hostname needs the network; compiled, never run. // tag::forward_resolve[] -capy::task<> forward_resolve(corosio::resolver& r) +capy::task<> +forward_resolve(corosio::resolver& r) { auto [ec, results] = co_await r.resolve("www.example.com", "https"); if (ec) @@ -46,7 +47,8 @@ capy::task<> forward_resolve(corosio::resolver& r) // end::forward_resolve[] // tag::reverse_resolve[] -capy::task<> reverse_resolve(corosio::resolver& r) +capy::task<> +reverse_resolve(corosio::resolver& r) { corosio::endpoint ep(corosio::ipv4_address({127, 0, 0, 1}), 80); auto [ec, result] = co_await r.resolve(ep); diff --git a/test/doc/reference/signal_set.record.cpp b/test/doc/reference/signal_set.record.cpp index 5d21656da..a5a7aadcc 100644 --- a/test/doc/reference/signal_set.record.cpp +++ b/test/doc/reference/signal_set.record.cpp @@ -23,13 +23,14 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { // Waits for a real SIGINT/SIGTERM if ever launched; compiled, never run. // tag::wait_for_shutdown[] -capy::task<> wait_for_shutdown(corosio::io_context& ctx) +capy::task<> +wait_for_shutdown(corosio::io_context& ctx) { corosio::signal_set signals(ctx, SIGINT, SIGTERM); diff --git a/test/doc/reference/socket_option__broadcast.record.cpp b/test/doc/reference/socket_option__broadcast.record.cpp index cf5861bac..317c04c9c 100644 --- a/test/doc/reference/socket_option__broadcast.record.cpp +++ b/test/doc/reference/socket_option__broadcast.record.cpp @@ -24,11 +24,12 @@ namespace corosio = boost::corosio; namespace { // tag::broadcast[] -void allow_sending_to_a_broadcast_address(corosio::io_context& ioc) +void +allow_sending_to_a_broadcast_address(corosio::io_context& ioc) { corosio::udp_socket sock(ioc); if (auto ec = sock.open(corosio::udp::v4())) - return; // report the error + return; // report the error // Without this the kernel refuses a send_to a broadcast address; the // permission is opt-in so a stray destination cannot flood a segment. diff --git a/test/doc/reference/socket_option__join_group_v4.record.cpp b/test/doc/reference/socket_option__join_group_v4.record.cpp index ea385141a..361c8a862 100644 --- a/test/doc/reference/socket_option__join_group_v4.record.cpp +++ b/test/doc/reference/socket_option__join_group_v4.record.cpp @@ -26,11 +26,12 @@ namespace corosio = boost::corosio; namespace { // tag::join_group_v4[] -void receive_an_ipv4_multicast_group(corosio::io_context& ioc) +void +receive_an_ipv4_multicast_group(corosio::io_context& ioc) { corosio::udp_socket sock(ioc); if (auto ec = sock.open(corosio::udp::v4())) - return; // report the error + return; // report the error // Lets other listeners on this host bind the same port and receive the // same group. set_option reports failure by throwing, not by returning @@ -39,16 +40,17 @@ void receive_an_ipv4_multicast_group(corosio::io_context& ioc) // Bind before joining: a membership attaches to the socket's local port, // so there is nothing for the join to attach to until the bind succeeds. - if (auto ec = sock.bind( - corosio::endpoint(corosio::ipv4_address::any(), 9000))) - return; // report the error + if (auto ec = + sock.bind(corosio::endpoint(corosio::ipv4_address::any(), 9000))) + return; // report the error // 239.0.0.0/8 is the administratively scoped range, the IPv4 counterpart // of a private address range. The optional second argument names the // local interface to receive on; the default, 0.0.0.0, lets the kernel // choose one. - sock.set_option(corosio::socket_option::join_group_v4( - corosio::ipv4_address("239.255.0.1"))); + sock.set_option( + corosio::socket_option::join_group_v4( + corosio::ipv4_address("239.255.0.1"))); } // end::join_group_v4[] diff --git a/test/doc/reference/socket_option__join_group_v6.record.cpp b/test/doc/reference/socket_option__join_group_v6.record.cpp index b0e1a12cc..1c6e1f349 100644 --- a/test/doc/reference/socket_option__join_group_v6.record.cpp +++ b/test/doc/reference/socket_option__join_group_v6.record.cpp @@ -26,11 +26,12 @@ namespace corosio = boost::corosio; namespace { // tag::join_group_v6[] -void receive_an_ipv6_multicast_group(corosio::io_context& ioc) +void +receive_an_ipv6_multicast_group(corosio::io_context& ioc) { corosio::udp_socket sock(ioc); if (auto ec = sock.open(corosio::udp::v6())) - return; // report the error + return; // report the error // Lets other listeners on this host bind the same port and receive the // same group. set_option reports failure by throwing, not by returning @@ -39,16 +40,17 @@ void receive_an_ipv6_multicast_group(corosio::io_context& ioc) // Bind before joining: a membership attaches to the socket's local port, // so there is nothing for the join to attach to until the bind succeeds. - if (auto ec = sock.bind( - corosio::endpoint(corosio::ipv6_address::any(), 9000))) - return; // report the error + if (auto ec = + sock.bind(corosio::endpoint(corosio::ipv6_address::any(), 9000))) + return; // report the error // ff15::1234 is a transient, site-scoped group: the 1 marks it // non-permanent, the 5 sets the scope. The interface index selects which // link to join on; 0 lets the kernel choose, and if_nametoindex() maps a // name such as "eth0". - sock.set_option(corosio::socket_option::join_group_v6( - corosio::ipv6_address("ff15::1234"), 0)); + sock.set_option( + corosio::socket_option::join_group_v6( + corosio::ipv6_address("ff15::1234"), 0)); } // end::join_group_v6[] diff --git a/test/doc/reference/socket_option__keep_alive.record.cpp b/test/doc/reference/socket_option__keep_alive.record.cpp index 1faa2b7f6..0f7b30381 100644 --- a/test/doc/reference/socket_option__keep_alive.record.cpp +++ b/test/doc/reference/socket_option__keep_alive.record.cpp @@ -22,7 +22,8 @@ namespace corosio = boost::corosio; namespace { // tag::keep_alive[] -void detect_a_peer_that_went_away(corosio::tcp_socket& sock) +void +detect_a_peer_that_went_away(corosio::tcp_socket& sock) { // Probe an idle connection so a peer that vanished without closing is // eventually reported as an error instead of hanging forever. diff --git a/test/doc/reference/socket_option__leave_group_v4.record.cpp b/test/doc/reference/socket_option__leave_group_v4.record.cpp index 7feb27c64..1c61a1a48 100644 --- a/test/doc/reference/socket_option__leave_group_v4.record.cpp +++ b/test/doc/reference/socket_option__leave_group_v4.record.cpp @@ -23,7 +23,8 @@ namespace corosio = boost::corosio; namespace { // tag::leave_group_v4[] -void stop_receiving_an_ipv4_multicast_group(corosio::udp_socket& sock) +void +stop_receiving_an_ipv4_multicast_group(corosio::udp_socket& sock) { // Precondition: sock is open on udp::v4() and joined this group. // @@ -32,8 +33,9 @@ void stop_receiving_an_ipv4_multicast_group(corosio::udp_socket& sock) // attempting to leave a (group, interface) pair the kernel has no // membership for fails with EADDRNOTAVAIL, which set_option reports by // throwing. - sock.set_option(corosio::socket_option::leave_group_v4( - corosio::ipv4_address("239.255.0.1"))); + sock.set_option( + corosio::socket_option::leave_group_v4( + corosio::ipv4_address("239.255.0.1"))); } // end::leave_group_v4[] diff --git a/test/doc/reference/socket_option__leave_group_v6.record.cpp b/test/doc/reference/socket_option__leave_group_v6.record.cpp index 727b5ae0d..48581acac 100644 --- a/test/doc/reference/socket_option__leave_group_v6.record.cpp +++ b/test/doc/reference/socket_option__leave_group_v6.record.cpp @@ -23,7 +23,8 @@ namespace corosio = boost::corosio; namespace { // tag::leave_group_v6[] -void stop_receiving_an_ipv6_multicast_group(corosio::udp_socket& sock) +void +stop_receiving_an_ipv6_multicast_group(corosio::udp_socket& sock) { // Precondition: sock is open on udp::v6() and joined this group. // @@ -32,8 +33,9 @@ void stop_receiving_an_ipv6_multicast_group(corosio::udp_socket& sock) // attempting to leave a (group, interface) pair the kernel has no // membership for fails with EADDRNOTAVAIL, which set_option reports by // throwing. - sock.set_option(corosio::socket_option::leave_group_v6( - corosio::ipv6_address("ff15::1234"), 0)); + sock.set_option( + corosio::socket_option::leave_group_v6( + corosio::ipv6_address("ff15::1234"), 0)); } // end::leave_group_v6[] diff --git a/test/doc/reference/socket_option__linger.record.cpp b/test/doc/reference/socket_option__linger.record.cpp index 5412d8f4c..f6edcbb55 100644 --- a/test/doc/reference/socket_option__linger.record.cpp +++ b/test/doc/reference/socket_option__linger.record.cpp @@ -22,7 +22,8 @@ namespace corosio = boost::corosio; namespace { // tag::linger[] -void control_what_close_does_with_queued_data(corosio::tcp_socket& sock) +void +control_what_close_does_with_queued_data(corosio::tcp_socket& sock) { // A non-zero timeout can make close() block the calling thread for up // to that many seconds. close() also runs from the destructor and from @@ -32,8 +33,8 @@ void control_what_close_does_with_queued_data(corosio::tcp_socket& sock) // close() discards whatever is queued and sends an RST. sock.set_option(corosio::socket_option::linger(true, 5)); - auto opt = sock.get_option(); - bool waits = opt.enabled(); + auto opt = sock.get_option(); + bool waits = opt.enabled(); int seconds = opt.timeout(); } // end::linger[] diff --git a/test/doc/reference/socket_option__multicast_hops_v4.record.cpp b/test/doc/reference/socket_option__multicast_hops_v4.record.cpp index 3a8506fbf..cb431995e 100644 --- a/test/doc/reference/socket_option__multicast_hops_v4.record.cpp +++ b/test/doc/reference/socket_option__multicast_hops_v4.record.cpp @@ -22,7 +22,8 @@ namespace corosio = boost::corosio; namespace { // tag::multicast_hops_v4[] -void limit_how_far_multicast_travels_v4(corosio::udp_socket& sock) +void +limit_how_far_multicast_travels_v4(corosio::udp_socket& sock) { // Precondition: sock is open on udp::v4(). // diff --git a/test/doc/reference/socket_option__multicast_hops_v6.record.cpp b/test/doc/reference/socket_option__multicast_hops_v6.record.cpp index df26c850a..2dd3d3696 100644 --- a/test/doc/reference/socket_option__multicast_hops_v6.record.cpp +++ b/test/doc/reference/socket_option__multicast_hops_v6.record.cpp @@ -22,7 +22,8 @@ namespace corosio = boost::corosio; namespace { // tag::multicast_hops_v6[] -void limit_how_far_multicast_travels_v6(corosio::udp_socket& sock) +void +limit_how_far_multicast_travels_v6(corosio::udp_socket& sock) { // Precondition: sock is open on udp::v6(). // diff --git a/test/doc/reference/socket_option__multicast_interface_v4.record.cpp b/test/doc/reference/socket_option__multicast_interface_v4.record.cpp index 7c19409e8..c9bbb7d6c 100644 --- a/test/doc/reference/socket_option__multicast_interface_v4.record.cpp +++ b/test/doc/reference/socket_option__multicast_interface_v4.record.cpp @@ -23,7 +23,8 @@ namespace corosio = boost::corosio; namespace { // tag::multicast_interface_v4[] -void choose_the_outgoing_interface_v4(corosio::udp_socket& sock) +void +choose_the_outgoing_interface_v4(corosio::udp_socket& sock) { // Precondition: sock is open on udp::v4(). // @@ -31,8 +32,9 @@ void choose_the_outgoing_interface_v4(corosio::udp_socket& sock) // multicast_interface_v6 takes an interface index. The default, // 0.0.0.0, leaves the choice to the routing table -- which on a // multi-homed host is rarely the interface you meant. - sock.set_option(corosio::socket_option::multicast_interface_v4( - corosio::ipv4_address("192.168.1.1"))); + sock.set_option( + corosio::socket_option::multicast_interface_v4( + corosio::ipv4_address("192.168.1.1"))); } // end::multicast_interface_v4[] diff --git a/test/doc/reference/socket_option__multicast_interface_v6.record.cpp b/test/doc/reference/socket_option__multicast_interface_v6.record.cpp index 945d7af33..5f6cdfed7 100644 --- a/test/doc/reference/socket_option__multicast_interface_v6.record.cpp +++ b/test/doc/reference/socket_option__multicast_interface_v6.record.cpp @@ -22,7 +22,8 @@ namespace corosio = boost::corosio; namespace { // tag::multicast_interface_v6[] -void choose_the_outgoing_interface_v6( +void +choose_the_outgoing_interface_v6( corosio::udp_socket& sock, unsigned int if_index) { // Precondition: sock is open on udp::v6(), and if_index is what @@ -31,8 +32,9 @@ void choose_the_outgoing_interface_v6( // IPv6 names an interface by index, where multicast_interface_v4 takes a // local address. Zero, the default, leaves the choice to the routing // table -- which on a multi-homed host is rarely the interface you meant. - sock.set_option(corosio::socket_option::multicast_interface_v6( - static_cast(if_index))); + sock.set_option( + corosio::socket_option::multicast_interface_v6( + static_cast(if_index))); } // end::multicast_interface_v6[] diff --git a/test/doc/reference/socket_option__multicast_loop_v4.record.cpp b/test/doc/reference/socket_option__multicast_loop_v4.record.cpp index 759dc10dc..33a7cb902 100644 --- a/test/doc/reference/socket_option__multicast_loop_v4.record.cpp +++ b/test/doc/reference/socket_option__multicast_loop_v4.record.cpp @@ -22,7 +22,8 @@ namespace corosio = boost::corosio; namespace { // tag::multicast_loop_v4[] -void loop_multicast_back_to_this_host_v4(corosio::udp_socket& sock) +void +loop_multicast_back_to_this_host_v4(corosio::udp_socket& sock) { // Precondition: sock is open on udp::v4(). // diff --git a/test/doc/reference/socket_option__multicast_loop_v6.record.cpp b/test/doc/reference/socket_option__multicast_loop_v6.record.cpp index 337aee6ea..c07347e68 100644 --- a/test/doc/reference/socket_option__multicast_loop_v6.record.cpp +++ b/test/doc/reference/socket_option__multicast_loop_v6.record.cpp @@ -22,7 +22,8 @@ namespace corosio = boost::corosio; namespace { // tag::multicast_loop_v6[] -void loop_multicast_back_to_this_host_v6(corosio::udp_socket& sock) +void +loop_multicast_back_to_this_host_v6(corosio::udp_socket& sock) { // Precondition: sock is open on udp::v6(). // diff --git a/test/doc/reference/socket_option__no_delay.record.cpp b/test/doc/reference/socket_option__no_delay.record.cpp index 33ebe9872..1ab7ddc3a 100644 --- a/test/doc/reference/socket_option__no_delay.record.cpp +++ b/test/doc/reference/socket_option__no_delay.record.cpp @@ -27,13 +27,14 @@ namespace corosio = boost::corosio; namespace { // tag::no_delay[] -void disable_nagle_on_a_connected_socket(corosio::tcp_socket& sock) +void +disable_nagle_on_a_connected_socket(corosio::tcp_socket& sock) { // Send small writes immediately instead of coalescing them. sock.set_option(corosio::socket_option::no_delay(true)); - auto nd = sock.get_option(); - bool disabled = nd.value(); // true: Nagle's algorithm is off + auto nd = sock.get_option(); + bool disabled = nd.value(); // true: Nagle's algorithm is off } // end::no_delay[] diff --git a/test/doc/reference/socket_option__receive_buffer_size.record.cpp b/test/doc/reference/socket_option__receive_buffer_size.record.cpp index 84a33616a..ea9c2390f 100644 --- a/test/doc/reference/socket_option__receive_buffer_size.record.cpp +++ b/test/doc/reference/socket_option__receive_buffer_size.record.cpp @@ -22,14 +22,15 @@ namespace corosio = boost::corosio; namespace { // tag::receive_buffer_size[] -void widen_the_receive_buffer(corosio::tcp_socket& sock) +void +widen_the_receive_buffer(corosio::tcp_socket& sock) { sock.set_option(corosio::socket_option::receive_buffer_size(65536)); // The kernel is free to round the request up or clamp it, so read the // option back rather than assuming the value took effect verbatim. auto opt = sock.get_option(); - int sz = opt.value(); + int sz = opt.value(); } // end::receive_buffer_size[] diff --git a/test/doc/reference/socket_option__reuse_address.record.cpp b/test/doc/reference/socket_option__reuse_address.record.cpp index 2d1f473e3..654e8ccec 100644 --- a/test/doc/reference/socket_option__reuse_address.record.cpp +++ b/test/doc/reference/socket_option__reuse_address.record.cpp @@ -24,10 +24,11 @@ namespace corosio = boost::corosio; namespace { // tag::reuse_address[] -void restart_a_listener_on_the_same_port(corosio::tcp_acceptor& acc) +void +restart_a_listener_on_the_same_port(corosio::tcp_acceptor& acc) { if (auto ec = acc.open(corosio::tcp::v4())) - return; // report the error + return; // report the error // Lets bind() succeed while connections from a previous listener are // still in TIME_WAIT -- the difference between a server that restarts @@ -37,9 +38,9 @@ void restart_a_listener_on_the_same_port(corosio::tcp_acceptor& acc) acc.set_option(corosio::socket_option::reuse_address(true)); if (auto ec = acc.bind(corosio::endpoint(8080))) - return; // report the error + return; // report the error if (auto ec = acc.listen()) - return; // report the error + return; // report the error } // end::reuse_address[] diff --git a/test/doc/reference/socket_option__reuse_port.record.cpp b/test/doc/reference/socket_option__reuse_port.record.cpp index 10733984e..632be0678 100644 --- a/test/doc/reference/socket_option__reuse_port.record.cpp +++ b/test/doc/reference/socket_option__reuse_port.record.cpp @@ -25,10 +25,11 @@ namespace corosio = boost::corosio; namespace { // tag::reuse_port[] -void share_one_port_across_several_acceptors(corosio::tcp_acceptor& acc) +void +share_one_port_across_several_acceptors(corosio::tcp_acceptor& acc) { if (auto ec = acc.open(corosio::tcp::v6())) - return; // report the error + return; // report the error // Every acceptor that sets this -- typically one per thread or process -- // may bind the same port at the same time, and the kernel spreads @@ -40,11 +41,11 @@ void share_one_port_across_several_acceptors(corosio::tcp_acceptor& acc) // std::system_error. acc.set_option(corosio::socket_option::reuse_port(true)); - if (auto ec = acc.bind( - corosio::endpoint(corosio::ipv6_address::any(), 8080))) - return; // report the error + if (auto ec = + acc.bind(corosio::endpoint(corosio::ipv6_address::any(), 8080))) + return; // report the error if (auto ec = acc.listen()) - return; // report the error + return; // report the error } // end::reuse_port[] diff --git a/test/doc/reference/socket_option__send_buffer_size.record.cpp b/test/doc/reference/socket_option__send_buffer_size.record.cpp index e15499c5d..12cf476a0 100644 --- a/test/doc/reference/socket_option__send_buffer_size.record.cpp +++ b/test/doc/reference/socket_option__send_buffer_size.record.cpp @@ -22,7 +22,8 @@ namespace corosio = boost::corosio; namespace { // tag::send_buffer_size[] -void widen_the_send_buffer(corosio::tcp_socket& sock) +void +widen_the_send_buffer(corosio::tcp_socket& sock) { // Room for the kernel to hold data the peer has not acknowledged yet; // worth raising on a high-bandwidth, high-latency path. diff --git a/test/doc/reference/socket_option__v6_only.record.cpp b/test/doc/reference/socket_option__v6_only.record.cpp index 198250ab2..71db54c10 100644 --- a/test/doc/reference/socket_option__v6_only.record.cpp +++ b/test/doc/reference/socket_option__v6_only.record.cpp @@ -25,10 +25,11 @@ namespace corosio = boost::corosio; namespace { // tag::v6_only[] -void accept_ipv6_peers_only(corosio::tcp_acceptor& acc) +void +accept_ipv6_peers_only(corosio::tcp_acceptor& acc) { if (auto ec = acc.open(corosio::tcp::v6())) - return; // report the error + return; // report the error // Set between open() and bind(): once bound, the option no longer moves. // Disabled, an IPv6 acceptor also accepts IPv4 peers and reports them as @@ -40,11 +41,11 @@ void accept_ipv6_peers_only(corosio::tcp_acceptor& acc) // not by returning a code. acc.set_option(corosio::socket_option::v6_only(true)); - if (auto ec = acc.bind( - corosio::endpoint(corosio::ipv6_address::any(), 8080))) - return; // report the error + if (auto ec = + acc.bind(corosio::endpoint(corosio::ipv6_address::any(), 8080))) + return; // report the error if (auto ec = acc.listen()) - return; // report the error + return; // report the error } // end::v6_only[] diff --git a/test/doc/reference/stream_file.record.cpp b/test/doc/reference/stream_file.record.cpp index 4c479d89a..b4e7a42da 100644 --- a/test/doc/reference/stream_file.record.cpp +++ b/test/doc/reference/stream_file.record.cpp @@ -23,24 +23,25 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { // tag::stream_file[] // read_some has an implicit position: it advances automatically after // each call, unlike random_access_file's explicit offset. -capy::task<> read_a_file_until_eof(corosio::io_context& ioc) +capy::task<> +read_a_file_until_eof(corosio::io_context& ioc) { corosio::stream_file f(ioc); if (auto ec = f.open("data.bin", corosio::file_base::read_only)) - co_return; // report the error + co_return; // report the error char buf[4096]; for (;;) { - auto [ec, n] = co_await f.read_some( - capy::mutable_buffer(buf, sizeof(buf))); + auto [ec, n] = + co_await f.read_some(capy::mutable_buffer(buf, sizeof(buf))); if (ec == capy::cond::eof) break; if (ec) diff --git a/test/doc/reference/tcp.record.cpp b/test/doc/reference/tcp.record.cpp index f47fb898b..6bb867119 100644 --- a/test/doc/reference/tcp.record.cpp +++ b/test/doc/reference/tcp.record.cpp @@ -32,14 +32,15 @@ namespace { // open/bind/listen. Precondition: acc is not already open -- open() is a // no-op on an already-open acceptor, so an acceptor left over from a v4 // attempt would silently keep its v4 socket and fail later at bind(). -std::error_code open_an_ipv6_listener(corosio::io_context& ioc) +std::error_code +open_an_ipv6_listener(corosio::io_context& ioc) { corosio::tcp_acceptor acc(ioc); - if (auto ec = acc.open(corosio::tcp::v6())) // IPv6 socket + if (auto ec = acc.open(corosio::tcp::v6())) // IPv6 socket return ec; acc.set_option(corosio::socket_option::reuse_address(true)); - if (auto ec = acc.bind( - corosio::endpoint(corosio::ipv6_address::any(), 8080))) + if (auto ec = + acc.bind(corosio::endpoint(corosio::ipv6_address::any(), 8080))) return ec; if (auto ec = acc.listen()) return ec; diff --git a/test/doc/reference/tcp_acceptor.record.cpp b/test/doc/reference/tcp_acceptor.record.cpp index b428e6302..631d34bce 100644 --- a/test/doc/reference/tcp_acceptor.record.cpp +++ b/test/doc/reference/tcp_acceptor.record.cpp @@ -28,14 +28,15 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { // tag::convenience_construction[] // open + SO_REUSEADDR/SO_EXCLUSIVEADDRUSE + bind + listen in one call. // Throws std::system_error if any of those steps fails. -capy::task<> accept_with_the_convenience_constructor(corosio::io_context& ioc) +capy::task<> +accept_with_the_convenience_constructor(corosio::io_context& ioc) { corosio::tcp_acceptor acc(ioc, corosio::endpoint(8080)); @@ -58,15 +59,16 @@ capy::task<> accept_with_the_convenience_constructor(corosio::io_context& ioc) // open/bind/listen. Precondition: acc is not already open -- open() is a // no-op on an already-open acceptor, so an acceptor left over from a v4 // attempt would silently keep its v4 socket and fail later at bind(). -std::error_code open_ipv6_explicitly(corosio::io_context& ioc) +std::error_code +open_ipv6_explicitly(corosio::io_context& ioc) { corosio::tcp_acceptor acc(ioc); if (auto ec = acc.open(corosio::tcp::v6())) return ec; acc.set_option(corosio::socket_option::reuse_address(true)); acc.set_option(corosio::socket_option::v6_only(true)); - if (auto ec = acc.bind( - corosio::endpoint(corosio::ipv6_address::any(), 8080))) + if (auto ec = + acc.bind(corosio::endpoint(corosio::ipv6_address::any(), 8080))) return ec; if (auto ec = acc.listen()) return ec; diff --git a/test/doc/reference/tcp_acceptor__accept.function.cpp b/test/doc/reference/tcp_acceptor__accept.function.cpp index 6ea79bfbc..860b0c8fd 100644 --- a/test/doc/reference/tcp_acceptor__accept.function.cpp +++ b/test/doc/reference/tcp_acceptor__accept.function.cpp @@ -29,7 +29,7 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { @@ -37,7 +37,8 @@ namespace { // Precondition: acc is open, bound, and listening. peer must share acc's // execution context; constructing it from acc.context() ties the two // structurally instead of leaving the pairing to be asserted in prose. -capy::task<> accept_into_a_reused_socket(corosio::tcp_acceptor& acc) +capy::task<> +accept_into_a_reused_socket(corosio::tcp_acceptor& acc) { // The caller owns peer and can accept into it repeatedly -- its // lifetime outlives any single connection, unlike the value-returning @@ -52,20 +53,20 @@ capy::task<> accept_into_a_reused_socket(corosio::tcp_acceptor& acc) if (ec) co_return; - char msg[] = "ping"; - auto [wec, n] = co_await peer.write_some( - capy::const_buffer(msg, 4)); + char msg[] = "ping"; + auto [wec, n] = co_await peer.write_some(capy::const_buffer(msg, 4)); if (wec) co_return; - peer.close(); // ready to accept the next connection into peer + peer.close(); // ready to accept the next connection into peer } } // end::accept_into_a_reused_socket[] // tag::accept_returning_a_new_socket[] // Precondition: acc is open, bound, and listening. -capy::task<> accept_returning_a_new_socket(corosio::tcp_acceptor& acc) +capy::task<> +accept_returning_a_new_socket(corosio::tcp_acceptor& acc) { // Each call returns a fresh socket sharing acc's execution context -- // there is no caller-owned socket to reuse, unlike accept(tcp_socket&). @@ -73,9 +74,8 @@ capy::task<> accept_returning_a_new_socket(corosio::tcp_acceptor& acc) if (ec) co_return; - char msg[] = "ping"; - auto [wec, n] = co_await peer.write_some( - capy::const_buffer(msg, 4)); + char msg[] = "ping"; + auto [wec, n] = co_await peer.write_some(capy::const_buffer(msg, 4)); if (wec) co_return; } diff --git a/test/doc/reference/tcp_acceptor__get_option.function.cpp b/test/doc/reference/tcp_acceptor__get_option.function.cpp index ba5305296..18cc1a7b1 100644 --- a/test/doc/reference/tcp_acceptor__get_option.function.cpp +++ b/test/doc/reference/tcp_acceptor__get_option.function.cpp @@ -24,7 +24,8 @@ namespace { // tag::get_option[] // Precondition: acc is open (get_option throws bad_file_descriptor // otherwise). -bool reuse_address_is_enabled(corosio::tcp_acceptor& acc) +bool +reuse_address_is_enabled(corosio::tcp_acceptor& acc) { auto opt = acc.get_option(); return opt.value(); diff --git a/test/doc/reference/tcp_acceptor__open.function.cpp b/test/doc/reference/tcp_acceptor__open.function.cpp index ce08b33c0..f17ebf7bc 100644 --- a/test/doc/reference/tcp_acceptor__open.function.cpp +++ b/test/doc/reference/tcp_acceptor__open.function.cpp @@ -31,13 +31,14 @@ namespace { // open/bind/listen. Precondition: acc is not already open -- open() is a // no-op on an already-open acceptor, so an acceptor left over from a v4 // attempt would silently keep its v4 socket and fail later at bind(). -std::error_code open_bind_and_listen(corosio::tcp_acceptor& acc) +std::error_code +open_bind_and_listen(corosio::tcp_acceptor& acc) { if (auto ec = acc.open(corosio::tcp::v6())) return ec; acc.set_option(corosio::socket_option::reuse_address(true)); - if (auto ec = acc.bind( - corosio::endpoint(corosio::ipv6_address::any(), 8080))) + if (auto ec = + acc.bind(corosio::endpoint(corosio::ipv6_address::any(), 8080))) return ec; if (auto ec = acc.listen()) return ec; diff --git a/test/doc/reference/tcp_acceptor__set_option.function.cpp b/test/doc/reference/tcp_acceptor__set_option.function.cpp index 3b03df017..b638ae980 100644 --- a/test/doc/reference/tcp_acceptor__set_option.function.cpp +++ b/test/doc/reference/tcp_acceptor__set_option.function.cpp @@ -31,13 +31,14 @@ namespace { // open/bind/listen. Precondition: acc is not already open -- open() is a // no-op on an already-open acceptor, so an acceptor left over from a v4 // attempt would silently keep its v4 socket and fail later at bind(). -std::error_code open_with_reuse_port(corosio::tcp_acceptor& acc) +std::error_code +open_with_reuse_port(corosio::tcp_acceptor& acc) { if (auto ec = acc.open(corosio::tcp::v6())) return ec; acc.set_option(corosio::socket_option::reuse_port(true)); - if (auto ec = acc.bind( - corosio::endpoint(corosio::ipv6_address::any(), 8080))) + if (auto ec = + acc.bind(corosio::endpoint(corosio::ipv6_address::any(), 8080))) return ec; if (auto ec = acc.listen()) return ec; diff --git a/test/doc/reference/tcp_server.record.cpp b/test/doc/reference/tcp_server.record.cpp index cb4f0c614..302ba6e0a 100644 --- a/test/doc/reference/tcp_server.record.cpp +++ b/test/doc/reference/tcp_server.record.cpp @@ -28,31 +28,33 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { // tag::running_the_server[] // Stopped -> Running: bind before start, start before run. The worker pool // must be built against the same io_context the server itself runs on. -void run_the_server( +void +run_the_server( corosio::io_context& ioc, std::vector> workers) { corosio::tcp_server srv(ioc, ioc.get_executor()); srv.set_workers(std::move(workers)); - if (auto ec = srv.bind( - corosio::endpoint{corosio::ipv4_address::any(), 8080})) - return; // report the error + if (auto ec = + srv.bind(corosio::endpoint{corosio::ipv4_address::any(), 8080})) + return; // report the error srv.start(); - ioc.run(); // Blocks until all work completes + ioc.run(); // Blocks until all work completes } // end::running_the_server[] // tag::graceful_shutdown[] // Precondition: srv is Running, and ioc is the io_context it was started on. // To shut down gracefully, call stop then drain the io_context. -void shut_down_gracefully(corosio::io_context& ioc, corosio::tcp_server& srv) +void +shut_down_gracefully(corosio::io_context& ioc, corosio::tcp_server& srv) { // stop() is the only call here that may come from another context -- // a signal handler or a timer callback typically makes it while the @@ -65,7 +67,7 @@ void shut_down_gracefully(corosio::io_context& ioc, corosio::tcp_server& srv) ioc.run(); // Once ioc.run() returns: - srv.join(); // Wait for accept loops to finish + srv.join(); // Wait for accept loops to finish } // end::graceful_shutdown[] @@ -73,30 +75,31 @@ void shut_down_gracefully(corosio::io_context& ioc, corosio::tcp_server& srv) // Precondition: srv is bound and has workers. The server can be restarted // after a complete shutdown cycle; you must drain the io_context, call // join, and restart the io_context itself before restarting the server. -void restart_after_stop(corosio::io_context& ioc, corosio::tcp_server& srv) +void +restart_after_stop(corosio::io_context& ioc, corosio::tcp_server& srv) { using namespace std::chrono_literals; srv.start(); - ioc.run_for( 10s ); // Run for a while - srv.stop(); // Signal shutdown + ioc.run_for(10s); // Run for a while + srv.stop(); // Signal shutdown // REQUIRED: stop() only requests the accept loops end -- it does not // drive them to completion itself. Only running the executor does: // ioc.run() is what actually finishes the loops and brings // active_accepts_ back to zero. - ioc.run(); // REQUIRED: drain pending completions + ioc.run(); // REQUIRED: drain pending completions // REQUIRED: start() throws std::logic_error if a previous session's // accept loops have not yet reached zero; join blocks until they have. - srv.join(); // REQUIRED: wait for accept loops + srv.join(); // REQUIRED: wait for accept loops // REQUIRED: the reactor scheduler stops itself once its outstanding // work reaches zero (which draining above just caused), so ioc.run() // below would return immediately without restart() -- the posted // accept loops would never actually run, and join() would then block // forever waiting for a completion that never happens. - ioc.restart(); // REQUIRED: io_context must be restarted too + ioc.restart(); // REQUIRED: io_context must be restarted too // Now safe to restart srv.start(); @@ -115,35 +118,37 @@ class my_worker : public corosio::tcp_server::worker_base { corosio::io_context& ctx_; corosio::tcp_socket sock_; + public: - my_worker(corosio::io_context& ctx) - : ctx_(ctx) - , sock_(ctx) + my_worker(corosio::io_context& ctx) : ctx_(ctx), sock_(ctx) {} + + corosio::tcp_socket& socket() override { + return sock_; } - corosio::tcp_socket& socket() override { return sock_; } - void run(corosio::tcp_server::launcher launch) override { - launch(ctx_.get_executor(), [](corosio::tcp_socket* sock) -> capy::task<> - { - // handle connection using sock - co_return; - }(&sock_)); + launch( + ctx_.get_executor(), [](corosio::tcp_socket* sock) -> capy::task<> { + // handle connection using sock + co_return; + }(&sock_)); } }; -auto make_workers(corosio::io_context& ctx, int n) +auto +make_workers(corosio::io_context& ctx, int n) { std::vector> v; v.reserve(n); - for(int i = 0; i < n; ++i) + for (int i = 0; i < n; ++i) v.push_back(std::make_unique(ctx)); return v; } -void build_a_worker_pool() +void +build_a_worker_pool() { corosio::io_context ioc; corosio::tcp_server srv(ioc, ioc.get_executor()); diff --git a/test/doc/reference/tcp_server__join.function.cpp b/test/doc/reference/tcp_server__join.function.cpp index 1d708f114..c2fc1ff72 100644 --- a/test/doc/reference/tcp_server__join.function.cpp +++ b/test/doc/reference/tcp_server__join.function.cpp @@ -21,19 +21,19 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { // tag::correct_usage[] // Precondition: srv is bound and has workers. -void run_server_to_completion( - corosio::io_context& ioc, corosio::tcp_server& srv) +void +run_server_to_completion(corosio::io_context& ioc, corosio::tcp_server& srv) { // main thread srv.start(); - ioc.run(); // Blocks until work completes - srv.join(); // Safe: called after ioc.run() returns + ioc.run(); // Blocks until work completes + srv.join(); // Safe: called after ioc.run() returns } // end::correct_usage[] @@ -44,6 +44,7 @@ class self_joining_worker : public corosio::tcp_server::worker_base corosio::io_context& ctx_; corosio::tcp_socket sock_; corosio::tcp_server& srv_; + public: self_joining_worker(corosio::io_context& ctx, corosio::tcp_server& srv) : ctx_(ctx) @@ -52,13 +53,15 @@ class self_joining_worker : public corosio::tcp_server::worker_base { } - corosio::tcp_socket& socket() override { return sock_; } + corosio::tcp_socket& socket() override + { + return sock_; + } void run(corosio::tcp_server::launcher launch) override { - launch(ctx_.get_executor(), [this]() -> capy::task<> - { - srv_.join(); // DEADLOCK: blocks the executor + launch(ctx_.get_executor(), [this]() -> capy::task<> { + srv_.join(); // DEADLOCK: blocks the executor co_return; }()); } diff --git a/test/doc/reference/tcp_server__set_workers.function.cpp b/test/doc/reference/tcp_server__set_workers.function.cpp index 5ec88b5dc..a4bde704d 100644 --- a/test/doc/reference/tcp_server__set_workers.function.cpp +++ b/test/doc/reference/tcp_server__set_workers.function.cpp @@ -33,7 +33,7 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { @@ -44,21 +44,21 @@ class my_worker : public corosio::tcp_server::worker_base { corosio::io_context& ctx_; corosio::tcp_socket sock_; + public: - my_worker(corosio::io_context& ctx) - : ctx_(ctx) - , sock_(ctx) + my_worker(corosio::io_context& ctx) : ctx_(ctx), sock_(ctx) {} + + corosio::tcp_socket& socket() override { + return sock_; } - corosio::tcp_socket& socket() override { return sock_; } - void run(corosio::tcp_server::launcher launch) override { - launch(ctx_.get_executor(), [](corosio::tcp_socket* sock) -> capy::task<> - { - co_return; - }(&sock_)); + launch( + ctx_.get_executor(), [](corosio::tcp_socket* sock) -> capy::task<> { + co_return; + }(&sock_)); } }; @@ -66,11 +66,11 @@ class my_worker : public corosio::tcp_server::worker_base // Precondition: none the type system enforces on srv's state, but calling // this while srv is running discards any worker mid-connection -- the // idle/active lists are cleared before the new pool is populated. -void configure_the_worker_pool( - corosio::io_context& ctx, corosio::tcp_server& srv) +void +configure_the_worker_pool(corosio::io_context& ctx, corosio::tcp_server& srv) { std::vector> workers; - for(int i = 0; i < 100; ++i) + for (int i = 0; i < 100; ++i) workers.push_back(std::make_unique(ctx)); srv.set_workers(std::move(workers)); } diff --git a/test/doc/reference/tcp_server__start.function.cpp b/test/doc/reference/tcp_server__start.function.cpp index 2ebf4848b..2f6f37cfc 100644 --- a/test/doc/reference/tcp_server__start.function.cpp +++ b/test/doc/reference/tcp_server__start.function.cpp @@ -26,15 +26,16 @@ namespace { // tag::start[] // Precondition: srv is bound and has workers, and is Stopped -- either // fresh, or after a complete prior stop()/run()/join() cycle. -void restart_after_full_drain(corosio::io_context& ioc, corosio::tcp_server& srv) +void +restart_after_full_drain(corosio::io_context& ioc, corosio::tcp_server& srv) { using namespace std::chrono_literals; srv.start(); - ioc.run_for( 1s ); - srv.stop(); // 1. Signal shutdown - ioc.run(); // 2. Drain remaining completions - srv.join(); // 3. Wait for accept loops + ioc.run_for(1s); + srv.stop(); // 1. Signal shutdown + ioc.run(); // 2. Drain remaining completions + srv.join(); // 3. Wait for accept loops // 4. Restart the io_context itself: draining above ran its outstanding // work to zero, which stops it, so io_context::run() below would diff --git a/test/doc/reference/tcp_server__tcp_server.function.cpp b/test/doc/reference/tcp_server__tcp_server.function.cpp index a562d9c41..b7ab741e1 100644 --- a/test/doc/reference/tcp_server__tcp_server.function.cpp +++ b/test/doc/reference/tcp_server__tcp_server.function.cpp @@ -28,15 +28,16 @@ namespace corosio = boost::corosio; namespace { // tag::tcp_server[] -void construct_and_start( +void +construct_and_start( corosio::io_context& ctx, std::vector> workers) { corosio::tcp_server srv(ctx, ctx.get_executor()); srv.set_workers(std::move(workers)); - if (auto ec = srv.bind( - corosio::endpoint{corosio::ipv4_address::any(), 8080})) - return; // report the error + if (auto ec = + srv.bind(corosio::endpoint{corosio::ipv4_address::any(), 8080})) + return; // report the error srv.start(); } // end::tcp_server[] diff --git a/test/doc/reference/tcp_socket.record.cpp b/test/doc/reference/tcp_socket.record.cpp index 310b51a03..42995b1fa 100644 --- a/test/doc/reference/tcp_socket.record.cpp +++ b/test/doc/reference/tcp_socket.record.cpp @@ -23,12 +23,13 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { // tag::connect_and_read[] -capy::task<> connect_and_read(corosio::io_context& ioc) +capy::task<> +connect_and_read(corosio::io_context& ioc) { corosio::tcp_socket s(ioc); @@ -39,8 +40,8 @@ capy::task<> connect_and_read(corosio::io_context& ioc) co_return; char buf[1024]; - auto [read_ec, n] = co_await s.read_some( - capy::mutable_buffer(buf, sizeof(buf))); + auto [read_ec, n] = + co_await s.read_some(capy::mutable_buffer(buf, sizeof(buf))); if (read_ec) co_return; } diff --git a/test/doc/reference/tcp_socket__connect.function.cpp b/test/doc/reference/tcp_socket__connect.function.cpp index d317a0813..591613206 100644 --- a/test/doc/reference/tcp_socket__connect.function.cpp +++ b/test/doc/reference/tcp_socket__connect.function.cpp @@ -21,12 +21,13 @@ #include namespace corosio = boost::corosio; -namespace capy = boost::capy; +namespace capy = boost::capy; namespace { // tag::connect[] -capy::task<> connect_to_a_server(corosio::io_context& ioc, corosio::endpoint ep) +capy::task<> +connect_to_a_server(corosio::io_context& ioc, corosio::endpoint ep) { // s is freshly constructed and so is not yet open: connect() only // opens the socket automatically when it is not already open, using diff --git a/test/doc/reference/tcp_socket__get_option.function.cpp b/test/doc/reference/tcp_socket__get_option.function.cpp index 443013fe1..a31ed75af 100644 --- a/test/doc/reference/tcp_socket__get_option.function.cpp +++ b/test/doc/reference/tcp_socket__get_option.function.cpp @@ -36,7 +36,8 @@ namespace { // Option is always an explicit template argument -- it is never deduced // from sock or from any function argument. template -Option read_option(corosio::tcp_socket& sock) +Option +read_option(corosio::tcp_socket& sock) { return sock.get_option