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