Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion .drone.star
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ def main(ctx):
docs=False,
coverage=False,
cache_dir='cache')
# Note: liburing-dev is not added to generate()'s package list.
# generate() emits jobs on Ubuntu focal (which has no liburing-dev
# package at all) and jammy (liburing 2.1, which our probe rejects
# for being too old). Either way io_uring stays disabled, so the
# install would just fail focal. The manual jobs below that target
# noble (24.04) explicitly install liburing-dev where it works.

# macOS: generate() skips apple-clang when cxx_range='>=20' because
# ci-automation's compiler_supports() doesn't list C++20 for apple-clang
Expand Down Expand Up @@ -67,7 +73,7 @@ def main(ctx):

# Jobs not covered by generate()
jobs += [
linux_cxx("Valgrind", "clang++-17", packages="clang-17 libc6-dbg libstdc++-12-dev",
linux_cxx("Valgrind", "clang++-17", packages="clang-17 libc6-dbg libstdc++-12-dev liburing-dev",
llvm_os="jammy", llvm_ver="17",
buildscript="drone", buildtype="valgrind",
image="cppalliance/droneubuntu2204:1",
Expand All @@ -82,6 +88,15 @@ def main(ctx):
},
globalenv=globalenv),

# Note: no liburing-dev on the Drone cmake jobs even though the
# noble image has 2.5+. Docker's default seccomp profile blocks
# the io_uring_setup syscall (post-CVE hardening), so io_uring
# tests would compile in but abort at runtime with EPERM
# ('io_uring_queue_init_params: Operation not permitted').
# Without liburing-dev the CMake probe disables the backend and
# the cmake-mainproject/subdirectory jobs exercise epoll only.
# io_uring runtime coverage is provided by the GitHub Actions
# Linux jobs, which run on unrestricted GitHub-hosted runners.
linux_cxx("cmake-mainproject", "g++-13", packages="g++-13",
image="cppalliance/droneubuntu2404:1",
buildtype="cmake-mainproject", buildscript="drone",
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ jobs:
${{ matrix.install }}
build-essential
libssl-dev
liburing-dev
curl zip unzip tar pkg-config

- name: Clone Capy
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/code-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ jobs:
- name: Install Python packages
run: pip install gcovr

- name: Install liburing
run: sudo apt-get update && sudo apt-get install -y liburing-dev

- name: Checkout ci-automation
uses: actions/checkout@v6
with:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
/build/*
!/build/Jamfile
!/build/wolfssl.jam
!/build/has_liburing.cpp
/out/
/CMakeUserPresets.json
/tmpclaude-*-cwd
21 changes: 21 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,27 @@ target_link_libraries(boost_corosio
Boost::capy
Threads::Threads
$<$<PLATFORM_ID:Windows>:ws2_32>)
if(BOOST_COROSIO_HAVE_LIBURING)
# PUBLIC because the io_uring scheduler/op headers are reached from
# public native_*.hpp tag-dispatch wrappers and contain inline calls
# to io_uring_submit / io_uring_wait_cqe_timeout / ... — consumers
# that include those wrappers must link liburing too.
#
# Split BUILD vs INSTALL interface: use the imported target during
# build (brings include dirs + correct library path), but emit a
# raw -luring for install consumers. The boost_install superproject
# path generates its package config from a hard-coded dependency
# whitelist (BoostInstall.cmake) that does not know about liburing,
# so an INSTALL_INTERFACE reference to liburing::liburing leaves
# the consumer with an undefined target. Raw -luring matches asio's
# approach and works as long as liburing-dev is on the system.
target_link_libraries(boost_corosio PUBLIC
$<BUILD_INTERFACE:liburing::liburing>
$<INSTALL_INTERFACE:uring>)
target_compile_definitions(boost_corosio PUBLIC BOOST_COROSIO_HAVE_LIBURING=1)
else()
target_compile_definitions(boost_corosio PUBLIC BOOST_COROSIO_HAVE_LIBURING=0)
endif()
target_compile_definitions(boost_corosio
PUBLIC
BOOST_COROSIO_NO_LIB
Expand Down
28 changes: 28 additions & 0 deletions build/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import ac ;
import config : requires ;
import os ;

constant c20-requires :
[ requires
Expand All @@ -32,6 +33,31 @@ project boost/corosio
lib ws2_32 ;
lib crypt32 ;

# liburing (Linux io_uring proactor). Gated on host OS = Linux because
# io_uring is a Linux-only kernel facility; on other hosts the probe
# would fail noisily (searched-lib uring can't resolve -luring) and
# abort Jamfile parsing. When the host is Linux, check-target-builds
# runs a tiny probe (build/has_liburing.cpp) to detect liburing-dev,
# mirroring the CMake auto-detect behavior. Probe failure => io_uring
# backend disabled at compile time via BOOST_COROSIO_HAVE_LIBURING=0.
if [ os.name ] = LINUX
{
searched-lib uring : : <link>shared ;

exe has_liburing : build/has_liburing.cpp uring ;
explicit has_liburing ;

constant liburing-requirements :
[ check-target-builds has_liburing
: <define>BOOST_COROSIO_HAVE_LIBURING=1 <library>uring
: <define>BOOST_COROSIO_HAVE_LIBURING=0 ]
;
}
else
{
constant liburing-requirements : <define>BOOST_COROSIO_HAVE_LIBURING=0 ;
}

alias corosio_sources : [ glob-tree-ex src/corosio/src : *.cpp ] ;

lib boost_corosio
Expand All @@ -42,10 +68,12 @@ lib boost_corosio
<target-os>windows:<define>_WIN32_WINNT=0x0602
<include>../include
<include>../src/corosio
$(liburing-requirements)
: usage-requirements
<library>/boost/capy//boost_capy
<target-os>windows:<library>ws2_32
<include>../include
$(liburing-requirements)
;

# OpenSSL
Expand Down
35 changes: 35 additions & 0 deletions build/has_liburing.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// Copyright (c) 2026 Michael Vandeberg
//
// 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
//

// Probe file used by build/Jamfile via b2's check-target-builds to detect
// whether a sufficiently recent liburing is installed and linkable. The
// CMake build uses find_package(liburing 2.5); this probe matches that
// requirement by referencing symbols and flags the io_uring backend uses
// that only exist in liburing 2.3+ (multishot accept, cancel-by-fd,
// DEFER_TASKRUN, submit_and_get_events). On Ubuntu 22.04's liburing 2.1
// these are missing and the probe fails, so the io_uring backend is
// correctly disabled.

#include <liburing.h>

int main()
{
struct io_uring ring;
struct io_uring_params params{};
params.flags = IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN;
io_uring_queue_init_params(8, &ring, &params);

struct io_uring_sqe* sqe = io_uring_get_sqe(&ring);
io_uring_prep_multishot_accept(sqe, 0, nullptr, nullptr, 0);
io_uring_prep_cancel_fd(sqe, 0, IORING_ASYNC_CANCEL_ALL);
io_uring_submit_and_get_events(&ring);

io_uring_queue_exit(&ring);
return 0;
}
19 changes: 19 additions & 0 deletions cmake/CorosioBuild.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,21 @@ macro(corosio_resolve_deps)
endif()

find_package(Threads REQUIRED)

# liburing 2.5+ for the optional io_uring backend on Linux.
# Missing or older liburing → io_uring backend is disabled at compile time.
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
find_package(liburing 2.5 QUIET)
if(liburing_FOUND)
message(STATUS "Building with liburing ${liburing_VERSION} — io_uring backend enabled")
set(BOOST_COROSIO_HAVE_LIBURING 1)
else()
message(STATUS "liburing 2.5+ not found — io_uring backend disabled")
set(BOOST_COROSIO_HAVE_LIBURING 0)
endif()
else()
set(BOOST_COROSIO_HAVE_LIBURING 0)
endif()
endmacro()

# corosio_setup_mrdocs()
Expand Down Expand Up @@ -185,6 +200,10 @@ function(corosio_install)
list(APPEND _corosio_config_files
${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindWolfSSL.cmake)
endif()
if(liburing_FOUND)
list(APPEND _corosio_config_files
${CMAKE_CURRENT_SOURCE_DIR}/cmake/Findliburing.cmake)
endif()
install(FILES ${_corosio_config_files}
DESTINATION ${BOOST_COROSIO_INSTALL_CMAKEDIR})
else()
Expand Down
45 changes: 45 additions & 0 deletions cmake/Findliburing.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#
# 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 liburing via pkg-config and expose an imported target liburing::liburing.
# Sets: liburing_FOUND, liburing_VERSION

# The liburing target is linked PUBLIC (see CMakeLists.txt) because the
# io_uring scheduler/op headers are reached from public native_*.hpp
# tag-dispatch wrappers and contain inline calls into liburing. The
# imported target is marked IMPORTED_GLOBAL so it propagates out of any
# add_subdirectory() scope into the consuming parent project, matching
# how the PUBLIC link interface is observed there.

find_package(PkgConfig QUIET)

if(PkgConfig_FOUND)
pkg_check_modules(_liburing QUIET liburing)

if(_liburing_FOUND)
set(liburing_VERSION "${_liburing_VERSION}")

if(NOT TARGET liburing::liburing)
add_library(liburing::liburing INTERFACE IMPORTED)
set_target_properties(liburing::liburing
PROPERTIES IMPORTED_GLOBAL TRUE)
target_include_directories(liburing::liburing
INTERFACE ${_liburing_INCLUDE_DIRS})
target_link_libraries(liburing::liburing
INTERFACE ${_liburing_LINK_LIBRARIES})
target_compile_options(liburing::liburing
INTERFACE ${_liburing_CFLAGS_OTHER})
endif()
endif()
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(liburing
REQUIRED_VARS _liburing_FOUND
VERSION_VAR liburing_VERSION)
5 changes: 5 additions & 0 deletions cmake/boost_corosio-config.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,10 @@ if(@WolfSSL_FOUND@)
find_dependency(WolfSSL)
endif()

if(@liburing_FOUND@)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
find_dependency(liburing 2.5)
endif()

include("${CMAKE_CURRENT_LIST_DIR}/boost_corosio-targets.cmake")
check_required_components(boost_corosio)
67 changes: 67 additions & 0 deletions include/boost/corosio/backend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,73 @@ inline constexpr kqueue_t kqueue{};

#endif // BOOST_COROSIO_HAS_KQUEUE

#if BOOST_COROSIO_HAS_IO_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 posix_signal;
class posix_signal_service;
class posix_resolver;
class posix_resolver_service;

} // namespace detail

/// Backend tag for the Linux io_uring proactor.
struct io_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 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;

/// Create the scheduler and services for this backend.
BOOST_COROSIO_DECL static detail::scheduler&
construct(capy::execution_context&, unsigned concurrency_hint);
};

/// Tag value for selecting the io_uring backend.
inline constexpr io_uring_t io_uring{};

#endif // BOOST_COROSIO_HAS_IO_URING

#if BOOST_COROSIO_HAS_IOCP

namespace detail {
Expand Down
6 changes: 6 additions & 0 deletions include/boost/corosio/detail/intrusive.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ class intrusive_list
return head_ == nullptr;
}

/// Peek at the head element without removing it.
T* front() const noexcept
{
return head_;
}

void push_back(T* w) noexcept
{
auto* n = static_cast<node*>(w);
Expand Down
10 changes: 10 additions & 0 deletions include/boost/corosio/detail/platform.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +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_POSIX 1

#else // !BOOST_COROSIO_MRDOCS
Expand Down Expand Up @@ -57,6 +58,15 @@
#define BOOST_COROSIO_HAS_SELECT 0
#endif

// io_uring - Linux 6.0+ proactor (requires liburing 2.5+ at build time).
// 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
#else
#define BOOST_COROSIO_HAS_IO_URING 0
#endif

// POSIX APIs (signals, resolver, etc.)
#if !defined(_WIN32)
#define BOOST_COROSIO_POSIX 1
Expand Down
8 changes: 8 additions & 0 deletions include/boost/corosio/detail/scheduler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,14 @@ struct BOOST_COROSIO_DECL scheduler

/// Run at most one ready handler without blocking.
virtual std::size_t poll_one() = 0;

/// True if the scheduler is configured for single-threaded use.
/// Default false; overridden by backends that support the mode.
virtual bool is_single_threaded() const noexcept { return false; }

/// Enable or disable single-threaded mode. Default no-op for
/// backends that don't support the mode.
virtual void configure_single_threaded(bool) noexcept {}
};

} // namespace boost::corosio::detail
Expand Down
Loading
Loading