Skip to content
Closed
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
29 changes: 29 additions & 0 deletions include/condy/async_operations.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,22 @@ inline auto async_socket_direct(int domain, int type, int protocol,
file_index, flags);
}

#if !IO_URING_CHECK_VERSION(2, 13) // >= 2.13
Comment thread
wokron marked this conversation as resolved.
/**
* @brief See io_uring_prep_uring_cmd
*/
template <FdLike Fd, typename CmdFunc>
inline auto async_uring_cmd(int cmd_op, Fd fd, CmdFunc &&cmd_func) {
auto prep_func = [cmd_op, fd, cmd_func = std::forward<CmdFunc>(cmd_func)](
io_uring_sqe *sqe) {
io_uring_prep_uring_cmd(sqe, cmd_op, fd);
cmd_func(sqe);
};
auto op = make_op_awaiter(std::move(prep_func));
return detail::maybe_flag_fixed_fd(std::move(op), fd);
Comment on lines +841 to +848
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

async_uring_cmd routes the user-supplied cmd_func through make_op_awaiter, which ultimately calls it from a const lambda. This implicitly requires cmd_func to be const-invocable; passing a callable with a non-const operator() (e.g., a mutable lambda) will fail to compile. Consider constructing the final SQE-prep lambda directly (capturing cmd_op, fd, and a decayed cmd_func) so the callback can be invoked without the extra wrapper and without the const-invocable restriction.

Copilot uses AI. Check for mistakes.
}
#endif

#if !IO_URING_CHECK_VERSION(2, 5) // >= 2.5
/**
* @brief See io_uring_prep_cmd_sock
Expand All @@ -846,6 +862,19 @@ inline auto async_cmd_sock(int cmd_op, Fd fd, int level, int optname,
}
#endif

#if !IO_URING_CHECK_VERSION(2, 13) // >= 2.13
Comment thread
wokron marked this conversation as resolved.
/**
* @brief See io_uring_prep_cmd_getsockname
*/
template <FdLike Fd>
inline auto async_cmd_getsockname(Fd fd, struct sockaddr *sockaddr,
socklen_t *sockaddr_len, int peer) {
auto op = make_op_awaiter(io_uring_prep_cmd_getsockname, fd, sockaddr,
sockaddr_len, peer);
return detail::maybe_flag_fixed_fd(std::move(op), fd);
}
#endif

