]> git.ipfire.org Git - thirdparty/util-linux.git/blame - schedutils/chrt.c
cfisk: add /dev/vda as another default disk
[thirdparty/util-linux.git] / schedutils / chrt.c
CommitLineData
48d7b13a 1/*
a7560c06 2 * chrt.c - manipulate a task's real-time attributes
48d7b13a 3 *
a7560c06
BS
4 * 27-Apr-2002: initial version - Robert Love <rml@tech9.net>
5 * 04-May-2011: make it thread-aware - Davidlohr Bueso <dave@gnu.org>
48d7b13a
KZ
6 *
7 * This program is free software; you can redistribute it and/or modify
a7560c06 8 * it under the terms of the GNU General Public License, version 2, as
48d7b13a
KZ
9 * published by the Free Software Foundation
10 *
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.
15 *
7cebf0bb
SK
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.
48d7b13a
KZ
19 *
20 * Copyright (C) 2004 Robert Love
21 */
22
48d7b13a
KZ
23#include <stdio.h>
24#include <stdlib.h>
25#include <sched.h>
26#include <unistd.h>
27#include <getopt.h>
28#include <errno.h>
bd9d9f05 29
b6534e4f 30#include "c.h"
bd9d9f05 31#include "nls.h"
ed8ec2a6 32#include "closestream.h"
8abcf290 33#include "strutils.h"
78904e76 34#include "procutils.h"
24295096 35
09dd84ca
KZ
36/* the SCHED_BATCH is supported since Linux 2.6.16
37 * -- temporary workaround for people with old glibc headers
38 */
b64279da 39#if defined (__linux__) && !defined(SCHED_BATCH)
09dd84ca
KZ
40# define SCHED_BATCH 3
41#endif
42
c779d6e9
MS
43/* the SCHED_IDLE is supported since Linux 2.6.23
44 * commit id 0e6aca43e08a62a48d6770e9a159dbec167bf4c6
45 * -- temporary workaround for people with old glibc headers
46 */
b64279da 47#if defined (__linux__) && !defined(SCHED_IDLE)
c779d6e9
MS
48# define SCHED_IDLE 5
49#endif
50
acde3a05 51/* flag by sched_getscheduler() */
0fefbedc 52#if defined(__linux__) && !defined(SCHED_RESET_ON_FORK)
acde3a05
KZ
53# define SCHED_RESET_ON_FORK 0x40000000
54#endif
55
56/* flag by sched_getattr() */
57#if defined(__linux__) && !defined(SCHED_FLAG_RESET_ON_FORK)
58# define SCHED_FLAG_RESET_ON_FORK 0x01
0fefbedc
AK
59#endif
60
1a7e6395 61
15167589
KZ
62#if defined (__linux__) && !defined(HAVE_SCHED_SETATTR)
63# include <sys/syscall.h>
64#endif
65
66#if defined (__linux__) && !defined(HAVE_SCHED_SETATTR) && defined(SYS_sched_setattr)
67# define HAVE_SCHED_SETATTR
68
69struct sched_attr {
70 uint32_t size;
71 uint32_t sched_policy;
72 uint64_t sched_flags;
73
74 /* SCHED_NORMAL, SCHED_BATCH */
75 int32_t sched_nice;
76
77 /* SCHED_FIFO, SCHED_RR */
78 uint32_t sched_priority;
79
80 /* SCHED_DEADLINE (nsec) */
81 uint64_t sched_runtime;
82 uint64_t sched_deadline;
83 uint64_t sched_period;
84};
85
86static int sched_setattr(pid_t pid, const struct sched_attr *attr, unsigned int flags)
87{
88 return syscall(SYS_sched_setattr, pid, attr, flags);
89}
90
91static int sched_getattr(pid_t pid, struct sched_attr *attr, unsigned int size, unsigned int flags)
92{
93 return syscall(SYS_sched_getattr, pid, attr, size, flags);
94}
1a7e6395
KZ
95#endif
96
97/* the SCHED_DEADLINE is supported since Linux 3.14
98 * commit id aab03e05e8f7e26f51dee792beddcb5cca9215a5
99 * -- sched_setattr() is required for this policy!
100 */
101#if defined (__linux__) && !defined(SCHED_DEADLINE) && defined(HAVE_SCHED_SETATTR)
102# define SCHED_DEADLINE 6
103#endif
15167589 104
7a4ea566
KZ
105/* control struct */
106struct chrt_ctl {
107 pid_t pid;
108 int policy; /* SCHED_* */
109 int priority;
110
1a7e6395
KZ
111 uint64_t runtime; /* --sched-* options */
112 uint64_t deadline;
113 uint64_t period;
114
7a4ea566
KZ
115 unsigned int all_tasks : 1, /* all threads of the PID */
116 reset_on_fork : 1, /* SCHED_RESET_ON_FORK */
a30cf650 117 altered : 1, /* sched_set**() used */
7a4ea566
KZ
118 verbose : 1; /* verbose output */
119};
0fefbedc 120
98da1298 121static void __attribute__((__noreturn__)) show_usage(int rc)
48d7b13a 122{
aaf6349f
BS
123 FILE *out = rc == EXIT_SUCCESS ? stdout : stderr;
124
451dbcfa 125 fputs(_("Show or change the real-time scheduling attributes of a process.\n"), out);
9acbe2aa
BS
126 fputs(USAGE_SEPARATOR, out);
127 fputs(_("Set policy:\n"
128 " chrt [options] <priority> <command> [<arg>...]\n"
a6fec537 129 " chrt [options] --pid <priority> <pid>\n"), out);
9acbe2aa
BS
130 fputs(USAGE_SEPARATOR, out);
131 fputs(_("Get policy:\n"
132 " chrt [options] -p <pid>\n"), out);
aaf6349f 133
9acbe2aa
BS
134 fputs(USAGE_SEPARATOR, out);
135 fputs(_("Policy options:\n"), out);
136 fputs(_(" -b, --batch set policy to SCHED_BATCH\n"), out);
1a7e6395 137 fputs(_(" -d, --deadline set policy to SCHED_DEADLINE\n"), out);
9acbe2aa
BS
138 fputs(_(" -f, --fifo set policy to SCHED_FIFO\n"), out);
139 fputs(_(" -i, --idle set policy to SCHED_IDLE\n"), out);
140 fputs(_(" -o, --other set policy to SCHED_OTHER\n"), out);
141 fputs(_(" -r, --rr set policy to SCHED_RR (default)\n"), out);
aaf6349f 142
9acbe2aa 143 fputs(USAGE_SEPARATOR, out);
1a7e6395
KZ
144 fputs(_("Scheduling options:\n"), out);
145 fputs(_(" -R, --reset-on-fork set SCHED_RESET_ON_FORK for FIFO or RR\n"), out);
146 fputs(_(" -T, --sched-runtime <ns> runtime parameter for DEADLINE\n"), out);
147 fputs(_(" -P, --sched-period <ns> period parameter for DEADLINE\n"), out);
148 fputs(_(" -D, --sched-deadline <ns> deadline parameter for DEADLINE\n"), out);
149
9acbe2aa
BS
150 fputs(USAGE_SEPARATOR, out);
151 fputs(_("Other options:\n"), out);
152 fputs(_(" -a, --all-tasks operate on all the tasks (threads) for a given pid\n"), out);
153 fputs(_(" -m, --max show min and max valid priorities\n"), out);
154 fputs(_(" -p, --pid operate on existing given pid\n"), out);
155 fputs(_(" -v, --verbose display status information\n"), out);
156
157 fputs(USAGE_SEPARATOR, out);
158 fputs(USAGE_HELP, out);
159 fputs(USAGE_VERSION, out);
bd9d9f05 160
a587cc55 161 fprintf(out, USAGE_MAN_TAIL("chrt(1)"));
bd9d9f05 162 exit(rc);
48d7b13a
KZ
163}
164
acde3a05 165static const char *get_policy_name(int policy)
48d7b13a 166{
48d7b13a
KZ
167 switch (policy) {
168 case SCHED_OTHER:
acde3a05 169 return "SCHED_OTHER";
48d7b13a 170 case SCHED_FIFO:
a03eac52 171#ifdef SCHED_RESET_ON_FORK
110d680a 172 case SCHED_FIFO | SCHED_RESET_ON_FORK:
a03eac52 173#endif
acde3a05 174 return "SCHED_FIFO";
b64279da 175#ifdef SCHED_IDLE
c779d6e9 176 case SCHED_IDLE:
acde3a05 177 return "SCHED_IDLE";
b64279da 178#endif
48d7b13a 179 case SCHED_RR:
a03eac52 180#ifdef SCHED_RESET_ON_FORK
59e4a382 181 case SCHED_RR | SCHED_RESET_ON_FORK:
a03eac52 182#endif
acde3a05 183 return "SCHED_RR";
b64279da 184#ifdef SCHED_BATCH
df3773fb 185 case SCHED_BATCH:
acde3a05 186 return "SCHED_BATCH";
1a7e6395
KZ
187#endif
188#ifdef SCHED_DEADLINE
189 case SCHED_DEADLINE:
acde3a05 190 return "SCHED_DEADLINE";
b64279da 191#endif
48d7b13a 192 default:
acde3a05 193 break;
48d7b13a
KZ
194 }
195
acde3a05
KZ
196 return _("unknown");
197}
198
199static void show_sched_pid_info(struct chrt_ctl *ctl, pid_t pid)
200{
201 int policy, reset_on_fork = 0, prio = 0;
202#ifdef SCHED_DEADLINE
203 uint64_t deadline = 0, runtime = 0, period = 0;
204#endif
205
206 /* don't display "pid 0" as that is confusing */
207 if (!pid)
208 pid = getpid();
209
210#ifdef HAVE_SCHED_SETATTR
211 {
212 struct sched_attr sa;
213
214 if (sched_getattr(pid, &sa, sizeof(sa), 0) != 0)
215 err(EXIT_FAILURE, _("failed to get pid %d's policy"), pid);
216
217 policy = sa.sched_policy;
218 prio = sa.sched_priority;
219 reset_on_fork = sa.sched_flags & SCHED_FLAG_RESET_ON_FORK;
220 deadline = sa.sched_deadline;
221 runtime = sa.sched_runtime;
222 period = sa.sched_period;
223 }
224#else /* !HAVE_SCHED_SETATTR */
225 {
226 struct sched_param sp;
227
228 policy = sched_getscheduler(pid);
229 if (policy == -1)
230 err(EXIT_FAILURE, _("failed to get pid %d's policy"), pid);
231
232 if (sched_getparam(pid, &sp) != 0)
233 err(EXIT_FAILURE, _("failed to get pid %d's attributes"), pid);
234 else
235 prio = sp.sched_priority;
236# ifdef SCHED_RESET_ON_FORK
237 if (policy == (SCHED_FIFO|SCHED_RESET_ON_FORK) || policy == (SCHED_BATCH|SCHED_RESET_ON_FORK))
238 reset_on_fork = 1;
239# endif
240 }
241#endif /* !HAVE_SCHED_SETATTR */
48d7b13a 242
a30cf650 243 if (ctl->altered)
acde3a05 244 printf(_("pid %d's new scheduling policy: %s"), pid, get_policy_name(policy));
a9a3e5f2 245 else
acde3a05
KZ
246 printf(_("pid %d's current scheduling policy: %s"), pid, get_policy_name(policy));
247
248 if (reset_on_fork)
249 printf("|SCHED_RESET_ON_FORK");
250 putchar('\n');
251
252 if (ctl->altered)
253 printf(_("pid %d's new scheduling priority: %d\n"), pid, prio);
254 else
255 printf(_("pid %d's current scheduling priority: %d\n"), pid, prio);
256
257#ifdef SCHED_DEADLINE
258 if (policy == SCHED_DEADLINE) {
259 if (ctl->altered)
260 printf(_("pid %d's new runtime/deadline/period parameters: %ju/%ju/%ju\n"),
261 pid, runtime, deadline, period);
262 else
263 printf(_("pid %d's current runtime/deadline/period parameters: %ju/%ju/%ju\n"),
264 pid, runtime, deadline, period);
265 }
266#endif
48d7b13a
KZ
267}
268
a30cf650
KZ
269
270static void show_sched_info(struct chrt_ctl *ctl)
271{
272 if (ctl->all_tasks) {
273 pid_t tid;
274 struct proc_tasks *ts = proc_open_tasks(ctl->pid);
275
276 if (!ts)
277 err(EXIT_FAILURE, _("cannot obtain the list of tasks"));
278
279 while (!proc_next_tid(ts, &tid))
280 show_sched_pid_info(ctl, tid);
281
282 proc_close_tasks(ts);
283 } else
284 show_sched_pid_info(ctl, ctl->pid);
285}
286
48d7b13a
KZ
287static void show_min_max(void)
288{
90b7d261 289 unsigned long i;
110d680a
SK
290 int policies[] = {
291 SCHED_OTHER,
292 SCHED_FIFO,
293 SCHED_RR,
b64279da 294#ifdef SCHED_BATCH
110d680a 295 SCHED_BATCH,
b64279da
AJ
296#endif
297#ifdef SCHED_IDLE
110d680a 298 SCHED_IDLE,
1a7e6395
KZ
299#endif
300#ifdef SCHED_DEADLINE
301 SCHED_DEADLINE,
b64279da 302#endif
110d680a 303 };
bd9d9f05
KZ
304
305 for (i = 0; i < ARRAY_SIZE(policies); i++) {
acde3a05
KZ
306 int plc = policies[i];
307 int max = sched_get_priority_max(plc);
308 int min = sched_get_priority_min(plc);
bd9d9f05
KZ
309
310 if (max >= 0 && min >= 0)
311 printf(_("SCHED_%s min/max priority\t: %d/%d\n"),
acde3a05 312 get_policy_name(plc), min, max);
bd9d9f05 313 else
acde3a05 314 printf(_("SCHED_%s not supported?\n"), get_policy_name(plc));
bd9d9f05 315 }
48d7b13a
KZ
316}
317
15167589
KZ
318#ifndef HAVE_SCHED_SETATTR
319static int set_sched_one(struct chrt_ctl *ctl, pid_t pid)
4820a737
KZ
320{
321 struct sched_param sp = { .sched_priority = ctl->priority };
15167589 322 int policy = ctl->policy;
4820a737 323
15167589
KZ
324# ifdef SCHED_RESET_ON_FORK
325 if (ctl->reset_on_fork)
326 policy |= SCHED_RESET_ON_FORK;
327# endif
328 return sched_setscheduler(pid, policy, &sp);
329}
330
331#else /* !HAVE_SCHED_SETATTR */
332static int set_sched_one(struct chrt_ctl *ctl, pid_t pid)
333{
1a7e6395 334 /* use main() to check if the setting makes sense */
15167589 335 struct sched_attr sa = {
acde3a05 336 .size = sizeof(struct sched_attr),
15167589 337 .sched_policy = ctl->policy,
1a7e6395 338 .sched_priority = ctl->priority,
acde3a05
KZ
339 .sched_runtime = ctl->runtime,
340 .sched_period = ctl->period,
1a7e6395 341 .sched_deadline = ctl->deadline
15167589
KZ
342 };
343# ifdef SCHED_RESET_ON_FORK
344 if (ctl->reset_on_fork)
345 sa.sched_flags |= SCHED_RESET_ON_FORK;
346# endif
347 return sched_setattr(pid, &sa, 0);
348}
349#endif /* HAVE_SCHED_SETATTR */
350
351static void set_sched(struct chrt_ctl *ctl)
352{
4820a737
KZ
353 if (ctl->all_tasks) {
354 pid_t tid;
355 struct proc_tasks *ts = proc_open_tasks(ctl->pid);
356
357 if (!ts)
358 err(EXIT_FAILURE, _("cannot obtain the list of tasks"));
359
360 while (!proc_next_tid(ts, &tid))
15167589 361 if (set_sched_one(ctl, tid) == -1)
4820a737
KZ
362 err(EXIT_FAILURE, _("failed to set tid %d's policy"), tid);
363
364 proc_close_tasks(ts);
365
15167589 366 } else if (set_sched_one(ctl, ctl->pid) == -1)
4820a737
KZ
367 err(EXIT_FAILURE, _("failed to set pid %d's policy"), ctl->pid);
368
369 ctl->altered = 1;
370}
371
110d680a 372int main(int argc, char **argv)
48d7b13a 373{
7a4ea566 374 struct chrt_ctl _ctl = { .pid = -1 }, *ctl = &_ctl;
4820a737 375 int c;
48d7b13a 376
6c7d5ae9 377 static const struct option longopts[] = {
1a7e6395
KZ
378 { "all-tasks", no_argument, NULL, 'a' },
379 { "batch", no_argument, NULL, 'b' },
380 { "deadline", no_argument, NULL, 'd' },
381 { "fifo", no_argument, NULL, 'f' },
382 { "idle", no_argument, NULL, 'i' },
383 { "pid", no_argument, NULL, 'p' },
384 { "help", no_argument, NULL, 'h' },
385 { "max", no_argument, NULL, 'm' },
386 { "other", no_argument, NULL, 'o' },
387 { "rr", no_argument, NULL, 'r' },
388 { "sched-runtime", required_argument, NULL, 'T' },
389 { "sched-period", required_argument, NULL, 'P' },
390 { "sched-deadline", required_argument, NULL, 'D' },
391 { "reset-on-fork", no_argument, NULL, 'R' },
392 { "verbose", no_argument, NULL, 'v' },
393 { "version", no_argument, NULL, 'V' },
394 { NULL, no_argument, NULL, 0 }
48d7b13a
KZ
395 };
396
bd9d9f05
KZ
397 setlocale(LC_ALL, "");
398 bindtextdomain(PACKAGE, LOCALEDIR);
399 textdomain(PACKAGE);
ed8ec2a6 400 atexit(close_stdout);
bd9d9f05 401
b3a50671 402 while((c = getopt_long(argc, argv, "+abdD:fiphmoP:T:rRvV", longopts, NULL)) != -1)
48d7b13a 403 {
bd9d9f05 404 int ret = EXIT_FAILURE;
48d7b13a 405
4820a737 406 switch (c) {
78904e76 407 case 'a':
7a4ea566 408 ctl->all_tasks = 1;
78904e76 409 break;
df3773fb 410 case 'b':
b64279da 411#ifdef SCHED_BATCH
7a4ea566 412 ctl->policy = SCHED_BATCH;
1a7e6395
KZ
413#endif
414 break;
415
416 case 'd':
417#ifdef SCHED_DEADLINE
418 ctl->policy = SCHED_DEADLINE;
b64279da 419#endif
df3773fb 420 break;
48d7b13a 421 case 'f':
7a4ea566 422 ctl->policy = SCHED_FIFO;
48d7b13a 423 break;
cdfb1e88 424 case 'R':
7a4ea566 425 ctl->reset_on_fork = 1;
c150589f 426 break;
c779d6e9 427 case 'i':
b64279da 428#ifdef SCHED_IDLE
7a4ea566 429 ctl->policy = SCHED_IDLE;
b64279da 430#endif
c779d6e9 431 break;
48d7b13a
KZ
432 case 'm':
433 show_min_max();
110d680a 434 return EXIT_SUCCESS;
48d7b13a 435 case 'o':
7a4ea566 436 ctl->policy = SCHED_OTHER;
48d7b13a
KZ
437 break;
438 case 'p':
439 errno = 0;
7a4ea566 440 ctl->pid = strtos32_or_err(argv[argc - 1], _("invalid PID argument"));
48d7b13a
KZ
441 break;
442 case 'r':
7a4ea566 443 ctl->policy = SCHED_RR;
48d7b13a
KZ
444 break;
445 case 'v':
7a4ea566 446 ctl->verbose = 1;
48d7b13a 447 break;
1a7e6395
KZ
448 case 'T':
449 ctl->runtime = strtou64_or_err(optarg, _("invalid runtime argument"));
450 break;
451 case 'P':
452 ctl->period = strtou64_or_err(optarg, _("invalid period argument"));
453 break;
454 case 'D':
455 ctl->deadline = strtou64_or_err(optarg, _("invalid deadline argument"));
456 break;
48d7b13a 457 case 'V':
f6277500 458 printf(UTIL_LINUX_VERSION);
110d680a 459 return EXIT_SUCCESS;
48d7b13a 460 case 'h':
bd9d9f05 461 ret = EXIT_SUCCESS;
337b8ead 462 /* fallthrough */
48d7b13a 463 default:
bd9d9f05 464 show_usage(ret);
48d7b13a 465 }
48d7b13a
KZ
466 }
467
7a4ea566
KZ
468 if (((ctl->pid > -1) && argc - optind < 1) ||
469 ((ctl->pid == -1) && argc - optind < 2))
bd9d9f05 470 show_usage(EXIT_FAILURE);
48d7b13a 471
7a4ea566 472 if ((ctl->pid > -1) && (ctl->verbose || argc - optind == 1)) {
a30cf650 473 show_sched_info(ctl);
48d7b13a 474 if (argc - optind == 1)
bd9d9f05 475 return EXIT_SUCCESS;
48d7b13a
KZ
476 }
477
478 errno = 0;
7a4ea566 479 ctl->priority = strtos32_or_err(argv[optind], _("invalid priority argument"));
48d7b13a 480
4951f9b3 481#ifdef SCHED_RESET_ON_FORK
1a7e6395
KZ
482 if (ctl->reset_on_fork && ctl->policy != SCHED_FIFO && ctl->policy != SCHED_RR)
483 errx(EXIT_FAILURE, _("--reset-on-fork option is supported for "
484 "SCHED_FIFO and SCHED_RR policies only"));
485#endif
486#ifdef SCHED_DEADLINE
487 if ((ctl->runtime || ctl->deadline || ctl->period) && ctl->policy != SCHED_DEADLINE)
488 errx(EXIT_FAILURE, _("--sched-{runtime,deadline,period} options "
489 "are supported for SCHED_DEADLINE only"));
490 if (ctl->policy == SCHED_DEADLINE) {
491 /* The basic rule is runtime <= deadline <= period, so we can
492 * make deadline and runtime optional on command line. Note we
493 * don't check any values or set any defaults, it's kernel
494 * responsibility.
495 */
496 if (ctl->deadline == 0)
497 ctl->deadline = ctl->period;
498 if (ctl->runtime == 0)
499 ctl->runtime = ctl->deadline;
500 }
501#else
502 if (ctl->runtime || ctl->deadline || ctl->period)
503 errx(EXIT_FAILURE, _("SCHED_DEADLINE is unsupported"));
4951f9b3 504#endif
7a4ea566
KZ
505 if (ctl->pid == -1)
506 ctl->pid = 0;
2e31d1c3
SK
507 if (ctl->priority < sched_get_priority_min(ctl->policy) ||
508 sched_get_priority_max(ctl->policy) < ctl->priority)
509 errx(EXIT_FAILURE,
510 _("unsupported priority value for the policy: %d: see --max for valid range"),
511 ctl->priority);
4820a737 512 set_sched(ctl);
a30cf650 513
7a4ea566 514 if (ctl->verbose)
a30cf650 515 show_sched_info(ctl);
48d7b13a 516
7a4ea566 517 if (!ctl->pid) {
48d7b13a
KZ
518 argv += optind + 1;
519 execvp(argv[0], argv);
bd9d9f05 520 err(EXIT_FAILURE, _("failed to execute %s"), argv[0]);
48d7b13a
KZ
521 }
522
bd9d9f05 523 return EXIT_SUCCESS;
48d7b13a 524}