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 2012/10/27 00:07:02 UTC

svn commit: r1402687 - in /incubator/mesos/trunk: src/linux/cgroups.cpp src/linux/cgroups.hpp third_party/libprocess/include/stout/path.hpp

Author: benh
Date: Fri Oct 26 22:07:02 2012
New Revision: 1402687

URL: http://svn.apache.org/viewvc?rev=1402687&view=rev
Log:
Added cgroups::hierarchies to list the currently active hierarchies
and cgroups::internal::cloneCpusetValues in order to copy cpuset.cpus
and cpuset.mems from a parent to a child cgroup. Also updated code to
use path::join as appropriate.

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

Modified:
    incubator/mesos/trunk/src/linux/cgroups.cpp
    incubator/mesos/trunk/src/linux/cgroups.hpp
    incubator/mesos/trunk/third_party/libprocess/include/stout/path.hpp

Modified: incubator/mesos/trunk/src/linux/cgroups.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/linux/cgroups.cpp?rev=1402687&r1=1402686&r2=1402687&view=diff
==============================================================================
--- incubator/mesos/trunk/src/linux/cgroups.cpp (original)
+++ incubator/mesos/trunk/src/linux/cgroups.cpp Fri Oct 26 22:07:02 2012
@@ -27,8 +27,12 @@
 #include <glog/logging.h>
 
 #include <fstream>
+#include <list>
 #include <map>
+#include <set>
 #include <sstream>
+#include <string>
+#include <vector>
 
 #include <process/collect.hpp>
 #include <process/defer.hpp>
@@ -41,6 +45,7 @@
 #include <stout/lambda.hpp>
 #include <stout/option.hpp>
 #include <stout/os.hpp>
+#include <stout/path.hpp>
 #include <stout/stringify.hpp>
 #include <stout/strings.hpp>
 
@@ -48,16 +53,23 @@
 #include "linux/fs.hpp"
 #include "linux/proc.hpp"
 
+// TODO(bmahler): Change all unnecessary Future<bool>'s to Future<Nothing>'s.
+
 using namespace process;
+
+// TODO(benh): Move linux/fs.hpp out of 'mesos- namespace.
 using namespace mesos::internal;
 
