Support manipulating scheduler policy on Linux.

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


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

Branch: refs/heads/master
Commit: 6de149e4715743345add600ade967a79351555f9
Parents: d7c0873
Author: Ian Downes <[email protected]>
Authored: Fri May 15 17:58:28 2015 -0700
Committer: Ian Downes <[email protected]>
Committed: Fri May 29 14:33:21 2015 -0700

----------------------------------------------------------------------
 src/Makefile.am           |  2 +
 src/linux/sched.hpp       | 93 ++++++++++++++++++++++++++++++++++++++++
 src/tests/sched_tests.cpp | 96 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 191 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/6de149e4/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index e7281ac..9d1f0d5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -550,6 +550,7 @@ libmesos_no_3rdparty_la_SOURCES +=                          
        \
        linux/fs.hpp                                                    \
        linux/ns.hpp                                                    \
        linux/perf.hpp                                                  \
+       linux/sched.hpp                                                 \
        local/flags.hpp                                                 \
        local/local.hpp                                                 \
        logging/flags.hpp                                               \
@@ -1480,6 +1481,7 @@ if OS_LINUX
   mesos_tests_SOURCES += tests/memory_pressure_tests.cpp
   mesos_tests_SOURCES += tests/ns_tests.cpp
   mesos_tests_SOURCES += tests/perf_tests.cpp
+  mesos_tests_SOURCES += tests/sched_tests.cpp
   mesos_tests_SOURCES += tests/setns_test_helper.cpp
 endif
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/6de149e4/src/linux/sched.hpp
----------------------------------------------------------------------
diff --git a/src/linux/sched.hpp b/src/linux/sched.hpp
new file mode 100644
index 0000000..2ae80be
--- /dev/null
+++ b/src/linux/sched.hpp
@@ -0,0 +1,93 @@
+/**
+ * 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 __LINUX_SCHED_HPP__
+#define __LINUX_SCHED_HPP__
+
+// This file contains Linux-only OS utilities.
+#ifndef __linux__
+#error "linux/sched.hpp is only available on Linux systems."
+#endif
+
+#include <sched.h>
+
+#include <sys/types.h>
+
+#include <stout/error.hpp>
+#include <stout/none.hpp>
+#include <stout/nothing.hpp>
+#include <stout/option.hpp>
+#include <stout/try.hpp>
+
+namespace sched {
+
+enum Policy
+{
+  OTHER = SCHED_OTHER,  // Default policy.
+  BATCH = SCHED_BATCH,  // Non-interactive, CPU intensive.
+  IDLE  = SCHED_IDLE,   // Very low priority.
+  FIFO  = SCHED_FIFO,   // Realtime.
+  RR    = SCHED_RR      // Realtime, round-robin.
+};
+
+
+namespace policy {
+
+// Return the current scheduling policy for the specified pid, or for
+// the caller if pid is None() or zero.
+inline Try<Policy> get(const Option<pid_t>& pid = None())
+{
+  int status = sched_getscheduler(pid.isSome() ? pid.get() : 0);
+
+  if (status == -1) {
+    return ErrnoError("Failed to get scheduler policy");
+  }
+
+  return static_cast<Policy>(status);
+}
+
+
+// Set the scheduling policy for the specified pid, or for the caller
+// if pid is None() or zero. Only realtime scheduling policies (FIFO
+// and RR) accept a priority (within a range, see
+// sched_setscheduler(2)).
+// TODO(idownes): Add wrappers around sched_get_priority_{min,max}.
+inline Try<Nothing> set(
+    Policy policy,
+    const Option<pid_t>& pid = None(),
+    int priority = 0)
+{
+  if ((policy == OTHER || policy == BATCH || policy == IDLE) &&
+      priority != 0) {
+    return Error("Non-real-time scheduling policies only support priority = 
0");
+  }
+
+  sched_param param;
+  param.sched_priority = priority;
+
+  if (sched_setscheduler(pid.isSome() ? pid.get() : 0, policy, &param) == -1) {
+    return ErrnoError("Failed to set scheduler policy");
+  }
+
+  return Nothing();
+}
+
+} // namespace policy {
+} // namespace sched {
+
+#endif // __LINUX_SCHED_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/6de149e4/src/tests/sched_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/sched_tests.cpp b/src/tests/sched_tests.cpp
new file mode 100644
index 0000000..00723d0
--- /dev/null
+++ b/src/tests/sched_tests.cpp
@@ -0,0 +1,96 @@
+/**
+ * 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 "linux/sched.hpp"
+
+#include <process/gtest.hpp>
+#include <process/reap.hpp>
+
+#include <gtest/gtest.h>
+
+#include <stout/gtest.hpp>
+
+using sched::Policy;
+
+namespace mesos {
+namespace internal {
+namespace tests {
+
+// TODO(idownes): Test the priority and preemption behavior for
+// running competing SCHED_OTHER and SCHED_IDLE tasks.
+
+TEST(SchedTest, ROOT_PolicySelf)
+{
+  Try<Policy> original = sched::policy::get();
+  ASSERT_SOME(original);
+
+  Policy different = (original.get() == Policy::OTHER ? Policy::IDLE
+                                                      : Policy::OTHER);
+
+  // Change our own scheduling policy.
+  EXPECT_SOME(sched::policy::set(different));
+  EXPECT_SOME_EQ(different, sched::policy::get());
+
+  // Change it back.
+  EXPECT_SOME(sched::policy::set(original.get()));
+  EXPECT_SOME_EQ(original.get(), sched::policy::get());
+}
+
+
+// Change the scheduling policy of a different process (our child).
+TEST(SchedTest, ROOT_PolicyChild)
+{
+  Try<Policy> original = sched::policy::get();
+  ASSERT_SOME(original);
+
+  Policy different = (original.get() == Policy::OTHER ? Policy::IDLE
+                                                      : Policy::OTHER);
+
+  pid_t pid = ::fork();
+  ASSERT_NE(-1, pid);
+
+  if (pid == 0) {
+    // Child.
+    sleep(10);
+
+    ABORT("Child process should not reach here");
+  }
+
+  // Continue in parent.
+  // Check the child has inherited our policy.
+  EXPECT_SOME_EQ(original.get(), sched::policy::get(pid));
+
+  // Check we can change the child's policy.
+  EXPECT_SOME(sched::policy::set(different, pid));
+  EXPECT_SOME_EQ(different, sched::policy::get(pid));
+
+  process::Future<Option<int>> status = process::reap(pid);
+
+  // Kill the child process.
+  ASSERT_NE(-1, ::kill(pid, SIGKILL));
+
+  // Wait for the child process.
+  AWAIT_READY(status);
+  ASSERT_SOME(status.get());
+  EXPECT_TRUE(WIFSIGNALED(status.get().get()));
+  EXPECT_EQ(SIGKILL, WTERMSIG(status.get().get()));
+}
+
+} // namespace tests {
+} // namespace internal {
+} // namespace mesos {

Reply via email to