aboutsummaryrefslogtreecommitdiff
path: root/util-linux/taskset.c
diff options
context:
space:
mode:
Diffstat (limited to 'util-linux/taskset.c')
-rw-r--r--util-linux/taskset.c140
1 files changed, 129 insertions, 11 deletions
diff --git a/util-linux/taskset.c b/util-linux/taskset.c
index ed8878ad4..b542f8c83 100644
--- a/util-linux/taskset.c
+++ b/util-linux/taskset.c
@@ -20,6 +20,14 @@
20//config: Needed for machines with more than 32-64 CPUs: 20//config: Needed for machines with more than 32-64 CPUs:
21//config: affinity parameter 0xHHHHHHHHHHHHHHHHHHHH can be arbitrarily long 21//config: affinity parameter 0xHHHHHHHHHHHHHHHHHHHH can be arbitrarily long
22//config: in this case. Otherwise, it is limited to sizeof(long). 22//config: in this case. Otherwise, it is limited to sizeof(long).
23//config:
24//config:config FEATURE_TASKSET_CPULIST
25//config: bool "CPU list support (-c option)"
26//config: default y
27//config: depends on FEATURE_TASKSET_FANCY
28//config: help
29//config: Add support for taking/printing affinity as CPU list when '-c'
30//config: option is used. For example, it prints '0-3,7' instead of mask '8f'.
23 31
24//applet:IF_TASKSET(APPLET_NOEXEC(taskset, taskset, BB_DIR_USR_BIN, BB_SUID_DROP, taskset)) 32//applet:IF_TASKSET(APPLET_NOEXEC(taskset, taskset, BB_DIR_USR_BIN, BB_SUID_DROP, taskset))
25 33
@@ -108,26 +116,120 @@ static unsigned long *get_aff(int pid, unsigned *sz)
108 return mask; 116 return mask;
109} 117}
110 118
119#if ENABLE_FEATURE_TASKSET_CPULIST
120/*
121 * Parse the CPU list and set the mask accordingly.
122 *
123 * The list element can be either a CPU index or a range of CPU indices.
124 * Example: "1,3,5-7". Stride can be specified: "0-7:2" is "0,2,4,6".
125 * Note: leading and trailing whitespace is not allowed.
126 * util-linux 2.31 allows leading and sometimes trailing whitespace:
127 * ok: taskset -c ' 1, 2'
128 * ok: taskset -c ' 1 , 2'
129 * ok: taskset -c ' 1-7: 2 ,8'
130 * not ok: taskset -c ' 1 '
131 * not ok: taskset -c ' 1-7: 2 '
132 */
133static void parse_cpulist(ul *mask, unsigned max, char *s)
134{
135 char *aff = s;
136 for (;;) {
137 unsigned bit, end;
138 unsigned stride = 1;
139
140 bit = end = bb_strtou(s, &s, 10);
141 if (*s == '-') {
142 s++;
143 end = bb_strtou(s, &s, 10);
144 if (*s == ':') {
145 s++;
146 stride = bb_strtou(s, &s, 10);
147 }
148 }
149 if ((*s != ',' && *s != '\0')
150 || bit > end
151 || end == UINT_MAX /* bb_strtou returns this on malformed / ERANGE numbers */
152 || (stride - 1) > (UINT_MAX / 4)
153 /* disallow 0, malformed input, and too large stride prone to overflows */
154 ) {
155 bb_error_msg_and_die("bad affinity '%s'", aff);
156 }
157 while (bit <= end && bit < max) {
158 mask[bit / BITS_UL] |= (1UL << (bit & MASK_UL));
159 bit += stride;
160 }
161 if (*s == '\0')
162 break;
163 s++;
164 }
165}
166static void print_cpulist(const ul *mask, unsigned mask_size_in_bytes)
167{
168 const ul *mask_end;
169 const char *delim;
170 unsigned pos;
171 ul bit;
172
173 mask_end = mask + mask_size_in_bytes / sizeof(mask[0]);
174 delim = "";
175 pos = 0;
176 bit = 1;
177 for (;;) {
178 if (*mask & bit) {
179 unsigned onebit = pos + 1;
180 printf("%s%u", delim, pos);
181 do {
182 pos++;
183 bit <<= 1;
184 if (bit == 0) {
185 mask++;
186 if (mask >= mask_end)
187 break;
188 bit = 1;
189 }
190 } while (*mask & bit);
191 if (onebit != pos)
192 printf("-%u", pos - 1);
193 delim = ",";
194 }
195 pos++;
196 bit <<= 1;
197 if (bit == 0) {
198 mask++;
199 if (mask >= mask_end)
200 break;
201 bit = 1;
202 }
203 }
204 bb_putchar('\n');
205}
206#endif
207
111int taskset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 208int taskset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
112int taskset_main(int argc UNUSED_PARAM, char **argv) 209int taskset_main(int argc UNUSED_PARAM, char **argv)
113{ 210{
114 ul *mask; 211 ul *mask;
115 unsigned mask_size_in_bytes; 212 unsigned mask_size_in_bytes;
116 pid_t pid = 0; 213 pid_t pid = 0;
117 unsigned opt_p;
118 const char *current_new; 214 const char *current_new;
119 char *aff; 215 char *aff;
216 unsigned opts;
217 enum {
218 OPT_p = 1 << 0,
219 OPT_c = (1 << 1) * ENABLE_FEATURE_TASKSET_CPULIST,
220 };
120 221
121 /* NB: we mimic util-linux's taskset: -p does not take 222 /* NB: we mimic util-linux's taskset: -p does not take
122 * an argument, i.e., "-pN" is NOT valid, only "-p N"! 223 * an argument, i.e., "-pN" is NOT valid, only "-p N"!
123 * Indeed, util-linux-2.13-pre7 uses: 224 * Indeed, util-linux-2.13-pre7 uses:
124 * getopt_long(argc, argv, "+pchV", ...), not "...p:..." */ 225 * getopt_long(argc, argv, "+pchV", ...), not "...p:..." */
125 226
126 opt_p = getopt32(argv, "^+" "p" "\0" "-1" /* at least 1 arg */); 227 opts = getopt32(argv, "^+" "p"IF_FEATURE_TASKSET_CPULIST("c")
228 "\0" "-1" /* at least 1 arg */);
127 argv += optind; 229 argv += optind;
128 230
129 aff = *argv++; 231 aff = *argv++;
130 if (opt_p) { 232 if (opts & OPT_p) {
131 char *pid_str = aff; 233 char *pid_str = aff;
132 if (*argv) { /* "-p <aff> <pid> ...rest.is.ignored..." */ 234 if (*argv) { /* "-p <aff> <pid> ...rest.is.ignored..." */
133 pid_str = *argv; /* NB: *argv != NULL in this case */ 235 pid_str = *argv; /* NB: *argv != NULL in this case */
@@ -144,8 +246,14 @@ int taskset_main(int argc UNUSED_PARAM, char **argv)
144 current_new = "current"; 246 current_new = "current";
145 print_aff: 247 print_aff:
146 mask = get_aff(pid, &mask_size_in_bytes); 248 mask = get_aff(pid, &mask_size_in_bytes);
147 if (opt_p) { 249 if (opts & OPT_p) {
148 printf("pid %d's %s affinity mask: "TASKSET_PRINTF_MASK"\n", 250#if ENABLE_FEATURE_TASKSET_CPULIST
251 if (opts & OPT_c) {
252 printf("pid %d's %s affinity list: ", pid, current_new);
253 print_cpulist(mask, mask_size_in_bytes);
254 } else
255#endif
256 printf("pid %d's %s affinity mask: "TASKSET_PRINTF_MASK"\n",
149 pid, current_new, from_mask(mask, mask_size_in_bytes)); 257 pid, current_new, from_mask(mask, mask_size_in_bytes));
150 if (*argv == NULL) { 258 if (*argv == NULL) {
151 /* Either it was just "-p <pid>", 259 /* Either it was just "-p <pid>",
@@ -158,17 +266,27 @@ int taskset_main(int argc UNUSED_PARAM, char **argv)
158 } 266 }
159 memset(mask, 0, mask_size_in_bytes); 267 memset(mask, 0, mask_size_in_bytes);
160 268
161 /* Affinity was specified, translate it into mask */
162 /* it is always in hex, skip "0x" if it exists */
163 if (aff[0] == '0' && (aff[1]|0x20) == 'x')
164 aff += 2;
165
166 if (!ENABLE_FEATURE_TASKSET_FANCY) { 269 if (!ENABLE_FEATURE_TASKSET_FANCY) {
270 /* Affinity was specified, translate it into mask */
271 /* it is always in hex, skip "0x" if it exists */
272 if (aff[0] == '0' && (aff[1]|0x20) == 'x')
273 aff += 2;
167 mask[0] = xstrtoul(aff, 16); 274 mask[0] = xstrtoul(aff, 16);
168 } else { 275 }
276#if ENABLE_FEATURE_TASKSET_CPULIST
277 else if (opts & OPT_c) {
278 parse_cpulist(mask, mask_size_in_bytes * 8, aff);
279 }
280#endif
281 else {
169 unsigned i; 282 unsigned i;
170 char *last_char; 283 char *last_char;
171 284
285 /* Affinity was specified, translate it into mask */
286 /* it is always in hex, skip "0x" if it exists */
287 if (aff[0] == '0' && (aff[1]|0x20) == 'x')
288 aff += 2;
289
172 i = 0; /* bit pos in mask[] */ 290 i = 0; /* bit pos in mask[] */
173 291
174 /* aff is ASCII hex string, accept very long masks in this form. 292 /* aff is ASCII hex string, accept very long masks in this form.