[cgroups2] Adds the `CoreControllerProcess` to the `Cgroups2IsolatorProcess`

The `CoreControllerProcess`, referred to as the "core" controller, is
implemented and enabled by default by the cgroups v2 isolator process.

We enable it by default because all cgroups in cgroups v2 have the
core control files ("cgroup.*"), which the `CoreControllerProcess` manages.

Currently, `CoreControllerProcess` reports the number of processes and
threads in a cgroup, if the `cgroups_cpu_enable_pids_and_tids_count`
flag is provided.

This closes #547
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 46fc3b0..84f423f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -354,6 +354,7 @@
     linux/cgroups2.cpp
     linux/ebpf.cpp
     slave/containerizer/mesos/isolators/cgroups2/controller.cpp
+    slave/containerizer/mesos/isolators/cgroups2/controllers/core.cpp
     slave/containerizer/mesos/isolators/cgroups2/controllers/cpu.cpp)
 
 endif ()
diff --git a/src/Makefile.am b/src/Makefile.am
index efe45af..3677df5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1500,6 +1500,8 @@
   slave/containerizer/mesos/isolators/cgroups2/cgroups2.cpp     \
   slave/containerizer/mesos/isolators/cgroups2/cgroups2.hpp     \
   slave/containerizer/mesos/isolators/cgroups2/constants.hpp     \
+  slave/containerizer/mesos/isolators/cgroups2/controllers/core.cpp     \
+  slave/containerizer/mesos/isolators/cgroups2/controllers/core.hpp     \
   slave/containerizer/mesos/isolators/cgroups2/controllers/cpu.cpp    \
   slave/containerizer/mesos/isolators/cgroups2/controllers/cpu.hpp
 endif
diff --git a/src/slave/containerizer/mesos/isolators/cgroups2/cgroups2.cpp b/src/slave/containerizer/mesos/isolators/cgroups2/cgroups2.cpp
index 9c7bb6c..dfb4e0b 100644
--- a/src/slave/containerizer/mesos/isolators/cgroups2/cgroups2.cpp
+++ b/src/slave/containerizer/mesos/isolators/cgroups2/cgroups2.cpp
@@ -17,6 +17,7 @@
 #include "linux/cgroups2.hpp"
 
 #include "slave/containerizer/mesos/isolators/cgroups2/cgroups2.hpp"
+#include "slave/containerizer/mesos/isolators/cgroups2/controllers/core.hpp"
 #include "slave/containerizer/mesos/isolators/cgroups2/controllers/cpu.hpp"
 
 #include <set>