-namespace cgroups {
+using std::list;
+using std::map;
+using std::set;
+using std::string;
+using std::vector;
 
+namespace cgroups {
 namespace internal {
 
-
-// TODO(bmahler): Change all unnecessary Future<bool>'s to Future<Nothing>'s.
-// Snapshot a subsystem (modeled after a line in /proc/cgroups).
+// Snapshot of a subsystem (modeled after a line in /proc/cgroups).
 struct SubsystemInfo
 {
   SubsystemInfo()
@@ -65,7 +77,7 @@ struct SubsystemInfo
       cgroups(0),
       enabled(false) {}
 
-  SubsystemInfo(const std::string& _name,
+  SubsystemInfo(const string& _name,
                 int _hierarchy,
                 int _cgroups,
                 bool _enabled)
@@ -74,7 +86,7 @@ struct SubsystemInfo
       cgroups(_cgroups),
       enabled(_enabled) {}
 
-  std::string name; // Name of the subsystem.
+  string name;      // Name of the subsystem.
   int hierarchy;    // ID of the hierarchy the subsystem is attached to.
   int cgroups;      // Number of cgroups for the subsystem.
   bool enabled;     // Whether the subsystem is enabled or not.
@@ -85,25 +97,25 @@ struct SubsystemInfo
 // information from /proc/cgroups file. Each line in it describes a subsystem.
 // @return  A map from subsystem names to SubsystemInfo instances if succeeds.
 //          Error if any unexpected happens.
-static Try<std::map<std::string, SubsystemInfo> > subsystems()
+static Try<map<string, SubsystemInfo> > subsystems()
 {
   std::ifstream file("/proc/cgroups");
 
   if (!file.is_open()) {
-    return Try<std::map<std::string, SubsystemInfo> >::error(
+    return Try<map<string, SubsystemInfo> >::error(
         "Failed to open /proc/cgroups");
   }
 
-  std::map<std::string, SubsystemInfo> infos;
+  map<string, SubsystemInfo> infos;
 
   while (!file.eof()) {
-    std::string line;
+    string line;
     std::getline(file, line);
 
     if (file.fail()) {
       if (!file.eof()) {
         file.close();
-        return Try<std::map<std::string, SubsystemInfo> >::error(
+        return Try<map<string, SubsystemInfo> >::error(
             "Failed to read /proc/cgroups");
       }
     } else {
@@ -115,7 +127,7 @@ static Try<std::map<std::string, Subsyst
         continue;
       } else {
         // Parse line to get subsystem info.
-        std::string name;
+        string name;
         int hierarchy;
         int cgroups;
         bool enabled;
@@ -126,7 +138,7 @@ static Try<std::map<std::string, Subsyst
         // Check for any read/parse errors.
         if (ss.fail() && !ss.eof()) {
           file.close();
-          return Try<std::map<std::string, SubsystemInfo> >::error(
+          return Try<map<string, SubsystemInfo> >::error(
               "Failed to parse /proc/cgroups");
         }
 
@@ -153,8 +165,7 @@ static Try<std::map<std::string, Subsyst
 // @param   subsystems  Comma-separated subsystem names.
 // @return  Some if the operation succeeds.
 //          Error if the operation fails.
-static Try<Nothing> mount(const std::string& hierarchy,
-                          const std::string& subsystems)
+static Try<Nothing> mount(const string& hierarchy, const string& subsystems)
 {
   return fs::mount(subsystems, hierarchy, "cgroup", 0, subsystems.c_str());
 }
@@ -167,12 +178,55 @@ static Try<Nothing> mount(const std::str
 // @param   hierarchy   Path to the hierarchy root.
 // @return  Some if the operation succeeds.
 //          Error if the operation fails.
-static Try<Nothing> unmount(const std::string& hierarchy)
+static Try<Nothing> unmount(const string& hierarchy)
 {
   return fs::unmount(hierarchy);
 }
 
 
+// Copies the value of 'cpuset.cpus' and 'cpuset.mems' from a parent
+// cgroup to a child cgroup so the child cgroup can actually run tasks
+// (otherwise it gets the error 'Device or resource busy').
+// @param   hierarchy      Path to hierarchy root.
+// @param   parentCgroup   Path to parent cgroup relative to the hierarchy root.
+// @param   childCgroup    Path to child cgroup relative to the hierarchy root.
+// @return  Some if the operation succeeds.
+//          Error if the operation fails.
+static Try<Nothing> cloneCpusetCpusMems(
+    const string& hierarchy,
+    const string& parentCgroup,
+    const string& childCgroup)
+{
+  Try<string> cpus = readControl(hierarchy, parentCgroup, "cpuset.cpus");
+  if (cpus.isError()) {
+    return Try<Nothing>::error(
+        "Failed to read cpuset.cpus: " + cpus.error());
+  }
+
+  Try<string> mems = readControl(hierarchy, parentCgroup, "cpuset.mems");
+  if (mems.isError()) {
+    return Try<Nothing>::error(
+        "Failed to read cpuset.mems: " + mems.error());
+  }
+
+  Try<Nothing> write =
+    writeControl(hierarchy, childCgroup, "cpuset.cpus", cpus.get());
+  if (write.isError()) {
+    return Try<Nothing>::error(
+        "Failed to write cpuset.cpus: " + write.error());
+  }
+
+  write =
+    writeControl(hierarchy, childCgroup, "cpuset.mems", mems.get());
+  if (write.isError()) {
+    return Try<Nothing>::error(
+        "Failed to write cpuset.mems: " + write.error());
+  }
+
+  return Nothing();
+}
+
+
 // Create a cgroup in a given hierarchy. To create a cgroup, one just need to
 // create a directory in the cgroups virtual file system. The given cgroup is a
 // relative path to the given hierarchy. This function assumes the given
@@ -184,20 +238,30 @@ static Try<Nothing> unmount(const std::s
 // @param   cgroup      Path to the cgroup relative to the hierarchy root.
 // @return  Some if the operation succeeds.
 //          Error if the operation fails.
-static Try<Nothing> createCgroup(const std::string& hierarchy,
-                                 const std::string& cgroup)
+static Try<Nothing> createCgroup(const string& hierarchy, const string& cgroup)
 {
-  std::string path = hierarchy + "/" + cgroup;
+  string path = path::join(hierarchy, cgroup);
 
   // Do NOT recursively create cgroups.
   Try<Nothing> mkdir = os::mkdir(path, false);
-
   if (mkdir.isError()) {
     return Try<Nothing>::error(
-        "Failed to create cgroup at " + path + ": " + mkdir.error());
+        "Failed to create cgroup at '" + path + "': " + mkdir.error());
   }
 
-  return mkdir;
+  // Now clone 'cpuset.cpus' and 'cpuset.mems' if the 'cpuset'
+  // subsystem is attached to the hierarchy.
+  if (checkHierarchy(hierarchy, "cpuset").isSome()) {
+    Try<string> parent = os::dirname(path::join("/", cgroup));
+    if (parent.isError()) {
+      return Try<Nothing>::error(
+          "Failed to determine parent cgroup of '" + cgroup + "': " +
+          parent.error());
+    }
+    return cloneCpusetCpusMems(hierarchy, parent.get(), cgroup);
+  }
+
+  return Nothing();
 }
 
 
@@ -211,10 +275,9 @@ static Try<Nothing> createCgroup(const s
 // @param   cgroup      Path to the cgroup relative to the hierarchy root.
 // @return  Some if the operation succeeds.
 //          Error if the operation fails.
-static Try<Nothing> removeCgroup(const std::string& hierarchy,
-                                 const std::string& cgroup)
+static Try<Nothing> removeCgroup(const string& hierarchy, const string& cgroup)
 {
-  std::string path = hierarchy + "/" + cgroup;
+  string path = path::join(hierarchy, cgroup);
 
   // Do NOT recursively remove cgroups.
   Try<Nothing> rmdir = os::rmdir(path, false);
@@ -236,18 +299,19 @@ static Try<Nothing> removeCgroup(const s
 // @param   cgroup      Path to the cgroup relative to the hierarchy root.
 // @param   control     Name of the control file.
 // @return  The value read from the control file.
-static Try<std::string> readControl(const std::string& hierarchy,
-                                    const std::string& cgroup,
-                                    const std::string& control)
+static Try<string> readControl(
+    const string& hierarchy,
+    const string& cgroup,
+    const string& control)
 {
-  std::string path = hierarchy + "/" + cgroup + "/" + control;
+  string path = path::join(hierarchy, cgroup, control);
 
   // We do not use os::read here because it cannot correctly read proc or
   // cgroups control files (lseek will return error).
   std::ifstream file(path.c_str());
 
   if (!file.is_open()) {
-    return Try<std::string>::error("Failed to open file " + path);
+    return Try<string>::error("Failed to open file " + path);
   }
 
   std::ostringstream ss;
@@ -255,9 +319,9 @@ static Try<std::string> readControl(cons
 
   if (file.fail()) {
     // TODO(jieyu): Make sure that the way we get errno here is portable.
-    std::string msg = strerror(errno);
+    string msg = strerror(errno);
     file.close();
-    return Try<std::string>::error(msg);
+    return Try<string>::error(msg);
   }
 
   file.close();
@@ -272,12 +336,13 @@ static Try<std::string> readControl(cons
 // @param   value       Value to be written.
 // @return  Some if the operation succeeds.
 //          Error if the operation fails.
-static Try<Nothing> writeControl(const std::string& hierarchy,
-                                 const std::string& cgroup,
-                                 const std::string& control,
-                                 const std::string& value)
+static Try<Nothing> writeControl(
+    const string& hierarchy,
+    const string& cgroup,
+    const string& control,
+    const string& value)
 {
-  std::string path = hierarchy + "/" + cgroup + "/" + control;
+  string path = path::join(hierarchy, cgroup, control);
   std::ofstream file(path.c_str());
 
   if (!file.is_open()) {
@@ -288,7 +353,7 @@ static Try<Nothing> writeControl(const s
 
   if (file.fail()) {
     // TODO(jieyu): Make sure that the way we get errno here is portable.
-    std::string msg = strerror(errno);
+    string msg = strerror(errno);
     file.close();
     return Try<Nothing>::error(msg);
   }
@@ -306,23 +371,46 @@ bool enabled()
 }
 
 
-Try<bool> enabled(const std::string& subsystems)
+Try<set<string> > hierarchies()
 {
-  std::vector<std::string> names = strings::tokenize(subsystems, ",");
+  // Read currently mounted file systems from /proc/mounts.
+  Try<fs::MountTable> table = fs::MountTable::read("/proc/mounts");
+  if (table.isError()) {
+    return Try<set<string> >::error(table.error());
+  }
+
+  set<string> results;
+  foreach (const fs::MountTable::Entry& entry, table.get().entries) {
+    if (entry.type == "cgroup") {
+      Try<string> realpath = os::realpath(entry.dir);
+      if (realpath.isError()) {
+        return Try<set<string> >::error(realpath.error());
+      }
+      results.insert(realpath.get());
+    }
+  }
+
+  return results;
+}
+
+
+Try<bool> enabled(const string& subsystems)
+{
+  vector<string> names = strings::tokenize(subsystems, ",");
   if (names.empty()) {
     return Try<bool>::error("No subsystem is specified");
   }
 
-  Try<std::map<std::string, internal::SubsystemInfo> >
+  Try<map<string, internal::SubsystemInfo> >
     infosResult = internal::subsystems();
   if (infosResult.isError()) {
     return Try<bool>::error(infosResult.error());
   }
 
-  std::map<std::string, internal::SubsystemInfo> infos = infosResult.get();
+  map<string, internal::SubsystemInfo> infos = infosResult.get();
   bool disabled = false;  // Whether some subsystems are not enabled.
 
-  foreach (const std::string& name, names) {
+  foreach (const string& name, names) {
     if (infos.find(name) == infos.end()) {
       return Try<bool>::error("Subsystem " + name + " not found");
     }
@@ -337,23 +425,23 @@ Try<bool> enabled(const std::string& sub
 }
 
 
-Try<bool> busy(const std::string& subsystems)
+Try<bool> busy(const string& subsystems)
 {
-  std::vector<std::string> names = strings::tokenize(subsystems, ",");
+  vector<string> names = strings::tokenize(subsystems, ",");
   if (names.empty()) {
     return Try<bool>::error("No subsystem is specified");
   }
 
-  Try<std::map<std::string, internal::SubsystemInfo> >
+  Try<map<string, internal::SubsystemInfo> >
     infosResult = internal::subsystems();
   if (infosResult.isError()) {
     return Try<bool>::error(infosResult.error());
   }
 
-  std::map<std::string, internal::SubsystemInfo> infos = infosResult.get();
+  map<string, internal::SubsystemInfo> infos = infosResult.get();
   bool busy = false;
 
-  foreach (const std::string& name, names) {
+  foreach (const string& name, names) {
     if (infos.find(name) == infos.end()) {
       return Try<bool>::error("Subsystem " + name + " not found");
     }
@@ -368,15 +456,14 @@ Try<bool> busy(const std::string& subsys
 }
 
 
-Try<std::set<std::string> > subsystems()
+Try<set<string> > subsystems()
 {
-  Try<std::map<std::string, internal::SubsystemInfo> >
-    infos = internal::subsystems();
+  Try<map<string, internal::SubsystemInfo> > infos = internal::subsystems();
   if (infos.isError()) {
-    return Try<std::set<std::string> >::error(infos.error());
+    return Try<set<string> >::error(infos.error());
   }
 
-  std::set<std::string> names;
+  set<string> names;
   foreachvalue (const internal::SubsystemInfo& info, infos.get()) {
     if (info.enabled) {
       names.insert(info.name);
@@ -387,27 +474,27 @@ Try<std::set<std::string> > subsystems()
 }
 
 
-Try<std::set<std::string> > subsystems(const std::string& hierarchy)
+Try<set<string> > subsystems(const string& hierarchy)
 {
   // We compare the canonicalized absolute paths.
-  Try<std::string> hierarchyAbsPath = os::realpath(hierarchy);
+  Try<string> hierarchyAbsPath = os::realpath(hierarchy);
   if (hierarchyAbsPath.isError()) {
-    return Try<std::set<std::string> >::error(hierarchyAbsPath.error());
+    return Try<set<string> >::error(hierarchyAbsPath.error());
   }
 
   // Read currently mounted file systems from /proc/mounts.
   Try<fs::MountTable> table = fs::MountTable::read("/proc/mounts");
   if (table.isError()) {
-    return Try<std::set<std::string> >::error(table.error());
+    return Try<set<string> >::error(table.error());
   }
 
   // Check if hierarchy is a mount point of type cgroup.
   Option<fs::MountTable::Entry> hierarchyEntry;
   foreach (const fs::MountTable::Entry& entry, table.get().entries) {
     if (entry.type == "cgroup") {
-      Try<std::string> dirAbsPath = os::realpath(entry.dir);
+      Try<string> dirAbsPath = os::realpath(entry.dir);
       if (dirAbsPath.isError()) {
-        return Try<std::set<std::string> >::error(dirAbsPath.error());
+        return Try<set<string> >::error(dirAbsPath.error());
       }
 
       // Seems that a directory can be mounted more than once. Previous mounts
@@ -420,20 +507,20 @@ Try<std::set<std::string> > subsystems(c
   }
 
   if (hierarchyEntry.isNone()) {
-    return Try<std::set<std::string> >::error(
+    return Try<set<string> >::error(
         hierarchy + " is not a mount point for cgroups");
   }
 
   // Get the intersection of the currently enabled subsystems and mount
   // options. Notice that mount options may contain somethings (e.g. rw) that
   // are not in the set of enabled subsystems.
-  Try<std::set<std::string> > names = subsystems();
+  Try<set<string> > names = subsystems();
   if (names.isError()) {
-    return Try<std::set<std::string> >::error(names.error());
+    return Try<set<string> >::error(names.error());
   }
 
-  std::set<std::string> result;
-  foreach (const std::string& name, names.get()) {
+  set<string> result;
+  foreach (const string& name, names.get()) {
     if (hierarchyEntry.get().hasOption(name)) {
       result.insert(name);
     }
@@ -443,8 +530,7 @@ Try<std::set<std::string> > subsystems(c
 }
 
 
-Try<Nothing> createHierarchy(const std::string& hierarchy,
-                             const std::string& subsystems)
+Try<Nothing> createHierarchy(const string& hierarchy, const string& subsystems)
 {
   if (os::exists(hierarchy)) {
     return Try<Nothing>::error(
@@ -464,7 +550,7 @@ Try<Nothing> createHierarchy(const std::
   if (busyResult.isError()) {
     return Try<Nothing>::error(busyResult.error());
   } else if (busyResult.get()) {
-    return Try<Nothing>::error("Some subsystems are currently being attached");
+    return Try<Nothing>::error("Some subsystems are currently busy");
   }
 
   // Create the directory for the hierarchy.
@@ -486,7 +572,7 @@ Try<Nothing> createHierarchy(const std::
 }
 
 
-Try<Nothing> removeHierarchy(const std::string& hierarchy)
+Try<Nothing> removeHierarchy(const string& hierarchy)
 {
   Try<Nothing> check = checkHierarchy(hierarchy);
   if (check.isError()) {
@@ -507,9 +593,9 @@ Try<Nothing> removeHierarchy(const std::
 }
 
 
-Try<Nothing> checkHierarchy(const std::string& hierarchy)
+Try<Nothing> checkHierarchy(const string& hierarchy)
 {
-  Try<std::set<std::string> > names = subsystems(hierarchy);
+  Try<set<string> > names = subsystems(hierarchy);
   if (names.isError()) {
     return Try<Nothing>::error(names.error());
   }
@@ -518,8 +604,7 @@ Try<Nothing> checkHierarchy(const std::s
 }
 
 
-Try<Nothing> checkHierarchy(const std::string& hierarchy,
-                            const std::string& subsystems)
+Try<Nothing> checkHierarchy(const string& hierarchy, const string& subsystems)
 {
   // Check if subsystems are enabled in the system.
   Try<bool> enabledResult = enabled(subsystems);
@@ -529,13 +614,13 @@ Try<Nothing> checkHierarchy(const std::s
     return Try<Nothing>::error("Some subsystems are not enabled");
   }
 
-  Try<std::set<std::string> > namesResult = cgroups::subsystems(hierarchy);
+  Try<set<string> > namesResult = cgroups::subsystems(hierarchy);
   if (namesResult.isError()) {
     return Try<Nothing>::error(namesResult.error());
   }
 
-  std::set<std::string> names = namesResult.get();
-  foreach (const std::string& name, strings::tokenize(subsystems, ",")) {
+  set<string> names = namesResult.get();
+  foreach (const string& name, strings::tokenize(subsystems, ",")) {
     if (names.find(name) == names.end()) {
       return Try<Nothing>::error(
           "Subsystem " + name + " is not found or enabled");
@@ -546,8 +631,7 @@ Try<Nothing> checkHierarchy(const std::s
 }
 
 
-Try<Nothing> createCgroup(const std::string& hierarchy,
-                          const std::string& cgroup)
+Try<Nothing> createCgroup(const string& hierarchy, const string& cgroup)
 {
   Try<Nothing> check = checkHierarchy(hierarchy);
   if (check.isError()) {
@@ -558,15 +642,14 @@ Try<Nothing> createCgroup(const std::str
 }
 
 
-Try<Nothing> removeCgroup(const std::string& hierarchy,
-                          const std::string& cgroup)
+Try<Nothing> removeCgroup(const string& hierarchy, const string& cgroup)
 {
   Try<Nothing> check = checkCgroup(hierarchy, cgroup);
   if (check.isError()) {
     return check;
   }
 
-  Try<std::vector<std::string> > cgroups = getCgroups(hierarchy, cgroup);
+  Try<vector<string> > cgroups = getCgroups(hierarchy, cgroup);
   if (cgroups.isError()) {
     return Try<Nothing>::error(cgroups.error());
   }
@@ -579,15 +662,14 @@ Try<Nothing> removeCgroup(const std::str
 }
 
 
-Try<Nothing> checkCgroup(const std::string& hierarchy,
-                         const std::string& cgroup)
+Try<Nothing> checkCgroup(const string& hierarchy, const string& cgroup)
 {
   Try<Nothing> check = checkHierarchy(hierarchy);
   if (check.isError()) {
     return check;
   }
 
-  std::string path = hierarchy + "/" + cgroup;
+  string path = path::join(hierarchy, cgroup);
   if (!os::exists(path)) {
     return Try<Nothing>::error("Cgroup " + cgroup + " is not valid");
   }
@@ -596,23 +678,25 @@ Try<Nothing> checkCgroup(const std::stri
 }
 
 
-Try<std::string> readControl(const std::string& hierarchy,
-                             const std::string& cgroup,
-                             const std::string& control)
+Try<string> readControl(
+    const string& hierarchy,
+    const string& cgroup,
+    const string& control)
 {
   Try<Nothing> check = checkControl(hierarchy, cgroup, control);
   if (check.isError()) {
-    return Try<std::string>::error(check.error());
+    return Try<string>::error(check.error());
   }
 
   return internal::readControl(hierarchy, cgroup, control);
 }
 
 
-Try<Nothing> writeControl(const std::string& hierarchy,
-                          const std::string& cgroup,
-                          const std::string& control,
-                          const std::string& value)
+Try<Nothing> writeControl(
+    const string& hierarchy,
+    const string& cgroup,
+    const string& control,
+    const string& value)
 {
   Try<Nothing> check = checkControl(hierarchy, cgroup, control);
   if (check.isError()) {
@@ -623,16 +707,17 @@ Try<Nothing> writeControl(const std::str
 }
 
 
-Try<Nothing> checkControl(const std::string& hierarchy,
-                          const std::string& cgroup,
-                          const std::string& control)
+Try<Nothing> checkControl(
+    const string& hierarchy,
+    const string& cgroup,
+    const string& control)
 {
   Try<Nothing> check = checkCgroup(hierarchy, cgroup);
   if (check.isError()) {
     return check;
   }
 
-  std::string path = hierarchy + "/" + cgroup + "/" + control;
+  string path = path::join(hierarchy, cgroup, control);
   if (!os::exists(path)) {
     return Try<Nothing>::error("Control file " + path + " does not exist");
   }
@@ -641,34 +726,33 @@ Try<Nothing> checkControl(const std::str
 }
 
 
-Try<std::vector<std::string> > getCgroups(const std::string& hierarchy,
-                                          const std::string& cgroup)
+Try<vector<string> > getCgroups(const string& hierarchy, const string& cgroup)
 {
   Try<Nothing> check = checkCgroup(hierarchy, cgroup);
   if (check.isError()) {
-    return Try<std::vector<std::string> >::error(check.error());
+    return Try<vector<string> >::error(check.error());
   }
 
-  Try<std::string> hierarchyAbsPath = os::realpath(hierarchy);
+  Try<string> hierarchyAbsPath = os::realpath(hierarchy);
   if (hierarchyAbsPath.isError()) {
-    return Try<std::vector<std::string> >::error(hierarchyAbsPath.error());
+    return Try<vector<string> >::error(hierarchyAbsPath.error());
   }
 
-  Try<std::string> destAbsPath = os::realpath(hierarchy + "/" + cgroup);
+  Try<string> destAbsPath = os::realpath(path::join(hierarchy, cgroup));
   if (destAbsPath.isError()) {
-    return Try<std::vector<std::string> >::error(destAbsPath.error());
+    return Try<vector<string> >::error(destAbsPath.error());
   }
 
   char* paths[] = {const_cast<char*>(destAbsPath.get().c_str()), NULL};
 
   FTS* tree = fts_open(paths, FTS_NOCHDIR, NULL);
   if (tree == NULL) {
-    return Try<std::vector<std::string> >::error(
+    return Try<vector<string> >::error(
         "Failed to start file system walk: " +
-          std::string(strerror(errno)));
+          string(strerror(errno)));
   }
 
-  std::vector<std::string> cgroups;
+  vector<string> cgroups;
 
   FTSENT* node;
   while ((node = fts_read(tree)) != NULL) {
@@ -677,42 +761,43 @@ Try<std::vector<std::string> > getCgroup
     // itself is numbered 0. fts_info includes flags for the current node.
     // FTS_DP indicates a directory being visited in postorder.
     if (node->fts_level > 0 && node->fts_info & FTS_DP) {
-      cgroups.push_back(node->fts_path + hierarchyAbsPath.get().length());
+      string path =
+        strings::trim(node->fts_path + hierarchyAbsPath.get().length(), "/");
+      cgroups.push_back(path);
     }
   }
 
   if (errno != 0) {
-    return Try<std::vector<std::string> >::error(
+    return Try<vector<string> >::error(
         "Failed to read a node during the walk: " +
-          std::string(strerror(errno)));
+          string(strerror(errno)));
   }
 
   if (fts_close(tree) != 0) {
-    return Try<std::vector<std::string> >::error(
-        "Failed to stop a file system walk" +
-          std::string(strerror(errno)));
+    return Try<vector<string> >::error(
+        "Failed to stop a file system walk: " +
+          string(strerror(errno)));
   }
 
   return cgroups;
 }
 
 
-Try<std::set<pid_t> > getTasks(const std::string& hierarchy,
-                               const std::string& cgroup)
+Try<set<pid_t> > getTasks(const string& hierarchy, const string& cgroup)
 {
   Try<Nothing> check = checkCgroup(hierarchy, cgroup);
   if (check.isError()) {
-    return Try<std::set<pid_t> >::error(check.error());
+    return Try<set<pid_t> >::error(check.error());
   }
 
   // Read from the control file.
-  Try<std::string> value = internal::readControl(hierarchy, cgroup, "tasks");
+  Try<string> value = internal::readControl(hierarchy, cgroup, "tasks");
   if (value.isError()) {
-    return Try<std::set<pid_t> >::error(value.error());
+    return Try<set<pid_t> >::error(value.error());
   }
 
   // Parse the value read from the control file.
-  std::set<pid_t> pids;
+  set<pid_t> pids;
   std::istringstream ss(value.get());
   ss >> std::dec;
   while (!ss.eof()) {
@@ -721,7 +806,7 @@ Try<std::set<pid_t> > getTasks(const std
 
     if (ss.fail()) {
       if (!ss.eof()) {
-        return Try<std::set<pid_t> >::error("Parsing error");
+        return Try<set<pid_t> >::error("Parsing error");
       }
     } else {
       pids.insert(pid);
@@ -732,9 +817,7 @@ Try<std::set<pid_t> > getTasks(const std
 }
 
 
-Try<Nothing> assignTask(const std::string& hierarchy,
-                        const std::string& cgroup,
-                        pid_t pid)
+Try<Nothing> assignTask(const string& hierarchy, const string& cgroup, pid_t pid)
 {
   Try<Nothing> check = checkCgroup(hierarchy, cgroup);
   if (check.isError()) {
@@ -807,20 +890,20 @@ static int eventfd(unsigned int initval,
 // @param   args        Control specific arguments.
 // @return  The eventfd if the operation succeeds.
 //          Error if the operation fails.
-static Try<int> openNotifier(const std::string& hierarchy,
-                             const std::string& cgroup,
-                             const std::string& control,
-                             const Option<std::string>& args =
-                               Option<std::string>::none())
+static Try<int> openNotifier(
+    const string& hierarchy,
+    const string& cgroup,
+    const string& control,
+    const Option<string>& args = Option<string>::none())
 {
   int efd = internal::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
   if (efd < 0) {
     return Try<int>::error(
-        "Create eventfd failed: " + std::string(strerror(errno)));
+        "Create eventfd failed: " + string(strerror(errno)));
   }
 
   // Open the control file.
-  std::string path = hierarchy + "/" + cgroup + "/" + control;
+  string path = path::join(hierarchy, cgroup, control);
   Try<int> cfd = os::open(path, O_RDWR);
   if (cfd.isError()) {
     os::close(efd);
@@ -863,10 +946,10 @@ static Try<Nothing> closeNotifier(int fd
 class EventListener : public Process<EventListener>
 {
 public:
-  EventListener(const std::string& _hierarchy,
-                const std::string& _cgroup,
-                const std::string& _control,
-                const Option<std::string>& _args)
+  EventListener(const string& _hierarchy,
+                const string& _cgroup,
+                const string& _control,
+                const Option<string>& _args)
     : hierarchy(_hierarchy),
       cgroup(_cgroup),
       control(_control),
@@ -948,10 +1031,10 @@ private:
     terminate(self());
   }
 
-  std::string hierarchy;
-  std::string cgroup;
-  std::string control;
-  Option<std::string> args;
+  string hierarchy;
+  string cgroup;
+  string control;
+  Option<string> args;
   Promise<uint64_t> promise;
   Future<size_t> reading;
   Option<int> eventfd;  // The eventfd if opened.
@@ -961,10 +1044,11 @@ private:
 } // namespace internal {
 
 
-Future<uint64_t> listenEvent(const std::string& hierarchy,
-                             const std::string& cgroup,
-                             const std::string& control,
-                             const Option<std::string>& args)
+Future<uint64_t> listenEvent(
+    const string& hierarchy,
+    const string& cgroup,
+    const string& control,
+    const Option<string>& args)
 {
   Try<Nothing> check = checkControl(hierarchy, cgroup, control);
   if (check.isError()) {
@@ -986,9 +1070,9 @@ namespace internal {
 class Freezer : public Process<Freezer>
 {
 public:
-  Freezer(const std::string& _hierarchy,
-          const std::string& _cgroup,
-          const std::string& _action,
+  Freezer(const string& _hierarchy,
+          const string& _cgroup,
+          const string& _action,
           const Duration& _interval)
     : hierarchy(_hierarchy),
       cgroup(_cgroup),
@@ -1059,7 +1143,7 @@ private:
   {
     LOG(INFO) << "Checking frozen status of cgroup '" << cgroup << "'";
 
-    Try<std::string> state =
+    Try<string> state =
       internal::readControl(hierarchy, cgroup, "freezer.state");
 
     if (state.isError()) {
@@ -1082,7 +1166,7 @@ private:
       // make sure that the freezer can finish.
       // TODO(jieyu): This code can be removed in the future as the newer
       // version of the kernel solves this problem (e.g. Linux-3.2.0).
-      Try<std::set<pid_t> > pids = getTasks(hierarchy, cgroup);
+      Try<set<pid_t> > pids = getTasks(hierarchy, cgroup);
       if (pids.isError()) {
         promise.fail(pids.error());
         terminate(self());
@@ -1133,7 +1217,7 @@ private:
   {
     LOG(INFO) << "Checking thaw status of cgroup '" << cgroup << "'";
 
-    Try<std::string> state =
+    Try<string> state =
       internal::readControl(hierarchy, cgroup, "freezer.state");
 
     if (state.isError()) {
@@ -1154,9 +1238,9 @@ private:
     }
   }
 
-  const std::string hierarchy;
-  const std::string cgroup;
-  const std::string action;
+  const string hierarchy;
+  const string cgroup;
+  const string action;
   const Duration interval;
   Promise<bool> promise;
 };
@@ -1165,9 +1249,10 @@ private:
 } // namespace internal {
 
 
-Future<bool> freezeCgroup(const std::string& hierarchy,
-                          const std::string& cgroup,
-                          const Duration& interval)
+Future<bool> freezeCgroup(
+    const string& hierarchy,
+    const string& cgroup,
+    const Duration& interval)
 {
   Try<Nothing> check = checkControl(hierarchy, cgroup, "freezer.state");
   if (check.isError()) {
@@ -1175,7 +1260,7 @@ Future<bool> freezeCgroup(const std::str
   }
 
   // Check the current freezer state.
-  Try<std::string> state = internal::readControl(hierarchy,
+  Try<string> state = internal::readControl(hierarchy,
                                                  cgroup,
                                                  "freezer.state");
   if (state.isError()) {
@@ -1193,9 +1278,10 @@ Future<bool> freezeCgroup(const std::str
 }
 
 
-Future<bool> thawCgroup(const std::string& hierarchy,
-                        const std::string& cgroup,
-                        const Duration& interval)
+Future<bool> thawCgroup(
+    const string& hierarchy,
+    const string& cgroup,
+    const Duration& interval)
 {
   Try<Nothing> check = checkControl(hierarchy, cgroup, "freezer.state");
   if (check.isError()) {
@@ -1203,7 +1289,7 @@ Future<bool> thawCgroup(const std::strin
   }
 
   // Check the current freezer state.
-  Try<std::string> state = internal::readControl(hierarchy,
+  Try<string> state = internal::readControl(hierarchy,
                                                  cgroup,
                                                  "freezer.state");
   if (state.isError()) {
@@ -1221,14 +1307,14 @@ Future<bool> thawCgroup(const std::strin
 }
 
 
-namespace internal{
+namespace internal {
 
 // The process used to wait for a cgroup to become empty (no task in it).
 class EmptyWatcher: public Process<EmptyWatcher>
 {
 public:
-  EmptyWatcher(const std::string& _hierarchy,
-               const std::string& _cgroup,
+  EmptyWatcher(const string& _hierarchy,
+               const string& _cgroup,
                const Duration& _interval)
     : hierarchy(_hierarchy),
       cgroup(_cgroup),
@@ -1258,9 +1344,7 @@ protected:
 private:
   void check()
   {
-    Try<std::string> state = internal::readControl(hierarchy,
-                                                   cgroup,
-                                                   "tasks");
+    Try<string> state = internal::readControl(hierarchy, cgroup, "tasks");
     if (state.isError()) {
       promise.fail(state.error());
       terminate(self());
@@ -1276,8 +1360,8 @@ private:
     }
   }
 
-  std::string hierarchy;
-  std::string cgroup;
+  string hierarchy;
+  string cgroup;
   const Duration interval;
   Promise<bool> promise;
 };
@@ -1287,8 +1371,8 @@ private:
 class TasksKiller : public Process<TasksKiller>
 {
 public:
-  TasksKiller(const std::string& _hierarchy,
-              const std::string& _cgroup,
+  TasksKiller(const string& _hierarchy,
+              const string& _cgroup,
               const Duration& _interval)
     : hierarchy(_hierarchy),
       cgroup(_cgroup),
@@ -1346,7 +1430,7 @@ private:
 
   Future<bool> kill()
   {
-    Try<std::set<pid_t> > tasks = getTasks(hierarchy, cgroup);
+    Try<set<pid_t> > tasks = getTasks(hierarchy, cgroup);
     if (tasks.isError()) {
       return Future<bool>::failed(tasks.error());
     } else {
@@ -1392,8 +1476,8 @@ private:
     terminate(self());
   }
 
-  std::string hierarchy;
-  std::string cgroup;
+  string hierarchy;
+  string cgroup;
   const Duration interval;
   Promise<bool> promise;
   Future<bool> finish;
@@ -1402,9 +1486,10 @@ private:
 } // namespace internal {
 
 
-Future<bool> killTasks(const std::string& hierarchy,
-                       const std::string& cgroup,
-                       const Duration& interval)
+Future<bool> killTasks(
+    const string& hierarchy,
+    const string& cgroup,
+    const Duration& interval)
 {
   Try<Nothing> freezerCheck = checkHierarchy(hierarchy, "freezer");
   if (freezerCheck.isError()) {
@@ -1430,8 +1515,8 @@ namespace internal {
 class Destroyer : public Process<Destroyer>
 {
 public:
-  Destroyer(const std::string& _hierarchy,
-            const std::vector<std::string>& _cgroups,
+  Destroyer(const string& _hierarchy,
+            const vector<string>& _cgroups,
             const Duration& _interval)
     : hierarchy(_hierarchy),
       cgroups(_cgroups),
@@ -1457,7 +1542,7 @@ protected:
 
     // Kill tasks in the given cgroups in parallel. Use collect mechanism to
     // wait until all kill processes finish.
-    foreach (const std::string& cgroup, cgroups) {
+    foreach (const string& cgroup, cgroups) {
       Future<bool> killer = killTasks(hierarchy, cgroup, interval);
       killers.push_back(killer);
     }
@@ -1475,7 +1560,7 @@ protected:
   }
 
 private:
-  void killed(const Future<std::list<bool> >& kill)
+  void killed(const Future<list<bool> >& kill)
   {
     if (kill.isReady()) {
       remove();
@@ -1489,7 +1574,7 @@ private:
 
   void remove()
   {
-    foreach (const std::string& cgroup, cgroups) {
+    foreach (const string& cgroup, cgroups) {
       Try<Nothing> remove = internal::removeCgroup(hierarchy, cgroup);
       if (remove.isError()) {
         promise.fail(remove.error());
@@ -1502,21 +1587,22 @@ private:
     terminate(self());
   }
 
-  std::string hierarchy;
-  std::vector<std::string> cgroups;
+  string hierarchy;
+  vector<string> cgroups;
   const Duration interval;
   Promise<bool> promise;
 
   // The killer processes used to atomically kill tasks in each cgroup.
-  std::list<Future<bool> > killers;
+  list<Future<bool> > killers;
 };
 
 } // namespace internal {
 
 
-Future<bool> destroyCgroup(const std::string& hierarchy,
-                           const std::string& cgroup,
-                           const Duration& interval)
+Future<bool> destroyCgroup(
+    const string& hierarchy,
+    const string& cgroup,
+    const Duration& interval)
 {
   Try<Nothing> cgroupCheck = checkCgroup(hierarchy, cgroup);
   if (cgroupCheck.isError()) {
@@ -1524,12 +1610,12 @@ Future<bool> destroyCgroup(const std::st
   }
 
   // Construct the vector of cgroups to destroy.
-  Try<std::vector<std::string> > cgroups = getCgroups(hierarchy, cgroup);
+  Try<vector<string> > cgroups = getCgroups(hierarchy, cgroup);
   if (cgroups.isError()) {
     return Future<bool>::failed(cgroups.error());
   }
 
-  std::vector<std::string> toDestroy = cgroups.get();
+  vector<string> toDestroy = cgroups.get();
   if (cgroup != "/") {
     toDestroy.push_back(cgroup);
   }

Modified: incubator/mesos/trunk/src/linux/cgroups.hpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/linux/cgroups.hpp?rev=1402687&r1=1402686&r2=1402687&view=diff
==============================================================================
--- incubator/mesos/trunk/src/linux/cgroups.hpp (original)
+++ incubator/mesos/trunk/src/linux/cgroups.hpp Fri Oct 26 22:07:02 2012
@@ -55,6 +55,12 @@ namespace cgroups {
 bool enabled();
 
 
+// Return the currently active hierarchies.
+// @return  A set of active hierarchy paths (e.g., '/cgroup').
+//          Error if unexpected happens.
+Try<std::set<std::string> > hierarchies();
+
+
 // Check whether all the given subsystems are enabled on the current machine.
 // @param   subsystems  Comma-separated subsystem names.
 // @return  True if all the given subsystems are enabled.

Modified: incubator/mesos/trunk/third_party/libprocess/include/stout/path.hpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/third_party/libprocess/include/stout/path.hpp?rev=1402687&r1=1402686&r2=1402687&view=diff
==============================================================================
--- incubator/mesos/trunk/third_party/libprocess/include/stout/path.hpp (original)
+++ incubator/mesos/trunk/third_party/libprocess/include/stout/path.hpp Fri Oct 26 22:07:02 2012
@@ -16,6 +16,25 @@ inline std::string join(const std::strin
 }
 
 
+inline std::string join(
+    const std::string& path1,
+    const std::string& path2,
+    const std::string& path3)
+{
+  return join(path1, join(path2, path3));
+}
+
+
+inline std::string join(
+    const std::string& path1,
+    const std::string& path2,
+    const std::string& path3,
+    const std::string& path4)
+{
+  return join(path1, join(path2, join(path3, path4)));
+}
+
+
 inline std::string join(const std::vector<std::string>& paths)
 {
   if (paths.empty()) {