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__