]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - schedutils/chrt.c
2 * chrt.c - manipulate a task's real-time attributes
4 * 27-Apr-2002: initial version - Robert Love <rml@tech9.net>
5 * 04-May-2011: make it thread-aware - Davidlohr Bueso <dave@gnu.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License, version 2, as
9 * published by the Free Software Foundation
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * Copyright (C) 2004 Robert Love
30 #include <sys/resource.h>
34 #include "closestream.h"
36 #include "procutils.h"
38 /* the SCHED_BATCH is supported since Linux 2.6.16
39 * -- temporary workaround for people with old glibc headers
41 #if defined (__linux__) && !defined(SCHED_BATCH)
42 # define SCHED_BATCH 3
45 /* the SCHED_IDLE is supported since Linux 2.6.23
46 * commit id 0e6aca43e08a62a48d6770e9a159dbec167bf4c6
47 * -- temporary workaround for people with old glibc headers
49 #if defined (__linux__) && !defined(SCHED_IDLE)
53 /* flag by sched_getscheduler() */
54 #if defined(__linux__) && !defined(SCHED_RESET_ON_FORK)
55 # define SCHED_RESET_ON_FORK 0x40000000
58 /* flag by sched_getattr() */
59 #if defined(__linux__) && !defined(SCHED_FLAG_RESET_ON_FORK)
60 # define SCHED_FLAG_RESET_ON_FORK 0x01
63 #if defined (__linux__) && !defined(HAVE_SCHED_SETATTR)
64 # include <sys/syscall.h>
67 /* usable kernel-headers, but old glibc-headers */
68 #if defined (__linux__) && !defined(SYS_sched_setattr) && defined(__NR_sched_setattr)
69 # define SYS_sched_setattr __NR_sched_setattr
72 #if defined (__linux__) && !defined(SYS_sched_getattr) && defined(__NR_sched_getattr)
73 # define SYS_sched_getattr __NR_sched_getattr
76 #if defined (__linux__) && !defined(HAVE_SCHED_SETATTR) && defined(SYS_sched_setattr)
77 # define HAVE_SCHED_SETATTR
81 uint32_t sched_policy
;
84 /* SCHED_NORMAL, SCHED_BATCH */
87 /* SCHED_FIFO, SCHED_RR */
88 uint32_t sched_priority
;
90 /* SCHED_DEADLINE (nsec) */
91 uint64_t sched_runtime
;
92 uint64_t sched_deadline
;
93 uint64_t sched_period
;
96 static int sched_setattr(pid_t pid
, const struct sched_attr
*attr
, unsigned int flags
)
98 return syscall(SYS_sched_setattr
, pid
, attr
, flags
);
101 static int sched_getattr(pid_t pid
, struct sched_attr
*attr
, unsigned int size
, unsigned int flags
)
103 return syscall(SYS_sched_getattr
, pid
, attr
, size
, flags
);
107 /* the SCHED_DEADLINE is supported since Linux 3.14
108 * commit id aab03e05e8f7e26f51dee792beddcb5cca9215a5
109 * -- sched_setattr() is required for this policy!
111 #if defined (__linux__) && !defined(SCHED_DEADLINE) && defined(HAVE_SCHED_SETATTR)
112 # define SCHED_DEADLINE 6
118 int policy
; /* SCHED_* */
121 uint64_t runtime
; /* --sched-* options */
125 unsigned int all_tasks
: 1, /* all threads of the PID */
126 reset_on_fork
: 1, /* SCHED_RESET_ON_FORK */
127 altered
: 1, /* sched_set**() used */
128 verbose
: 1; /* verbose output */
131 static void __attribute__((__noreturn__
)) usage(void)
135 fputs(_("Show or change the real-time scheduling attributes of a process.\n"), out
);
136 fputs(USAGE_SEPARATOR
, out
);
137 fputs(_("Set policy:\n"
138 " chrt [options] <priority> <command> [<arg>...]\n"
139 " chrt [options] --pid <priority> <pid>\n"), out
);
140 fputs(USAGE_SEPARATOR
, out
);
141 fputs(_("Get policy:\n"
142 " chrt [options] -p <pid>\n"), out
);
144 fputs(USAGE_SEPARATOR
, out
);
145 fputs(_("Policy options:\n"), out
);
146 fputs(_(" -b, --batch set policy to SCHED_BATCH\n"), out
);
147 fputs(_(" -d, --deadline set policy to SCHED_DEADLINE\n"), out
);
148 fputs(_(" -f, --fifo set policy to SCHED_FIFO\n"), out
);
149 fputs(_(" -i, --idle set policy to SCHED_IDLE\n"), out
);
150 fputs(_(" -o, --other set policy to SCHED_OTHER\n"), out
);
151 fputs(_(" -r, --rr set policy to SCHED_RR (default)\n"), out
);
153 fputs(USAGE_SEPARATOR
, out
);
154 fputs(_("Scheduling options:\n"), out
);
155 fputs(_(" -R, --reset-on-fork set SCHED_RESET_ON_FORK for FIFO or RR\n"), out
);
156 fputs(_(" -T, --sched-runtime <ns> runtime parameter for DEADLINE\n"), out
);
157 fputs(_(" -P, --sched-period <ns> period parameter for DEADLINE\n"), out
);
158 fputs(_(" -D, --sched-deadline <ns> deadline parameter for DEADLINE\n"), out
);
160 fputs(USAGE_SEPARATOR
, out
);
161 fputs(_("Other options:\n"), out
);
162 fputs(_(" -a, --all-tasks operate on all the tasks (threads) for a given pid\n"), out
);
163 fputs(_(" -m, --max show min and max valid priorities\n"), out
);
164 fputs(_(" -p, --pid operate on existing given pid\n"), out
);
165 fputs(_(" -v, --verbose display status information\n"), out
);
167 fputs(USAGE_SEPARATOR
, out
);
168 printf(USAGE_HELP_OPTIONS(22));
170 printf(USAGE_MAN_TAIL("chrt(1)"));
174 static const char *get_policy_name(int policy
)
178 return "SCHED_OTHER";
180 #ifdef SCHED_RESET_ON_FORK
181 case SCHED_FIFO
| SCHED_RESET_ON_FORK
:
189 #ifdef SCHED_RESET_ON_FORK
190 case SCHED_RR
| SCHED_RESET_ON_FORK
:
195 return "SCHED_BATCH";
197 #ifdef SCHED_DEADLINE
199 return "SCHED_DEADLINE";
208 static void show_sched_pid_info(struct chrt_ctl
*ctl
, pid_t pid
)
210 int policy
= -1, reset_on_fork
= 0, prio
= 0;
211 #ifdef SCHED_DEADLINE
212 uint64_t deadline
= 0, runtime
= 0, period
= 0;
215 /* don't display "pid 0" as that is confusing */
224 #ifdef HAVE_SCHED_SETATTR
226 struct sched_attr sa
;
228 if (sched_getattr(pid
, &sa
, sizeof(sa
), 0) != 0) {
231 err(EXIT_FAILURE
, _("failed to get pid %d's policy"), pid
);
234 policy
= sa
.sched_policy
;
235 prio
= sa
.sched_priority
;
236 reset_on_fork
= sa
.sched_flags
& SCHED_FLAG_RESET_ON_FORK
;
237 deadline
= sa
.sched_deadline
;
238 runtime
= sa
.sched_runtime
;
239 period
= sa
.sched_period
;
249 struct sched_param sp
;
251 policy
= sched_getscheduler(pid
);
253 err(EXIT_FAILURE
, _("failed to get pid %d's policy"), pid
);
255 if (sched_getparam(pid
, &sp
) != 0)
256 err(EXIT_FAILURE
, _("failed to get pid %d's attributes"), pid
);
258 prio
= sp
.sched_priority
;
259 # ifdef SCHED_RESET_ON_FORK
260 if (policy
== (SCHED_FIFO
|SCHED_RESET_ON_FORK
) || policy
== (SCHED_BATCH
|SCHED_RESET_ON_FORK
))
266 printf(_("pid %d's new scheduling policy: %s"), pid
, get_policy_name(policy
));
268 printf(_("pid %d's current scheduling policy: %s"), pid
, get_policy_name(policy
));
271 printf("|SCHED_RESET_ON_FORK");
275 printf(_("pid %d's new scheduling priority: %d\n"), pid
, prio
);
277 printf(_("pid %d's current scheduling priority: %d\n"), pid
, prio
);
279 #ifdef SCHED_DEADLINE
280 if (policy
== SCHED_DEADLINE
) {
282 printf(_("pid %d's new runtime/deadline/period parameters: %ju/%ju/%ju\n"),
283 pid
, runtime
, deadline
, period
);
285 printf(_("pid %d's current runtime/deadline/period parameters: %ju/%ju/%ju\n"),
286 pid
, runtime
, deadline
, period
);
292 static void show_sched_info(struct chrt_ctl
*ctl
)
294 if (ctl
->all_tasks
) {
296 struct proc_tasks
*ts
= proc_open_tasks(ctl
->pid
);
299 err(EXIT_FAILURE
, _("cannot obtain the list of tasks"));
301 while (!proc_next_tid(ts
, &tid
))
302 show_sched_pid_info(ctl
, tid
);
304 proc_close_tasks(ts
);
306 show_sched_pid_info(ctl
, ctl
->pid
);
309 static void show_min_max(void)
322 #ifdef SCHED_DEADLINE
327 for (i
= 0; i
< ARRAY_SIZE(policies
); i
++) {
328 int plc
= policies
[i
];
329 int max
= sched_get_priority_max(plc
);
330 int min
= sched_get_priority_min(plc
);
332 if (max
>= 0 && min
>= 0)
333 printf(_("%s min/max priority\t: %d/%d\n"),
334 get_policy_name(plc
), min
, max
);
336 printf(_("%s not supported?\n"), get_policy_name(plc
));
340 static int set_sched_one_by_setscheduler(struct chrt_ctl
*ctl
, pid_t pid
)
342 struct sched_param sp
= { .sched_priority
= ctl
->priority
};
343 int policy
= ctl
->policy
;
346 # ifdef SCHED_RESET_ON_FORK
347 if (ctl
->reset_on_fork
)
348 policy
|= SCHED_RESET_ON_FORK
;
350 return sched_setscheduler(pid
, policy
, &sp
);
354 #ifndef HAVE_SCHED_SETATTR
355 static int set_sched_one(struct chrt_ctl
*ctl
, pid_t pid
)
357 return set_sched_one_by_setscheduler(ctl
, pid
);
360 #else /* !HAVE_SCHED_SETATTR */
361 static int set_sched_one(struct chrt_ctl
*ctl
, pid_t pid
)
363 struct sched_attr sa
= { .size
= sizeof(struct sched_attr
) };
365 /* old API is good enough for non-deadline */
366 if (ctl
->policy
!= SCHED_DEADLINE
)
367 return set_sched_one_by_setscheduler(ctl
, pid
);
369 /* no changeed by chrt, follow the current setting */
370 sa
.sched_nice
= getpriority(PRIO_PROCESS
, pid
);
372 /* use main() to check if the setting makes sense */
373 sa
.sched_policy
= ctl
->policy
;
374 sa
.sched_priority
= ctl
->priority
;
375 sa
.sched_runtime
= ctl
->runtime
;
376 sa
.sched_period
= ctl
->period
;
377 sa
.sched_deadline
= ctl
->deadline
;
379 # ifdef SCHED_RESET_ON_FORK
380 if (ctl
->reset_on_fork
)
381 sa
.sched_flags
|= SCHED_RESET_ON_FORK
;
384 return sched_setattr(pid
, &sa
, 0);
386 #endif /* HAVE_SCHED_SETATTR */
388 static void set_sched(struct chrt_ctl
*ctl
)
390 if (ctl
->all_tasks
) {
392 struct proc_tasks
*ts
= proc_open_tasks(ctl
->pid
);
395 err(EXIT_FAILURE
, _("cannot obtain the list of tasks"));
397 while (!proc_next_tid(ts
, &tid
))
398 if (set_sched_one(ctl
, tid
) == -1)
399 err(EXIT_FAILURE
, _("failed to set tid %d's policy"), tid
);
401 proc_close_tasks(ts
);
403 } else if (set_sched_one(ctl
, ctl
->pid
) == -1)
404 err(EXIT_FAILURE
, _("failed to set pid %d's policy"), ctl
->pid
);
409 int main(int argc
, char **argv
)
411 struct chrt_ctl _ctl
= { .pid
= -1, .policy
= SCHED_RR
}, *ctl
= &_ctl
;
414 static const struct option longopts
[] = {
415 { "all-tasks", no_argument
, NULL
, 'a' },
416 { "batch", no_argument
, NULL
, 'b' },
417 { "deadline", no_argument
, NULL
, 'd' },
418 { "fifo", no_argument
, NULL
, 'f' },
419 { "idle", no_argument
, NULL
, 'i' },
420 { "pid", no_argument
, NULL
, 'p' },
421 { "help", no_argument
, NULL
, 'h' },
422 { "max", no_argument
, NULL
, 'm' },
423 { "other", no_argument
, NULL
, 'o' },
424 { "rr", no_argument
, NULL
, 'r' },
425 { "sched-runtime", required_argument
, NULL
, 'T' },
426 { "sched-period", required_argument
, NULL
, 'P' },
427 { "sched-deadline", required_argument
, NULL
, 'D' },
428 { "reset-on-fork", no_argument
, NULL
, 'R' },
429 { "verbose", no_argument
, NULL
, 'v' },
430 { "version", no_argument
, NULL
, 'V' },
431 { NULL
, no_argument
, NULL
, 0 }
434 setlocale(LC_ALL
, "");
435 bindtextdomain(PACKAGE
, LOCALEDIR
);
437 close_stdout_atexit();
439 while((c
= getopt_long(argc
, argv
, "+abdD:fiphmoP:T:rRvV", longopts
, NULL
)) != -1)
447 ctl
->policy
= SCHED_BATCH
;
452 #ifdef SCHED_DEADLINE
453 ctl
->policy
= SCHED_DEADLINE
;
457 ctl
->policy
= SCHED_FIFO
;
460 ctl
->reset_on_fork
= 1;
464 ctl
->policy
= SCHED_IDLE
;
471 ctl
->policy
= SCHED_OTHER
;
475 ctl
->pid
= strtos32_or_err(argv
[argc
- 1], _("invalid PID argument"));
478 ctl
->policy
= SCHED_RR
;
484 ctl
->runtime
= strtou64_or_err(optarg
, _("invalid runtime argument"));
487 ctl
->period
= strtou64_or_err(optarg
, _("invalid period argument"));
490 ctl
->deadline
= strtou64_or_err(optarg
, _("invalid deadline argument"));
494 print_version(EXIT_SUCCESS
);
498 errtryhelp(EXIT_FAILURE
);
502 if (((ctl
->pid
> -1) && argc
- optind
< 1) ||
503 ((ctl
->pid
== -1) && argc
- optind
< 2)) {
504 warnx(_("bad usage"));
505 errtryhelp(EXIT_FAILURE
);
508 if ((ctl
->pid
> -1) && (ctl
->verbose
|| argc
- optind
== 1)) {
509 show_sched_info(ctl
);
510 if (argc
- optind
== 1)
515 ctl
->priority
= strtos32_or_err(argv
[optind
], _("invalid priority argument"));
517 #ifdef SCHED_RESET_ON_FORK
518 if (ctl
->reset_on_fork
&& ctl
->policy
!= SCHED_FIFO
&& ctl
->policy
!= SCHED_RR
)
519 errx(EXIT_FAILURE
, _("--reset-on-fork option is supported for "
520 "SCHED_FIFO and SCHED_RR policies only"));
522 #ifdef SCHED_DEADLINE
523 if ((ctl
->runtime
|| ctl
->deadline
|| ctl
->period
) && ctl
->policy
!= SCHED_DEADLINE
)
524 errx(EXIT_FAILURE
, _("--sched-{runtime,deadline,period} options "
525 "are supported for SCHED_DEADLINE only"));
526 if (ctl
->policy
== SCHED_DEADLINE
) {
527 /* The basic rule is runtime <= deadline <= period, so we can
528 * make deadline and runtime optional on command line. Note we
529 * don't check any values or set any defaults, it's kernel
532 if (ctl
->deadline
== 0)
533 ctl
->deadline
= ctl
->period
;
534 if (ctl
->runtime
== 0)
535 ctl
->runtime
= ctl
->deadline
;
538 if (ctl
->runtime
|| ctl
->deadline
|| ctl
->period
)
539 errx(EXIT_FAILURE
, _("SCHED_DEADLINE is unsupported"));
543 if (ctl
->priority
< sched_get_priority_min(ctl
->policy
) ||
544 sched_get_priority_max(ctl
->policy
) < ctl
->priority
)
546 _("unsupported priority value for the policy: %d: see --max for valid range"),
551 show_sched_info(ctl
);
555 execvp(argv
[0], argv
);