From 81a7fb77c69b426da5cc7428804b8a42b30c3043 Mon Sep 17 00:00:00 2001 From: He Jie Xu Date: Mon, 24 Jul 2023 07:12:31 +0000 Subject: [PATCH] IoUring: enable completion injection Signed-off-by: He Jie Xu --- envoy/common/io/BUILD | 20 +++ {source => envoy}/common/io/io_uring.h | 33 +++- source/common/common/BUILD | 2 +- source/common/io/BUILD | 13 +- source/common/io/io_uring_impl.cc | 55 ++++++- source/common/io/io_uring_impl.h | 21 ++- source/extensions/all_extensions.bzl | 2 +- test/common/io/BUILD | 1 + test/common/io/io_uring_impl_test.cc | 216 +++++++++++++++++++------ 9 files changed, 288 insertions(+), 75 deletions(-) create mode 100644 envoy/common/io/BUILD rename {source => envoy}/common/io/io_uring.h (76%) diff --git a/envoy/common/io/BUILD b/envoy/common/io/BUILD new file mode 100644 index 000000000000..5e082e96ad97 --- /dev/null +++ b/envoy/common/io/BUILD @@ -0,0 +1,20 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_library", + "envoy_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_package() + +envoy_cc_library( + name = "io_uring_interface", + hdrs = [ + "io_uring.h", + ], + deps = [ + "//envoy/buffer:buffer_interface", + "//envoy/network:address_interface", + ], +) diff --git a/source/common/io/io_uring.h b/envoy/common/io/io_uring.h similarity index 76% rename from source/common/io/io_uring.h rename to envoy/common/io/io_uring.h index c664cd4630a0..32a778e4d8e8 100644 --- a/source/common/io/io_uring.h +++ b/envoy/common/io/io_uring.h @@ -1,8 +1,7 @@ #pragma once #include "envoy/common/pure.h" - -#include "source/common/network/address_impl.h" +#include "envoy/network/address.h" namespace Envoy { namespace Io { @@ -12,8 +11,15 @@ namespace Io { * @param user_data is any data attached to an entry submitted to the submission * queue. * @param result is a return code of submitted system call. + * @param injected indicated the completion is injected or not. + */ +using CompletionCb = std::function; + +/** + * Callback for release the user data. + * @param user_data the pointer to the user data. */ -using CompletionCb = std::function; +using InjectedCompletionUserDataReleasor = std::function; enum class IoUringResult { Ok, Busy, Failed }; @@ -44,7 +50,7 @@ class IoUring { * Iterates over entries in the completion queue, calls the given callback for * every entry and marks them consumed. */ - virtual void forEveryCompletion(CompletionCb completion_cb) PURE; + virtual void forEveryCompletion(const CompletionCb& completion_cb) PURE; /** * Prepares an accept system call and puts it into the submission queue. @@ -95,8 +101,27 @@ class IoUring { * with the forEveryCompletion() method and try again. */ virtual IoUringResult submit() PURE; + + /** + * Inject a request completion into the io_uring. Those completions will be iterated + * when calling the `forEveryCompletion`. + * @param fd is the file descriptor of this completion refer to. + * @param user_data is the user data related to this completion. + * @param result is request result for this completion. + */ + virtual void injectCompletion(os_fd_t fd, void* user_data, int32_t result) PURE; + + /** + * Remove all the injected completions for the specific fd. + * @param fd is used to refer to the completions will be removed. + * @param releasor should be provided for how to release the related user data. + */ + virtual void removeInjectedCompletion(os_fd_t fd, + InjectedCompletionUserDataReleasor releasor) PURE; }; +using IoUringPtr = std::unique_ptr; + /** * Abstract factory for IoUring wrappers. */ diff --git a/source/common/common/BUILD b/source/common/common/BUILD index 7c00df446757..e1ba77d663da 100644 --- a/source/common/common/BUILD +++ b/source/common/common/BUILD @@ -211,7 +211,7 @@ envoy_cc_library( ":lock_guard_lib", ":macros", ":non_copyable", - "//source/common/protobuf:protobuf", + "//source/common/protobuf", ] + select({ "//bazel:android_logger": ["logger_impl_lib_android"], "//conditions:default": ["logger_impl_lib_standard"], diff --git a/source/common/io/BUILD b/source/common/io/BUILD index b8684f33999e..1dab89acf9df 100644 --- a/source/common/io/BUILD +++ b/source/common/io/BUILD @@ -8,16 +8,6 @@ licenses(["notice"]) # Apache 2 envoy_package() -envoy_cc_library( - name = "io_uring_interface", - hdrs = [ - "io_uring.h", - ], - deps = [ - "//source/common/network:address_lib", - ], -) - envoy_cc_library( name = "io_uring_impl_lib", srcs = [ @@ -29,6 +19,7 @@ envoy_cc_library( external_deps = ["uring"], tags = ["nocompdb"], deps = [ - ":io_uring_interface", + "//envoy/common/io:io_uring_interface", + "//envoy/thread_local:thread_local_interface", ], ) diff --git a/source/common/io/io_uring_impl.cc b/source/common/io/io_uring_impl.cc index ff9e77d50076..d0fa628e4388 100644 --- a/source/common/io/io_uring_impl.cc +++ b/source/common/io/io_uring_impl.cc @@ -47,13 +47,18 @@ IoUringImpl::~IoUringImpl() { io_uring_queue_exit(&ring_); } os_fd_t IoUringImpl::registerEventfd() { ASSERT(!isEventfdRegistered()); - event_fd_ = eventfd(0, 0); + // Mark the eventfd as non-blocking. since after injected completion is added. the eventfd + // will be activated to trigger the event callback. For the case of only injected completion + // is added and no actual iouring event. Then non-blocking can avoid the reading of eventfd + // blocking. + event_fd_ = eventfd(0, EFD_NONBLOCK); int res = io_uring_register_eventfd(&ring_, event_fd_); RELEASE_ASSERT(res == 0, fmt::format("unable to register eventfd: {}", errorDetails(-res))); return event_fd_; } void IoUringImpl::unregisterEventfd() { + ASSERT(isEventfdRegistered()); int res = io_uring_unregister_eventfd(&ring_); RELEASE_ASSERT(res == 0, fmt::format("unable to unregister eventfd: {}", errorDetails(-res))); SET_SOCKET_INVALID(event_fd_); @@ -61,20 +66,41 @@ void IoUringImpl::unregisterEventfd() { bool IoUringImpl::isEventfdRegistered() const { return SOCKET_VALID(event_fd_); } -void IoUringImpl::forEveryCompletion(CompletionCb completion_cb) { +void IoUringImpl::forEveryCompletion(const CompletionCb& completion_cb) { ASSERT(SOCKET_VALID(event_fd_)); eventfd_t v; - int ret = eventfd_read(event_fd_, &v); - RELEASE_ASSERT(ret == 0, "unable to drain eventfd"); + while (true) { + int ret = eventfd_read(event_fd_, &v); + if (ret != 0) { + ASSERT(errno == EAGAIN); + break; + } + } unsigned count = io_uring_peek_batch_cqe(&ring_, cqes_.data(), io_uring_size_); for (unsigned i = 0; i < count; ++i) { struct io_uring_cqe* cqe = cqes_[i]; - completion_cb(reinterpret_cast(cqe->user_data), cqe->res); + completion_cb(reinterpret_cast(cqe->user_data), cqe->res, false); } + io_uring_cq_advance(&ring_, count); + + ENVOY_LOG(trace, "the num of injected completion is {}", injected_completions_.size()); + // TODO(soulxu): Add bound here to avoid too many completion to stuck the thread too + // long. + // Iterate the injected completion. + while (!injected_completions_.empty()) { + auto& completion = injected_completions_.front(); + completion_cb(completion.user_data_, completion.result_, true); + // The socket may closed in the completion_cb and all the related completions are + // removed. + if (injected_completions_.empty()) { + break; + } + injected_completions_.pop_front(); + } } IoUringResult IoUringImpl::prepareAccept(os_fd_t fd, struct sockaddr* remote_addr, @@ -143,5 +169,24 @@ IoUringResult IoUringImpl::submit() { return res == -EBUSY ? IoUringResult::Busy : IoUringResult::Ok; } +void IoUringImpl::injectCompletion(os_fd_t fd, void* user_data, int32_t result) { + injected_completions_.emplace_back(fd, user_data, result); + ENVOY_LOG(trace, "inject completion, fd = {}, req = {}, num injects = {}", fd, + fmt::ptr(user_data), injected_completions_.size()); +} + +void IoUringImpl::removeInjectedCompletion(os_fd_t fd, + InjectedCompletionUserDataReleasor releasor) { + ENVOY_LOG(trace, "remove injected completions for fd = {}, size = {}", fd, + injected_completions_.size()); + injected_completions_.remove_if([fd, releasor](InjectedCompletion& completion) { + if (fd == completion.fd_) { + // Release the user data before remove this completion. + releasor(completion.user_data_); + } + return fd == completion.fd_; + }); +} + } // namespace Io } // namespace Envoy diff --git a/source/common/io/io_uring_impl.h b/source/common/io/io_uring_impl.h index af6a46297d9f..a8fcfd8dc675 100644 --- a/source/common/io/io_uring_impl.h +++ b/source/common/io/io_uring_impl.h @@ -1,8 +1,9 @@ #pragma once +#include "envoy/common/io/io_uring.h" #include "envoy/thread_local/thread_local.h" -#include "source/common/io/io_uring.h" +#include "source/common/common/logger.h" #include "liburing.h" @@ -11,7 +12,18 @@ namespace Io { bool isIoUringSupported(); -class IoUringImpl : public IoUring, public ThreadLocal::ThreadLocalObject { +struct InjectedCompletion { + InjectedCompletion(os_fd_t fd, void* user_data, int32_t result) + : fd_(fd), user_data_(user_data), result_(result) {} + + const os_fd_t fd_; + void* user_data_; + const int32_t result_; +}; + +class IoUringImpl : public IoUring, + public ThreadLocal::ThreadLocalObject, + protected Logger::Loggable { public: IoUringImpl(uint32_t io_uring_size, bool use_submission_queue_polling); ~IoUringImpl() override; @@ -19,7 +31,7 @@ class IoUringImpl : public IoUring, public ThreadLocal::ThreadLocalObject { os_fd_t registerEventfd() override; void unregisterEventfd() override; bool isEventfdRegistered() const override; - void forEveryCompletion(CompletionCb completion_cb) override; + void forEveryCompletion(const CompletionCb& completion_cb) override; IoUringResult prepareAccept(os_fd_t fd, struct sockaddr* remote_addr, socklen_t* remote_addr_len, void* user_data) override; IoUringResult prepareConnect(os_fd_t fd, const Network::Address::InstanceConstSharedPtr& address, @@ -30,12 +42,15 @@ class IoUringImpl : public IoUring, public ThreadLocal::ThreadLocalObject { off_t offset, void* user_data) override; IoUringResult prepareClose(os_fd_t fd, void* user_data) override; IoUringResult submit() override; + void injectCompletion(os_fd_t fd, void* user_data, int32_t result) override; + void removeInjectedCompletion(os_fd_t fd, InjectedCompletionUserDataReleasor releasor) override; private: const uint32_t io_uring_size_; struct io_uring ring_ {}; std::vector cqes_; os_fd_t event_fd_{INVALID_SOCKET}; + std::list injected_completions_; }; class IoUringFactoryImpl : public IoUringFactory { diff --git a/source/extensions/all_extensions.bzl b/source/extensions/all_extensions.bzl index 1a18c2cf44e1..96a0965d5058 100644 --- a/source/extensions/all_extensions.bzl +++ b/source/extensions/all_extensions.bzl @@ -14,7 +14,7 @@ def _selected_extension_target(target): return target + "_envoy_extension" # Return all extensions to be compiled into Envoy. -def envoy_all_extensions(denylist = []): +def envoy_all_extensions(denylist = ["envoy.transport_sockets.tcp_stats"]): all_extensions = dicts.add(_required_extensions, EXTENSIONS) # These extensions can be removed on a site specific basis. diff --git a/test/common/io/BUILD b/test/common/io/BUILD index d1231c0cb139..cb990fe222b4 100644 --- a/test/common/io/BUILD +++ b/test/common/io/BUILD @@ -17,6 +17,7 @@ envoy_cc_test( ], deps = [ "//source/common/io:io_uring_impl_lib", + "//source/common/network:address_lib", "//test/mocks/server:server_mocks", "//test/test_common:environment_lib", "//test/test_common:utility_lib", diff --git a/test/common/io/io_uring_impl_test.cc b/test/common/io/io_uring_impl_test.cc index 92fba458a7d4..e097b8c21c69 100644 --- a/test/common/io/io_uring_impl_test.cc +++ b/test/common/io/io_uring_impl_test.cc @@ -1,4 +1,5 @@ #include "source/common/io/io_uring_impl.h" +#include "source/common/network/address_impl.h" #include "test/mocks/server/mocks.h" #include "test/test_common/environment.h" @@ -12,12 +13,9 @@ namespace { class IoUringImplTest : public ::testing::Test { public: - IoUringImplTest() : api_(Api::createApiForTest()) { - if (isIoUringSupported()) { - factory_ = std::make_unique(2, false, context_.threadLocal()); - factory_->onServerInitialized(); - } else { - should_skip_ = true; + IoUringImplTest() : api_(Api::createApiForTest()), should_skip_(!isIoUringSupported()) { + if (!should_skip_) { + io_uring_ = std::make_unique(2, false); } } @@ -32,15 +30,13 @@ class IoUringImplTest : public ::testing::Test { return; } - auto& uring = factory_->getOrCreate(); - if (uring.isEventfdRegistered()) { - uring.unregisterEventfd(); + if (io_uring_->isEventfdRegistered()) { + io_uring_->unregisterEventfd(); } } Api::ApiPtr api_; - testing::NiceMock context_; - std::unique_ptr factory_{}; + IoUringPtr io_uring_{}; bool should_skip_{}; }; @@ -74,15 +70,13 @@ TEST_P(IoUringImplParamTest, InvalidParams) { SET_SOCKET_INVALID(fd); auto dispatcher = api_->allocateDispatcher("test_thread"); - auto& uring = factory_->getOrCreate(); - - os_fd_t event_fd = uring.registerEventfd(); + os_fd_t event_fd = io_uring_->registerEventfd(); const Event::FileTriggerType trigger = Event::PlatformDefaultTriggerType; int32_t completions_nr = 0; auto file_event = dispatcher->createFileEvent( event_fd, - [&uring, &completions_nr](uint32_t) { - uring.forEveryCompletion([&completions_nr](void*, int32_t res) { + [this, &completions_nr](uint32_t) { + io_uring_->forEveryCompletion([&completions_nr](void*, int32_t res, bool) { EXPECT_TRUE(res < 0); completions_nr++; }); @@ -90,36 +84,161 @@ TEST_P(IoUringImplParamTest, InvalidParams) { trigger, Event::FileReadyType::Read); auto prepare_method = GetParam(); - IoUringResult res = prepare_method(uring, fd); + IoUringResult res = prepare_method(*io_uring_, fd); EXPECT_EQ(res, IoUringResult::Ok); - res = prepare_method(uring, fd); + res = prepare_method(*io_uring_, fd); EXPECT_EQ(res, IoUringResult::Ok); - res = prepare_method(uring, fd); + res = prepare_method(*io_uring_, fd); EXPECT_EQ(res, IoUringResult::Failed); - res = uring.submit(); + res = io_uring_->submit(); EXPECT_EQ(res, IoUringResult::Ok); - res = uring.submit(); + res = io_uring_->submit(); EXPECT_EQ(res, IoUringResult::Ok); dispatcher->run(Event::Dispatcher::RunType::NonBlock); EXPECT_EQ(completions_nr, 2); } -TEST_F(IoUringImplTest, Instantiate) { - auto& uring1 = factory_->getOrCreate(); - auto& uring2 = factory_->getOrCreate(); - EXPECT_EQ(&uring1, &uring2); +TEST_F(IoUringImplTest, InjectCompletion) { + auto dispatcher = api_->allocateDispatcher("test_thread"); + + os_fd_t fd = 11; + os_fd_t event_fd = io_uring_->registerEventfd(); + const Event::FileTriggerType trigger = Event::PlatformDefaultTriggerType; + int32_t completions_nr = 0; + + auto file_event = dispatcher->createFileEvent( + event_fd, + [this, &fd, &completions_nr](uint32_t) { + io_uring_->forEveryCompletion( + [&fd, &completions_nr](void* user_data, int32_t res, bool injected) { + EXPECT_TRUE(injected); + EXPECT_EQ(&fd, user_data); + EXPECT_EQ(-11, res); + completions_nr++; + }); + }, + trigger, Event::FileReadyType::Read); + + io_uring_->injectCompletion(fd, &fd, -11); + + file_event->activate(Event::FileReadyType::Read); + + dispatcher->run(Event::Dispatcher::RunType::NonBlock); + EXPECT_EQ(completions_nr, 1); +} + +TEST_F(IoUringImplTest, NestInjectCompletion) { + auto dispatcher = api_->allocateDispatcher("test_thread"); + + os_fd_t fd = 11; + os_fd_t fd2 = 11; + os_fd_t event_fd = io_uring_->registerEventfd(); + const Event::FileTriggerType trigger = Event::PlatformDefaultTriggerType; + int32_t completions_nr = 0; + + auto file_event = dispatcher->createFileEvent( + event_fd, + [this, &fd, &fd2, &completions_nr](uint32_t) { + io_uring_->forEveryCompletion( + [this, &fd, &fd2, &completions_nr](void* user_data, int32_t res, bool injected) { + EXPECT_TRUE(injected); + if (completions_nr == 0) { + EXPECT_EQ(&fd, user_data); + EXPECT_EQ(-11, res); + io_uring_->injectCompletion(fd2, &fd2, -22); + } else { + EXPECT_EQ(&fd2, user_data); + EXPECT_EQ(-22, res); + } + + completions_nr++; + }); + }, + trigger, Event::FileReadyType::Read); + + io_uring_->injectCompletion(fd, &fd, -11); + + file_event->activate(Event::FileReadyType::Read); + + dispatcher->run(Event::Dispatcher::RunType::NonBlock); + EXPECT_EQ(completions_nr, 2); +} + +TEST_F(IoUringImplTest, RemoveInjectCompletion) { + auto dispatcher = api_->allocateDispatcher("test_thread"); + + os_fd_t fd = 11; + os_fd_t fd2 = 22; + os_fd_t event_fd = io_uring_->registerEventfd(); + const Event::FileTriggerType trigger = Event::PlatformDefaultTriggerType; + int32_t completions_nr = 0; + + auto file_event = dispatcher->createFileEvent( + event_fd, + [this, &fd, &completions_nr](uint32_t) { + io_uring_->forEveryCompletion( + [&fd, &completions_nr](void* user_data, int32_t res, bool injected) { + EXPECT_TRUE(injected); + EXPECT_EQ(&fd, user_data); + EXPECT_EQ(-11, res); + completions_nr++; + }); + }, + trigger, Event::FileReadyType::Read); + + io_uring_->injectCompletion(fd, &fd, -11); + io_uring_->injectCompletion(fd2, &fd2, -22); + io_uring_->removeInjectedCompletion( + fd2, [fd2](void* user_data) { EXPECT_EQ(fd2, *reinterpret_cast(user_data)); }); + file_event->activate(Event::FileReadyType::Read); + + dispatcher->run(Event::Dispatcher::RunType::NonBlock); + EXPECT_EQ(completions_nr, 1); +} + +TEST_F(IoUringImplTest, NestRemoveInjectCompletion) { + auto dispatcher = api_->allocateDispatcher("test_thread"); + + os_fd_t fd = 11; + os_fd_t fd2 = 22; + os_fd_t event_fd = io_uring_->registerEventfd(); + const Event::FileTriggerType trigger = Event::PlatformDefaultTriggerType; + int32_t completions_nr = 0; + + auto file_event = dispatcher->createFileEvent( + event_fd, + [this, &fd, &fd2, &completions_nr](uint32_t) { + io_uring_->forEveryCompletion( + [this, &fd, &fd2, &completions_nr](void* user_data, int32_t res, bool injected) { + EXPECT_TRUE(injected); + if (completions_nr == 0) { + EXPECT_EQ(&fd, user_data); + EXPECT_EQ(-11, res); + } else { + io_uring_->removeInjectedCompletion(fd2, [](void*) {}); + } + completions_nr++; + }); + }, + trigger, Event::FileReadyType::Read); + + io_uring_->injectCompletion(fd, &fd, -11); + io_uring_->injectCompletion(fd2, &fd2, -22); + + file_event->activate(Event::FileReadyType::Read); + + dispatcher->run(Event::Dispatcher::RunType::NonBlock); + EXPECT_EQ(completions_nr, 2); } TEST_F(IoUringImplTest, RegisterEventfd) { - auto& uring = factory_->getOrCreate(); - - EXPECT_FALSE(uring.isEventfdRegistered()); - uring.registerEventfd(); - EXPECT_TRUE(uring.isEventfdRegistered()); - uring.unregisterEventfd(); - EXPECT_FALSE(uring.isEventfdRegistered()); - EXPECT_DEATH(uring.unregisterEventfd(), "unable to unregister eventfd"); + EXPECT_FALSE(io_uring_->isEventfdRegistered()); + io_uring_->registerEventfd(); + EXPECT_TRUE(io_uring_->isEventfdRegistered()); + io_uring_->unregisterEventfd(); + EXPECT_FALSE(io_uring_->isEventfdRegistered()); + EXPECT_DEATH(io_uring_->unregisterEventfd(), ""); } TEST_F(IoUringImplTest, PrepareReadvAllDataFitsOneChunk) { @@ -135,15 +254,14 @@ TEST_F(IoUringImplTest, PrepareReadvAllDataFitsOneChunk) { iov.iov_base = buffer; iov.iov_len = 4096; - auto& uring = factory_->getOrCreate(); - os_fd_t event_fd = uring.registerEventfd(); + os_fd_t event_fd = io_uring_->registerEventfd(); const Event::FileTriggerType trigger = Event::PlatformDefaultTriggerType; int32_t completions_nr = 0; auto file_event = dispatcher->createFileEvent( event_fd, - [&uring, &completions_nr, d = dispatcher.get()](uint32_t) { - uring.forEveryCompletion([&completions_nr](void*, int32_t res) { + [this, &completions_nr, d = dispatcher.get()](uint32_t) { + io_uring_->forEveryCompletion([&completions_nr](void*, int32_t res, bool) { completions_nr++; EXPECT_EQ(res, strlen("test text")); }); @@ -151,9 +269,9 @@ TEST_F(IoUringImplTest, PrepareReadvAllDataFitsOneChunk) { }, trigger, Event::FileReadyType::Read); - uring.prepareReadv(fd, &iov, 1, 0, nullptr); + io_uring_->prepareReadv(fd, &iov, 1, 0, nullptr); EXPECT_STREQ(static_cast(iov.iov_base), ""); - uring.submit(); + io_uring_->submit(); dispatcher->run(Event::Dispatcher::RunType::Block); @@ -184,15 +302,13 @@ TEST_F(IoUringImplTest, PrepareReadvQueueOverflow) { iov3.iov_base = buffer3; iov3.iov_len = 2; - auto& uring = factory_->getOrCreate(); - - os_fd_t event_fd = uring.registerEventfd(); + os_fd_t event_fd = io_uring_->registerEventfd(); const Event::FileTriggerType trigger = Event::PlatformDefaultTriggerType; int32_t completions_nr = 0; auto file_event = dispatcher->createFileEvent( event_fd, - [&uring, &completions_nr](uint32_t) { - uring.forEveryCompletion([&completions_nr](void* user_data, int32_t res) { + [this, &completions_nr](uint32_t) { + io_uring_->forEveryCompletion([&completions_nr](void* user_data, int32_t res, bool) { EXPECT_TRUE(user_data != nullptr); EXPECT_EQ(res, 2); completions_nr++; @@ -204,14 +320,14 @@ TEST_F(IoUringImplTest, PrepareReadvQueueOverflow) { }, trigger, Event::FileReadyType::Read); - IoUringResult res = uring.prepareReadv(fd, &iov1, 1, 0, reinterpret_cast(1)); + IoUringResult res = io_uring_->prepareReadv(fd, &iov1, 1, 0, reinterpret_cast(1)); EXPECT_EQ(res, IoUringResult::Ok); - res = uring.prepareReadv(fd, &iov2, 1, 2, reinterpret_cast(2)); + res = io_uring_->prepareReadv(fd, &iov2, 1, 2, reinterpret_cast(2)); EXPECT_EQ(res, IoUringResult::Ok); - res = uring.prepareReadv(fd, &iov3, 1, 4, reinterpret_cast(3)); + res = io_uring_->prepareReadv(fd, &iov3, 1, 4, reinterpret_cast(3)); // Expect the submission queue overflow. EXPECT_EQ(res, IoUringResult::Failed); - res = uring.submit(); + res = io_uring_->submit(); EXPECT_EQ(res, IoUringResult::Ok); // Even though we haven't been notified about ops completion the buffers @@ -228,9 +344,9 @@ TEST_F(IoUringImplTest, PrepareReadvQueueOverflow) { EXPECT_EQ(completions_nr, 2); // Check a new event gets handled in the next dispatcher run. - res = uring.prepareReadv(fd, &iov3, 1, 4, reinterpret_cast(3)); + res = io_uring_->prepareReadv(fd, &iov3, 1, 4, reinterpret_cast(3)); EXPECT_EQ(res, IoUringResult::Ok); - res = uring.submit(); + res = io_uring_->submit(); EXPECT_EQ(res, IoUringResult::Ok); EXPECT_EQ(static_cast(iov3.iov_base)[0], 'e');