summaryrefslogtreecommitdiffhomepage
path: root/util-linux/chrt.c
blob: 4dd78dabfca41ccbb2976796e148dd35795dc597 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/* vi: set sw=4 ts=4: */
/*
 * chrt - manipulate real-time attributes of a process
 * Copyright (c) 2006-2007 Bernhard Reutner-Fischer
 *
 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
 */
//config:config CHRT
//config:	bool "chrt (4.7 kb)"
//config:	default y
//config:	help
//config:	Manipulate real-time attributes of a process.
//config:	This requires sched_{g,s}etparam support in your libc.

//applet:IF_CHRT(APPLET_NOEXEC(chrt, chrt, BB_DIR_USR_BIN, BB_SUID_DROP, chrt))

//kbuild:lib-$(CONFIG_CHRT) += chrt.o

//usage:#define chrt_trivial_usage
//usage:       "-m | -p [PRIO] PID | [-rfobi] PRIO PROG [ARGS]"
//usage:#define chrt_full_usage "\n\n"
//usage:       "Change scheduling priority and class for a process\n"
//usage:     "\n	-m	Show min/max priorities"
//usage:     "\n	-p	Operate on PID"
//usage:     "\n	-r	Set SCHED_RR class"
//usage:     "\n	-f	Set SCHED_FIFO class"
//usage:     "\n	-o	Set SCHED_OTHER class"
//usage:     "\n	-b	Set SCHED_BATCH class"
//usage:     "\n	-i	Set SCHED_IDLE class"
//usage:
//usage:#define chrt_example_usage
//usage:       "$ chrt -r 4 sleep 900; x=$!\n"
//usage:       "$ chrt -f -p 3 $x\n"
//usage:       "You need CAP_SYS_NICE privileges to set scheduling attributes of a process"

#include <sched.h>
#include "libbb.h"
#ifndef SCHED_IDLE
# define SCHED_IDLE 5
#endif

static const char *policy_name(int pol)
{
	if (pol > 6)
		return utoa(pol);
	return nth_string(
		"OTHER"   "\0" /* 0:SCHED_OTHER */
		"FIFO"    "\0" /* 1:SCHED_FIFO */
		"RR"      "\0" /* 2:SCHED_RR */
		"BATCH"   "\0" /* 3:SCHED_BATCH */
		"ISO"     "\0" /* 4:SCHED_ISO */
		"IDLE"    "\0" /* 5:SCHED_IDLE */
		"DEADLINE",    /* 6:SCHED_DEADLINE */
		pol
	);
}

static void show_min_max(int pol)
{
	const char *fmt = "SCHED_%s min/max priority\t: %u/%u\n";
	int max, min;

	max = sched_get_priority_max(pol);
	min = sched_get_priority_min(pol);
	if ((max|min) < 0)
		fmt = "SCHED_%s not supported\n";
	printf(fmt, policy_name(pol), min, max);
}

#define OPT_m (1<<0)
#define OPT_p (1<<1)
#define OPT_r (1<<2)
#define OPT_f (1<<3)
#define OPT_o (1<<4)
#define OPT_b (1<<5)
#define OPT_i (1<<6)

int chrt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int chrt_main(int argc UNUSED_PARAM, char **argv)
{
	pid_t pid = 0;
	unsigned opt;
	struct sched_param sp;
	char *pid_str;
	char *priority = priority; /* for compiler */
	const char *current_new;
	int policy = SCHED_RR;

	opt = getopt32(argv, "^"
			"+" "mprfobi"
			"\0"
			/* only one policy accepted: */
			"r--fobi:f--robi:o--rfbi:b--rfoi:i--rfob"
	);
	if (opt & OPT_m) { /* print min/max and exit */
		show_min_max(SCHED_OTHER);
		show_min_max(SCHED_FIFO);
		show_min_max(SCHED_RR);
		show_min_max(SCHED_BATCH);
		show_min_max(SCHED_IDLE);
		fflush_stdout_and_exit(EXIT_SUCCESS);
	}
	//if (opt & OPT_r)
	//	policy = SCHED_RR; - default, already set
	if (opt & OPT_f)
		policy = SCHED_FIFO;
	if (opt & OPT_o)
		policy = SCHED_OTHER;
	if (opt & OPT_b)
		policy = SCHED_BATCH;
	if (opt & OPT_i)
		policy = SCHED_IDLE;

	argv += optind;
	if (!argv[0])
		bb_show_usage();
	if (opt & OPT_p) {
		pid_str = *argv++;
		if (*argv) { /* "-p PRIO PID [...]" */
			priority = pid_str;
			pid_str = *argv;
		}
		/* else "-p PID", and *argv == NULL */
		pid = xatoul_range(pid_str, 1, ((unsigned)(pid_t)ULONG_MAX) >> 1);
	} else {
		priority = *argv++;
		if (!*argv)
			bb_show_usage();
	}

	current_new = "current\0new";
	if (opt & OPT_p) {
		int pol;
 print_rt_info:
		pol = sched_getscheduler(pid);
		if (pol < 0)
			bb_perror_msg_and_die("can't %cet pid %u's policy", 'g', (int)pid);
#ifdef SCHED_RESET_ON_FORK
		/* "Since Linux 2.6.32, the SCHED_RESET_ON_FORK flag
		 * can be ORed in policy when calling sched_setscheduler().
		 * As a result of including this flag, children created by
		 * fork(2) do not inherit privileged scheduling policies"
		 *
		 * This bit is also returned by sched_getscheduler()!
		 * (TODO: do we want to show it?)
		 */
		pol &= ~SCHED_RESET_ON_FORK;
#endif
		printf("pid %u's %s scheduling policy: SCHED_%s\n",
			pid, current_new, policy_name(pol)
		);
		if (sched_getparam(pid, &sp))
			bb_perror_msg_and_die("can't get pid %u's attributes", (int)pid);
		printf("pid %u's %s scheduling priority: %d\n",
			(int)pid, current_new, sp.sched_priority
		);
		if (!*argv) {
			/* Either it was just "-p PID",
			 * or it was "-p PRIO PID" and we came here
			 * for the second time (see goto below) */
			return EXIT_SUCCESS;
		}
		*argv = NULL;
		current_new += 8;
	}

	sp.sched_priority = xstrtou_range(priority, 0,
		sched_get_priority_min(policy), sched_get_priority_max(policy)
	);

	if (sched_setscheduler(pid, policy, &sp) < 0)
		bb_perror_msg_and_die("can't %cet pid %u's policy", 's', (int)pid);

	if (!argv[0]) /* "-p PRIO PID [...]" */
		goto print_rt_info;

	BB_EXECVP_or_die(argv);
}