dcavalca / rpms / util-linux

Forked from rpms/util-linux 2 years ago
Clone
b394b9
From 674769893bb8d5f1991c6a3e5d96337b37aeb86f Mon Sep 17 00:00:00 2001
b394b9
From: Karel Zak <kzak@redhat.com>
b394b9
Date: Mon, 27 Jun 2016 14:14:28 +0200
b394b9
Subject: [PATCH 81/86] chrt: backport DEADLINE scheduler support
b394b9
b394b9
Backport upstream commits:
b394b9
b394b9
2e31d1c chrt: validate priority before trying to use it
b394b9
b3a5067 chrt: make --sched-* short options to require an argument
b394b9
a03eac5 chrt: restore removed ifdef SCHED_RESET_ON_FORK
b394b9
59e4a38 chrt: fix case SCHED_RR
b394b9
acde3a0 chrt: use sched_getattr()
b394b9
1a7e639 chrt: add support for SCHED_DEADLINE
b394b9
1516758 chrt: use sched_setattr() if available
b394b9
a6fec53 chrt: make usage more readable
b394b9
4820a73 chrt: set function refactoring
b394b9
a30cf65 chrt: output function refactoring
b394b9
7a4ea56 chrt: add control struct
b394b9
9acbe2a chrt: slice up the usage text and normalize its layout
b394b9
4e4bc0c chrt: make the usage synopsis clearer
b394b9
3fabc36 chrt: fix --help inconsistency
b394b9
451dbcf textual: add a docstring to most of the utilities
b394b9
a587cc5 textual: use manual tail usage() macro
b394b9
f627750 textual: use version printing macro everywhere
b394b9
a7560c0 textual: make the license of chrt and taskset slightly more explicit
b394b9
4ce393f textual: fix several typos and angular brackets in messages
b394b9
6f27e44 chrt: add fallback to be usable on kernels without sched_{get,set}attr
b394b9
b394b9
* Fri Jul 01 2016 re-spin [kzak]:
b394b9
- add fallback for old glibc-headers without SYS_sched_{set,get}attr
b394b9
b394b9
* Tue Jul 12 016 re-spin [kzak]:
b394b9
- add runtime fallback for systems without sched_{get,set}attr syscalls
b394b9
b394b9
Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1298384
b394b9
Signed-off-by: Karel Zak <kzak@redhat.com>
b394b9
---
b394b9
 configure.ac      |  17 +-
b394b9
 m4/ul.m4          |   8 -
b394b9
 schedutils/chrt.c | 547 ++++++++++++++++++++++++++++++++++++++----------------
b394b9
 3 files changed, 400 insertions(+), 172 deletions(-)
