You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by be...@apache.org on 2013/06/17 21:40:25 UTC

git commit: Added os::sysctl to stout.

Updated Branches:
  refs/heads/master 028d500c6 -> b3c0a6551


Added os::sysctl to stout.

Review: https://reviews.apache.org/r/11895


Project: http://git-wip-us.apache.org/repos/asf/incubator-mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mesos/commit/b3c0a655
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mesos/tree/b3c0a655
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mesos/diff/b3c0a655

Branch: refs/heads/master
Commit: b3c0a65517d2550fb6832363cd3290cbf4e9e151
Parents: 028d500
Author: Benjamin Hindman <be...@twitter.com>
Authored: Sat Jun 15 14:46:26 2013 -0700
Committer: Benjamin Hindman <be...@twitter.com>
Committed: Mon Jun 17 12:39:30 2013 -0700

----------------------------------------------------------------------
 3rdparty/libprocess/3rdparty/stout/Makefile.am  |   1 +
 .../3rdparty/stout/include/stout/os/sysctl.hpp  | 243 +++++++++++++++++++
 .../3rdparty/stout/tests/os_tests.cpp           |  41 ++++
 3 files changed, 285 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/b3c0a655/3rdparty/libprocess/3rdparty/stout/Makefile.am
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/Makefile.am b/3rdparty/libprocess/3rdparty/stout/Makefile.am
index 84062a0..2b7ee9c 100644
--- a/3rdparty/libprocess/3rdparty/stout/Makefile.am
+++ b/3rdparty/libprocess/3rdparty/stout/Makefile.am
@@ -34,6 +34,7 @@ EXTRA_DIST =					\
   include/stout/numify.hpp			\
   include/stout/option.hpp			\
   include/stout/os.hpp				\
