You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by mp...@apache.org on 2017/02/06 20:07:17 UTC
[4/7] mesos git commit: Introduced `WindowsFD` class which is
analogous to an `int` in POSIX.
Introduced `WindowsFD` class which is analogous to an `int` in POSIX.
In POSIX the socket, pipe and a file are represented by the `int` type.
In Windows:
- A socket is kept in a `SOCKET` type (64 bit wide)
- A pipe or a WinAPI file descriptor in a `HANDLE` (64 bit wide)
- A CRT file descriptor in an `int`
The `WindowsFD` class is a type that brings all of these things
together and behaves analogously to an `int` in POSIX.
Review: https://reviews.apache.org/r/54591
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/e7a4061d
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/e7a4061d
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/e7a4061d
Branch: refs/heads/master
Commit: e7a4061d268142cf44f0bce3b64367b2e48cd05b
Parents: b150a4f
Author: Michael Park <mp...@apache.org>
Authored: Tue Dec 20 17:10:10 2016 -0500
Committer: Michael Park <mp...@apache.org>
Committed: Mon Feb 6 11:54:51 2017 -0800
----------------------------------------------------------------------
3rdparty/stout/include/Makefile.am | 2 +
3rdparty/stout/include/stout/os.hpp | 1 +
3rdparty/stout/include/stout/os/int_fd.hpp | 38 ++
3rdparty/stout/include/stout/os/windows/fd.hpp | 455 ++++++++++++++++++++
4 files changed, 496 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/e7a4061d/3rdparty/stout/include/Makefile.am
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/Makefile.am b/3rdparty/stout/include/Makefile.am
index 53d04a9..8686223 100644
--- a/3rdparty/stout/include/Makefile.am
+++ b/3rdparty/stout/include/Makefile.am
@@ -75,6 +75,7 @@ nobase_include_HEADERS = \
stout/os/fsync.hpp \
stout/os/ftruncate.hpp \
stout/os/getcwd.hpp \
+ stout/os/int_fd.hpp \
stout/os/kill.hpp \
stout/os/killtree.hpp \
stout/os/linux.hpp \
@@ -142,6 +143,7 @@ nobase_include_HEADERS = \
stout/os/windows/close.hpp \
stout/os/windows/exists.hpp \
stout/os/windows/fcntl.hpp \
+ stout/os/windows/fd.hpp \
stout/os/windows/fork.hpp \
stout/os/windows/fsync.hpp \
stout/os/windows/ftruncate.hpp \
http://git-wip-us.apache.org/repos/asf/mesos/blob/e7a4061d/3rdparty/stout/include/stout/os.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os.hpp b/3rdparty/stout/include/stout/os.hpp
index ed6fec3..2d81440 100644
--- a/3rdparty/stout/include/stout/os.hpp
+++ b/3rdparty/stout/include/stout/os.hpp
@@ -47,6 +47,7 @@
#include <stout/os/chdir.hpp>
#include <stout/os/chroot.hpp>
#include <stout/os/exists.hpp>
+#include <stout/os/int_fd.hpp>
#include <stout/os/fcntl.hpp>
#include <stout/os/getenv.hpp>
#include <stout/os/kill.hpp>
http://git-wip-us.apache.org/repos/asf/mesos/blob/e7a4061d/3rdparty/stout/include/stout/os/int_fd.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/int_fd.hpp b/3rdparty/stout/include/stout/os/int_fd.hpp
new file mode 100644
index 0000000..5859d38
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/int_fd.hpp
@@ -0,0 +1,38 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_INT_FD_HPP__
+#define __STOUT_OS_INT_FD_HPP__
+
+
+// For readability, we minimize the number of #ifdef blocks in the code by
+// splitting platform specifc system calls into separate directories.
+#ifdef __WINDOWS__
+#include <stout/os/windows/fd.hpp>
+#endif // __WINDOWS__
+
+// The `int_fd` type is designed to be able to keep / continue to write the
+// existing POSIX file descriptor pattern in a portable manner with Windows.
+//
+// IMPORTANT: Use the `int_fd` in platform-agnostic code paths, and use `int`
+// or `os::WindowsFD` directly in platform-specific code paths.
+//
+// NOTE: The `int_` prefix is meant to indicate that on POSIX, `int_fd` will
+// behave exactly as-is.
+using int_fd =
+#ifdef __WINDOWS__
+ os::WindowsFD;
+#else
+ int;
+#endif // __WINDOWS__
+
+#endif // __STOUT_OS_INT_FD_HPP__
http://git-wip-us.apache.org/repos/asf/mesos/blob/e7a4061d/3rdparty/stout/include/stout/os/windows/fd.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/windows/fd.hpp b/3rdparty/stout/include/stout/os/windows/fd.hpp
new file mode 100644
index 0000000..24d3661
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/windows/fd.hpp
@@ -0,0 +1,455 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_WINDOWS_FD_HPP__
+#define __STOUT_OS_WINDOWS_FD_HPP__
+
+#include <windows.h>
+#include <WinSock2.h>
+
+#include <array>
+#include <memory>
+#include <ostream>
+
+#include <stout/check.hpp>
+#include <stout/nothing.hpp>
+#include <stout/try.hpp>
+#include <stout/unreachable.hpp>
+
+namespace os {
+
+// The `WindowsFD` class exists to provide an common interface with the POSIX
+// file descriptor. While the bare `int` representation of the POSIX file
+// descriptor API is undesirable, we rendezvous there in order to maintain the
+// existing code in Mesos.
+//
+// In the platform-agnostic code paths, the `int_fd` type is aliased to
+// `WindowsFD`. The `os::*` functions return a type appropriate to the platform,
+// which allows us to write code like this:
+//
+// Try<int_fd> fd = os::open(...);
+//
+// The `WindowsFD` constructs off one of:
+// (1) `int` - from the WinCRT API
+// (2) `HANDLE` - from the Win32 API
+// (3) `SOCKET` - from the WinSock API
+//
+// The `os::*` functions then take an instance of `WindowsFD`, examines
+// the state and dispatches to the appropriate API.
+
+class WindowsFD
+{
+public:
+ enum Type
+ {
+ FD_CRT,
+ FD_HANDLE,
+ FD_SOCKET
+ };
+
+ WindowsFD() = default;
+
+ WindowsFD(int crt)
+ : type_(FD_CRT),
+ crt_(crt),
+ handle_(
+ crt < 0 ? INVALID_HANDLE_VALUE
+ : reinterpret_cast<HANDLE>(::_get_osfhandle(crt))) {}
+
+ // IMPORTANT: The `HANDLE` here is expected to be file handles. Specifically,
+ // `HANDLE`s returned by file API such as `CreateFile`. There are
+ // APIs that return `HANDLE`s with different error values, and
+ // thereofre must be handled accordingly. For example, a thread API
+ // such as `CreateThread` returns `NULL` as the error value, rather
+ // than `INVALID_HANDLE_VALUE`.
+ // TODO(mpark): Consider adding a second parameter which tells us what the
+ // error values are.
+ WindowsFD(HANDLE handle)
+ : type_(FD_HANDLE),
+ crt_(
+ handle == INVALID_HANDLE_VALUE
+ ? -1
+ : ::_open_osfhandle(reinterpret_cast<intptr_t>(handle), O_RDWR)),
+ handle_(handle) {}
+
+ WindowsFD(SOCKET socket) : type_(FD_SOCKET), socket_(socket) {}
+
+ WindowsFD(const WindowsFD&) = default;
+ WindowsFD(WindowsFD&&) = default;
+
+ ~WindowsFD() = default;
+
+ WindowsFD& operator=(const WindowsFD&) = default;
+ WindowsFD& operator=(WindowsFD&&) = default;
+
+ int crt() const
+ {
+ CHECK_EQ(FD_CRT, type());
+ return crt_;
+ }
+
+ operator HANDLE() const
+ {
+ CHECK_EQ(FD_HANDLE, type());
+ return handle_;
+ }
+
+ operator SOCKET() const
+ {
+ CHECK_EQ(FD_SOCKET, type());
+ return socket_;
+ }
+
+ // On Winodws, libevent's `evutil_socket_t` is set to `intptr_t`.
+ operator intptr_t() const
+ {
+ CHECK_EQ(FD_SOCKET, type());
+ return static_cast<intptr_t>(socket_);
+ }
+
+ Type type() const { return type_; }
+
+private:
+ Type type_;
+
+ union
+ {
+ // We keep both a CRT FD as well as a `HANDLE`
+ // regardless of whether we were constructed
+ // from a file or a handle.
+ //
+ // This is because once we request for a CRT FD
+ // from a `HANDLE`, we're required to close it
+ // via `_close`. If we were to do the conversion
+ // lazily upon request, the resulting CRT FD
+ // would be dangling.
+ struct
+ {
+ int crt_;
+ HANDLE handle_;
+ };
+ SOCKET socket_;
+ };
+};
+
+
+inline std::ostream& operator<<(std::ostream& stream, const WindowsFD& fd)
+{
+ switch (fd.type()) {
+ case WindowsFD::FD_CRT: {
+ stream << fd.crt();
+ break;
+ }
+ case WindowsFD::FD_HANDLE: {
+ stream << static_cast<HANDLE>(fd);
+ break;
+ }
+ case WindowsFD::FD_SOCKET: {
+ stream << static_cast<SOCKET>(fd);
+ break;
+ }
+ }
+ return stream;
+}
+
+
+// The complexity in this function is due to our effort in trying to support the
+// cases where file descriptors are compared as an `int` on POSIX. For example,
+// we use expressions such as `fd < 0` to check for validity.
+// TODO(mpark): Consider introducing an `is_valid` function for `int_fd`.
+inline bool operator<(const WindowsFD& left, const WindowsFD& right)
+{
+ // In general, when compared against a `WindowsFD` in the `FD_CRT`, we map
+ // `INVALD_HANDLE_VALUE` and `INVALID_SOCKET` to `-1` before performing the
+ // comparison. The check for `< 0` followed by cast to `HANDLE` or `SOCKET` is
+ // due to the fact that `HANDLE` and `SOCKET` are both unsigned.
+ switch (left.type()) {
+ case WindowsFD::FD_CRT: {
+ switch (right.type()) {
+ case WindowsFD::FD_CRT: {
+ return left.crt() < right.crt();
+ }
+ case WindowsFD::FD_HANDLE: {
+ if (static_cast<HANDLE>(right) == INVALID_HANDLE_VALUE) {
+ return left.crt() < -1;
+ }
+ if (left.crt() < 0) {
+ return true;
+ }
+ return reinterpret_cast<HANDLE>(left.crt()) <
+ static_cast<HANDLE>(right);
+ }
+ case WindowsFD::FD_SOCKET: {
+ if (static_cast<SOCKET>(right) == INVALID_SOCKET) {
+ return left.crt() < -1;
+ }
+ if (left.crt() < 0) {
+ return true;
+ }
+ return static_cast<SOCKET>(left.crt()) < static_cast<SOCKET>(right);
+ }
+ }
+ }
+ case WindowsFD::FD_HANDLE: {
+ switch (right.type()) {
+ case WindowsFD::FD_CRT: {
+ if (static_cast<HANDLE>(left) == INVALID_HANDLE_VALUE) {
+ return -1 < right.crt();
+ }
+ if (right.crt() < 0) {
+ return false;
+ }
+ return static_cast<HANDLE>(left) <
+ reinterpret_cast<HANDLE>(right.crt());
+ }
+ case WindowsFD::FD_HANDLE: {
+ return static_cast<HANDLE>(left) < static_cast<HANDLE>(right);
+ }
+ case WindowsFD::FD_SOCKET: {
+ return static_cast<HANDLE>(left) <
+ reinterpret_cast<HANDLE>(static_cast<SOCKET>(right));
+ }
+ }
+ }
+ case WindowsFD::FD_SOCKET: {
+ switch (right.type()) {
+ case WindowsFD::FD_CRT: {
+ if (static_cast<SOCKET>(left) == INVALID_SOCKET) {
+ return -1 < right.crt();
+ }
+ if (right.crt() < 0) {
+ return false;
+ }
+ return static_cast<SOCKET>(left) < static_cast<SOCKET>(right.crt());
+ }
+ case WindowsFD::FD_HANDLE: {
+ return reinterpret_cast<HANDLE>(static_cast<SOCKET>(left)) <
+ static_cast<HANDLE>(right);
+ }
+ case WindowsFD::FD_SOCKET: {
+ return static_cast<SOCKET>(left) < static_cast<SOCKET>(right);
+ }
+ }
+ }
+ }
+ UNREACHABLE();
+}
+
+
+inline bool operator<(int left, const WindowsFD& right)
+{
+ return WindowsFD(left) < right;
+}
+
+
+inline bool operator<(const WindowsFD& left, int right)
+{
+ return left < WindowsFD(right);
+}
+
+
+inline bool operator>(const WindowsFD& left, const WindowsFD& right)
+{
+ return right < left;
+}
+
+
+inline bool operator>(int left, const WindowsFD& right)
+{
+ return WindowsFD(left) > right;
+}
+
+
+inline bool operator>(const WindowsFD& left, int right)
+{
+ return left > WindowsFD(right);
+}
+
+
+inline bool operator<=(const WindowsFD& left, const WindowsFD& right)
+{
+ return !(left > right);
+}
+
+
+inline bool operator<=(int left, const WindowsFD& right)
+{
+ return WindowsFD(left) <= right;
+}
+
+
+inline bool operator<=(const WindowsFD& left, int right)
+{
+ return left <= WindowsFD(right);
+}
+
+
+inline bool operator>=(const WindowsFD& left, const WindowsFD& right)
+{
+ return !(left < right);
+}
+
+
+inline bool operator>=(int left, const WindowsFD& right)
+{
+ return WindowsFD(left) >= right;
+}
+
+
+inline bool operator>=(const WindowsFD& left, int right)
+{
+ return left >= WindowsFD(right);
+}
+
+
+// The complexity in this function is due to our effort in trying to support the
+// cases where file descriptors are compared as an `int` on POSIX. For example,
+// we use expressions such as `fd != -1` to check for validity.
+// TODO(mpark): Consider introducing an `is_valid` function for `int_fd`.
+inline bool operator==(const WindowsFD& left, const WindowsFD& right)
+{
+ // In general, when compared against a `WindowsFD` in the `FD_CRT`, we map
+ // `INVALD_HANDLE_VALUE` and `INVALID_SOCKET` to `-1` before performing the
+ // comparison. The check for `< 0` followed by cast to `HANDLE` or `SOCKET` is
+ // due to the fact that `HANDLE` and `SOCKET` are both unsigned.
+ switch (left.type()) {
+ case WindowsFD::FD_CRT: {
+ switch (right.type()) {
+ case WindowsFD::FD_CRT: {
+ return left.crt() == right.crt();
+ }
+ case WindowsFD::FD_HANDLE: {
+ if (static_cast<HANDLE>(right) == INVALID_HANDLE_VALUE) {
+ return left.crt() == -1;
+ }
+ if (left.crt() < 0) {
+ return false;
+ }
+ return reinterpret_cast<HANDLE>(left.crt()) ==
+ static_cast<HANDLE>(right);
+ }
+ case WindowsFD::FD_SOCKET: {
+ if (static_cast<SOCKET>(right) == INVALID_SOCKET) {
+ return left.crt() == -1;
+ }
+ if (left.crt() < 0) {
+ return false;
+ }
+ return static_cast<SOCKET>(left.crt()) == static_cast<SOCKET>(right);
+ }
+ }
+ }
+ case WindowsFD::FD_HANDLE: {
+ switch (right.type()) {
+ case WindowsFD::FD_CRT: {
+ if (static_cast<HANDLE>(left) == INVALID_HANDLE_VALUE) {
+ return -1 == right.crt();
+ }
+ if (right.crt() < 0) {
+ return false;
+ }
+ return static_cast<HANDLE>(left) ==
+ reinterpret_cast<HANDLE>(right.crt());
+ }
+ case WindowsFD::FD_HANDLE: {
+ return static_cast<HANDLE>(left) == static_cast<HANDLE>(right);
+ }
+ case WindowsFD::FD_SOCKET: {
+ return static_cast<HANDLE>(left) ==
+ reinterpret_cast<HANDLE>(static_cast<SOCKET>(right));
+ }
+ }
+ }
+ case WindowsFD::FD_SOCKET: {
+ switch (right.type()) {
+ case WindowsFD::FD_CRT: {
+ if (static_cast<SOCKET>(left) == INVALID_SOCKET) {
+ return -1 == right.crt();
+ }
+ if (right.crt() < 0) {
+ return false;
+ }
+ return static_cast<SOCKET>(left) == static_cast<SOCKET>(right.crt());
+ }
+ case WindowsFD::FD_HANDLE: {
+ return reinterpret_cast<HANDLE>(static_cast<SOCKET>(left)) ==
+ static_cast<HANDLE>(right);
+ }
+ case WindowsFD::FD_SOCKET: {
+ return static_cast<SOCKET>(left) == static_cast<SOCKET>(right);
+ }
+ }
+ }
+ }
+ UNREACHABLE();
+}
+
+
+inline bool operator==(int left, const WindowsFD& right)
+{
+ return WindowsFD(left) == right;
+}
+
+
+inline bool operator==(const WindowsFD& left, int right)
+{
+ return left == WindowsFD(right);
+}
+
+
+inline bool operator!=(const WindowsFD& left, const WindowsFD& right)
+{
+ return !(left == right);
+}
+
+
+inline bool operator!=(int left, const WindowsFD& right)
+{
+ return WindowsFD(left) != right;
+}
+
+
+inline bool operator!=(const WindowsFD& left, int right)
+{
+ return left != WindowsFD(right);
+}
+
+} // namespace os {
+
+namespace std {
+
+template <>
+struct hash<os::WindowsFD>
+{
+ using argument_type = os::WindowsFD;
+ using result_type = size_t;
+
+ result_type operator()(const argument_type& fd) const
+ {
+ switch (fd.type()) {
+ case os::WindowsFD::FD_CRT: {
+ return static_cast<result_type>(fd.crt());
+ }
+ case os::WindowsFD::FD_HANDLE: {
+ return reinterpret_cast<result_type>(static_cast<HANDLE>(fd));
+ }
+ case os::WindowsFD::FD_SOCKET: {
+ return static_cast<result_type>(static_cast<SOCKET>(fd));
+ }
+ }
+ UNREACHABLE();
+ }
+};
+
+} // namespace std {
+
+#endif // __STOUT_OS_WINDOWS_FD_HPP__