]> git.ipfire.org Git - thirdparty/util-linux.git/blob - schedutils/chrt.c
chrt: make the usage synopsis clearer
[thirdparty/util-linux.git] / schedutils / chrt.c
1 /*
2 * chrt.c - manipulate a task's real-time attributes
3 *
4 * 27-Apr-2002: initial version - Robert Love <rml@tech9.net>
5 * 04-May-2011: make it thread-aware - Davidlohr Bueso <dave@gnu.org>
6 *
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
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 *
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.
19 *
20 * Copyright (C) 2004 Robert Love
21 */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <sched.h>
26 #include <unistd.h>
27 #include <getopt.h>
28 #include <errno.h>
29
30 #include "c.h"
31 #include "nls.h"
32 #include "closestream.h"
33 #include "strutils.h"
34 #include "procutils.h"
35
36 /* the SCHED_BATCH is supported since Linux 2.6.16
37 * -- temporary workaround for people with old glibc headers
38 */
39 #if defined (__linux__) && !defined(SCHED_BATCH)
40 # define SCHED_BATCH 3
41 #endif
42
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 */
47 #if defined (__linux__) && !defined(SCHED_IDLE)
48 # define SCHED_IDLE 5
49 #endif
50
51 #if defined(__linux__) && !defined(SCHED_RESET_ON_FORK)
52 #define SCHED_RESET_ON_FORK 0x40000000
53 #endif
54
55
56 static void __attribute__((__noreturn__)) show_usage(int rc)
57 {
58 FILE *out = rc == EXIT_SUCCESS ? stdout : stderr;
59
60 fputs(_("Show or change the real-time scheduling attributes of a process.\n"), out);
61 fprintf(out, _(
62 "\nSet policy:\n"
63 " chrt [options] <priority> <command> [<arg>...]\n"
64 " chrt [options] -p <priority> <pid>\n"
65 "\nGet policy:\n"
66 " chrt [options] -p <pid>\n"));
67
68 fprintf(out, _(
69 "\nScheduling policies:\n"
70 " -b | --batch set policy to SCHED_BATCH\n"
71 " -f | --fifo set policy to SCHED_FIFO\n"
72 " -i | --idle set policy to SCHED_IDLE\n"
73 " -o | --other set policy to SCHED_OTHER\n"
74 " -r | --rr set policy to SCHED_RR (default)\n"));
75
76 #ifdef SCHED_RESET_ON_FORK
77 fprintf(out, _(
78 "\nScheduling flags:\n"
79 " -R | --reset-on-fork set SCHED_RESET_ON_FORK for FIFO or RR\n"));
80 #endif
81 fprintf(out, _(
82 "\nOptions:\n"
83 " -a | --all-tasks operate on all the tasks (threads) for a given pid\n"
84 " -h | --help display this help\n"
85 " -m | --max show min and max valid priorities\n"
86 " -p | --pid operate on existing given pid\n"
87 " -v | --verbose display status information\n"
88 " -V | --version output version information\n\n"));
89
90 fprintf(out, USAGE_MAN_TAIL("chrt(1)"));
91 exit(rc);
92 }
93
94 static void show_rt_info(pid_t pid, int isnew)
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);
104 if (policy == -1)
105 err(EXIT_FAILURE, _("failed to get pid %d's policy"), pid);
106
107 if (isnew)
108 printf(_("pid %d's new scheduling policy: "), pid);
109 else
110 printf(_("pid %d's current scheduling policy: "), pid);
111
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;
119 #ifdef SCHED_RESET_ON_FORK
120 case SCHED_FIFO | SCHED_RESET_ON_FORK:
121 printf("SCHED_FIFO|SCHED_RESET_ON_FORK\n");
122 break;
123 #endif
124 #ifdef SCHED_IDLE
125 case SCHED_IDLE:
126 printf("SCHED_IDLE\n");
127 break;
128 #endif
129 case SCHED_RR:
130 printf("SCHED_RR\n");
131 break;
132 #ifdef SCHED_RESET_ON_FORK
133 case SCHED_RR | SCHED_RESET_ON_FORK:
134 printf("SCHED_RR|SCHED_RESET_ON_FORK\n");
135 break;
136 #endif
137 #ifdef SCHED_BATCH
138 case SCHED_BATCH:
139 printf("SCHED_BATCH\n");
140 break;
141 #endif
142 default:
143 warnx(_("unknown scheduling policy"));
144 }
145
146 if (sched_getparam(pid, &sp))
147 err(EXIT_FAILURE, _("failed to get pid %d's attributes"), pid);
148
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);
155 }
156
157 static void show_min_max(void)
158 {
159 unsigned long i;
160 int policies[] = {
161 SCHED_OTHER,
162 SCHED_FIFO,
163 SCHED_RR,
164 #ifdef SCHED_BATCH
165 SCHED_BATCH,
166 #endif
167 #ifdef SCHED_IDLE
168 SCHED_IDLE,
169 #endif
170 };
171 const char *names[] = {
172 "OTHER",
173 "FIFO",
174 "RR",
175 #ifdef SCHED_BATCH
176 "BATCH",
177 #endif
178 #ifdef SCHED_IDLE
179 "IDLE",
180 #endif
181 };
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 }
193 }
194
195 int main(int argc, char **argv)
196 {
197 int i, policy = SCHED_RR, priority = 0, verbose = 0, policy_flag = 0,
198 all_tasks = 0;
199 struct sched_param sp;
200 pid_t pid = -1;
201
202 static const struct option longopts[] = {
203 { "all-tasks", 0, NULL, 'a' },
204 { "batch", 0, NULL, 'b' },
205 { "fifo", 0, NULL, 'f' },
206 { "idle", 0, NULL, 'i' },
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' },
212 { "reset-on-fork", 0, NULL, 'R' },
213 { "verbose", 0, NULL, 'v' },
214 { "version", 0, NULL, 'V' },
215 { NULL, 0, NULL, 0 }
216 };
217
218 setlocale(LC_ALL, "");
219 bindtextdomain(PACKAGE, LOCALEDIR);
220 textdomain(PACKAGE);
221 atexit(close_stdout);
222
223 while((i = getopt_long(argc, argv, "+abfiphmoRrvV", longopts, NULL)) != -1)
224 {
225 int ret = EXIT_FAILURE;
226
227 switch (i) {
228 case 'a':
229 all_tasks = 1;
230 break;
231 case 'b':
232 #ifdef SCHED_BATCH
233 policy = SCHED_BATCH;
234 #endif
235 break;
236 case 'f':
237 policy = SCHED_FIFO;
238 break;
239 case 'R':
240 #ifdef SCHED_RESET_ON_FORK
241 policy_flag |= SCHED_RESET_ON_FORK;
242 #endif
243 break;
244 case 'i':
245 #ifdef SCHED_IDLE
246 policy = SCHED_IDLE;
247 #endif
248 break;
249 case 'm':
250 show_min_max();
251 return EXIT_SUCCESS;
252 case 'o':
253 policy = SCHED_OTHER;
254 break;
255 case 'p':
256 errno = 0;
257 pid = strtos32_or_err(argv[argc - 1], _("invalid PID argument"));
258 break;
259 case 'r':
260 policy = SCHED_RR;
261 break;
262 case 'v':
263 verbose = 1;
264 break;
265 case 'V':
266 printf(UTIL_LINUX_VERSION);
267 return EXIT_SUCCESS;
268 case 'h':
269 ret = EXIT_SUCCESS;
270 /* fallthrough */
271 default:
272 show_usage(ret);
273 }
274 }
275
276 if (((pid > -1) && argc - optind < 1) ||
277 ((pid == -1) && argc - optind < 2))
278 show_usage(EXIT_FAILURE);
279
280 if ((pid > -1) && (verbose || argc - optind == 1)) {
281 if (all_tasks) {
282 pid_t tid;
283 struct proc_tasks *ts = proc_open_tasks(pid);
284
285 if (!ts)
286 err(EXIT_FAILURE, _("cannot obtain the list of tasks"));
287 while (!proc_next_tid(ts, &tid))
288 show_rt_info(tid, FALSE);
289 proc_close_tasks(ts);
290 } else
291 show_rt_info(pid, FALSE);
292
293 if (argc - optind == 1)
294 return EXIT_SUCCESS;
295 }
296
297 errno = 0;
298 priority = strtos32_or_err(argv[optind], _("invalid priority argument"));
299
300 #ifdef SCHED_RESET_ON_FORK
301 /* sanity check */
302 if ((policy_flag & SCHED_RESET_ON_FORK) &&
303 !(policy == SCHED_FIFO || policy == SCHED_RR))
304 errx(EXIT_FAILURE, _("SCHED_RESET_ON_FORK flag is supported for "
305 "SCHED_FIFO and SCHED_RR policies only"));
306 #endif
307
308 policy |= policy_flag;
309
310 if (pid == -1)
311 pid = 0;
312 sp.sched_priority = priority;
313
314 if (all_tasks) {
315 pid_t tid;
316 struct proc_tasks *ts = proc_open_tasks(pid);
317
318 if (!ts)
319 err(EXIT_FAILURE, _("cannot obtain the list of tasks"));
320 while (!proc_next_tid(ts, &tid))
321 if (sched_setscheduler(tid, policy, &sp) == -1)
322 err(EXIT_FAILURE, _("failed to set tid %d's policy"), tid);
323 proc_close_tasks(ts);
324 } else if (sched_setscheduler(pid, policy, &sp) == -1)
325 err(EXIT_FAILURE, _("failed to set pid %d's policy"), pid);
326
327 if (verbose)
328 show_rt_info(pid, TRUE);
329
330 if (!pid) {
331 argv += optind + 1;
332 execvp(argv[0], argv);
333 err(EXIT_FAILURE, _("failed to execute %s"), argv[0]);
334 }
335
336 return EXIT_SUCCESS;
337 }