-
Notifications
You must be signed in to change notification settings - Fork 86
IOCP support (draft) #359
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
PyXiion
wants to merge
28
commits into
jbaldwin:main
Choose a base branch
from
PyXiion:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
IOCP support (draft) #359
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
83e31ac
Introduce signal abstractions for Unix-based event handling.
PyXiion cd877c6
IOCP, signals, sockets
PyXiion 0ff8c84
Merge branch 'jbaldwin:main' into main
PyXiion 28c4882
Platform macros
PyXiion 963bfce
Merge branch 'main' of https://github.com/PyXiion/libcoro
PyXiion faa03fa
Adds read/write methods and noexcept to move constructor.
PyXiion 0cc7d0c
Uses trailing return type for pipe accessors
PyXiion f6589e0
socket code refactor
PyXiion d8de051
Fixes socket API calls and `native_handle_t` type.
PyXiion 60f2c90
Uncomments network-related source files in CMakeLists.
PyXiion cacef81
Merge remote-tracking branch 'origin/main'
PyXiion 627cc66
Uncomments network-related source files in CMakeLists.
PyXiion ddd6f1a
read_status, write_status
PyXiion 541bf89
Merge remote-tracking branch 'origin/main'
PyXiion d6ff687
Client accept
PyXiion e162793
IOCP write/read, enum for completion keys, IOCP timers
PyXiion 79268e9
IOCP support for TCP networking
PyXiion 50a789b
server::accept_client: fix timeout handling
PyXiion f2d94f4
Fix sync requests with sockets
PyXiion 46116b9
udp::peer: write_to, read_from cross-platform methods
PyXiion 8aa6114
Add UDP support for Windows
PyXiion 8639ed5
Fixes Linux tests, compilation, and UDP functionality.
PyXiion a009c98
Add notes and clarify code behavior in IOCP implementation details.
PyXiion bbb274f
Remove unused file
PyXiion 6a2f19d
io_notifier_iocp: using GetQueuedCompletionStatusEx instead of GetQue…
PyXiion 7dc9562
timer_handle: remove mutables, use RegisterWaitForSingleObject instea…
PyXiion 9c7a26f
handle close on zero bytes in the client, generic function for WinSoc…
PyXiion 86a78b5
fix some Codacy problems, remove mutable from signal_win32
PyXiion File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,5 +36,7 @@ | |
/RelWithDebInfo/ | ||
/Release/ | ||
/Testing/ | ||
/out/ | ||
|
||
/.vscode/ | ||
/.vs/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ | |
#include "coro/detail/poll_info.hpp" | ||
#include "coro/fd.hpp" | ||
#include "coro/poll.hpp" | ||
#include "coro/signal.hpp" | ||
|
||
namespace coro::detail | ||
{ | ||
|
@@ -42,6 +43,8 @@ class io_notifier_epoll | |
|
||
auto watch(fd_t fd, coro::poll_op op, void* data, bool keep = false) -> bool; | ||
|
||
auto watch(const signal& signal, void* data) -> bool; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This also needs to be added to |
||
|
||
auto watch(detail::poll_info& pi) -> bool; | ||
|
||
auto unwatch(detail::poll_info& pi) -> bool; | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
#pragma once | ||
#include "coro/detail/poll_info.hpp" | ||
#include "coro/fd.hpp" | ||
#include "coro/poll.hpp" | ||
#include "coro/signal.hpp" | ||
#include <mutex> | ||
|
||
namespace coro::detail | ||
{ | ||
class timer_handle; | ||
|
||
class io_notifier_iocp | ||
{ | ||
public: | ||
enum class completion_key : unsigned long long | ||
{ | ||
signal_set, | ||
signal_unset, | ||
socket, | ||
timer | ||
}; | ||
|
||
public: | ||
io_notifier_iocp(); | ||
|
||
io_notifier_iocp(const io_notifier_iocp&) = delete; | ||
io_notifier_iocp(io_notifier_iocp&&) = delete; | ||
auto operator=(const io_notifier_iocp&) -> io_notifier_iocp& = delete; | ||
auto operator=(io_notifier_iocp&&) -> io_notifier_iocp& = delete; | ||
|
||
~io_notifier_iocp(); | ||
|
||
auto watch_timer(detail::timer_handle& timer, std::chrono::nanoseconds duration) -> bool; | ||
|
||
auto watch(coro::signal& signal, void* data) -> bool; | ||
|
||
auto unwatch_timer(detail::timer_handle& timer) -> bool; | ||
|
||
auto next_events( | ||
std::vector<std::pair<detail::poll_info*, coro::poll_status>>& ready_events, | ||
std::chrono::milliseconds timeout) -> void; | ||
|
||
// static auto event_to_poll_status(const event_t& event) -> poll_status; | ||
|
||
auto iocp() const noexcept -> void* { return m_iocp; } | ||
|
||
private: | ||
void* m_iocp{}; | ||
|
||
void set_signal_active(void* data, bool active); | ||
void process_active_signals(std::vector<std::pair<detail::poll_info*, coro::poll_status>>& ready_events); | ||
|
||
std::mutex m_active_signals_mutex; | ||
std::vector<void*> m_active_signals; | ||
|
||
static constexpr std::size_t max_events = 16; | ||
}; | ||
} // namespace coro::detail |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// NOTE: This file includes <Windows.h>, which pulls in many global symbols. | ||
// Do not include this file from headers. Include only in implementation files (.cpp) or modules. | ||
|
||
#pragma once | ||
#include "coro/io_scheduler.hpp" | ||
#include <coro/detail/poll_info.hpp> | ||
|
||
// clang-format off | ||
#define WIN32_LEAN_AND_MEAN | ||
#define NOMINMAX | ||
#include <winsock2.h> | ||
#include <ws2ipdef.h> | ||
#include <MSWSock.h> | ||
#include "coro/detail/iocp_overlapped.hpp" | ||
// clang-format on | ||
|
||
namespace coro::detail | ||
{ | ||
struct overlapped_io_operation | ||
{ | ||
OVERLAPPED ov{}; // Base Windows OVERLAPPED structure for async I/O | ||
poll_info pi; | ||
DWORD bytes_transferred{}; // Number of bytes read or written once the operation completes | ||
|
||
SOCKET socket{}; | ||
}; | ||
|
||
template<typename status_enum, typename buffer_type, bool is_read, typename operation_fn> | ||
requires std::is_invocable_r_v<int, operation_fn, SOCKET, overlapped_io_operation&, WSABUF&> | ||
auto perform_write_read_operation( | ||
const std::shared_ptr<io_scheduler>& scheduler, | ||
SOCKET socket, | ||
operation_fn&& operation, | ||
buffer_type buffer, | ||
std::chrono::milliseconds timeout) -> task<std::pair<status_enum, buffer_type>> | ||
{ | ||
overlapped_io_operation ov{}; | ||
WSABUF buf{}; | ||
|
||
ov.socket = socket; | ||
|
||
buf.buf = const_cast<char*>(buffer.data()); | ||
buf.len = buffer.size(); | ||
|
||
auto get_result_buffer = [&]() | ||
{ | ||
if constexpr (is_read) | ||
return ov.bytes_transferred == 0 ? buffer_type{} : buffer_type{buffer.data(), ov.bytes_transferred}; | ||
else | ||
return ov.bytes_transferred == 0 | ||
? buffer_type{} | ||
: buffer_type{buffer.data() + ov.bytes_transferred, buffer.size() - ov.bytes_transferred}; | ||
}; | ||
|
||
auto r = operation(socket, std::ref(ov), std::ref(buf)); | ||
|
||
// Operation has been completed synchronously, no need to wait for event. | ||
if (r == 0) | ||
{ | ||
co_return {ov.bytes_transferred == 0 ? status_enum::closed : status_enum::ok, get_result_buffer()}; | ||
} | ||
if (WSAGetLastError() != WSA_IO_PENDING) | ||
{ | ||
co_return {status_enum::error, buffer}; | ||
} | ||
|
||
// We need loop in case the operation completes right away with the timeout. | ||
// In this case we just co_await our poll_info once more to correct status. | ||
while (true) | ||
{ | ||
switch (co_await scheduler->poll(ov.pi, timeout)) | ||
{ | ||
case poll_status::event: | ||
co_return {status_enum::ok, get_result_buffer()}; | ||
case poll_status::timeout: | ||
{ | ||
if (const BOOL success = CancelIoEx(reinterpret_cast<HANDLE>(socket), &ov.ov); !success) | ||
{ | ||
if (const auto err = GetLastError(); err == ERROR_NOT_FOUND) | ||
{ | ||
// Operation has been completed, we need to co_await once more | ||
timeout = {}; // No need in timeout | ||
continue; | ||
} | ||
} | ||
co_return {status_enum::timeout, get_result_buffer()}; | ||
} | ||
case poll_status::closed: | ||
co_return {status_enum::closed, buffer}; | ||
case poll_status::error: | ||
default: | ||
co_return {status_enum::error, buffer}; | ||
} | ||
} | ||
} | ||
|
||
} // namespace coro::detail |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
#pragma once | ||
#include "coro/fd.hpp" | ||
|
||
#include <array> | ||
|
||
namespace coro::detail | ||
{ | ||
class signal_unix | ||
{ | ||
public: | ||
signal_unix(); | ||
~signal_unix(); | ||
|
||
void set(); | ||
|
||
void unset(); | ||
|
||
[[nodiscard]] auto read_fd() const noexcept -> fd_t { return m_pipe[0]; } | ||
[[nodiscard]] auto write_fd() const noexcept -> fd_t { return m_pipe[1]; } | ||
|
||
private: | ||
std::array<fd_t, 2> m_pipe{-1}; | ||
}; | ||
} // namespace coro::detail |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dont't think that it is a good idea to have platform-dependent definitions of concepts. The main point of concepts is to abstract away those things and to have one unified interface.
With that being said, I would also strongly suggest to keep the interface of the
ececutor_type::poll
function the same over all platforms. If necessary we should add some new type that allows use to have the same definition for that function (e.g. usecoro::poll_info
instead of the file descriptor and operation on unix systems too as it should contain all the necessary information). The internals of type can differ throughout the platforms but the interfaces should be the same especially for public facing types as I did it with the introduction of kqueue backend. What do you think of that?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice idea, it'll be much simpler