+  include/stout/os/sysctl.hpp			\
   include/stout/owned.hpp			\
   include/stout/path.hpp			\
   include/stout/preprocessor.hpp		\

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/b3c0a655/3rdparty/libprocess/3rdparty/stout/include/stout/os/sysctl.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/include/stout/os/sysctl.hpp b/3rdparty/libprocess/3rdparty/stout/include/stout/os/sysctl.hpp
new file mode 100644
index 0000000..e36f3b5
--- /dev/null
+++ b/3rdparty/libprocess/3rdparty/stout/include/stout/os/sysctl.hpp
@@ -0,0 +1,243 @@
+#ifndef __STOUT_OS_SYSCTL_HPP__
+#define __STOUT_OS_SYSCTL_HPP__
+
+// Only provide sysctl support for OS X.
+#ifndef __APPLE__
+#error "stout/os/sysctl.hpp is only available on OS X."
+#endif
+
+#include <string>
+#include <vector>
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <stout/error.hpp>
+#include <stout/none.hpp>
+#include <stout/option.hpp>
+#include <stout/strings.hpp>
+#include <stout/try.hpp>
+
+namespace os {
+
+// Provides an abstraction for getting system information via the
+// underlying 'sysctl' system call. You describe the sysctl
+// "Management Information Base" (MIB) name via the constructor, for
+// example, to describe "maximum number of processes allowed in the
+// system" you would do:
+//
+//   os::sysctl(CTL_KERN, KERN_MAXPROC)
+//
+// To _retrieve_ the value you need to use one of the 'integer',
+// 'string', or 'table' methods to indicate the type of the value
+// being retrieved. For example:
+//
+//   Try<int> maxproc = os::sysctl(CTL_KERN, KERN_MAXPROC).integer();
+//
+// Note that the 'table' method requires specifying a length. If you
+// would like the length to be looked up dynamically you can just pass
+// None. Here's an example using 'table' that builds on above:
+//
+//   Try<vector<kinfo_proc> > processes =
+//     os::sysctl(CTL_KERN, KERN_PROC, KERN_PROC_ALL).table(maxprox.get());
+//
+// TODO(benh): Provide an 'integer(i)', 'string(s)', and 'table(t)' to
+// enable setting system information.
+struct sysctl
+{
+  // Note that we create a constructor for each number of levels
+  // because we can't pick a suitable default for unused levels (in
+  // order to distinguish no value from some value) and while Option
+  // would solve that it could also cause people to use None which
+  // we'd need to later handle as an error.
+  explicit sysctl(int level1);
+  sysctl(int level1, int level2);
+  sysctl(int level1, int level2, int level3);
+  sysctl(int level1, int level2, int level3, int level4);
+  sysctl(int level1, int level2, int level3, int level4, int level5);
+  ~sysctl();
+
+  // Get system information as an integer.
+  Try<int> integer() const;
+
+  // Get system information as a string.
+  Try<std::string> string() const;
+
+  // Get system information as a table, optionally specifying a
+  // length. Note that this function is lazy and will not actually
+  // perform the syscall until you cast (implicitely or explicitly) a
+  // 'Table' to a std::vector<T>. For example, to get the first 10
+  // processes in the process table you can do:
+  //
+  //     Try<std::vector<kinfo_proc> > processes =
+  //       os::sysctl(CTL_KERN, KERN_PROC, KERN_PROC_ALL).table(10);
+  //
+private: struct Table; // Forward declaration.
+public:
+  Table table(const Option<size_t>& length = None()) const;
+
+private:
+  struct Table
+  {
+    Table(int _levels, int* _name, const Option<size_t>& _length);
+
+    template <typename T>
+    operator Try<std::vector<T> > ();
+
+    const int levels;
+    int* name;
+    Option<size_t> length;
+  };
+
+  const int levels;
+  int* name;
+};
+
+
+sysctl::sysctl(int level1)
+  : levels(1), name(new int[levels])
+{
+  name[0] = level1;
+}
+
+
+sysctl::sysctl(int level1, int level2)
+  : levels(2), name(new int[levels])
+{
+  name[0] = level1;
+  name[1] = level2;
+}
+
+
+sysctl::sysctl(int level1, int level2, int level3)
+  : levels(3), name(new int[levels])
+{
+  name[0] = level1;
+  name[1] = level2;
+  name[2] = level3;
+}
+
+
+sysctl::sysctl(int level1, int level2, int level3, int level4)
+  : levels(4), name(new int[levels])
+{
+  name[0] = level1;
+  name[1] = level2;
+  name[2] = level3;
+  name[3] = level4;
+}
+
+
+sysctl::sysctl(int level1, int level2, int level3, int level4, int level5)
+  : levels(5), name(new int[levels])
+{
+  name[0] = level1;
+  name[1] = level2;
+  name[2] = level3;
+  name[3] = level4;
+  name[4] = level5;
+}
+
+
+sysctl::~sysctl()
+{
+  delete[] name;
+}
+
+
+inline Try<int> sysctl::integer() const
+{
+  int i;
+  size_t size = sizeof(i);
+  if (::sysctl(name, levels, &i, &size, NULL, 0) == -1) {
+    return ErrnoError();
+  }
+  return i;
+}
+
+
+inline Try<std::string> sysctl::string() const
+{
+  // First determine the size of the string.
+  size_t size = 0;
+  if (::sysctl(name, levels, NULL, &size, NULL, 0) == -1) {
+    return ErrnoError();
+  }
+
+  // Now read it.
+  size_t length = size / sizeof(char);
+  char* temp = new char[length];
+  if (::sysctl(name, levels, temp, &size, NULL, 0) == -1) {
+    Error error = ErrnoError();
+    delete[] temp;
+    return error;
+  }
+
+  // TODO(benh): It's possible that the value has changed since we
+  // determined it's length above. We should really check that we
+  // get back the same length and if not throw an error.
+
+  std::string result(temp);
+  delete[] temp;
+  return result;
+}
+
+
+inline sysctl::Table sysctl::table(const Option<size_t>& length) const
+{
+  return Table(levels, name, length);
+}
+
+
+inline sysctl::Table::Table(
+    int _levels,
+    int* _name,
+    const Option<size_t>& _length)
+  : levels(_levels),
+    name(_name),
+    length(_length)
+{}
+
+
+template <typename T>
+sysctl::Table::operator Try<std::vector<T> > ()
+{
+  size_t size = 0;
+  if (length.isNone()) {
+    if (::sysctl(name, levels, NULL, &size, NULL, 0) == -1) {
+      return ErrnoError();
+    }
+    if (size % sizeof(T) != 0) {
+      return Error("Failed to determine the length of result, "
+                   "amount of available data is not a multiple "
+                   "of the table type");
+    }
+    length = Option<size_t>(size / sizeof(T));
+  }
+
+  T* ts = new T[length.get()];
+  size = length.get() * sizeof(T);
+  if (::sysctl(name, levels, ts, &size, NULL, 0) == -1) {
+    Error error = ErrnoError();
+    delete[] ts;
+    return error;
+  }
+
+  // TODO(benh): It's possible that the value has changed since we
+  // determined it's length above (or from what was specified). We
+  // should really check that we get back the same length and if not
+  // throw an error.
+
+  length = size / sizeof(T);
+
+  std::vector<T> results;
+  for (size_t i = 0; i < length.get(); i++) {
+    results.push_back(ts[i]);
+  }
+  delete[] ts;
+  return results;
+}
+
+} // namespace os {
+
+#endif // __STOUT_OS_SYSCTL_HPP__

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/b3c0a655/3rdparty/libprocess/3rdparty/stout/tests/os_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/tests/os_tests.cpp b/3rdparty/libprocess/3rdparty/stout/tests/os_tests.cpp
index 047778d..73b2336 100644
--- a/3rdparty/libprocess/3rdparty/stout/tests/os_tests.cpp
+++ b/3rdparty/libprocess/3rdparty/stout/tests/os_tests.cpp
@@ -13,6 +13,10 @@
 #include <stout/try.hpp>
 #include <stout/uuid.hpp>
 
+#ifdef __APPLE__
+#include <stout/os/sysctl.hpp>
+#endif
+
 using std::string;
 
 
@@ -206,3 +210,40 @@ TEST_F(OsTest, sleep)
 
   ASSERT_ERROR(os::sleep(Milliseconds(-10)));
 }
+
+
+#ifdef __APPLE__
+TEST_F(OsTest, sysctl)
+{
+  Try<os::UTSInfo> uname = os::uname();
+
+  ASSERT_SOME(uname);
+
+  Try<string> release = os::sysctl(CTL_KERN, KERN_OSRELEASE).string();
+
+  ASSERT_SOME(release);
+  EXPECT_EQ(uname.get().release, release.get());
+
+  Try<string> type = os::sysctl(CTL_KERN, KERN_OSTYPE).string();
+
+  ASSERT_SOME(type);
+  EXPECT_EQ(uname.get().sysname, type.get());
+
+  Try<int> maxproc = os::sysctl(CTL_KERN, KERN_MAXPROC).integer();
+
+  ASSERT_SOME(maxproc);
+
+  Try<std::vector<kinfo_proc> > processes =
+    os::sysctl(CTL_KERN, KERN_PROC, KERN_PROC_ALL).table(maxproc.get());
+
+  ASSERT_SOME(processes);
+
+  std::set<pid_t> pids;
+
+  foreach (const kinfo_proc& process, processes.get()) {
+    pids.insert(process.kp_proc.p_pid);
+  }
+
+  EXPECT_EQ(1, pids.count(getpid()));
+}
+#endif // __APPLE__