]>
Commit | Line | Data |
---|---|---|
48d7b13a KZ |
1 | /* |
2 | * chrt.c - chrt | |
3 | * Command-line utility for manipulating a task's real-time attributes | |
4 | * | |
5 | * Robert Love <rml@tech9.net> | |
6 | * 27-Apr-2002: initial version | |
78904e76 | 7 | * 04-May-2011: make thread aware - Davidlohr Bueso <dave@gnu.org> |
48d7b13a KZ |
8 | * |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License, v2, as | |
11 | * published by the Free Software Foundation | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
7cebf0bb SK |
18 | * You should have received a copy of the GNU General Public License along |
19 | * with this program; if not, write to the Free Software Foundation, Inc., | |
20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
48d7b13a KZ |
21 | * |
22 | * Copyright (C) 2004 Robert Love | |
23 | */ | |
24 | ||
48d7b13a KZ |
25 | #include <stdio.h> |
26 | #include <stdlib.h> | |
27 | #include <sched.h> | |
28 | #include <unistd.h> | |
29 | #include <getopt.h> | |
30 | #include <errno.h> | |
bd9d9f05 | 31 | |
b6534e4f | 32 | #include "c.h" |
bd9d9f05 | 33 | #include "nls.h" |
ed8ec2a6 | 34 | #include "closestream.h" |
8abcf290 | 35 | #include "strutils.h" |
78904e76 | 36 | #include "procutils.h" |
24295096 | 37 | |
09dd84ca KZ |
38 | /* the SCHED_BATCH is supported since Linux 2.6.16 |
39 | * -- temporary workaround for people with old glibc headers | |
40 | */ | |
b64279da | 41 | #if defined (__linux__) && !defined(SCHED_BATCH) |
09dd84ca KZ |
42 | # define SCHED_BATCH 3 |
43 | #endif | |
44 | ||
c779d6e9 MS |
45 | /* the SCHED_IDLE is supported since Linux 2.6.23 |
46 | * commit id 0e6aca43e08a62a48d6770e9a159dbec167bf4c6 | |
47 | * -- temporary workaround for people with old glibc headers | |
48 | */ | |
b64279da | 49 | #if defined (__linux__) && !defined(SCHED_IDLE) |
c779d6e9 MS |
50 | # define SCHED_IDLE 5 |
51 | #endif | |
52 | ||
0fefbedc AK |
53 | #if defined(__linux__) && !defined(SCHED_RESET_ON_FORK) |
54 | #define SCHED_RESET_ON_FORK 0x40000000 | |
55 | #endif | |
56 | ||
57 | ||
98da1298 | 58 | static void __attribute__((__noreturn__)) show_usage(int rc) |
48d7b13a | 59 | { |
aaf6349f BS |
60 | FILE *out = rc == EXIT_SUCCESS ? stdout : stderr; |
61 | ||
62 | fprintf(out, _( | |
63 | "\nchrt - manipulate real-time attributes of a process\n" | |
bd9d9f05 KZ |
64 | "\nSet policy:\n" |
65 | " chrt [options] <policy> <priority> {<pid> | <command> [<arg> ...]}\n" | |
66 | "\nGet policy:\n" | |
aaf6349f BS |
67 | " chrt [options] {<pid> | <command> [<arg> ...]}\n")); |
68 | ||
69 | fprintf(out, _( | |
bd9d9f05 KZ |
70 | "\nScheduling policies:\n" |
71 | " -b | --batch set policy to SCHED_BATCH\n" | |
72 | " -f | --fifo set policy to SCHED_FIFO\n" | |
73 | " -i | --idle set policy to SCHED_IDLE\n" | |
74 | " -o | --other set policy to SCHED_OTHER\n" | |
aaf6349f BS |
75 | " -r | --rr set policy to SCHED_RR (default)\n")); |
76 | ||
4951f9b3 | 77 | #ifdef SCHED_RESET_ON_FORK |
aaf6349f | 78 | fprintf(out, _( |
cdfb1e88 | 79 | "\nScheduling flags:\n" |
aaf6349f | 80 | " -R | --reset-on-fork set SCHED_RESET_ON_FORK for FIFO or RR\n")); |
4951f9b3 | 81 | #endif |
aaf6349f | 82 | fprintf(out, _( |
bd9d9f05 | 83 | "\nOptions:\n" |
1b9b57ac | 84 | " -a | --all-tasks operate on all the tasks (threads) for a given pid\n" |
bd9d9f05 | 85 | " -h | --help display this help\n" |
bd9d9f05 | 86 | " -m | --max show min and max valid priorities\n" |
aaf6349f | 87 | " -p | --pid operate on existing given pid\n" |
bd9d9f05 KZ |
88 | " -v | --verbose display status information\n" |
89 | " -V | --version output version information\n\n")); | |
90 | ||
91 | exit(rc); | |
48d7b13a KZ |
92 | } |
93 | ||
a9a3e5f2 | 94 | static void show_rt_info(pid_t pid, int isnew) |
48d7b13a KZ |
95 | { |
96 | struct sched_param sp; | |
97 | int policy; | |
98 | ||
99 | /* don't display "pid 0" as that is confusing */ | |
100 | if (!pid) | |
101 | pid = getpid(); | |
102 | ||
103 | policy = sched_getscheduler(pid); | |
bd9d9f05 KZ |
104 | if (policy == -1) |
105 | err(EXIT_FAILURE, _("failed to get pid %d's policy"), pid); | |
48d7b13a | 106 | |
a9a3e5f2 BS |
107 | if (isnew) |
108 | printf(_("pid %d's new scheduling policy: "), pid); | |
109 | else | |
110 | printf(_("pid %d's current scheduling policy: "), pid); | |
111 | ||
48d7b13a KZ |
112 | switch (policy) { |
113 | case SCHED_OTHER: | |
114 | printf("SCHED_OTHER\n"); | |
115 | break; | |
116 | case SCHED_FIFO: | |
117 | printf("SCHED_FIFO\n"); | |
118 | break; | |
4951f9b3 | 119 | #ifdef SCHED_RESET_ON_FORK |
110d680a | 120 | case SCHED_FIFO | SCHED_RESET_ON_FORK: |
0fefbedc AK |
121 | printf("SCHED_FIFO|SCHED_RESET_ON_FORK\n"); |
122 | break; | |
4951f9b3 | 123 | #endif |
b64279da | 124 | #ifdef SCHED_IDLE |
c779d6e9 MS |
125 | case SCHED_IDLE: |
126 | printf("SCHED_IDLE\n"); | |
6c00cbbe | 127 | break; |
b64279da | 128 | #endif |
48d7b13a KZ |
129 | case SCHED_RR: |
130 | printf("SCHED_RR\n"); | |
131 | break; | |
4951f9b3 | 132 | #ifdef SCHED_RESET_ON_FORK |
110d680a | 133 | case SCHED_RR | SCHED_RESET_ON_FORK: |
0fefbedc AK |
134 | printf("SCHED_RR|SCHED_RESET_ON_FORK\n"); |
135 | break; | |
4951f9b3 | 136 | #endif |
b64279da | 137 | #ifdef SCHED_BATCH |
df3773fb KZ |
138 | case SCHED_BATCH: |
139 | printf("SCHED_BATCH\n"); | |
140 | break; | |
b64279da | 141 | #endif |
48d7b13a | 142 | default: |
8a44fb01 | 143 | warnx(_("unknown scheduling policy")); |
48d7b13a KZ |
144 | } |
145 | ||
bd9d9f05 KZ |
146 | if (sched_getparam(pid, &sp)) |
147 | err(EXIT_FAILURE, _("failed to get pid %d's attributes"), pid); | |
48d7b13a | 148 | |
a9a3e5f2 BS |
149 | if (isnew) |
150 | printf(_("pid %d's new scheduling priority: %d\n"), | |
151 | pid, sp.sched_priority); | |
152 | else | |
153 | printf(_("pid %d's current scheduling priority: %d\n"), | |
154 | pid, sp.sched_priority); | |
48d7b13a KZ |
155 | } |
156 | ||
157 | static void show_min_max(void) | |
158 | { | |
90b7d261 | 159 | unsigned long i; |
110d680a SK |
160 | int policies[] = { |
161 | SCHED_OTHER, | |
162 | SCHED_FIFO, | |
163 | SCHED_RR, | |
b64279da | 164 | #ifdef SCHED_BATCH |
110d680a | 165 | SCHED_BATCH, |
b64279da AJ |
166 | #endif |
167 | #ifdef SCHED_IDLE | |
110d680a | 168 | SCHED_IDLE, |
b64279da | 169 | #endif |
110d680a SK |
170 | }; |
171 | const char *names[] = { | |
172 | "OTHER", | |
173 | "FIFO", | |
174 | "RR", | |
b64279da | 175 | #ifdef SCHED_BATCH |
110d680a | 176 | "BATCH", |
b64279da AJ |
177 | #endif |
178 | #ifdef SCHED_IDLE | |
110d680a | 179 | "IDLE", |
b64279da | 180 | #endif |
110d680a | 181 | }; |
bd9d9f05 KZ |
182 | |
183 | for (i = 0; i < ARRAY_SIZE(policies); i++) { | |
184 | int max = sched_get_priority_max(policies[i]); | |
185 | int min = sched_get_priority_min(policies[i]); | |
186 | ||
187 | if (max >= 0 && min >= 0) | |
188 | printf(_("SCHED_%s min/max priority\t: %d/%d\n"), | |
189 | names[i], min, max); | |
190 | else | |
191 | printf(_("SCHED_%s not supported?\n"), names[i]); | |
192 | } | |
48d7b13a KZ |
193 | } |
194 | ||
110d680a | 195 | int main(int argc, char **argv) |
48d7b13a | 196 | { |
503cbbe1 KZ |
197 | int i, policy = SCHED_RR, priority = 0, verbose = 0, policy_flag = 0, |
198 | all_tasks = 0; | |
48d7b13a | 199 | struct sched_param sp; |
697d58e8 | 200 | pid_t pid = -1; |
48d7b13a | 201 | |
6c7d5ae9 | 202 | static const struct option longopts[] = { |
78904e76 | 203 | { "all-tasks", 0, NULL, 'a' }, |
df3773fb | 204 | { "batch", 0, NULL, 'b' }, |
48d7b13a | 205 | { "fifo", 0, NULL, 'f' }, |
c779d6e9 | 206 | { "idle", 0, NULL, 'i' }, |
48d7b13a KZ |
207 | { "pid", 0, NULL, 'p' }, |
208 | { "help", 0, NULL, 'h' }, | |
209 | { "max", 0, NULL, 'm' }, | |
210 | { "other", 0, NULL, 'o' }, | |
211 | { "rr", 0, NULL, 'r' }, | |
cdfb1e88 | 212 | { "reset-on-fork", 0, NULL, 'R' }, |
48d7b13a KZ |
213 | { "verbose", 0, NULL, 'v' }, |
214 | { "version", 0, NULL, 'V' }, | |
215 | { NULL, 0, NULL, 0 } | |
216 | }; | |
217 | ||
bd9d9f05 KZ |
218 | setlocale(LC_ALL, ""); |
219 | bindtextdomain(PACKAGE, LOCALEDIR); | |
220 | textdomain(PACKAGE); | |
ed8ec2a6 | 221 | atexit(close_stdout); |
bd9d9f05 | 222 | |
78904e76 | 223 | while((i = getopt_long(argc, argv, "+abfiphmoRrvV", longopts, NULL)) != -1) |
48d7b13a | 224 | { |
bd9d9f05 | 225 | int ret = EXIT_FAILURE; |
48d7b13a KZ |
226 | |
227 | switch (i) { | |
78904e76 DB |
228 | case 'a': |
229 | all_tasks = 1; | |
230 | break; | |
df3773fb | 231 | case 'b': |
b64279da | 232 | #ifdef SCHED_BATCH |
df3773fb | 233 | policy = SCHED_BATCH; |
b64279da | 234 | #endif |
df3773fb | 235 | break; |
48d7b13a KZ |
236 | case 'f': |
237 | policy = SCHED_FIFO; | |
238 | break; | |
cdfb1e88 | 239 | case 'R': |
c150589f | 240 | #ifdef SCHED_RESET_ON_FORK |
cdfb1e88 | 241 | policy_flag |= SCHED_RESET_ON_FORK; |
4951f9b3 | 242 | #endif |
c150589f | 243 | break; |
c779d6e9 | 244 | case 'i': |
b64279da | 245 | #ifdef SCHED_IDLE |
c779d6e9 | 246 | policy = SCHED_IDLE; |
b64279da | 247 | #endif |
c779d6e9 | 248 | break; |
48d7b13a KZ |
249 | case 'm': |
250 | show_min_max(); | |
110d680a | 251 | return EXIT_SUCCESS; |
48d7b13a KZ |
252 | case 'o': |
253 | policy = SCHED_OTHER; | |
254 | break; | |
255 | case 'p': | |
256 | errno = 0; | |
8abcf290 | 257 | pid = strtol_or_err(argv[argc - 1], _("failed to parse pid")); |
48d7b13a KZ |
258 | break; |
259 | case 'r': | |
260 | policy = SCHED_RR; | |
261 | break; | |
262 | case 'v': | |
263 | verbose = 1; | |
264 | break; | |
265 | case 'V': | |
110d680a SK |
266 | printf("%s from %s\n", program_invocation_short_name, |
267 | PACKAGE_STRING); | |
268 | return EXIT_SUCCESS; | |
48d7b13a | 269 | case 'h': |
bd9d9f05 | 270 | ret = EXIT_SUCCESS; |
337b8ead | 271 | /* fallthrough */ |
48d7b13a | 272 | default: |
bd9d9f05 | 273 | show_usage(ret); |
48d7b13a | 274 | } |
48d7b13a KZ |
275 | } |
276 | ||
110d680a SK |
277 | if (((pid > -1) && argc - optind < 1) || |
278 | ((pid == -1) && argc - optind < 2)) | |
bd9d9f05 | 279 | show_usage(EXIT_FAILURE); |
48d7b13a | 280 | |
697d58e8 | 281 | if ((pid > -1) && (verbose || argc - optind == 1)) { |
503cbbe1 KZ |
282 | if (all_tasks) { |
283 | pid_t tid; | |
284 | struct proc_tasks *ts = proc_open_tasks(pid); | |
285 | ||
286 | if (!ts) | |
8a44fb01 | 287 | err(EXIT_FAILURE, _("cannot obtain the list of tasks")); |
503cbbe1 KZ |
288 | while (!proc_next_tid(ts, &tid)) |
289 | show_rt_info(tid, FALSE); | |
290 | proc_close_tasks(ts); | |
291 | } else | |
292 | show_rt_info(pid, FALSE); | |
293 | ||
48d7b13a | 294 | if (argc - optind == 1) |
bd9d9f05 | 295 | return EXIT_SUCCESS; |
48d7b13a KZ |
296 | } |
297 | ||
298 | errno = 0; | |
8abcf290 | 299 | priority = strtol_or_err(argv[optind], _("failed to parse priority")); |
48d7b13a | 300 | |
4951f9b3 | 301 | #ifdef SCHED_RESET_ON_FORK |
cdfb1e88 KZ |
302 | /* sanity check */ |
303 | if ((policy_flag & SCHED_RESET_ON_FORK) && | |
304 | !(policy == SCHED_FIFO || policy == SCHED_RR)) | |
305 | errx(EXIT_FAILURE, _("SCHED_RESET_ON_FORK flag is suppoted for " | |
110d680a | 306 | "SCHED_FIFO and SCHED_RR policies only")); |
4951f9b3 | 307 | #endif |
cdfb1e88 KZ |
308 | |
309 | policy |= policy_flag; | |
310 | ||
697d58e8 MK |
311 | if (pid == -1) |
312 | pid = 0; | |
48d7b13a | 313 | sp.sched_priority = priority; |
78904e76 DB |
314 | |
315 | if (all_tasks) { | |
316 | pid_t tid; | |
317 | struct proc_tasks *ts = proc_open_tasks(pid); | |
318 | ||
319 | if (!ts) | |
8a44fb01 | 320 | err(EXIT_FAILURE, _("cannot obtain the list of tasks")); |
78904e76 DB |
321 | while (!proc_next_tid(ts, &tid)) |
322 | if (sched_setscheduler(tid, policy, &sp) == -1) | |
323 | err(EXIT_FAILURE, _("failed to set tid %d's policy"), tid); | |
78904e76 | 324 | proc_close_tasks(ts); |
110d680a SK |
325 | } else if (sched_setscheduler(pid, policy, &sp) == -1) |
326 | err(EXIT_FAILURE, _("failed to set pid %d's policy"), pid); | |
48d7b13a KZ |
327 | |
328 | if (verbose) | |
a9a3e5f2 | 329 | show_rt_info(pid, TRUE); |
48d7b13a KZ |
330 | |
331 | if (!pid) { | |
332 | argv += optind + 1; | |
333 | execvp(argv[0], argv); | |
334 | perror("execvp"); | |
bd9d9f05 | 335 | err(EXIT_FAILURE, _("failed to execute %s"), argv[0]); |
48d7b13a KZ |
336 | } |
337 | ||
bd9d9f05 | 338 | return EXIT_SUCCESS; |
48d7b13a | 339 | } |