b394b9
b394b9
diff --git a/configure.ac b/configure.ac
b394b9
index fe0a011..266ef08 100644
b394b9
--- a/configure.ac
b394b9
+++ b/configure.ac
b394b9
@@ -338,6 +338,8 @@ AC_CHECK_FUNCS([ \
b394b9
 	scandirat \
b394b9
 	setresgid \
b394b9
 	setresuid \
b394b9
+	sched_setattr \
b394b9
+	sched_setscheduler \
b394b9
 	sigqueue \
b394b9
 	srandom \
b394b9
 	strnchr \
b394b9
@@ -1383,6 +1385,20 @@ UL_REQUIRES_SYSCALL_CHECK([taskset],
b394b9
 AM_CONDITIONAL(BUILD_TASKSET, test "x$build_taskset" = xyes)
b394b9
 
b394b9
 
b394b9
+have_schedsetter=no
b394b9
+AS_IF([test "x$ac_cv_func_sched_setscheduler" = xyes], [have_schedsetter=yes],
b394b9
+      [test "x$ac_cv_func_sched_setattr" = xyes], [have_schedsetter=yes])
b394b9
+
b394b9
+UL_BUILD_INIT([chrt], [check])
b394b9
+UL_REQUIRES_BUILD([chrt], [schedutils])
b394b9
+UL_REQUIRES_HAVE([chrt], [schedsetter], [sched_set functions])
b394b9
+AM_CONDITIONAL([BUILD_CHRT], [test "x$build_chrt" = xyes])
b394b9
+
b394b9
+AS_IF([test "x$build_chrt" = xyes], [
b394b9
+	UL_CHECK_SYSCALL([sched_setattr])
b394b9
+])
b394b9
+
b394b9
+
b394b9
 AC_ARG_ENABLE([wall],
b394b9
   AS_HELP_STRING([--disable-wall], [do not build wall]),
b394b9
   [], enable_wall=yes
b394b9
@@ -1562,7 +1578,6 @@ AC_ARG_VAR([SOLIB_LDFLAGS],
b394b9
 
b394b9
 LIBS=""
b394b9
 
b394b9
-
b394b9
 AC_CONFIG_HEADERS(config.h)
b394b9
 
b394b9
 #
b394b9
diff --git a/m4/ul.m4 b/m4/ul.m4
b394b9
index c0082d0..db44589 100644
b394b9
--- a/m4/ul.m4
b394b9
+++ b/m4/ul.m4
b394b9
@@ -92,7 +92,6 @@ AC_DEFUN([UL_CHECK_SYSCALL], [
b394b9
       ])
b394b9
     ul_cv_syscall_$1=$syscall
b394b9
     ])
b394b9
-  AM_CONDITIONAL([HAVE_]m4_toupper($1), [test "x$ul_cv_syscall_$1" != xno])
b394b9
   case $ul_cv_syscall_$1 in #(
b394b9
   no) AC_MSG_WARN([Unable to detect syscall $1.]) ;;
b394b9
   SYS_*) ;;
b394b9
@@ -266,13 +265,6 @@ AC_DEFUN([UL_REQUIRES_SYSCALL_CHECK], [
b394b9
   m4_define([suffix], m4_default([$4],$1))
b394b9
   m4_define([callname], m4_default([$3],$1))
b394b9
 
b394b9
-  dnl This is default, $3 will redefine the condition
b394b9
-  dnl
b394b9
-  dnl TODO: remove this junk, AM_CONDITIONAL should not be used for any HAVE_*
b394b9
-  dnl       variables, all we need is BUILD_* only.
b394b9
-  dnl
b394b9
-  AM_CONDITIONAL([HAVE_]m4_toupper(callname), [false])
b394b9
-
b394b9
   if test "x$[build_]suffix" != xno; then
b394b9
     if test "x$[enable_]suffix" = xno; then
b394b9
       [build_]suffix=no
b394b9
diff --git a/schedutils/chrt.c b/schedutils/chrt.c
b394b9
index 20df6fa..edae0d9 100644
b394b9
--- a/schedutils/chrt.c
b394b9
+++ b/schedutils/chrt.c
b394b9
@@ -1,13 +1,11 @@
b394b9
 /*
b394b9
- * chrt.c - chrt
b394b9
- * Command-line utility for manipulating a task's real-time attributes 
b394b9
+ * chrt.c - manipulate a task's real-time attributes
b394b9
  *
b394b9
- * Robert Love <rml@tech9.net>
b394b9
- * 27-Apr-2002: initial version
b394b9
- * 04-May-2011: make thread aware - Davidlohr Bueso <dave@gnu.org>
b394b9
+ * 27-Apr-2002: initial version - Robert Love <rml@tech9.net>
b394b9
+ * 04-May-2011: make it thread-aware - Davidlohr Bueso <dave@gnu.org>
b394b9
  *
b394b9
  * This program is free software; you can redistribute it and/or modify
b394b9
- * it under the terms of the GNU General Public License, v2, as
b394b9
+ * it under the terms of the GNU General Public License, version 2, as
b394b9
  * published by the Free Software Foundation
b394b9
  *
b394b9
  * This program is distributed in the hope that it will be useful,
b394b9
@@ -50,108 +48,260 @@
b394b9
 # define SCHED_IDLE 5
b394b9
 #endif
b394b9
 
b394b9
+/* flag by sched_getscheduler() */
b394b9
 #if defined(__linux__) && !defined(SCHED_RESET_ON_FORK)
b394b9
-#define SCHED_RESET_ON_FORK 0x40000000
b394b9
+# define SCHED_RESET_ON_FORK 0x40000000
b394b9
 #endif
b394b9
 
b394b9
+/* flag by sched_getattr() */
b394b9
+#if defined(__linux__) && !defined(SCHED_FLAG_RESET_ON_FORK)
b394b9
+# define SCHED_FLAG_RESET_ON_FORK 0x01
b394b9
+#endif
b394b9
 
b394b9
-static void __attribute__((__noreturn__)) show_usage(int rc)
b394b9
-{
b394b9
-	FILE *out = rc == EXIT_SUCCESS ? stdout : stderr;
b394b9
+#if defined (__linux__) && !defined(HAVE_SCHED_SETATTR)
b394b9
+# include <sys/syscall.h>
b394b9
+#endif
b394b9
 
b394b9
-	fprintf(out, _(
b394b9
-	"\nchrt - manipulate real-time attributes of a process\n"
b394b9
-	"\nSet policy:\n"
b394b9
-	"  chrt [options] [-policy] <priority> [-p <pid> | <command> <arg> ...]\n"
b394b9
-	"\nGet policy:\n"
b394b9
-	"  chrt [options] -p <pid>\n"));
b394b9
-
b394b9
-	fprintf(out, _(
b394b9
-	"\nScheduling policies:\n"
b394b9
-	"  -b | --batch         set policy to SCHED_BATCH\n"
b394b9
-	"  -f | --fifo          set policy to SCHED_FIFO\n"
b394b9
-	"  -i | --idle          set policy to SCHED_IDLE\n"
b394b9
-	"  -o | --other         set policy to SCHED_OTHER\n"
b394b9
-	"  -r | --rr            set policy to SCHED_RR (default)\n"));
b394b9
+/* usable kernel-headers, but old glibc-headers */
b394b9
+#if defined (__linux__) && !defined(SYS_sched_setattr) && defined(__NR_sched_setattr)
b394b9
+# define SYS_sched_setattr __NR_sched_setattr
b394b9
+#endif
b394b9
 
b394b9
-#ifdef SCHED_RESET_ON_FORK
b394b9
-	fprintf(out, _(
b394b9
-	"\nScheduling flags:\n"
b394b9
-	"  -R | --reset-on-fork set SCHED_RESET_ON_FORK for FIFO or RR\n"));
b394b9
+#if defined (__linux__) && !defined(SYS_sched_getattr) && defined(__NR_sched_getattr)
b394b9
+# define SYS_sched_getattr __NR_sched_getattr
b394b9
 #endif
b394b9
-	fprintf(out, _(
b394b9
-	"\nOptions:\n"
b394b9
-	"  -a | --all-tasks     operate on all the tasks (threads) for a given pid\n"
b394b9
-	"  -h | --help          display this help\n"
b394b9
-	"  -m | --max           show min and max valid priorities\n"
b394b9
-	"  -p | --pid           operate on existing given pid\n"
b394b9
-	"  -v | --verbose       display status information\n"
b394b9
-	"  -V | --version       output version information\n\n"));
b394b9
 
b394b9
-	exit(rc);
b394b9
+#if defined (__linux__) && !defined(HAVE_SCHED_SETATTR) && defined(SYS_sched_setattr)
b394b9
+# define HAVE_SCHED_SETATTR
b394b9
+
b394b9
+struct sched_attr {
b394b9
+	uint32_t size;
b394b9
+	uint32_t sched_policy;
b394b9
+	uint64_t sched_flags;
b394b9
+
b394b9
+	/* SCHED_NORMAL, SCHED_BATCH */
b394b9
+	int32_t sched_nice;
b394b9
+
b394b9
+	/* SCHED_FIFO, SCHED_RR */
b394b9
+	uint32_t sched_priority;
b394b9
+
b394b9
+	/* SCHED_DEADLINE (nsec) */
b394b9
+	uint64_t sched_runtime;
b394b9
+	uint64_t sched_deadline;
b394b9
+	uint64_t sched_period;
b394b9
+};
b394b9
+
b394b9
+static int sched_setattr(pid_t pid, const struct sched_attr *attr, unsigned int flags)
b394b9
+{
b394b9
+	return syscall(SYS_sched_setattr, pid, attr, flags);
b394b9
 }
b394b9
 
b394b9
-static void show_rt_info(pid_t pid, int isnew)
b394b9
+static int sched_getattr(pid_t pid, struct sched_attr *attr, unsigned int size, unsigned int flags)
b394b9
 {
b394b9
-	struct sched_param sp;
b394b9
-	int policy;
b394b9
+	return syscall(SYS_sched_getattr, pid, attr, size, flags);
b394b9
+}
b394b9
+#endif
b394b9
 
b394b9
-	/* don't display "pid 0" as that is confusing */
b394b9
-	if (!pid)
b394b9
-		pid = getpid();
b394b9
+/* the SCHED_DEADLINE is supported since Linux 3.14
b394b9
+ * commit id aab03e05e8f7e26f51dee792beddcb5cca9215a5
b394b9
+ * -- sched_setattr() is required for this policy!
b394b9
+ */
b394b9
+#if defined (__linux__) && !defined(SCHED_DEADLINE) && defined(HAVE_SCHED_SETATTR)
b394b9
+# define SCHED_DEADLINE 6
b394b9
+#endif
b394b9
 
b394b9
-	policy = sched_getscheduler(pid);
b394b9
-	if (policy == -1)
b394b9
-		err(EXIT_FAILURE, _("failed to get pid %d's policy"), pid);
b394b9
+/* control struct */
b394b9
+struct chrt_ctl {
b394b9
+	pid_t	pid;
b394b9
+	int	policy;				/* SCHED_* */
b394b9
+	int	priority;
b394b9
 
b394b9
-	if (isnew)
b394b9
-		printf(_("pid %d's new scheduling policy: "), pid);
b394b9
-	else
b394b9
-		printf(_("pid %d's current scheduling policy: "), pid);
b394b9
+	uint64_t runtime;			/* --sched-* options */
b394b9
+	uint64_t deadline;
b394b9
+	uint64_t period;
b394b9
+
b394b9
+	unsigned int all_tasks : 1,		/* all threads of the PID */
b394b9
+		     reset_on_fork : 1,		/* SCHED_RESET_ON_FORK */
b394b9
+		     altered : 1,		/* sched_set**() used */
b394b9
+		     verbose : 1;		/* verbose output */
b394b9
+};
b394b9
+
b394b9
+static void __attribute__((__noreturn__)) show_usage(int rc)
b394b9
+{
b394b9
+	FILE *out = rc == EXIT_SUCCESS ? stdout : stderr;
b394b9
 
b394b9
+	fputs(_("Show or change the real-time scheduling attributes of a process.\n"), out);
b394b9
+	fputs(USAGE_SEPARATOR, out);
b394b9
+	fputs(_("Set policy:\n"
b394b9
+	" chrt [options] <priority> <command> [<arg>...]\n"
b394b9
+	" chrt [options] --pid <priority> <pid>\n"), out);
b394b9
+	fputs(USAGE_SEPARATOR, out);
b394b9
+	fputs(_("Get policy:\n"
b394b9
+	" chrt [options] -p <pid>\n"), out);
b394b9
+
b394b9
+	fputs(USAGE_SEPARATOR, out);
b394b9
+	fputs(_("Policy options:\n"), out);
b394b9
+	fputs(_(" -b, --batch          set policy to SCHED_BATCH\n"), out);
b394b9
+	fputs(_(" -d, --deadline       set policy to SCHED_DEADLINE\n"), out);
b394b9
+	fputs(_(" -f, --fifo           set policy to SCHED_FIFO\n"), out);
b394b9
+	fputs(_(" -i, --idle           set policy to SCHED_IDLE\n"), out);
b394b9
+	fputs(_(" -o, --other          set policy to SCHED_OTHER\n"), out);
b394b9
+	fputs(_(" -r, --rr             set policy to SCHED_RR (default)\n"), out);
b394b9
+
b394b9
+	fputs(USAGE_SEPARATOR, out);
b394b9
+	fputs(_("Scheduling options:\n"), out);
b394b9
+	fputs(_(" -R, --reset-on-fork       set SCHED_RESET_ON_FORK for FIFO or RR\n"), out);
b394b9
+	fputs(_(" -T, --sched-runtime <ns>  runtime parameter for DEADLINE\n"), out);
b394b9
+	fputs(_(" -P, --sched-period <ns>   period parameter for DEADLINE\n"), out);
b394b9
+	fputs(_(" -D, --sched-deadline <ns> deadline parameter for DEADLINE\n"), out);
b394b9
+
b394b9
+	fputs(USAGE_SEPARATOR, out);
b394b9
+	fputs(_("Other options:\n"), out);
b394b9
+	fputs(_(" -a, --all-tasks      operate on all the tasks (threads) for a given pid\n"), out);
b394b9
+	fputs(_(" -m, --max            show min and max valid priorities\n"), out);
b394b9
+	fputs(_(" -p, --pid            operate on existing given pid\n"), out);
b394b9
+	fputs(_(" -v, --verbose        display status information\n"), out);
b394b9
+
b394b9
+	fputs(USAGE_SEPARATOR, out);
b394b9
+	fputs(USAGE_HELP, out);
b394b9
+	fputs(USAGE_VERSION, out);
b394b9
+
b394b9
+	fprintf(out, USAGE_MAN_TAIL("chrt(1)"));
b394b9
+	exit(rc);
b394b9
+}
b394b9
+
b394b9
+static const char *get_policy_name(int policy)
b394b9
+{
b394b9
 	switch (policy) {
b394b9
 	case SCHED_OTHER:
b394b9
-		printf("SCHED_OTHER\n");
b394b9
-		break;
b394b9
+		return "SCHED_OTHER";
b394b9
 	case SCHED_FIFO:
b394b9
-		printf("SCHED_FIFO\n");
b394b9
-		break;
b394b9
 #ifdef SCHED_RESET_ON_FORK
b394b9
 	case SCHED_FIFO | SCHED_RESET_ON_FORK:
b394b9
-		printf("SCHED_FIFO|SCHED_RESET_ON_FORK\n");
b394b9
-		break;
b394b9
 #endif
b394b9
+		return "SCHED_FIFO";
b394b9
 #ifdef SCHED_IDLE
b394b9
 	case SCHED_IDLE:
b394b9
-		printf("SCHED_IDLE\n");
b394b9
-		break;
b394b9
+		return "SCHED_IDLE";
b394b9
 #endif
b394b9
 	case SCHED_RR:
b394b9
-		printf("SCHED_RR\n");
b394b9
-		break;
b394b9
 #ifdef SCHED_RESET_ON_FORK
b394b9
 	case SCHED_RR | SCHED_RESET_ON_FORK:
b394b9
-		printf("SCHED_RR|SCHED_RESET_ON_FORK\n");
b394b9
-		break;
b394b9
 #endif
b394b9
+		return "SCHED_RR";
b394b9
 #ifdef SCHED_BATCH
b394b9
 	case SCHED_BATCH:
b394b9
-		printf("SCHED_BATCH\n");
b394b9
-		break;
b394b9
+		return "SCHED_BATCH";
b394b9
+#endif
b394b9
+#ifdef SCHED_DEADLINE
b394b9
+	case SCHED_DEADLINE:
b394b9
+		return "SCHED_DEADLINE";
b394b9
 #endif
b394b9
 	default:
b394b9
-		warnx(_("unknown scheduling policy"));
b394b9
+		break;
b394b9
+	}
b394b9
+
b394b9
+	return _("unknown");
b394b9
+}
b394b9
+
b394b9
+static void show_sched_pid_info(struct chrt_ctl *ctl, pid_t pid)
b394b9
+{
b394b9
+	int policy, reset_on_fork = 0, prio = 0;
b394b9
+#ifdef SCHED_DEADLINE
b394b9
+	uint64_t deadline = 0, runtime = 0, period = 0;
b394b9
+#endif
b394b9
+
b394b9
+	/* don't display "pid 0" as that is confusing */
b394b9
+	if (!pid)
b394b9
+		pid = getpid();
b394b9
+
b394b9
+	errno = 0;
b394b9
+
b394b9
+	/*
b394b9
+	 * New way
b394b9
+	 */
b394b9
+#ifdef HAVE_SCHED_SETATTR
b394b9
+	{
b394b9
+		struct sched_attr sa;
b394b9
+
b394b9
+		if (sched_getattr(pid, &sa, sizeof(sa), 0) != 0) {
b394b9
+			if (errno == ENOSYS)
b394b9
+				goto fallback;
b394b9
+			err(EXIT_FAILURE, _("failed to get pid %d's policy"), pid);
b394b9
+		}
b394b9
+
b394b9
+		policy = sa.sched_policy;
b394b9
+		prio = sa.sched_priority;
b394b9
+		reset_on_fork = sa.sched_flags & SCHED_FLAG_RESET_ON_FORK;
b394b9
+		deadline = sa.sched_deadline;
b394b9
+		runtime = sa.sched_runtime;
b394b9
+		period = sa.sched_period;
b394b9
 	}
b394b9
+#endif
b394b9
+
b394b9
+	/*
b394b9
+	 * Old way
b394b9
+	 */
b394b9
+fallback:
b394b9
+	if (errno == ENOSYS) {
b394b9
+		struct sched_param sp;
b394b9
 
b394b9
-	if (sched_getparam(pid, &sp))
b394b9
-		err(EXIT_FAILURE, _("failed to get pid %d's attributes"), pid);
b394b9
+		policy = sched_getscheduler(pid);
b394b9
+		if (policy == -1)
b394b9
+			err(EXIT_FAILURE, _("failed to get pid %d's policy"), pid);
b394b9
 
b394b9
-	if (isnew)
b394b9
-		printf(_("pid %d's new scheduling priority: %d\n"),
b394b9
-		       pid, sp.sched_priority);
b394b9
+		if (sched_getparam(pid, &sp) != 0)
b394b9
+			err(EXIT_FAILURE, _("failed to get pid %d's attributes"), pid);
b394b9
+		else
b394b9
+			prio = sp.sched_priority;
b394b9
+# ifdef SCHED_RESET_ON_FORK
b394b9
+		if (policy == (SCHED_FIFO|SCHED_RESET_ON_FORK) || policy == (SCHED_BATCH|SCHED_RESET_ON_FORK))
b394b9
+			reset_on_fork = 1;
b394b9
+# endif
b394b9
+	}
b394b9
+
b394b9
+	if (ctl->altered)
b394b9
+		printf(_("pid %d's new scheduling policy: %s"), pid, get_policy_name(policy));
b394b9
+	else
b394b9
+		printf(_("pid %d's current scheduling policy: %s"), pid, get_policy_name(policy));
b394b9
+
b394b9
+	if (reset_on_fork)
b394b9
+		printf("|SCHED_RESET_ON_FORK");
b394b9
+	putchar('\n');
b394b9
+
b394b9
+	if (ctl->altered)
b394b9
+		printf(_("pid %d's new scheduling priority: %d\n"), pid, prio);
b394b9
 	else
b394b9
-		printf(_("pid %d's current scheduling priority: %d\n"),
b394b9
-		       pid, sp.sched_priority);
b394b9
+		printf(_("pid %d's current scheduling priority: %d\n"), pid, prio);
b394b9
+
b394b9
+#ifdef SCHED_DEADLINE
b394b9
+	if (policy == SCHED_DEADLINE) {
b394b9
+		if (ctl->altered)
b394b9
+			printf(_("pid %d's new runtime/deadline/period parameters: %ju/%ju/%ju\n"),
b394b9
+					pid, runtime, deadline, period);
b394b9
+		else
b394b9
+			printf(_("pid %d's current runtime/deadline/period parameters: %ju/%ju/%ju\n"),
b394b9
+					pid, runtime, deadline, period);
b394b9
+	}
b394b9
+#endif
b394b9
+}
b394b9
+
b394b9
+
b394b9
+static void show_sched_info(struct chrt_ctl *ctl)
b394b9
+{
b394b9
+	if (ctl->all_tasks) {
b394b9
+		pid_t tid;
b394b9
+		struct proc_tasks *ts = proc_open_tasks(ctl->pid);
b394b9
+
b394b9
+		if (!ts)
b394b9
+			err(EXIT_FAILURE, _("cannot obtain the list of tasks"));
b394b9
+
b394b9
+		while (!proc_next_tid(ts, &tid))
b394b9
+			show_sched_pid_info(ctl, tid);
b394b9
+
b394b9
+		proc_close_tasks(ts);
b394b9
+	} else
b394b9
+		show_sched_pid_info(ctl, ctl->pid);
b394b9
 }
b394b9
 
b394b9
 static void show_min_max(void)
b394b9
@@ -167,52 +317,116 @@ static void show_min_max(void)
b394b9
 #ifdef SCHED_IDLE
b394b9
 		SCHED_IDLE,
b394b9
 #endif
b394b9
-	};
b394b9
-	const char *names[] = {
b394b9
-		"OTHER",
b394b9
-		"FIFO",
b394b9
-		"RR",
b394b9
-#ifdef SCHED_BATCH
b394b9
-		"BATCH",
b394b9
-#endif
b394b9
-#ifdef SCHED_IDLE
b394b9
-		"IDLE",
b394b9
+#ifdef SCHED_DEADLINE
b394b9
+		SCHED_DEADLINE,
b394b9
 #endif
b394b9
 	};
b394b9
 
b394b9
 	for (i = 0; i < ARRAY_SIZE(policies); i++) {
b394b9
-		int max = sched_get_priority_max(policies[i]);
b394b9
-		int min = sched_get_priority_min(policies[i]);
b394b9
+		int plc = policies[i];
b394b9
+		int max = sched_get_priority_max(plc);
b394b9
+		int min = sched_get_priority_min(plc);
b394b9
 
b394b9
 		if (max >= 0 && min >= 0)
b394b9
-			printf(_("SCHED_%s min/max priority\t: %d/%d\n"),
b394b9
-					names[i], min, max);
b394b9
+			printf(_("%s min/max priority\t: %d/%d\n"),
b394b9
+					get_policy_name(plc), min, max);
b394b9
 		else
b394b9
-			printf(_("SCHED_%s not supported?\n"), names[i]);
b394b9
+			printf(_("%s not supported?\n"), get_policy_name(plc));
b394b9
 	}
b394b9
 }
b394b9
 
b394b9
+static int set_sched_one_by_setscheduler(struct chrt_ctl *ctl, pid_t pid)
b394b9
+{
b394b9
+	struct sched_param sp = { .sched_priority = ctl->priority };
b394b9
+	int policy = ctl->policy;
b394b9
+
b394b9
+# ifdef SCHED_RESET_ON_FORK
b394b9
+	if (ctl->reset_on_fork)
b394b9
+		policy |= SCHED_RESET_ON_FORK;
b394b9
+# endif
b394b9
+	return sched_setscheduler(pid, policy, &sp);
b394b9
+}
b394b9
+
b394b9
+
b394b9
+#ifndef HAVE_SCHED_SETATTR
b394b9
+static int set_sched_one(struct chrt_ctl *ctl, pid_t pid)
b394b9
+{
b394b9
+	return set_sched_one_by_setscheduler(ctl, pid);
b394b9
+}
b394b9
+
b394b9
+#else /* !HAVE_SCHED_SETATTR */
b394b9
+static int set_sched_one(struct chrt_ctl *ctl, pid_t pid)
b394b9
+{
b394b9
+	/* use main() to check if the setting makes sense */
b394b9
+	struct sched_attr sa = {
b394b9
+		.size		= sizeof(struct sched_attr),
b394b9
+		.sched_policy	= ctl->policy,
b394b9
+		.sched_priority	= ctl->priority,
b394b9
+		.sched_runtime  = ctl->runtime,
b394b9
+		.sched_period   = ctl->period,
b394b9
+		.sched_deadline = ctl->deadline
b394b9
+	};
b394b9
+	int rc;
b394b9
+
b394b9
+# ifdef SCHED_RESET_ON_FORK
b394b9
+	if (ctl->reset_on_fork)
b394b9
+		sa.sched_flags |= SCHED_RESET_ON_FORK;
b394b9
+# endif
b394b9
+	errno = 0;
b394b9
+	rc = sched_setattr(pid, &sa, 0);
b394b9
+
b394b9
+	if (rc != 0 && errno == ENOSYS && ctl->policy != SCHED_DEADLINE)
b394b9
+		/* fallback -- build with new kernel/libc, but executed on old kernels */
b394b9
+		rc = set_sched_one_by_setscheduler(ctl, pid);
b394b9
+
b394b9
+	return rc;
b394b9
+}
b394b9
+#endif /* HAVE_SCHED_SETATTR */
b394b9
+
b394b9
+static void set_sched(struct chrt_ctl *ctl)
b394b9
+{
b394b9
+	if (ctl->all_tasks) {
b394b9
+		pid_t tid;
b394b9
+		struct proc_tasks *ts = proc_open_tasks(ctl->pid);
b394b9
+
b394b9
+		if (!ts)
b394b9
+			err(EXIT_FAILURE, _("cannot obtain the list of tasks"));
b394b9
+
b394b9
+		while (!proc_next_tid(ts, &tid))
b394b9
+			if (set_sched_one(ctl, tid) == -1)
b394b9
+				err(EXIT_FAILURE, _("failed to set tid %d's policy"), tid);
b394b9
+
b394b9
+		proc_close_tasks(ts);
b394b9
+
b394b9
+	} else if (set_sched_one(ctl, ctl->pid) == -1)
b394b9
+		err(EXIT_FAILURE, _("failed to set pid %d's policy"), ctl->pid);
b394b9
+
b394b9
+	ctl->altered = 1;
b394b9
+}
b394b9
+
b394b9
 int main(int argc, char **argv)
b394b9
 {
b394b9
-	int i, policy = SCHED_RR, priority = 0, verbose = 0, policy_flag = 0,
b394b9
-	    all_tasks = 0;
b394b9
-	struct sched_param sp;
b394b9
-	pid_t pid = -1;
b394b9
+	struct chrt_ctl _ctl = { .pid = -1 }, *ctl = &_ctl;
b394b9
+	int c;
b394b9
 
b394b9
 	static const struct option longopts[] = {
b394b9
-		{ "all-tasks",  0, NULL, 'a' },
b394b9
-		{ "batch",	0, NULL, 'b' },
b394b9
-		{ "fifo",	0, NULL, 'f' },
b394b9
-		{ "idle",	0, NULL, 'i' },
b394b9
-		{ "pid",	0, NULL, 'p' },
b394b9
-		{ "help",	0, NULL, 'h' },
b394b9
-		{ "max",        0, NULL, 'm' },
b394b9
-		{ "other",	0, NULL, 'o' },
b394b9
-		{ "rr",		0, NULL, 'r' },
b394b9
-		{ "reset-on-fork", 0, NULL, 'R' },
b394b9
-		{ "verbose",	0, NULL, 'v' },
b394b9
-		{ "version",	0, NULL, 'V' },
b394b9
-		{ NULL,		0, NULL, 0 }
b394b9
+		{ "all-tasks",  no_argument, NULL, 'a' },
b394b9
+		{ "batch",	no_argument, NULL, 'b' },
b394b9
+		{ "deadline",   no_argument, NULL, 'd' },
b394b9
+		{ "fifo",	no_argument, NULL, 'f' },
b394b9
+		{ "idle",	no_argument, NULL, 'i' },
b394b9
+		{ "pid",	no_argument, NULL, 'p' },
b394b9
+		{ "help",	no_argument, NULL, 'h' },
b394b9
+		{ "max",        no_argument, NULL, 'm' },
b394b9
+		{ "other",	no_argument, NULL, 'o' },
b394b9
+		{ "rr",		no_argument, NULL, 'r' },
b394b9
+		{ "sched-runtime",  required_argument, NULL, 'T' },
b394b9
+		{ "sched-period",   required_argument, NULL, 'P' },
b394b9
+		{ "sched-deadline", required_argument, NULL, 'D' },
b394b9
+		{ "reset-on-fork",  no_argument,       NULL, 'R' },
b394b9
+		{ "verbose",	no_argument, NULL, 'v' },
b394b9
+		{ "version",	no_argument, NULL, 'V' },
b394b9
+		{ NULL,		no_argument, NULL, 0 }
b394b9
 	};
b394b9
 
b394b9
 	setlocale(LC_ALL, "");
b394b9
@@ -220,51 +434,63 @@ int main(int argc, char **argv)
b394b9
 	textdomain(PACKAGE);
b394b9
 	atexit(close_stdout);
b394b9
 
b394b9
-	while((i = getopt_long(argc, argv, "+abfiphmoRrvV", longopts, NULL)) != -1)
b394b9
+	while((c = getopt_long(argc, argv, "+abdD:fiphmoP:T:rRvV", longopts, NULL)) != -1)
b394b9
 	{
b394b9
 		int ret = EXIT_FAILURE;
b394b9
 
b394b9
-		switch (i) {
b394b9
+		switch (c) {
b394b9
 		case 'a':
b394b9
-			all_tasks = 1;
b394b9
+			ctl->all_tasks = 1;
b394b9
 			break;
b394b9
 		case 'b':
b394b9
 #ifdef SCHED_BATCH
b394b9
-			policy = SCHED_BATCH;
b394b9
+			ctl->policy = SCHED_BATCH;
b394b9
+#endif
b394b9
+			break;
b394b9
+
b394b9
+		case 'd':
b394b9
+#ifdef SCHED_DEADLINE
b394b9
+			ctl->policy = SCHED_DEADLINE;
b394b9
 #endif
b394b9
 			break;
b394b9
 		case 'f':
b394b9
-			policy = SCHED_FIFO;
b394b9
+			ctl->policy = SCHED_FIFO;
b394b9
 			break;
b394b9
 		case 'R':
b394b9
-#ifdef SCHED_RESET_ON_FORK
b394b9
-			policy_flag |= SCHED_RESET_ON_FORK;
b394b9
-#endif
b394b9
+			ctl->reset_on_fork = 1;
b394b9
 			break;
b394b9
 		case 'i':
b394b9
 #ifdef SCHED_IDLE
b394b9
-			policy = SCHED_IDLE;
b394b9
+			ctl->policy = SCHED_IDLE;
b394b9
 #endif
b394b9
 			break;
b394b9
 		case 'm':
b394b9
 			show_min_max();
b394b9
 			return EXIT_SUCCESS;
b394b9
 		case 'o':
b394b9
-			policy = SCHED_OTHER;
b394b9
+			ctl->policy = SCHED_OTHER;
b394b9
 			break;
b394b9
 		case 'p':
b394b9
 			errno = 0;
b394b9
-			pid = strtos32_or_err(argv[argc - 1], _("invalid PID argument"));
b394b9
+			ctl->pid = strtos32_or_err(argv[argc - 1], _("invalid PID argument"));
b394b9
 			break;
b394b9
 		case 'r':
b394b9
-			policy = SCHED_RR;
b394b9
+			ctl->policy = SCHED_RR;
b394b9
 			break;
b394b9
 		case 'v':
b394b9
-			verbose = 1;
b394b9
+			ctl->verbose = 1;
b394b9
+			break;
b394b9
+		case 'T':
b394b9
+			ctl->runtime = strtou64_or_err(optarg, _("invalid runtime argument"));
b394b9
+			break;
b394b9
+		case 'P':
b394b9
+			ctl->period = strtou64_or_err(optarg, _("invalid period argument"));
b394b9
+			break;
b394b9
+		case 'D':
b394b9
+			ctl->deadline = strtou64_or_err(optarg, _("invalid deadline argument"));
b394b9
 			break;
b394b9
 		case 'V':
b394b9
-			printf(_("%s from %s\n"), program_invocation_short_name,
b394b9
-			       PACKAGE_STRING);
b394b9
+			printf(UTIL_LINUX_VERSION);
b394b9
 			return EXIT_SUCCESS;
b394b9
 		case 'h':
b394b9
 			ret = EXIT_SUCCESS;
b394b9
@@ -274,61 +500,56 @@ int main(int argc, char **argv)
b394b9
 		}
b394b9
 	}
b394b9
 
b394b9
-	if (((pid > -1) && argc - optind < 1) ||
b394b9
-	    ((pid == -1) && argc - optind < 2))
b394b9
+	if (((ctl->pid > -1) && argc - optind < 1) ||
b394b9
+	    ((ctl->pid == -1) && argc - optind < 2))
b394b9
 		show_usage(EXIT_FAILURE);
b394b9
 
b394b9
-	if ((pid > -1) && (verbose || argc - optind == 1)) {
b394b9
-		if (all_tasks) {
b394b9
-			pid_t tid;
b394b9
-			struct proc_tasks *ts = proc_open_tasks(pid);
b394b9
-
b394b9
-			if (!ts)
b394b9
-				err(EXIT_FAILURE, _("cannot obtain the list of tasks"));
b394b9
-			while (!proc_next_tid(ts, &tid))
b394b9
-				show_rt_info(tid, FALSE);
b394b9
-			proc_close_tasks(ts);
b394b9
-		} else
b394b9
-			show_rt_info(pid, FALSE);
b394b9
-
b394b9
+	if ((ctl->pid > -1) && (ctl->verbose || argc - optind == 1)) {
b394b9
+		show_sched_info(ctl);
b394b9
 		if (argc - optind == 1)
b394b9
 			return EXIT_SUCCESS;
b394b9
 	}
b394b9
 
b394b9
 	errno = 0;
b394b9
-	priority = strtos32_or_err(argv[optind], _("invalid priority argument"));
b394b9
+	ctl->priority = strtos32_or_err(argv[optind], _("invalid priority argument"));
b394b9
 
b394b9
 #ifdef SCHED_RESET_ON_FORK
b394b9
-	/* sanity check */
b394b9
-	if ((policy_flag & SCHED_RESET_ON_FORK) &&
b394b9
-	    !(policy == SCHED_FIFO || policy == SCHED_RR))
b394b9
-		errx(EXIT_FAILURE, _("SCHED_RESET_ON_FORK flag is supported for "
b394b9
+	if (ctl->reset_on_fork && ctl->policy != SCHED_FIFO && ctl->policy != SCHED_RR)
b394b9
+		errx(EXIT_FAILURE, _("--reset-on-fork option is supported for "
b394b9
 				     "SCHED_FIFO and SCHED_RR policies only"));
b394b9
 #endif
b394b9
-
b394b9
-	policy |= policy_flag;
b394b9
-
b394b9
-	if (pid == -1)
b394b9
-		pid = 0;
b394b9
-	sp.sched_priority = priority;
b394b9
-
b394b9
-	if (all_tasks) {
b394b9
-		pid_t tid;
b394b9
-		struct proc_tasks *ts = proc_open_tasks(pid);
b394b9
-
b394b9
-		if (!ts)
b394b9
-			err(EXIT_FAILURE, _("cannot obtain the list of tasks"));
b394b9
-		while (!proc_next_tid(ts, &tid))
b394b9
-			if (sched_setscheduler(tid, policy, &sp) == -1)
b394b9
-				err(EXIT_FAILURE, _("failed to set tid %d's policy"), tid);
b394b9
-		proc_close_tasks(ts);
b394b9
-	} else if (sched_setscheduler(pid, policy, &sp) == -1)
b394b9
-		err(EXIT_FAILURE, _("failed to set pid %d's policy"), pid);
b394b9
-
b394b9
-	if (verbose)
b394b9
-		show_rt_info(pid, TRUE);
b394b9
-
b394b9
-	if (!pid) {
b394b9
+#ifdef SCHED_DEADLINE
b394b9
+	if ((ctl->runtime || ctl->deadline || ctl->period) && ctl->policy != SCHED_DEADLINE)
b394b9
+		errx(EXIT_FAILURE, _("--sched-{runtime,deadline,period} options "
b394b9
+				     "are supported for SCHED_DEADLINE only"));
b394b9
+	if (ctl->policy == SCHED_DEADLINE) {
b394b9
+		/* The basic rule is runtime <= deadline <= period, so we can
b394b9
+		 * make deadline and runtime optional on command line. Note we
b394b9
+		 * don't check any values or set any defaults, it's kernel
b394b9
+		 * responsibility.
b394b9
+		 */
b394b9
+		if (ctl->deadline == 0)
b394b9
+			ctl->deadline = ctl->period;
b394b9
+		if (ctl->runtime == 0)
b394b9
+			ctl->runtime = ctl->deadline;
b394b9
+	}
b394b9
+#else
b394b9
+	if (ctl->runtime || ctl->deadline || ctl->period)
b394b9
+		errx(EXIT_FAILURE, _("SCHED_DEADLINE is unsupported"));
b394b9
+#endif
b394b9
+	if (ctl->pid == -1)
b394b9
+		ctl->pid = 0;
b394b9
+	if (ctl->priority < sched_get_priority_min(ctl->policy) ||
b394b9
+	    sched_get_priority_max(ctl->policy) < ctl->priority)
b394b9
+		errx(EXIT_FAILURE,
b394b9
+		     _("unsupported priority value for the policy: %d: see --max for valid range"),
b394b9
+		     ctl->priority);
b394b9
+	set_sched(ctl);
b394b9
+
b394b9
+	if (ctl->verbose)
b394b9
+		show_sched_info(ctl);
b394b9
+
b394b9
+	if (!ctl->pid) {
b394b9
 		argv += optind + 1;
b394b9
 		execvp(argv[0], argv);
b394b9
 		err(EXIT_FAILURE, _("failed to execute %s"), argv[0]);
b394b9
-- 
b394b9
2.7.4
b394b9