@@ -49,11 +50,15 @@
 Try<Isolator*> Cgroups2IsolatorProcess::create(const Flags& flags)
 {
   hashmap<string, Try<Owned<ControllerProcess>>(*)(const Flags&)> creators = {
+    {"core", &CoreControllerProcess::create},
     {"cpu", &CpuControllerProcess::create}
   };
 
   hashmap<string, Owned<Controller>> controllers;
-  set<string> controllersToCreate;
+
+  // The "core" controller is always enabled because the "cgroup.*" control
+  // files which it interfaces with exist and are updated for all cgroups.
+  set<string> controllersToCreate = { "core" };
 
   if (strings::contains(flags.isolation, "cgroups/all")) {
     Try<set<string>> available =
diff --git a/src/slave/containerizer/mesos/isolators/cgroups2/constants.hpp b/src/slave/containerizer/mesos/isolators/cgroups2/constants.hpp
index 501e3e3..dafc7f9 100644
--- a/src/slave/containerizer/mesos/isolators/cgroups2/constants.hpp
+++ b/src/slave/containerizer/mesos/isolators/cgroups2/constants.hpp
@@ -32,7 +32,7 @@
 const Duration CPU_CFS_PERIOD = Milliseconds(100); // Linux default.
 const Duration MIN_CPU_CFS_QUOTA = Milliseconds(1);
 
-// Controller names.
+const std::string CGROUPS_V2_CONTROLLER_CORE_NAME = "core";
 const std::string CGROUPS_V2_CONTROLLER_CPU_NAME = "cpu";
 
 } // namespace slave {
diff --git a/src/slave/containerizer/mesos/isolators/cgroups2/controllers/core.cpp b/src/slave/containerizer/mesos/isolators/cgroups2/controllers/core.cpp
new file mode 100644
index 0000000..54f60c8
--- /dev/null
+++ b/src/slave/containerizer/mesos/isolators/cgroups2/controllers/core.cpp
@@ -0,0 +1,83 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+
+#include <set>
+#include <string>
+
+#include "linux/cgroups2.hpp"
+
+#include "slave/containerizer/mesos/isolators/cgroups2/constants.hpp"
+#include "slave/containerizer/mesos/isolators/cgroups2/controllers/core.hpp"
+
+#include <process/id.hpp>
+#include <process/owned.hpp>
+
+using process::Failure;
+using process::Future;
+using process::Owned;
+
+using std::set;
+using std::string;
+
+namespace mesos {
+namespace internal {
+namespace slave {
+
+Try<Owned<ControllerProcess>> CoreControllerProcess::create(const Flags& flags)
+{
+  return Owned<ControllerProcess>(new CoreControllerProcess(flags));
+}
+
+
+CoreControllerProcess::CoreControllerProcess(const Flags& _flags)
+  : ProcessBase(process::ID::generate("cgroups-v2-core-controller")),
+    ControllerProcess(_flags) {}
+
+
+string CoreControllerProcess::name() const
+{
+  return CGROUPS_V2_CONTROLLER_CORE_NAME;
+}
+
+
+process::Future<ResourceStatistics> CoreControllerProcess::usage(
+    const ContainerID& containerId,
+    const std::string& cgroup)
+{
+  ResourceStatistics stats;
+
+  if (flags.cgroups_cpu_enable_pids_and_tids_count) {
+    Try<set<pid_t>> pids = cgroups2::processes(cgroup);
+    if (pids.isError()) {
+      return Failure("Failed to get processes in cgroup: " + pids.error());
+    }
+
+    stats.set_processes(pids->size());
+
+    Try<set<pid_t>> tids = cgroups2::threads(cgroup);
+    if (tids.isError()) {
+      return Failure("Failed to get threads in cgroup: " + tids.error());
+    }
+
+    stats.set_threads(tids->size());
+  }
+
+  return stats;
+}
+
+} // namespace slave {
+} // namespace internal {
+} // namespace mesos {
diff --git a/src/slave/containerizer/mesos/isolators/cgroups2/controllers/core.hpp b/src/slave/containerizer/mesos/isolators/cgroups2/controllers/core.hpp
new file mode 100644
index 0000000..1879a0b
--- /dev/null
+++ b/src/slave/containerizer/mesos/isolators/cgroups2/controllers/core.hpp
@@ -0,0 +1,55 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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 __CORE_HPP__
+#define __CORE_HPP__
+
+#include <string>
+
+#include <process/future.hpp>
+
+#include "slave/containerizer/mesos/isolators/cgroups2/controller.hpp"
+#include "slave/flags.hpp"
+
+namespace mesos {
+namespace internal {
+namespace slave {
+
+// Controller to interface with the cgroups core control files. That is,
+// control files "cgroup.*", which exist in all cgroups.
+class CoreControllerProcess : public ControllerProcess
+{
+public:
+  static Try<process::Owned<ControllerProcess>> create(
+      const Flags& flags);
+
+  ~CoreControllerProcess() override = default;
+
+  std::string name() const override;
+
+  process::Future<ResourceStatistics> usage(
+      const ContainerID& containerId,
+      const std::string& cgroup) override;
+
+private:
+  CoreControllerProcess(const Flags& flags);
+};
+
+} // namespace slave {
+} // namespace internal {
+} // namespace mesos {
+
+#endif // __CORE_HPP__