Windows: Added overlapped support to `os::write`. Added overlapped handle support to `os::write`. Now, `os::write` will do a blocking write no matter the handle type. Also, `os::write_async` will do an overlapped write on an overlapped handle.
Review: https://reviews.apache.org/r/66956/ Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/bd4a8008 Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/bd4a8008 Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/bd4a8008 Branch: refs/heads/master Commit: bd4a8008e0eb1a286e9c45a8ff6cf4cf1792ad6c Parents: 5cdd29f Author: Akash Gupta <akash-gu...@hotmail.com> Authored: Wed May 23 14:01:17 2018 -0700 Committer: Andrew Schwartzmeyer <and...@schwartzmeyer.com> Committed: Wed May 23 14:01:17 2018 -0700 ---------------------------------------------------------------------- .../stout/include/stout/os/windows/write.hpp | 92 ++++++++++++++++++-- 1 file changed, 87 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/bd4a8008/3rdparty/stout/include/stout/os/windows/write.hpp ---------------------------------------------------------------------- diff --git a/3rdparty/stout/include/stout/os/windows/write.hpp b/3rdparty/stout/include/stout/os/windows/write.hpp index 295c031..232218e 100644 --- a/3rdparty/stout/include/stout/os/windows/write.hpp +++ b/3rdparty/stout/include/stout/os/windows/write.hpp @@ -18,23 +18,105 @@ #include <stout/unreachable.hpp> #include <stout/windows.hpp> +#include <stout/internal/windows/overlapped.hpp> + #include <stout/os/int_fd.hpp> #include <stout/os/socket.hpp> namespace os { +// Asynchronous write on a overlapped int_fd. Returns `Error` on fatal errors, +// `None()` on a successful pending IO operation or number of bytes written on +// a successful IO operation that finished immediately. +inline Result<size_t> write_async( + const int_fd& fd, + const void* data, + size_t size, + OVERLAPPED* overlapped) +{ + CHECK_LE(size, UINT_MAX); + + switch (fd.type()) { + case WindowsFD::Type::HANDLE: { + DWORD bytes; + const bool success = + ::WriteFile(fd, data, static_cast<DWORD>(size), &bytes, overlapped); + + return ::internal::windows::process_async_io_result(success, bytes); + } + case WindowsFD::Type::SOCKET: { + static_assert( + std::is_same<OVERLAPPED, WSAOVERLAPPED>::value, + "Expected `WSAOVERLAPPED` to be of type `OVERLAPPED`."); + + // Note that it's okay to allocate this on the stack, since the WinSock + // providers must copy the WSABUF to their internal buffers. See + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms741688(v=vs.85).aspx // NOLINT(whitespace/line_length) + WSABUF buf = { + static_cast<u_long>(size), + static_cast<char*>(const_cast<void*>(data)) + }; + + DWORD bytes; + const int result = + ::WSASend(fd, &buf, 1, &bytes, 0, overlapped, nullptr); + + return ::internal::windows::process_async_io_result(result == 0, bytes); + } + } + + UNREACHABLE(); +} + + inline ssize_t write(const int_fd& fd, const void* data, size_t size) { CHECK_LE(size, INT_MAX); switch (fd.type()) { case WindowsFD::Type::HANDLE: { + // Handle non-overlapped case. We just use the regular `WriteFile` since + // seekable overlapped files require an offset, which we don't track. + if (!fd.is_overlapped()) { + DWORD bytes; + const BOOL result = + ::WriteFile(fd, data, static_cast<DWORD>(size), &bytes, nullptr); + + if (result == FALSE) { + // Indicates an error, but we can't return a `WindowsError`. + return -1; + } + + return static_cast<ssize_t>(bytes); + } + + // Asynchronous handle, we can use the `write_async` function + // and then wait on the overlapped object for a synchronous write. + Try<OVERLAPPED> overlapped_ = + ::internal::windows::init_overlapped_for_sync_io(); + + if (overlapped_.isError()) { + return -1; + } + + OVERLAPPED overlapped = overlapped_.get(); + Result<size_t> result = write_async(fd, data, size, &overlapped); + + if (result.isError()) { + return -1; + } + + if (result.isSome()) { + return result.get(); + } + + // IO is pending, so wait for the overlapped object. DWORD bytes; - // TODO(andschwa): Handle overlapped I/O. - const BOOL result = - ::WriteFile(fd, data, static_cast<DWORD>(size), &bytes, nullptr); - if (result == FALSE) { - return -1; // Indicates an error, but we can't return a `WindowsError`. + const BOOL wait_success = + ::GetOverlappedResult(fd, &overlapped, &bytes, TRUE); + + if (wait_success == FALSE) { + return -1; } return static_cast<ssize_t>(bytes);