Remove io_context and just use io_service& directly.
Added io_work_scope RAII class to help with scoped lifetime of io_service event loop. Having io_context always increment the ref-count of active I/O operations whenever passed by-value to a function seems like unnecessary atomic operations when compared to selected usages of io_work_scope which generally only need creation for top-level operations.
This commit is contained in:
parent
0a46465b2e
commit
a34527617d
12 changed files with 39 additions and 63 deletions
|
@ -19,7 +19,7 @@
|
|||
|
||||
namespace cppcoro
|
||||
{
|
||||
class io_context;
|
||||
class io_service;
|
||||
|
||||
class file
|
||||
{
|
||||
|
@ -39,7 +39,7 @@ namespace cppcoro
|
|||
|
||||
static detail::win32::safe_handle open(
|
||||
detail::win32::dword_t fileAccess,
|
||||
io_context& ioContext,
|
||||
io_service& ioService,
|
||||
const std::experimental::filesystem::path& path,
|
||||
file_open_mode openMode,
|
||||
file_share_mode shareMode,
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
|
||||
namespace cppcoro
|
||||
{
|
||||
class io_context;
|
||||
|
||||
class io_service
|
||||
{
|
||||
public:
|
||||
|
@ -93,8 +91,6 @@ namespace cppcoro
|
|||
|
||||
void notify_work_finished() noexcept;
|
||||
|
||||
io_context get_context() noexcept;
|
||||
|
||||
#if CPPCORO_OS_WINNT
|
||||
detail::win32::handle_t native_iocp_handle() noexcept;
|
||||
#endif
|
||||
|
@ -149,17 +145,17 @@ namespace cppcoro
|
|||
std::experimental::coroutine_handle<> m_awaiter;
|
||||
};
|
||||
|
||||
class io_context
|
||||
class io_work_scope
|
||||
{
|
||||
public:
|
||||
|
||||
io_context(io_service& service) noexcept
|
||||
io_work_scope(io_service& service) noexcept
|
||||
: m_service(&service)
|
||||
{
|
||||
service.notify_work_started();
|
||||
}
|
||||
|
||||
io_context(const io_context& other) noexcept
|
||||
io_work_scope(const io_work_scope& other) noexcept
|
||||
: m_service(other.m_service)
|
||||
{
|
||||
if (m_service != nullptr)
|
||||
|
@ -168,13 +164,13 @@ namespace cppcoro
|
|||
}
|
||||
}
|
||||
|
||||
io_context(io_context&& other) noexcept
|
||||
io_work_scope(io_work_scope&& other) noexcept
|
||||
: m_service(other.m_service)
|
||||
{
|
||||
other.m_service = nullptr;
|
||||
}
|
||||
|
||||
~io_context()
|
||||
~io_work_scope()
|
||||
{
|
||||
if (m_service != nullptr)
|
||||
{
|
||||
|
@ -182,29 +178,21 @@ namespace cppcoro
|
|||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
io_service::schedule_operation schedule() noexcept
|
||||
{
|
||||
return m_service->schedule();
|
||||
}
|
||||
|
||||
void swap(io_context& other) noexcept
|
||||
void swap(io_work_scope& other) noexcept
|
||||
{
|
||||
std::swap(m_service, other.m_service);
|
||||
}
|
||||
|
||||
io_context& operator=(io_context other) noexcept
|
||||
io_work_scope& operator=(io_work_scope other) noexcept
|
||||
{
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if CPPCORO_OS_WINNT
|
||||
detail::win32::handle_t native_iocp_handle() noexcept
|
||||
io_service& service() noexcept
|
||||
{
|
||||
return m_service->native_iocp_handle();
|
||||
return *m_service;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
|
@ -212,7 +200,7 @@ namespace cppcoro
|
|||
|
||||
};
|
||||
|
||||
inline void swap(io_context& a, io_context& b)
|
||||
inline void swap(io_work_scope& a, io_work_scope& b)
|
||||
{
|
||||
a.swap(b);
|
||||
}
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
|
||||
namespace cppcoro
|
||||
{
|
||||
class io_context;
|
||||
|
||||
class read_only_file : public readable_file
|
||||
{
|
||||
public:
|
||||
|
@ -44,7 +42,7 @@ namespace cppcoro
|
|||
/// If the file could not be opened for read.
|
||||
[[nodiscard]]
|
||||
static read_only_file open(
|
||||
io_context& ioContext,
|
||||
io_service& ioService,
|
||||
const std::experimental::filesystem::path& path,
|
||||
file_share_mode shareMode = file_share_mode::read,
|
||||
file_buffering_mode bufferingMode = file_buffering_mode::default_);
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
|
||||
namespace cppcoro
|
||||
{
|
||||
class io_context;
|
||||
|
||||
class read_write_file : public readable_file, public writable_file
|
||||
{
|
||||
public:
|
||||
|
@ -50,7 +48,7 @@ namespace cppcoro
|
|||
/// If the file could not be opened for write.
|
||||
[[nodiscard]]
|
||||
static read_write_file open(
|
||||
io_context& ioContext,
|
||||
io_service& ioService,
|
||||
const std::experimental::filesystem::path& path,
|
||||
file_open_mode openMode = file_open_mode::create_or_open,
|
||||
file_share_mode shareMode = file_share_mode::none,
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
|
||||
namespace cppcoro
|
||||
{
|
||||
class io_context;
|
||||
|
||||
class write_only_file : public writable_file
|
||||
{
|
||||
public:
|
||||
|
@ -49,7 +47,7 @@ namespace cppcoro
|
|||
/// If the file could not be opened for write.
|
||||
[[nodiscard]]
|
||||
static write_only_file open(
|
||||
io_context& ioContext,
|
||||
io_service& ioService,
|
||||
const std::experimental::filesystem::path& path,
|
||||
file_open_mode openMode = file_open_mode::create_or_open,
|
||||
file_share_mode shareMode = file_share_mode::none,
|
||||
|
|
|
@ -44,7 +44,7 @@ cppcoro::file::file(detail::win32::safe_handle&& fileHandle) noexcept
|
|||
|
||||
cppcoro::detail::win32::safe_handle cppcoro::file::open(
|
||||
detail::win32::dword_t fileAccess,
|
||||
io_context& ioContext,
|
||||
io_service& ioService,
|
||||
const std::experimental::filesystem::path& path,
|
||||
file_open_mode openMode,
|
||||
file_share_mode shareMode,
|
||||
|
@ -130,7 +130,7 @@ cppcoro::detail::win32::safe_handle cppcoro::file::open(
|
|||
// Associate with the I/O service's completion port.
|
||||
const HANDLE result = ::CreateIoCompletionPort(
|
||||
fileHandle.handle(),
|
||||
ioContext.native_iocp_handle(),
|
||||
ioService.native_iocp_handle(),
|
||||
0,
|
||||
0);
|
||||
if (result == nullptr)
|
||||
|
|
|
@ -158,11 +158,6 @@ void cppcoro::io_service::notify_work_finished() noexcept
|
|||
}
|
||||
}
|
||||
|
||||
cppcoro::io_context cppcoro::io_service::get_context() noexcept
|
||||
{
|
||||
return io_context{ *this };
|
||||
}
|
||||
|
||||
cppcoro::detail::win32::handle_t cppcoro::io_service::native_iocp_handle() noexcept
|
||||
{
|
||||
return m_iocpHandle.handle();
|
||||
|
|
|
@ -10,14 +10,14 @@
|
|||
# include <Windows.h>
|
||||
|
||||
cppcoro::read_only_file cppcoro::read_only_file::open(
|
||||
io_context& ioContext,
|
||||
io_service& ioService,
|
||||
const std::experimental::filesystem::path& path,
|
||||
file_share_mode shareMode,
|
||||
file_buffering_mode bufferingMode)
|
||||
{
|
||||
return read_only_file(file::open(
|
||||
GENERIC_READ,
|
||||
ioContext,
|
||||
ioService,
|
||||
path,
|
||||
file_open_mode::open_existing,
|
||||
shareMode,
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
# include <Windows.h>
|
||||
|
||||
cppcoro::read_write_file cppcoro::read_write_file::open(
|
||||
io_context& ioContext,
|
||||
io_service& ioService,
|
||||
const std::experimental::filesystem::path& path,
|
||||
file_open_mode openMode,
|
||||
file_share_mode shareMode,
|
||||
|
@ -18,7 +18,7 @@ cppcoro::read_write_file cppcoro::read_write_file::open(
|
|||
{
|
||||
return read_write_file(file::open(
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
ioContext,
|
||||
ioService,
|
||||
path,
|
||||
openMode,
|
||||
shareMode,
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
# include <Windows.h>
|
||||
|
||||
cppcoro::write_only_file cppcoro::write_only_file::open(
|
||||
io_context& ioContext,
|
||||
io_service& ioService,
|
||||
const std::experimental::filesystem::path& path,
|
||||
file_open_mode openMode,
|
||||
file_share_mode shareMode,
|
||||
|
@ -18,7 +18,7 @@ cppcoro::write_only_file cppcoro::write_only_file::open(
|
|||
{
|
||||
return write_only_file(file::open(
|
||||
GENERIC_WRITE,
|
||||
ioContext,
|
||||
ioService,
|
||||
path,
|
||||
openMode,
|
||||
shareMode,
|
||||
|
|
|
@ -80,9 +80,9 @@ TEST_CASE_FIXTURE(temp_dir_fixture, "write a file")
|
|||
|
||||
auto filePath = temp_dir() / "foo";
|
||||
|
||||
auto write = [&](cppcoro::io_context io) -> cppcoro::lazy_task<>
|
||||
auto write = [&](cppcoro::io_service& ioService) -> cppcoro::lazy_task<>
|
||||
{
|
||||
auto f = cppcoro::write_only_file::open(io, filePath);
|
||||
auto f = cppcoro::write_only_file::open(ioService, filePath);
|
||||
|
||||
CHECK(f.size() == 0);
|
||||
|
||||
|
@ -98,7 +98,7 @@ TEST_CASE_FIXTURE(temp_dir_fixture, "write a file")
|
|||
}
|
||||
};
|
||||
|
||||
auto read = [&](cppcoro::io_context io) -> cppcoro::lazy_task<>
|
||||
auto read = [&](cppcoro::io_service& io) -> cppcoro::lazy_task<>
|
||||
{
|
||||
auto f = cppcoro::read_only_file::open(io, filePath);
|
||||
|
||||
|
@ -122,9 +122,9 @@ TEST_CASE_FIXTURE(temp_dir_fixture, "write a file")
|
|||
{
|
||||
try
|
||||
{
|
||||
auto io = ioService.get_context();
|
||||
co_await write(io);
|
||||
co_await read(io);
|
||||
cppcoro::io_work_scope scope{ ioService };
|
||||
co_await write(ioService);
|
||||
co_await read(ioService);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
@ -146,8 +146,8 @@ TEST_CASE_FIXTURE(temp_dir_fixture, "read write file")
|
|||
|
||||
auto run = [&]() -> cppcoro::task<>
|
||||
{
|
||||
auto ioContext = ioService.get_context();
|
||||
auto f = cppcoro::read_write_file::open(ioContext, temp_dir() / "foo.txt");
|
||||
cppcoro::io_work_scope ioScope{ ioService };
|
||||
auto f = cppcoro::read_write_file::open(ioService, temp_dir() / "foo.txt");
|
||||
|
||||
char buffer1[100];
|
||||
std::memset(buffer1, 0xAB, sizeof(buffer1));
|
||||
|
|
|
@ -39,15 +39,16 @@ TEST_CASE("schedule coroutine")
|
|||
|
||||
bool reachedPointA = false;
|
||||
bool reachedPointB = false;
|
||||
auto startTask = [&](cppcoro::io_context ioCtx) -> cppcoro::task<>
|
||||
auto startTask = [&](cppcoro::io_service& ioService) -> cppcoro::task<>
|
||||
{
|
||||
cppcoro::io_work_scope ioScope(ioService);
|
||||
reachedPointA = true;
|
||||
co_await ioCtx.schedule();
|
||||
co_await ioService.schedule();
|
||||
reachedPointB = true;
|
||||
};
|
||||
|
||||
{
|
||||
auto t = startTask(service.get_context());
|
||||
auto t = startTask(service);
|
||||
|
||||
CHECK_FALSE(t.is_ready());
|
||||
CHECK(reachedPointA);
|
||||
|
@ -58,11 +59,8 @@ TEST_CASE("schedule coroutine")
|
|||
CHECK(reachedPointB);
|
||||
CHECK(t.is_ready());
|
||||
|
||||
// Stop isn't requested until task goes out of scope.
|
||||
CHECK_FALSE(service.is_stop_requested());
|
||||
CHECK(service.is_stop_requested());
|
||||
}
|
||||
|
||||
CHECK(service.is_stop_requested());
|
||||
}
|
||||
|
||||
TEST_CASE("multiple I/O threads servicing events")
|
||||
|
@ -77,12 +75,13 @@ TEST_CASE("multiple I/O threads servicing events")
|
|||
|
||||
auto runOnIoThread = [&]() -> cppcoro::task<>
|
||||
{
|
||||
co_await ioService.get_context().schedule();
|
||||
cppcoro::io_work_scope ioScope(ioService);
|
||||
co_await ioService.schedule();
|
||||
};
|
||||
|
||||
std::vector<cppcoro::task<>> tasks;
|
||||
{
|
||||
auto ioContext = ioService.get_context();
|
||||
cppcoro::io_work_scope ioScope(ioService);
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
tasks.emplace_back(runOnIoThread());
|
||||
|
|
Loading…
Reference in a new issue