]>
Commit | Line | Data |
---|---|---|
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 | ||
0fefbedc AK |
51 | #if defined(__linux__) && !defined(SCHED_RESET_ON_FORK) |
52 | #define SCHED_RESET_ON_FORK 0x40000000 | |
53 | #endif | |
54 | ||
7a4ea566 KZ |
55 | /* control struct */ |
56 | struct chrt_ctl { | |
57 | pid_t pid; | |
58 | int policy; /* SCHED_* */ | |
59 | int priority; | |
60 | ||
61 | unsigned int all_tasks : 1, /* all threads of the PID */ | |
62 | reset_on_fork : 1, /* SCHED_RESET_ON_FORK */ | |
a30cf650 | 63 | altered : 1, /* sched_set**() used */ |
7a4ea566 KZ |
64 | verbose : 1; /* verbose output */ |
65 | }; | |
0fefbedc | 66 | |
98da1298 | 67 | static void __attribute__((__noreturn__)) show_usage(int rc) |
48d7b13a | 68 | { |
aaf6349f BS |
69 | FILE *out = rc == EXIT_SUCCESS ? stdout : stderr; |
70 | ||
451dbcfa | 71 | fputs(_("Show or change the real-time scheduling attributes of a process.\n"), out); |
9acbe2aa BS |
72 | fputs(USAGE_SEPARATOR, out); |
73 | fputs(_("Set policy:\n" | |
74 | " chrt [options] <priority> <command> [<arg>...]\n" | |
a6fec537 | 75 | " chrt [options] --pid <priority> <pid>\n"), out); |
9acbe2aa BS |
76 | fputs(USAGE_SEPARATOR, out); |
77 | fputs(_("Get policy:\n" | |
78 | " chrt [options] -p <pid>\n"), out); | |
aaf6349f | 79 | |
9acbe2aa BS |
80 | fputs(USAGE_SEPARATOR, out); |
81 | fputs(_("Policy options:\n"), out); | |
82 | fputs(_(" -b, --batch set policy to SCHED_BATCH\n"), out); | |
83 | fputs(_(" -f, --fifo set policy to SCHED_FIFO\n"), out); | |
84 | fputs(_(" -i, --idle set policy to SCHED_IDLE\n"), out); | |
85 | fputs(_(" -o, --other set policy to SCHED_OTHER\n"), out); | |
86 | fputs(_(" -r, --rr set policy to SCHED_RR (default)\n"), out); | |
aaf6349f | 87 | |
4951f9b3 | 88 | #ifdef SCHED_RESET_ON_FORK |
9acbe2aa BS |
89 | fputs(USAGE_SEPARATOR, out); |
90 | fputs(_("Scheduling flag:\n"), out); | |
91 | fputs(_(" -R, --reset-on-fork set SCHED_RESET_ON_FORK for FIFO or RR\n"), out); | |
4951f9b3 | 92 | #endif |
9acbe2aa BS |
93 | fputs(USAGE_SEPARATOR, out); |
94 | fputs(_("Other options:\n"), out); | |
95 | fputs(_(" -a, --all-tasks operate on all the tasks (threads) for a given pid\n"), out); | |
96 | fputs(_(" -m, --max show min and max valid priorities\n"), out); | |
97 | fputs(_(" -p, --pid operate on existing given pid\n"), out); | |
98 | fputs(_(" -v, --verbose display status information\n"), out); | |
99 | ||
100 | fputs(USAGE_SEPARATOR, out); | |
101 | fputs(USAGE_HELP, out); | |
102 | fputs(USAGE_VERSION, out); | |
bd9d9f05 | 103 | |
a587cc55 | 104 | fprintf(out, USAGE_MAN_TAIL("chrt(1)")); |
bd9d9f05 | 105 | exit(rc); |
48d7b13a KZ |
106 | } |
107 | ||
a30cf650 | 108 | static void show_sched_pid_info(struct chrt_ctl *ctl, pid_t pid) |
48d7b13a KZ |
109 | { |
110 | struct sched_param sp; | |
111 | int policy; | |
112 | ||
113 | /* don't display "pid 0" as that is confusing */ | |
114 | if (!pid) | |
115 | pid = getpid(); | |
116 | ||
117 | policy = sched_getscheduler(pid); | |
bd9d9f05 KZ |
118 | if (policy == -1) |
119 | err(EXIT_FAILURE, _("failed to get pid %d's policy"), pid); | |
48d7b13a | 120 | |
a30cf650 | 121 | if (ctl->altered) |
a9a3e5f2 BS |
122 | printf(_("pid %d's new scheduling policy: "), pid); |
123 | else | |
124 | printf(_("pid %d's current scheduling policy: "), pid); | |
125 | ||
48d7b13a KZ |
126 | switch (policy) { |
127 | case SCHED_OTHER: | |
128 | printf("SCHED_OTHER\n"); | |
129 | break; | |
130 | case SCHED_FIFO: | |
131 | printf("SCHED_FIFO\n"); | |
132 | break; | |
4951f9b3 | 133 | #ifdef SCHED_RESET_ON_FORK |
110d680a | 134 | case SCHED_FIFO | SCHED_RESET_ON_FORK: |
0fefbedc AK |
135 | printf("SCHED_FIFO|SCHED_RESET_ON_FORK\n"); |
136 | break; | |
4951f9b3 | 137 | #endif |
b64279da | 138 | #ifdef SCHED_IDLE |
c779d6e9 MS |
139 | case SCHED_IDLE: |
140 | printf("SCHED_IDLE\n"); | |
6c00cbbe | 141 | break; |
b64279da | 142 | #endif |
48d7b13a KZ |
143 | case SCHED_RR: |
144 | printf("SCHED_RR\n"); | |
145 | break; | |
4951f9b3 | 146 | #ifdef SCHED_RESET_ON_FORK |
110d680a | 147 | case SCHED_RR | SCHED_RESET_ON_FORK: |
0fefbedc AK |
148 | printf("SCHED_RR|SCHED_RESET_ON_FORK\n"); |
149 | break; | |
4951f9b3 | 150 | #endif |
b64279da | 151 | #ifdef SCHED_BATCH |
df3773fb KZ |
152 | case SCHED_BATCH: |
153 | printf("SCHED_BATCH\n"); | |
154 | break; | |
b64279da | 155 | #endif |
48d7b13a | 156 | default: |
8a44fb01 | 157 | warnx(_("unknown scheduling policy")); |
48d7b13a KZ |
158 | } |
159 | ||
bd9d9f05 KZ |
160 | if (sched_getparam(pid, &sp)) |
161 | err(EXIT_FAILURE, _("failed to get pid %d's attributes"), pid); | |
48d7b13a | 162 | |
a30cf650 | 163 | if (ctl->altered) |
a9a3e5f2 BS |
164 | printf(_("pid %d's new scheduling priority: %d\n"), |
165 | pid, sp.sched_priority); | |
166 | else | |
167 | printf(_("pid %d's current scheduling priority: %d\n"), | |
168 | pid, sp.sched_priority); | |
48d7b13a KZ |
169 | } |
170 | ||
a30cf650 KZ |
171 | |
172 | static void show_sched_info(struct chrt_ctl *ctl) | |
173 | { | |
174 | if (ctl->all_tasks) { | |
175 | pid_t tid; | |
176 | struct proc_tasks *ts = proc_open_tasks(ctl->pid); | |
177 | ||
178 | if (!ts) | |
179 | err(EXIT_FAILURE, _("cannot obtain the list of tasks")); | |
180 | ||
181 | while (!proc_next_tid(ts, &tid)) | |
182 | show_sched_pid_info(ctl, tid); | |
183 | ||
184 | proc_close_tasks(ts); | |
185 | } else | |
186 | show_sched_pid_info(ctl, ctl->pid); | |
187 | } | |
188 | ||
48d7b13a KZ |
189 | static void show_min_max(void) |
190 | { | |
90b7d261 | 191 | unsigned long i; |
110d680a SK |
192 | int policies[] = { |
193 | SCHED_OTHER, | |
194 | SCHED_FIFO, | |
195 | SCHED_RR, | |
b64279da | 196 | #ifdef SCHED_BATCH |
110d680a | 197 | SCHED_BATCH, |
b64279da AJ |
198 | #endif |
199 | #ifdef SCHED_IDLE | |
110d680a | 200 | SCHED_IDLE, |
b64279da | 201 | #endif |
110d680a SK |
202 | }; |
203 | const char *names[] = { | |
204 | "OTHER", | |
205 | "FIFO", | |
206 | "RR", | |
b64279da | 207 | #ifdef SCHED_BATCH |
110d680a | 208 | "BATCH", |
b64279da AJ |
209 | #endif |
210 | #ifdef SCHED_IDLE | |
110d680a | 211 | "IDLE", |
b64279da | 212 | #endif |
110d680a | 213 | }; |
bd9d9f05 KZ |
214 | |
215 | for (i = 0; i < ARRAY_SIZE(policies); i++) { | |
216 | int max = sched_get_priority_max(policies[i]); | |
217 | int min = sched_get_priority_min(policies[i]); | |
218 | ||
219 | if (max >= 0 && min >= 0) | |
220 | printf(_("SCHED_%s min/max priority\t: %d/%d\n"), | |
221 | names[i], min, max); | |
222 | else | |
223 | printf(_("SCHED_%s not supported?\n"), names[i]); | |
224 | } | |
48d7b13a KZ |
225 | } |
226 | ||
4820a737 KZ |
227 | static void set_sched(struct chrt_ctl *ctl) |
228 | { | |
229 | struct sched_param sp = { .sched_priority = ctl->priority }; | |
230 | ||
231 | if (ctl->all_tasks) { | |
232 | pid_t tid; | |
233 | struct proc_tasks *ts = proc_open_tasks(ctl->pid); | |
234 | ||
235 | if (!ts) | |
236 | err(EXIT_FAILURE, _("cannot obtain the list of tasks")); | |
237 | ||
238 | while (!proc_next_tid(ts, &tid)) | |
239 | if (sched_setscheduler(tid, ctl->policy, &sp) == -1) | |
240 | err(EXIT_FAILURE, _("failed to set tid %d's policy"), tid); | |
241 | ||
242 | proc_close_tasks(ts); | |
243 | ||
244 | } else if (sched_setscheduler(ctl->pid, ctl->policy, &sp) == -1) | |
245 | err(EXIT_FAILURE, _("failed to set pid %d's policy"), ctl->pid); | |
246 | ||
247 | ctl->altered = 1; | |
248 | } | |
249 | ||
110d680a | 250 | int main(int argc, char **argv) |
48d7b13a | 251 | { |
7a4ea566 | 252 | struct chrt_ctl _ctl = { .pid = -1 }, *ctl = &_ctl; |
4820a737 | 253 | int c; |
48d7b13a | 254 | |
6c7d5ae9 | 255 | static const struct option longopts[] = { |
78904e76 | 256 | { "all-tasks", 0, NULL, 'a' }, |
df3773fb | 257 | { "batch", 0, NULL, 'b' }, |
48d7b13a | 258 | { "fifo", 0, NULL, 'f' }, |
c779d6e9 | 259 | { "idle", 0, NULL, 'i' }, |
48d7b13a KZ |
260 | { "pid", 0, NULL, 'p' }, |
261 | { "help", 0, NULL, 'h' }, | |
262 | { "max", 0, NULL, 'm' }, | |
263 | { "other", 0, NULL, 'o' }, | |
264 | { "rr", 0, NULL, 'r' }, | |
cdfb1e88 | 265 | { "reset-on-fork", 0, NULL, 'R' }, |
48d7b13a KZ |
266 | { "verbose", 0, NULL, 'v' }, |
267 | { "version", 0, NULL, 'V' }, | |
268 | { NULL, 0, NULL, 0 } | |
269 | }; | |
270 | ||
bd9d9f05 KZ |
271 | setlocale(LC_ALL, ""); |
272 | bindtextdomain(PACKAGE, LOCALEDIR); | |
273 | textdomain(PACKAGE); | |
ed8ec2a6 | 274 | atexit(close_stdout); |
bd9d9f05 | 275 | |
4820a737 | 276 | while((c = getopt_long(argc, argv, "+abfiphmoRrvV", longopts, NULL)) != -1) |
48d7b13a | 277 | { |
bd9d9f05 | 278 | int ret = EXIT_FAILURE; |
48d7b13a | 279 | |
4820a737 | 280 | switch (c) { |
78904e76 | 281 | case 'a': |
7a4ea566 | 282 | ctl->all_tasks = 1; |
78904e76 | 283 | break; |
df3773fb | 284 | case 'b': |
b64279da | 285 | #ifdef SCHED_BATCH |
7a4ea566 | 286 | ctl->policy = SCHED_BATCH; |
b64279da | 287 | #endif |
df3773fb | 288 | break; |
48d7b13a | 289 | case 'f': |
7a4ea566 | 290 | ctl->policy = SCHED_FIFO; |
48d7b13a | 291 | break; |
cdfb1e88 | 292 | case 'R': |
7a4ea566 | 293 | ctl->reset_on_fork = 1; |
c150589f | 294 | break; |
c779d6e9 | 295 | case 'i': |
b64279da | 296 | #ifdef SCHED_IDLE |
7a4ea566 | 297 | ctl->policy = SCHED_IDLE; |
b64279da | 298 | #endif |
c779d6e9 | 299 | break; |
48d7b13a KZ |
300 | case 'm': |
301 | show_min_max(); | |
110d680a | 302 | return EXIT_SUCCESS; |
48d7b13a | 303 | case 'o': |
7a4ea566 | 304 | ctl->policy = SCHED_OTHER; |
48d7b13a KZ |
305 | break; |
306 | case 'p': | |
307 | errno = 0; | |
7a4ea566 | 308 | ctl->pid = strtos32_or_err(argv[argc - 1], _("invalid PID argument")); |
48d7b13a KZ |
309 | break; |
310 | case 'r': | |
7a4ea566 | 311 | ctl->policy = SCHED_RR; |
48d7b13a KZ |
312 | break; |
313 | case 'v': | |
7a4ea566 | 314 | ctl->verbose = 1; |
48d7b13a KZ |
315 | break; |
316 | case 'V': | |
f6277500 | 317 | printf(UTIL_LINUX_VERSION); |
110d680a | 318 | return EXIT_SUCCESS; |
48d7b13a | 319 | case 'h': |
bd9d9f05 | 320 | ret = EXIT_SUCCESS; |
337b8ead | 321 | /* fallthrough */ |
48d7b13a | 322 | default: |
bd9d9f05 | 323 | show_usage(ret); |
48d7b13a | 324 | } |
48d7b13a KZ |
325 | } |
326 | ||
7a4ea566 KZ |
327 | if (((ctl->pid > -1) && argc - optind < 1) || |
328 | ((ctl->pid == -1) && argc - optind < 2)) | |
bd9d9f05 | 329 | show_usage(EXIT_FAILURE); |
48d7b13a | 330 | |
7a4ea566 | 331 | if ((ctl->pid > -1) && (ctl->verbose || argc - optind == 1)) { |
a30cf650 | 332 | show_sched_info(ctl); |
48d7b13a | 333 | if (argc - optind == 1) |
bd9d9f05 | 334 | return EXIT_SUCCESS; |
48d7b13a KZ |
335 | } |
336 | ||
337 | errno = 0; | |
7a4ea566 | 338 | ctl->priority = strtos32_or_err(argv[optind], _("invalid priority argument")); |
48d7b13a | 339 | |
4951f9b3 | 340 | #ifdef SCHED_RESET_ON_FORK |
7a4ea566 KZ |
341 | if (ctl->reset_on_fork) { |
342 | if (ctl->policy != SCHED_FIFO && ctl->policy != SCHED_RR) | |
343 | errx(EXIT_FAILURE, _("SCHED_RESET_ON_FORK flag is supported for " | |
344 | "SCHED_FIFO and SCHED_RR policies only")); | |
345 | ctl->policy |= SCHED_RESET_ON_FORK; | |
346 | } | |
4951f9b3 | 347 | #endif |
cdfb1e88 | 348 | |
7a4ea566 KZ |
349 | if (ctl->pid == -1) |
350 | ctl->pid = 0; | |
48d7b13a | 351 | |
4820a737 | 352 | set_sched(ctl); |
a30cf650 | 353 | |
7a4ea566 | 354 | if (ctl->verbose) |
a30cf650 | 355 | show_sched_info(ctl); |
48d7b13a | 356 | |
7a4ea566 | 357 | if (!ctl->pid) { |
48d7b13a KZ |
358 | argv += optind + 1; |
359 | execvp(argv[0], argv); | |
bd9d9f05 | 360 | err(EXIT_FAILURE, _("failed to execute %s"), argv[0]); |
48d7b13a KZ |
361 | } |
362 | ||
bd9d9f05 | 363 | return EXIT_SUCCESS; |
48d7b13a | 364 | } |