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:
Lewis Baker 2017-06-25 22:03:46 +09:30
parent 0a46465b2e
commit a34527617d
12 changed files with 39 additions and 63 deletions

View file

@ -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,

View file

@ -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);
}

View file

@ -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_);

View file

@ -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,

View file

@ -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,

View file

@ -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)

View file

@ -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();

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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));

View file

@ -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());