Add cgroup class for management of cgroupfs 62/132162/4 accepted/tizen/unified/20170627.043412 accepted/tizen/unified/20170629.085716 submit/tizen/20170621.051505 submit/tizen/20170626.035422
authorSungbae Yoo <sungbae.yoo@samsung.com>
Wed, 31 May 2017 11:23:37 +0000 (20:23 +0900)
committerSungbae Yoo <sungbae.yoo@samsung.com>
Thu, 8 Jun 2017 02:30:09 +0000 (11:30 +0900)
Signed-off-by: Sungbae Yoo <sungbae.yoo@samsung.com>
Change-Id: If0f280c8484c424117727aa04fa88b523056e590

include/klay/cgroup.h [new file with mode: 0644]
src/CMakeLists.txt
src/cgroup.cpp [new file with mode: 0644]

diff --git a/include/klay/cgroup.h b/include/klay/cgroup.h
new file mode 100644 (file)
index 0000000..a9cb217
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  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 __RUNTIME_CGROUP_H__
+#define __RUNTIME_CGROUP_H__
+
+#include <string>
+#include <vector>
+
+namespace runtime {
+
+class Cgroup final {
+public:
+       Cgroup() = delete;
+
+       static bool existSubsystem(const std::string& name);
+       static void createSubsystem(const std::string& name);
+       static void destroySubsystem(const std::string& name);
+
+       static bool exist(const std::string& subsystem, const std::string& path);
+       static void create(const std::string& subsystem, const std::string& path);
+       static void destroy(const std::string& subsystem, const std::string& path);
+
+       static void addProcess(const std::string& subsystem,
+                                                       const std::string& path, const pid_t pid);
+       static std::vector<pid_t> getProcessList(const std::string& subsystem,
+                                                                                       const std::string& path);
+
+       static const std::string getPath(const std::string& subsystem, const pid_t pid);
+};
+
+} // namespace runtime
+
+#endif //!__RUNTIME_CGROUP_H__
index 1e5f8ec78b0cda9e65f205f8d234f614cdfa368e..a1fb0bc5021569bb68141566ad9dcae3e50f5c19 100755 (executable)
@@ -14,6 +14,7 @@
 # limitations under the License.
 #
 SET (KLAY_SOURCES              ${KLAY_SRC}/error.cpp
+                                               ${KLAY_SRC}/cgroup.cpp
                                                ${KLAY_SRC}/process.cpp
                                                ${KLAY_SRC}/eventfd.cpp
                                                ${KLAY_SRC}/mainloop.cpp
diff --git a/src/cgroup.cpp b/src/cgroup.cpp
new file mode 100644 (file)
index 0000000..0087226
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  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
+ */
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+
+#include <regex>
+#include <fstream>
+
+#include <klay/cgroup.h>
+#include <klay/exception.h>
+#include <klay/filesystem.h>
+
+
+namespace runtime {
+
+namespace {
+
+static std::regex namePattern("^[A-Za-z_][A-Za-z0-9_-]*");
+static std::regex pathPattern("(/*[A-Za-z_][A-Za-z0-9_-]*)*");
+
+} // namespace
+
+bool Cgroup::existSubsystem(const std::string& name)
+{
+       if (!std::regex_match(name, namePattern)) {
+               return false;
+       }
+
+       runtime::File dir("/sys/fs/cgroup/" + name);
+       if (dir.exists()) {
+               if (dir.isDirectory()) {
+                       return true;
+               }
+               throw runtime::Exception("Invalid subsystem name");
+       }
+
+       return false;
+}
+
+void Cgroup::createSubsystem(const std::string& name)
+{
+       if (!std::regex_match(name, namePattern)) {
+               throw runtime::Exception("Invalid subsystem name");
+       }
+
+       if (existSubsystem(name)) {
+               return;
+       }
+
+       runtime::File subsystem("/sys/fs/cgroup/" + name);
+       if (::mount(NULL, "/sys/fs/cgroup/", NULL, MS_REMOUNT |
+                       MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME,
+                       "mode=755")) {
+               throw runtime::Exception("Failed to remount cgroupfs as the writable");
+       }
+
+       if (!subsystem.exists()) {
+               subsystem.makeDirectory(true);
+       }
+
+       if (::mount(name.c_str(), subsystem.getPath().c_str(),
+                       "cgroup", MS_NODEV | MS_NOSUID | MS_NOEXEC,
+                       ("none,name=" + name).c_str())) {
+               subsystem.remove(false);
+               throw runtime::Exception("Failed to mount cgroup subsystem");
+       }
+
+       if (::mount(NULL, "/sys/fs/cgroup/", NULL, MS_REMOUNT | MS_RDONLY |
+                       MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME,
+                       "mode=755")) {
+               throw runtime::Exception("Failed to remount cgroupfs as the read-only");
+       }
+}
+
+void Cgroup::destroySubsystem(const std::string& name)
+{
+       if (!existSubsystem(name)) {
+                throw runtime::Exception("No such subsystem");
+       }
+
+       if (::mount(NULL, "/sys/fs/cgroup/", NULL, MS_REMOUNT |
+                       MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME,
+                       "mode=755")) {
+               throw runtime::Exception("Failed to remount cgroupfs as the writable");
+       }
+
+       runtime::File subsystem("/sys/fs/cgroup/" + name);
+       ::umount2(subsystem.getPath().c_str(), MNT_EXPIRE);
+
+       subsystem.remove(false);
+
+       if (::mount(NULL, "/sys/fs/cgroup/", NULL, MS_REMOUNT | MS_RDONLY |
+                       MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME,
+                       "mode=755")) {
+               throw runtime::Exception("Failed to remount cgroupfs as the read-only");
+       }
+}
+
+bool Cgroup::exist(const std::string& subsystem, const std::string& path)
+{
+       if (!std::regex_match(path, pathPattern)) {
+               return false;
+       }
+
+       runtime::File dir("/sys/fs/cgroup/" + subsystem + "/" + path);
+       if (dir.exists()) {
+               if (dir.isDirectory()) {
+                       return true;
+               }
+               throw runtime::Exception("Invalid path");
+       }
+
+       return false;
+}
+
+void Cgroup::create(const std::string& subsystem, const std::string& path)
+{
+       if (!std::regex_match(path, pathPattern)) {
+               throw runtime::Exception("Invalid path");
+       }
+
+       if (exist(subsystem, path)) {
+               return;
+       }
+
+       runtime::File dir("/sys/fs/cgroup/" + subsystem + "/" + path);
+       dir.makeDirectory(true);
+}
+
+void Cgroup::destroy(const std::string& subsystem, const std::string& path)
+{
+       if (!exist(subsystem, path)) {
+               throw runtime::Exception("No such path in subsystem");
+       }
+
+       runtime::File dir("/sys/fs/cgroup/" + subsystem + "/" + path);
+       dir.remove(false);
+}
+
+void Cgroup::addProcess(const std::string& subsystem, const std::string& path, const pid_t pid)
+{
+       if (!exist(subsystem, path)) {
+               throw runtime::Exception("No such path in subsystem");
+       }
+
+       std::ofstream ofs("/sys/fs/cgroup/" + subsystem + "/" + path +
+                                               "/tasks");
+
+       ofs << pid << std::endl;
+}
+
+std::vector<pid_t> Cgroup::getProcessList(const std::string& subsystem, const std::string& path)
+{
+       std::vector<pid_t> ret;
+       std::ifstream ifs("/sys/fs/cgroup/" + subsystem + "/" + path +
+                                               "/tasks");
+
+       while (ifs.good()) {
+               pid_t pid;
+               ifs >> pid;
+               ret.push_back(pid);
+       }
+
+       return ret;
+}
+
+const std::string Cgroup::getPath(const std::string& subsystem, const pid_t pid)
+{
+       std::ifstream ifs("/proc/" + std::to_string(pid) + "/cgroup");
+       std::string ret = "/", line;
+
+       while (std::getline(ifs, line)) {
+               std::stringstream lineStream(line);
+               std::string name;
+
+               //the first getline is for removing the first argument
+               std::getline(lineStream, name, ':');
+               std::getline(lineStream, name, ':');
+
+               if (name == subsystem || name == "name=" + subsystem) {
+                       ret = line.substr(line.find('/'));
+               }
+       }
+       return ret;
+}
+
+} // namespace runtime