#if !IO_URING_CHECK_VERSION(2, 6) // >= 2.6
/**
* @brief See io_uring_prep_waitid
Expand Down
109 changes: 107 additions & 2 deletions tests/test_async_operations.4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,13 +267,75 @@ TEST_CASE("test async_operations - test socket - direct") {
condy::sync_wait(func());
}

#if !IO_URING_CHECK_VERSION(2, 13) // >= 2.13
TEST_CASE("test async_operations - test uring_cmd - basic") {
auto my_async_cmd_sock = [](int cmd_op, int fd, int level, int optname,
void *optval, int optlen) {
return condy::async_uring_cmd(cmd_op, fd, [=](io_uring_sqe *sqe) {
sqe->optval = (unsigned long)(uintptr_t)optval;
sqe->optname = optname;
sqe->optlen = optlen;
sqe->level = level;
});
Comment thread
wokron marked this conversation as resolved.
};

int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
REQUIRE(listen_fd >= 0);

auto func = [&]() -> condy::Coro<void> {
int val = 1;
int r = co_await my_async_cmd_sock(SOCKET_URING_OP_SETSOCKOPT,
listen_fd, SOL_SOCKET, SO_REUSEADDR,
&val, sizeof(val));
REQUIRE(r == 0);
};
condy::sync_wait(func());

close(listen_fd);
}
#endif

#if !IO_URING_CHECK_VERSION(2, 13) // >= 2.13
TEST_CASE("test async_operations - test uring_cmd - fixed fd") {
auto my_async_cmd_sock_fixed = [](int cmd_op, int fd, int level,
int optname, void *optval, int optlen) {
return condy::async_uring_cmd(
cmd_op, condy::fixed(fd), [=](io_uring_sqe *sqe) {
sqe->optval = (unsigned long)(uintptr_t)optval;
sqe->optname = optname;
sqe->optlen = optlen;
sqe->level = level;
});
Comment thread
wokron marked this conversation as resolved.
};

int listen_fd = create_accept_socket();

auto func = [&]() -> condy::Coro<void> {
auto &fd_table = condy::current_runtime().fd_table();
fd_table.init(1);
int r = co_await condy::async_files_update(&listen_fd, 1, 0);
REQUIRE(r == 1);

int val = 1;
r = co_await my_async_cmd_sock_fixed(SOCKET_URING_OP_SETSOCKOPT, 0,
SOL_SOCKET, SO_REUSEADDR, &val,
sizeof(val));
REQUIRE(r == 0);
};

condy::sync_wait(func());

close(listen_fd);
}
#endif

#if !IO_URING_CHECK_VERSION(2, 5) // >= 2.5
TEST_CASE("test async_operations - test cmd_sock - basic") {
int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
REQUIRE(listen_fd >= 0);

auto func = [&]() -> condy::Coro<void> {
int val;
int val = 1;
int r = co_await condy::async_cmd_sock(SOCKET_URING_OP_SETSOCKOPT,
listen_fd, SOL_SOCKET,
SO_REUSEADDR, &val, sizeof(val));
Expand All @@ -295,7 +357,7 @@ TEST_CASE("test async_operations - test cmd_sock - fixed fd") {
int r = co_await condy::async_files_update(&listen_fd, 1, 0);
REQUIRE(r == 1);

int val;
int val = 1;
r = co_await condy::async_cmd_sock(SOCKET_URING_OP_SETSOCKOPT,
condy::fixed(0), SOL_SOCKET,
SO_REUSEADDR, &val, sizeof(val));
Expand All @@ -306,6 +368,49 @@ TEST_CASE("test async_operations - test cmd_sock - fixed fd") {
}
#endif

#if !IO_URING_CHECK_VERSION(2, 13) // >= 2.13
TEST_CASE("test async_operations - test cmd_getsockname - basic") {
int listen_fd = create_accept_socket();

auto func = [&]() -> condy::Coro<void> {
struct sockaddr_in addr {};
socklen_t addrlen = sizeof(addr);
int r = co_await condy::async_cmd_getsockname(
listen_fd, (struct sockaddr *)&addr, &addrlen, 0);
REQUIRE(r == 0);
REQUIRE(addrlen == sizeof(addr));
REQUIRE(addr.sin_family == AF_INET);
};
condy::sync_wait(func());

close(listen_fd);
}
#endif

#if !IO_URING_CHECK_VERSION(2, 13) // >= 2.13
TEST_CASE("test async_operations - test cmd_getsockname - fixed fd") {
int listen_fd = create_accept_socket();

auto func = [&]() -> condy::Coro<void> {
auto &fd_table = condy::current_runtime().fd_table();
fd_table.init(1);
int r = co_await condy::async_files_update(&listen_fd, 1, 0);
REQUIRE(r == 1);

struct sockaddr_in addr {};
socklen_t addrlen = sizeof(addr);
r = co_await condy::async_cmd_getsockname(
condy::fixed(0), (struct sockaddr *)&addr, &addrlen, 0);
REQUIRE(r == 0);
REQUIRE(addrlen == sizeof(addr));
REQUIRE(addr.sin_family == AF_INET);
};
condy::sync_wait(func());

close(listen_fd);
}
#endif

#if !IO_URING_CHECK_VERSION(2, 6) // >= 2.6
TEST_CASE("test async_operations - test waitid") {
pid_t pid = fork();
Expand Down
Loading