diff --git a/.github/workflows/ci-latest-kernel.yml b/.github/workflows/ci-latest-kernel.yml index 4828140..28508ad 100644 --- a/.github/workflows/ci-latest-kernel.yml +++ b/.github/workflows/ci-latest-kernel.yml @@ -99,6 +99,7 @@ jobs: -DUBLKCPP_BUILD_TESTS=ON \ -DUBLKCPP_BUILD_UBLKCTL=ON \ -DUBLKCPP_TESTS_STATIC_LINK=ON \ + -DCONDY_LINK_STDEXEC=ON \ -DCMAKE_C_COMPILER=clang \ -DCMAKE_CXX_COMPILER=clang++ \ -DCMAKE_BUILD_TYPE=Release diff --git a/.github/workflows/ci-main.yml b/.github/workflows/ci-main.yml index 6b6ef46..60d3bab 100644 --- a/.github/workflows/ci-main.yml +++ b/.github/workflows/ci-main.yml @@ -54,7 +54,7 @@ jobs: -DUBLKCPP_BUILD_TESTS=ON \ -DUBLKCPP_BUILD_UBLKCTL=ON \ -DUBLKCPP_BUILD_EXAMPLES=ON \ - -DUBLKCPP_EXECUTION_BACKEND=stdexec \ + -DCONDY_LINK_STDEXEC=ON \ $SANITIZER_FLAG \ -DCMAKE_C_COMPILER=${{matrix.compiler.cc}} \ -DCMAKE_CXX_COMPILER=${{matrix.compiler.cxx}} \ diff --git a/.github/workflows/ci-static-check.yml b/.github/workflows/ci-static-check.yml index 0f21dfb..57c1ed3 100644 --- a/.github/workflows/ci-static-check.yml +++ b/.github/workflows/ci-static-check.yml @@ -39,6 +39,7 @@ jobs: cmake -B ${{github.workspace}}/build \ -DUBLKCPP_BUILD_TESTS=ON \ -DUBLKCPP_BUILD_UBLKCTL=ON \ + -DCONDY_LINK_STDEXEC=ON \ -DCMAKE_C_COMPILER=clang \ -DCMAKE_CXX_COMPILER=clang++ \ -DCMAKE_BUILD_TYPE=Debug \ diff --git a/.github/workflows/ci-toolchain.yml b/.github/workflows/ci-toolchain.yml index 44993da..faa7a8e 100644 --- a/.github/workflows/ci-toolchain.yml +++ b/.github/workflows/ci-toolchain.yml @@ -20,7 +20,7 @@ jobs: strategy: fail-fast: false matrix: - backend: [ "stdexec", "beman" ] + backend: [ STDEXEC, BEMAN ] compiler: - { cc: gcc, cxx: g++ } - { cc: clang, cxx: clang++ } @@ -49,7 +49,7 @@ jobs: -DUBLKCPP_BUILD_TESTS=ON \ -DUBLKCPP_BUILD_UBLKCTL=ON \ -DUBLKCPP_BUILD_EXAMPLES=ON \ - -DUBLKCPP_EXECUTION_BACKEND=${{ matrix.backend }} \ + -DCONDY_LINK_${{ matrix.backend }}=ON \ -DCMAKE_C_COMPILER=${{matrix.compiler.cc}} \ -DCMAKE_CXX_COMPILER=${{matrix.compiler.cxx}} \ -DCMAKE_BUILD_TYPE=Debug diff --git a/CMakeLists.txt b/CMakeLists.txt index 75f323e..885de91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.13) +cmake_minimum_required(VERSION 3.24) # Version is defined once in the version header. set(UBLKCPP_VERSION_HEADER include/ublk/version.hpp) @@ -20,8 +20,6 @@ option(UBLKCPP_USE_URING_CMD128 "Use IORING_OP_URING_CMD128 for control commands option(UBLKCPP_TESTS_STATIC_LINK "Use static linking for tests" OFF) option(UBLKCPP_TESTS_ASAN "Enable address and undefined behavior sanitizers for tests" OFF) option(UBLKCPP_TESTS_TSAN "Enable thread sanitizer for tests" OFF) -set(UBLKCPP_EXECUTION_BACKEND "stdexec" CACHE STRING - "std::execution implementation used via Condy: stdexec (default) or beman") include(FetchContent) @@ -47,23 +45,11 @@ FetchContent_Declare( add_library(ublkcpp INTERFACE) target_include_directories(ublkcpp INTERFACE include) -target_compile_features(ublkcpp INTERFACE cxx_std_23) # TODO: cxx_std_26 +target_compile_features(ublkcpp INTERFACE cxx_std_20) if(UBLKCPP_USE_URING_CMD128) target_compile_definitions(ublkcpp INTERFACE UBLKCPP_USE_URING_CMD128) endif() -if(UBLKCPP_EXECUTION_BACKEND STREQUAL "beman") - set(CONDY_ENABLE_STDEXEC OFF) - set(CONDY_ENABLE_BEMAN ON) -elseif(UBLKCPP_EXECUTION_BACKEND STREQUAL "stdexec") - set(CONDY_ENABLE_STDEXEC ON) - set(CONDY_ENABLE_BEMAN OFF) -else() - message(FATAL_ERROR - "UBLKCPP_EXECUTION_BACKEND must be 'stdexec' or 'beman', got '" - "${UBLKCPP_EXECUTION_BACKEND}'") -endif() -message(STATUS "ublkcpp: execution backend: ${UBLKCPP_EXECUTION_BACKEND}") add_subdirectory(third_party/condy) target_link_libraries(ublkcpp INTERFACE condy) diff --git a/README.md b/README.md index 6272b63..643b381 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ublk-cpp -![C++](https://img.shields.io/badge/C++-26-blue) +![C++](https://img.shields.io/badge/C++-20-blue) ![License](https://img.shields.io/github/license/condy-cpp/ublk-cpp) ![Release](https://img.shields.io/github/v/release/condy-cpp/ublk-cpp) ![Stars](https://img.shields.io/github/stars/condy-cpp/ublk-cpp?style=social) @@ -10,7 +10,7 @@ ![CI (Static Check)](https://github.com/condy-cpp/ublk-cpp/actions/workflows/ci-static-check.yml/badge.svg?branch=master) ![Deploy Docs](https://github.com/condy-cpp/ublk-cpp/actions/workflows/deploy-docs.yml/badge.svg?branch=master) -ublk-cpp is a C++ library for writing [ublk servers](https://docs.kernel.org/block/ublk.html), targeting the C++26 `std::execution` sender model: +ublk-cpp is a C++ library for writing [ublk servers](https://docs.kernel.org/block/ublk.html), built on the `std::execution` sender model: - **Comprehensive ublk Support** Full coverage of the ublk userspace interface — device lifecycle management, per-queue I/O loops, and advanced features such as user recovery and shm buffer registration. @@ -18,13 +18,9 @@ ublk-cpp is a C++ library for writing [ublk servers](https://docs.kernel.org/blo - **Full io_uring Ecosystem** Built on top of [Condy](https://github.com/condy-cpp/condy), all io_uring operations can be used directly inside your ublk server. -- **C++26 Sender Model** +- **Sender Model** The API is built on `std::execution` senders — composable with standard algorithms and interoperable with any asynchronous driver. -> [!NOTE] -> This repository is experimental and will not reach a stable state until -> `std::execution` (C++26) is finalized. - ## Documentation - **[Online Docs (GitHub Pages)](https://condy-cpp.github.io/ublk-cpp/)** diff --git a/bin/ublkctl.cpp b/bin/ublkctl.cpp index 81b0e2d..cf3c72b 100644 --- a/bin/ublkctl.cpp +++ b/bin/ublkctl.cpp @@ -11,16 +11,17 @@ #include #include #include +#include #include -#include #include +#include #include #include #include #include #include -namespace ex = condy::detail::ex; +namespace ex = ublk::detail::ex; struct AddCmd { uint32_t dev_id = -1; @@ -127,18 +128,20 @@ std::string flags_str(uint64_t flags) noexcept { void dump_dev_info(uint32_t dev_id, const ublksrv_ctrl_dev_info &info, const ublk_params ¶ms) { - std::println("dev id {}: nr_hw_queues {} queue_depth {} block size {} " - "dev_capacity {}", - dev_id, info.nr_hw_queues, info.queue_depth, - 1U << params.basic.logical_bs_shift, params.basic.dev_sectors); - std::println("\tmax rq size {} daemon pid {} state {}", - info.max_io_buf_bytes, info.ublksrv_pid, - state_str(info.state)); - std::println("\tflags 0x{:x} [{}]", info.flags, flags_str(info.flags)); - std::println("\tublkc: {}:{} ublkb: {}:{} owner: {}:{}", - params.devt.char_major, params.devt.char_minor, - params.devt.disk_major, params.devt.disk_minor, info.owner_uid, - info.owner_gid); + std::cout << std::format("dev id {}: nr_hw_queues {} queue_depth {} block " + "size {} dev_capacity {}\n", + dev_id, info.nr_hw_queues, info.queue_depth, + 1U << params.basic.logical_bs_shift, + params.basic.dev_sectors); + std::cout << std::format("\tmax rq size {} daemon pid {} state {}\n", + info.max_io_buf_bytes, info.ublksrv_pid, + state_str(info.state)); + std::cout << std::format("\tflags 0x{:x} [{}]\n", info.flags, + flags_str(info.flags)); + std::cout << std::format("\tublkc: {}:{} ublkb: {}:{} owner: {}:{}\n", + params.devt.char_major, params.devt.char_minor, + params.devt.disk_major, params.devt.disk_minor, + info.owner_uid, info.owner_gid); } std::string cpu_str(const cpu_set_t &cpuset) noexcept { @@ -171,7 +174,8 @@ ex::task dump_queue_affinity(int ctrl_fd, for (uint16_t q_id = 0; q_id < info.nr_hw_queues; q_id++) { cpu_set_t cpuset; co_await ublk::get_queue_affinity(ctrl_fd, info.dev_id, q_id, &cpuset); - std::println("\tqueue {}: affinity({})", q_id, cpu_str(cpuset)); + std::cout << std::format("\tqueue {}: affinity({})\n", q_id, + cpu_str(cpuset)); } } @@ -253,10 +257,11 @@ ex::task run_cmd(int ctrl_fd, const FeaturesCmd &) { uint64_t features = 0; co_await ublk::get_features(ctrl_fd, &features); - std::println("ublk_drv features: 0x{:x}", features); + std::cout << std::format("ublk_drv features: 0x{:x}\n", features); for (const auto &e : FLAG_TABLE) { if (features & e.flag) - std::println("\t{:<20s}: 0x{:x}", e.short_name, e.flag); + std::cout << std::format("\t{:<20s}: 0x{:x}\n", e.short_name, + e.flag); } } @@ -367,7 +372,7 @@ Cmd parse_args(int argc, char *argv[]) { } else if (app.got_subcommand("quiesce")) { return quiesce_opts; } else { - std::unreachable(); + throw std::runtime_error("unhandled subcommand"); } } @@ -391,10 +396,10 @@ int main(int argc, char *argv[]) noexcept(false) { std::visit([&](const auto &c) { return run_cmd(ctrl_fd, c); }, cmd))); } catch (const std::system_error &e) { - std::println(std::cerr, "ublkctl: {}", e.what()); + std::cerr << std::format("ublkctl: {}\n", e.what()); return e.code().value(); } catch (const std::exception &e) { - std::println(std::cerr, "ublkctl: {}", e.what()); + std::cerr << std::format("ublkctl: {}\n", e.what()); return 1; } return 0; diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in index db801f5..df3c270 100644 --- a/docs/Doxyfile.in +++ b/docs/Doxyfile.in @@ -54,7 +54,7 @@ PROJECT_NUMBER = @UBLKCPP_VERSION_STRING@ # for a project that appears at the top of each page and should give viewers a # quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = A ublk library targeting C++26 std::execution. +PROJECT_BRIEF = A ublk library for std::execution. # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 diff --git a/docs/build.md b/docs/build.md index 7c67c36..cec0535 100644 --- a/docs/build.md +++ b/docs/build.md @@ -3,7 +3,7 @@ @brief How to build and integrate ublk-cpp in your project. > [!NOTE] -> ublk-cpp currently depends on condy's **experimental execution integration**, which can be backed by either **stdexec** (default) or **beman/execution**. Once `std::execution` is finalized in C++26, it will migrate to the standard library implementation. +> ublk-cpp requires condy with `std::execution` support. Condy uses the standard library implementation when available, or a fetched backend ([stdexec](https://github.com/NVIDIA/stdexec) or [beman/execution](https://github.com/bemanproject/execution)) enabled through condy's `CONDY_LINK_STDEXEC` / `CONDY_LINK_BEMAN` options. ## Using ublk-cpp as a Submodule @@ -42,7 +42,7 @@ target_link_libraries(my_app PRIVATE ublkcpp) Condy fetches and **statically links liburing** by default (`CONDY_LINK_LIBURING=ON`). To use the liburing installed on your system instead, configure with `CONDY_LINK_LIBURING=OFF`. -ublk-cpp currently also fetches and depends on **[stdexec](https://github.com/NVIDIA/stdexec)**, or **[beman/execution](https://github.com/bemanproject/execution)** when enabled via the `UBLKCPP_EXECUTION_BACKEND` option. Once `std::execution` is finalized in C++26, this dependency is expected to be replaced by the standard library implementation. +ublk-cpp requires condy with `std::execution` support. When the standard library provides it, condy detects it automatically. Otherwise enable a fetched backend with `CONDY_LINK_STDEXEC=ON` ([stdexec](https://github.com/NVIDIA/stdexec)) or `CONDY_LINK_BEMAN=ON` ([beman/execution](https://github.com/bemanproject/execution)). ## Building @@ -55,15 +55,13 @@ ublk-cpp provides CMake options to build tests, the `ublkctl` tool, examples, an | `UBLKCPP_BUILD_EXAMPLES` | Build examples | OFF | | `UBLKCPP_BUILD_DOCS` | Build Doxygen documentation | OFF | | `UBLKCPP_USE_URING_CMD128` | Use `IORING_OP_URING_CMD128` for control commands | ON | -| `UBLKCPP_TESTS_STATIC_LINK` | Use static linking for tests | OFF | -| `UBLKCPP_TESTS_ASAN` | Enable ASan/UBSan for tests | OFF | -| `UBLKCPP_EXECUTION_BACKEND` | `std::execution` implementation used via Condy: `stdexec` or `beman` | `stdexec` | ```bash cmake -B build -S . \ -DUBLKCPP_BUILD_TESTS=ON \ -DUBLKCPP_BUILD_UBLKCTL=ON \ -DUBLKCPP_BUILD_EXAMPLES=ON \ + -DCONDY_LINK_STDEXEC=ON \ -DCMAKE_BUILD_TYPE=Release cmake --build build -j$(nproc) ``` diff --git a/docs/guide.md b/docs/guide.md index 16726b6..588d05b 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -9,6 +9,7 @@ ublk is a kernel framework for implementing block device drivers in userspace. I The runtime is represented by `condy::Runtime`, and a scheduler object can be obtained via `condy::get_scheduler()`. All interfaces provided by ublk-cpp are required to run on that scheduler. ```cpp +namespace ex = std::execution; // or stdexec / beman::execution // sqe128 is required for ublk control cmd condy::Runtime runtime(condy::RuntimeOptions().enable_sqe128()); std::jthread loop([&]() { runtime.run(); }); @@ -180,15 +181,16 @@ Then run `ublk::daemon::run()` and `ublk::daemon::start()` concurrently. After ` ```cpp ex::task wait_signal(int ctrl_fd, int signal_fd, uint32_t dev_id, ex::inplace_stop_source &source) { - std::println("ublk-nop: ublk device {} is running...", dev_id); + std::cout << std::format("ublk-nop: ublk device {} is running...\n", + dev_id); auto parent_token = co_await ex::read_env(ex::get_stop_token); ex::inplace_stop_callback cb{parent_token, - [&] noexcept { source.request_stop(); }}; + [&]() noexcept { source.request_stop(); }}; signalfd_siginfo si; co_await (condy::async_read(signal_fd, condy::buffer(&si, sizeof(si)), 0) | ex::write_env(ex::prop{ex::get_stop_token, source.get_token()})); - std::println("ublk-nop: received signal {}, shutting down...", - si.ssi_signo); + std::cout << std::format( + "ublk-nop: received signal {}, shutting down...\n", si.ssi_signo); co_await ublk::stop_dev(ctrl_fd, dev_id); } // ... diff --git a/examples/loop.cpp b/examples/loop.cpp index 86208b6..2eae2d8 100644 --- a/examples/loop.cpp +++ b/examples/loop.cpp @@ -13,10 +13,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include @@ -26,7 +26,7 @@ #include #include -namespace ex = condy::detail::ex; +namespace ex = ublk::detail::ex; namespace { @@ -163,35 +163,36 @@ static_assert(ublk::QueueHandler); ex::task wait_signal(int ctrl_fd, int signal_fd, uint32_t dev_id, ex::inplace_stop_source &source) { - std::println("ublk-loop: ublk device {} is running...", dev_id); + std::cout << std::format("ublk-loop: ublk device {} is running...\n", + dev_id); auto parent_token = co_await ex::read_env(ex::get_stop_token); - auto stop_request = [&] noexcept { source.request_stop(); }; + auto stop_request = [&]() noexcept { source.request_stop(); }; ex::inplace_stop_callback cb{ parent_token, std::move(stop_request)}; signalfd_siginfo si; co_await (condy::async_read(signal_fd, condy::buffer(&si, sizeof(si)), 0) | ex::write_env(ex::prop{ex::get_stop_token, source.get_token()})); - std::println("ublk-loop: received signal {}, shutting down...", - si.ssi_signo); + std::cout << std::format( + "ublk-loop: received signal {}, shutting down...\n", si.ssi_signo); co_await ublk::stop_dev(ctrl_fd, dev_id); } void print_usage(const char *prog) { - std::println("Usage: {} [OPTIONS] -f ", prog); - std::println( - "Run a ublk loop device backed by a regular file or block device."); - std::println(); - std::println("Options:"); - std::println(" -f backing file or block device (required)"); - std::println( - " -n ublk device id, -1: auto-allocation (default)"); - std::println(" -q nr_hw_queues (default: 1)"); - std::println( - " -d queue depth, max in-flight io commands (default: 64)"); - std::println(" -b io buffer size (default: 524288)"); - std::println( - " -p enable UBLK_F_UNPRIVILEGED_DEV (unprivileged mode)"); - std::println(" -h show this help and exit"); + std::cout << std::format("Usage: {} [OPTIONS] -f \n", prog); + std::cout << "Run a ublk loop device backed by a regular file or block " + "device.\n"; + std::cout << '\n'; + std::cout << "Options:\n"; + std::cout << " -f backing file or block device (required)\n"; + std::cout << " -n ublk device id, -1: auto-allocation " + "(default)\n"; + std::cout << " -q nr_hw_queues (default: 1)\n"; + std::cout << " -d queue depth, max in-flight io commands " + "(default: 64)\n"; + std::cout << " -b io buffer size (default: 524288)\n"; + std::cout << " -p enable UBLK_F_UNPRIVILEGED_DEV " + "(unprivileged mode)\n"; + std::cout << " -h show this help and exit\n"; } } // namespace @@ -245,24 +246,24 @@ int main(int argc, char *argv[]) noexcept(false) { "open backing file"); } auto d_backing = - ublk::detail::defer([&] noexcept { close(backing_fd); }); + ublk::detail::defer([&]() noexcept { close(backing_fd); }); int flags = fcntl(backing_fd, F_GETFL); if (flags >= 0 && fcntl(backing_fd, F_SETFL, flags | O_DIRECT) < 0) { - std::println( - std::cerr, - "ublk-loop: failed to set O_DIRECT on backing file: {}", + std::cerr << std::format( + "ublk-loop: failed to set O_DIRECT on backing " + "file: {}\n", std::strerror(errno)); } FileInfo file_info; lo_file_size(backing_fd, file_info); uint64_t dev_sectors = file_info.size / SECTOR_SIZE; - std::println("ublk-loop: backing file {} ({} bytes, {} sectors, " - "logical {}B, physical {}B)", - backing_path, file_info.size, dev_sectors, - 1u << file_info.logical_bs_shift, - 1u << file_info.physical_bs_shift); + std::cout << std::format("ublk-loop: backing file {} ({} bytes, {}" + " sectors, logical {}B, physical {}B)\n", + backing_path, file_info.size, dev_sectors, + 1u << file_info.logical_bs_shift, + 1u << file_info.physical_bs_shift); sigset_t mask; sigemptyset(&mask); @@ -274,20 +275,20 @@ int main(int argc, char *argv[]) noexcept(false) { if (signal_fd < 0) { throw std::system_error(errno, std::generic_category(), "signalfd"); } - auto d = ublk::detail::defer([&] noexcept { close(signal_fd); }); + auto d = ublk::detail::defer([&]() noexcept { close(signal_fd); }); int ctrl_fd = open("/dev/ublk-control", O_RDWR | O_CLOEXEC); if (ctrl_fd < 0) { throw std::system_error(errno, std::generic_category(), "open /dev/ublk-control"); } - auto d2 = ublk::detail::defer([&] noexcept { close(ctrl_fd); }); + auto d2 = ublk::detail::defer([&]() noexcept { close(ctrl_fd); }); condy::RuntimeOptions options; options.enable_sqe128(); condy::Runtime runtime(options); std::jthread loop([&]() { runtime.run(); }); - auto d3 = ublk::detail::defer([&] noexcept { runtime.allow_exit(); }); + auto d3 = ublk::detail::defer([&]() noexcept { runtime.allow_exit(); }); ex::scheduler auto sched = condy::get_scheduler(runtime); uint64_t features; @@ -334,10 +335,10 @@ int main(int argc, char *argv[]) noexcept(false) { ex::sync_wait(ex::starts_on(sched, s)); } catch (const std::system_error &e) { - std::println(std::cerr, "ublk-loop: {}", e.what()); + std::cerr << std::format("ublk-loop: {}\n", e.what()); return e.code().value(); } catch (const std::exception &e) { - std::println(std::cerr, "ublk-loop: {}", e.what()); + std::cerr << std::format("ublk-loop: {}\n", e.what()); return 1; } diff --git a/examples/nop.cpp b/examples/nop.cpp index bcf31d4..4b22cff 100644 --- a/examples/nop.cpp +++ b/examples/nop.cpp @@ -11,16 +11,16 @@ #include #include #include +#include #include #include -#include #include #include #include #include #include -namespace ex = condy::detail::ex; +namespace ex = ublk::detail::ex; void prep_dev_info(ublksrv_ctrl_dev_info &info, uint32_t dev_id, uint64_t flags) noexcept { @@ -46,26 +46,27 @@ void prep_params(ublk_params ¶ms, } void print_usage(const char *prog) { - std::println("Usage: {} -n ", prog); - std::println("Run a no-op ublk block device."); - std::println(); - std::println("Options:"); - std::println(" -n ublk device id to use"); - std::println(" -h show this help and exit"); + std::cout << std::format("Usage: {} -n \n", prog); + std::cout << "Run a no-op ublk block device.\n"; + std::cout << '\n'; + std::cout << "Options:\n"; + std::cout << " -n ublk device id to use\n"; + std::cout << " -h show this help and exit\n"; } ex::task wait_signal(int ctrl_fd, int signal_fd, uint32_t dev_id, ex::inplace_stop_source &source) { - std::println("ublk-nop: ublk device {} is running...", dev_id); + std::cout << std::format("ublk-nop: ublk device {} is running...\n", + dev_id); auto parent_token = co_await ex::read_env(ex::get_stop_token); - auto stop_request = [&] noexcept { source.request_stop(); }; + auto stop_request = [&]() noexcept { source.request_stop(); }; ex::inplace_stop_callback cb{ parent_token, std::move(stop_request)}; signalfd_siginfo si; co_await (condy::async_read(signal_fd, condy::buffer(&si, sizeof(si)), 0) | ex::write_env(ex::prop{ex::get_stop_token, source.get_token()})); - std::println("ublk-nop: received signal {}, shutting down...", - si.ssi_signo); + std::cout << std::format("ublk-nop: received signal {}, shutting down...\n", + si.ssi_signo); co_await ublk::stop_dev(ctrl_fd, dev_id); } @@ -96,20 +97,20 @@ int main(int argc, char *argv[]) noexcept(false) { if (signal_fd < 0) { throw std::system_error(errno, std::generic_category(), "signalfd"); } - auto d = ublk::detail::defer([&] noexcept { close(signal_fd); }); + auto d = ublk::detail::defer([&]() noexcept { close(signal_fd); }); int ctrl_fd = open("/dev/ublk-control", O_RDWR | O_CLOEXEC); if (ctrl_fd < 0) { throw std::system_error(errno, std::generic_category(), "open /dev/ublk-control"); } - auto d2 = ublk::detail::defer([&] noexcept { close(ctrl_fd); }); + auto d2 = ublk::detail::defer([&]() noexcept { close(ctrl_fd); }); condy::RuntimeOptions options; options.enable_sqe128(); condy::Runtime runtime(options); std::jthread loop([&]() { runtime.run(); }); - auto d3 = ublk::detail::defer([&] noexcept { runtime.allow_exit(); }); + auto d3 = ublk::detail::defer([&]() noexcept { runtime.allow_exit(); }); ex::scheduler auto sched = condy::get_scheduler(runtime); uint64_t features; @@ -154,10 +155,10 @@ int main(int argc, char *argv[]) noexcept(false) { ex::sync_wait(ex::starts_on(sched, s)); } catch (const std::system_error &e) { - std::println(std::cerr, "ublk-nop: {}", e.what()); + std::cerr << std::format("ublk-nop: {}\n", e.what()); return e.code().value(); } catch (const std::exception &e) { - std::println(std::cerr, "ublk-nop: {}", e.what()); + std::cerr << std::format("ublk-nop: {}\n", e.what()); return 1; } diff --git a/include/ublk/detail/control.hpp b/include/ublk/detail/control.hpp index f9206c3..dcf7822 100644 --- a/include/ublk/detail/control.hpp +++ b/include/ublk/detail/control.hpp @@ -5,6 +5,7 @@ #pragma once +#include "ublk/detail/execution.hpp" #include "ublk/detail/path.hpp" #include "ublk/detail/retry.hpp" #include "ublk/detail/task.hpp" @@ -16,8 +17,6 @@ namespace ublk { namespace detail { -namespace ex = condy::detail::ex; - struct control_get_dev_info_t { template ex::task> invoke(int fd, uint32_t dev_id, diff --git a/include/ublk/detail/daemon.hpp b/include/ublk/detail/daemon.hpp index 2b59f88..10d15ab 100644 --- a/include/ublk/detail/daemon.hpp +++ b/include/ublk/detail/daemon.hpp @@ -7,6 +7,7 @@ #pragma once #include "ublk/detail/control.hpp" +#include "ublk/detail/execution.hpp" #include "ublk/detail/io.hpp" #include "ublk/detail/io_loop.hpp" #include "ublk/detail/shm.hpp" @@ -20,8 +21,6 @@ namespace ublk { namespace detail { -namespace ex = condy::detail::ex; - inline bool need_recovery(const ublksrv_ctrl_dev_info *info) noexcept { return info->state == UBLK_S_DEV_QUIESCED || info->state == UBLK_S_DEV_FAIL_IO; @@ -138,7 +137,7 @@ struct daemon_run_t { std::string path = dev_path(dev_id); int ublkc_fd = co_await condy::async_open(path.c_str(), O_RDWR, 0); - auto d = defer([&] noexcept { close(ublkc_fd); }); + auto d = defer([&]() noexcept { close(ublkc_fd); }); ex::simple_counting_scope scope; AllocVector errs(info.nr_hw_queues, diff --git a/include/ublk/detail/execution.hpp b/include/ublk/detail/execution.hpp new file mode 100644 index 0000000..f4230a4 --- /dev/null +++ b/include/ublk/detail/execution.hpp @@ -0,0 +1,20 @@ +/** + * @file execution.hpp + * @brief The std::execution backend namespace used by ublk-cpp. + */ + +#pragma once + +#include + +#ifndef CONDY_DETAIL_HAS_EXECUTION +#error "ublk-cpp requires a condy backend for std::execution" +#endif + +namespace ublk { +namespace detail { + +namespace ex = condy::detail::ex; + +} // namespace detail +} // namespace ublk diff --git a/include/ublk/detail/io.hpp b/include/ublk/detail/io.hpp index 890450a..fa1a4e0 100644 --- a/include/ublk/detail/io.hpp +++ b/include/ublk/detail/io.hpp @@ -6,6 +6,7 @@ #pragma once +#include "ublk/detail/execution.hpp" #include "ublk/detail/queue.hpp" #include "ublk/detail/task.hpp" #include "ublk/handler.hpp" @@ -16,8 +17,6 @@ namespace ublk { namespace detail { -namespace ex = condy::detail::ex; - struct io_run_dev_t { template ex::task> @@ -43,7 +42,7 @@ struct io_run_dev_t { constexpr int UBLKC_FD = 0; auto &fd_table = condy::current_runtime().fd_table(); auto r = fd_table.update(UBLKC_FD, &ublkc_fd, 1); - auto d = defer([&] noexcept { + auto d = defer([&]() noexcept { if (r >= 0) { int fd = -1; fd_table.update(UBLKC_FD, &fd, 1); // unregister diff --git a/include/ublk/detail/io_loop.hpp b/include/ublk/detail/io_loop.hpp index 128919d..fc53cd7 100644 --- a/include/ublk/detail/io_loop.hpp +++ b/include/ublk/detail/io_loop.hpp @@ -33,7 +33,7 @@ class IoLoop { "buffer_table init"); } } - thread_ = std::jthread([this, cpuset] { run_(cpuset); }); + thread_ = std::jthread([this, cpuset]() { run_(cpuset); }); } IoLoop(const IoLoop &) = delete; diff --git a/include/ublk/detail/queue.hpp b/include/ublk/detail/queue.hpp index 080cb99..c847813 100644 --- a/include/ublk/detail/queue.hpp +++ b/include/ublk/detail/queue.hpp @@ -5,6 +5,7 @@ #pragma once +#include "ublk/detail/execution.hpp" #include "ublk/detail/task.hpp" #include "ublk/detail/utils.hpp" #include "ublk/handler.hpp" @@ -24,8 +25,6 @@ namespace ublk { namespace detail { -namespace ex = condy::detail::ex; - inline bool need_alloc_buf(uint64_t flags) noexcept { return !(flags & (UBLK_F_SUPPORT_ZERO_COPY | UBLK_F_USER_COPY)); } @@ -117,7 +116,7 @@ template class IoQueue { queue_depth_(queue_depth), max_io_buf_bytes_(max_io_buf_bytes), handler_(handler), alloc_(alloc) { bool ok = false; - auto d = defer([&] noexcept { + auto d = defer([&]() noexcept { if (!ok) { cleanup_(); } @@ -304,7 +303,7 @@ template class BatchIoQueue { queue_depth_(queue_depth), max_io_buf_bytes_(max_io_buf_bytes), handler_(handler), alloc_(alloc) { bool ok = false; - auto d = defer([&] noexcept { + auto d = defer([&]() noexcept { if (!ok) { cleanup_(); } @@ -414,7 +413,7 @@ template class BatchIoQueue { ex::upon_error([&, tag](const std::exception_ptr &ep) noexcept { worker_errs[tag] = ep; }) | - ex::then([&] noexcept { + ex::then([&]() noexcept { if (--running_workers == 0) { flusher.futex.notify_one(); } diff --git a/include/ublk/detail/retry.hpp b/include/ublk/detail/retry.hpp index dfc6576..338f729 100644 --- a/include/ublk/detail/retry.hpp +++ b/include/ublk/detail/retry.hpp @@ -1,5 +1,6 @@ #pragma once +#include "ublk/detail/execution.hpp" #include "ublk/detail/task.hpp" #include #include @@ -9,8 +10,6 @@ namespace ublk { namespace detail { -namespace ex = condy::detail::ex; - template inline ex::task> retry(Fn fn, size_t max_retry, int64_t sleep_ms) { diff --git a/include/ublk/detail/shm.hpp b/include/ublk/detail/shm.hpp index 1e22d38..ca7a74e 100644 --- a/include/ublk/detail/shm.hpp +++ b/include/ublk/detail/shm.hpp @@ -7,6 +7,7 @@ #pragma once #include "ublk/detail/control.hpp" +#include "ublk/detail/execution.hpp" #include "ublk/detail/task.hpp" #include "ublk/handler.hpp" #include @@ -19,8 +20,6 @@ namespace ublk { namespace detail { -namespace ex = condy::detail::ex; - template inline ex::task> shm_session(int client_fd, Session session, ex::counting_scope &scope) { @@ -108,7 +107,7 @@ template inline ex::task> shm_server_run(std::string_view path, Session session) { int server_fd = co_await condy::async_socket(AF_UNIX, SOCK_STREAM, 0, 0); - auto d = defer([&] noexcept { close(server_fd); }); + auto d = defer([&]() noexcept { close(server_fd); }); sockaddr_un addr = {}; addr.sun_family = AF_UNIX; @@ -128,7 +127,7 @@ shm_server_run(std::string_view path, Session session) { co_await condy::async_bind(server_fd, reinterpret_cast(&addr), sizeof(addr)); - auto d2 = defer([&] noexcept { unlink(addr.sun_path); }); + auto d2 = defer([&]() noexcept { unlink(addr.sun_path); }); co_await condy::async_listen(server_fd, 128); ex::counting_scope scope; diff --git a/include/ublk/detail/task.hpp b/include/ublk/detail/task.hpp index 6ab022c..b4d24c8 100644 --- a/include/ublk/detail/task.hpp +++ b/include/ublk/detail/task.hpp @@ -5,6 +5,7 @@ #pragma once +#include "ublk/detail/execution.hpp" #include "ublk/query.hpp" #include "ublk/ublk_cmd.h" #include @@ -12,8 +13,6 @@ namespace ublk { namespace detail { -namespace ex = condy::detail::ex; - template struct TaskEnv { using start_scheduler_type = Sched; using allocator_type = Alloc; diff --git a/include/ublk/handler.hpp b/include/ublk/handler.hpp index 1bf40cc..db68d24 100644 --- a/include/ublk/handler.hpp +++ b/include/ublk/handler.hpp @@ -5,6 +5,7 @@ #pragma once +#include "ublk/detail/execution.hpp" #include "ublk/ublk_cmd.h" #include #include @@ -13,10 +14,6 @@ namespace ublk { -namespace detail { -namespace ex = condy::detail::ex; -} - /** * @brief Context of a single I/O request delivered to a handler. */ diff --git a/include/ublk/query.hpp b/include/ublk/query.hpp index ae55a1a..6b83409 100644 --- a/include/ublk/query.hpp +++ b/include/ublk/query.hpp @@ -5,16 +5,13 @@ #pragma once +#include "ublk/detail/execution.hpp" #include "ublk/ublk_cmd.h" #include #include namespace ublk { -namespace detail { -namespace ex = condy::detail::ex; -} - /** * @brief Environment query for the cached ublk device info. Returns nullptr if * the environment doesn't provide it. diff --git a/tests/helpers.hpp b/tests/helpers.hpp index 8dd718d..0aea6df 100644 --- a/tests/helpers.hpp +++ b/tests/helpers.hpp @@ -139,15 +139,15 @@ struct ZeroHandler { ZeroHandler(const ZeroHandler &) = delete; ZeroHandler &operator=(const ZeroHandler &) = delete; - condy::detail::ex::task handle_reg_shm(int32_t index, void *base, - size_t size) noexcept { + ublk::detail::ex::task handle_reg_shm(int32_t index, void *base, + size_t size) noexcept { shm_bufs_[index] = ShmBuf{base, size}; co_return; } void handle_unreg_shm(int32_t index) noexcept { shm_bufs_.erase(index); } - condy::detail::ex::task + ublk::detail::ex::task handle_io(const ublk::IoData &data) noexcept { uint64_t start = data.iod->start_sector * 512; uint32_t nbytes = data.iod->nr_sectors * 512; diff --git a/tests/test_control.cpp b/tests/test_control.cpp index 5ae0b92..7e67f59 100644 --- a/tests/test_control.cpp +++ b/tests/test_control.cpp @@ -8,7 +8,7 @@ #include #include -namespace ex = condy::detail::ex; +namespace ex = ublk::detail::ex; TEST_CASE("test control") { ublk::detail::IoLoop loop(condy::RuntimeOptions().enable_sqe128(), 0, 0, diff --git a/tests/test_daemon.cpp b/tests/test_daemon.cpp index 02ba6bf..3923f32 100644 --- a/tests/test_daemon.cpp +++ b/tests/test_daemon.cpp @@ -8,7 +8,7 @@ #include #include -namespace ex = condy::detail::ex; +namespace ex = ublk::detail::ex; TEST_CASE("test daemon") { ublk::detail::IoLoop loop(condy::RuntimeOptions().enable_sqe128(), 0, 0, diff --git a/tests/test_io.cpp b/tests/test_io.cpp index eabc639..2c8dc4b 100644 --- a/tests/test_io.cpp +++ b/tests/test_io.cpp @@ -7,7 +7,7 @@ #include #include -namespace ex = condy::detail::ex; +namespace ex = ublk::detail::ex; TEST_CASE("test io") { ublk::detail::IoLoop loop(condy::RuntimeOptions().enable_sqe128(), 0, 32, diff --git a/tests/test_query.cpp b/tests/test_query.cpp index f4aa286..83a1b43 100644 --- a/tests/test_query.cpp +++ b/tests/test_query.cpp @@ -8,7 +8,7 @@ #include #include -namespace ex = condy::detail::ex; +namespace ex = ublk::detail::ex; TEST_CASE("test query - fetch_dev_info defaults to nullptr") { ex::env empty{}; diff --git a/tests/test_raw.cpp b/tests/test_raw.cpp index fc400d5..4aa1b34 100644 --- a/tests/test_raw.cpp +++ b/tests/test_raw.cpp @@ -8,7 +8,7 @@ #include #include -namespace ex = condy::detail::ex; +namespace ex = ublk::detail::ex; TEST_CASE("test raw - privileged") { ublk::detail::IoLoop loop(condy::RuntimeOptions().enable_sqe128(), 0, 0, diff --git a/tests/test_shm.cpp b/tests/test_shm.cpp index fea17cd..7c03e9c 100644 --- a/tests/test_shm.cpp +++ b/tests/test_shm.cpp @@ -13,7 +13,7 @@ #include #include -namespace ex = condy::detail::ex; +namespace ex = ublk::detail::ex; namespace { diff --git a/third_party/condy b/third_party/condy index 0181a81..16b7c83 160000 --- a/third_party/condy +++ b/third_party/condy @@ -1 +1 @@ -Subproject commit 0181a81cae1902e07663302eb55c281ae15cee9c +Subproject commit 16b7c83b8ea30d6f8efa44c1d4d39a70093d69c6