//config: Needed for machines with more than 32-64 CPUs:
//config: affinity parameter 0xHHHHHHHHHHHHHHHHHHHH can be arbitrarily long
//config: in this case. Otherwise, it is limited to sizeof(long).
+//config:
+//config:config FEATURE_TASKSET_CPULIST
+//config: bool "CPU list support (-c option)"
+//config: default y
+//config: depends on FEATURE_TASKSET_FANCY
+//config: help
+//config: Add support for taking/printing affinity as CPU list when '-c'
+//config: option is used. For example, it prints '0-3,7' instead of mask '8f'.
//applet:IF_TASKSET(APPLET_NOEXEC(taskset, taskset, BB_DIR_USR_BIN, BB_SUID_DROP, taskset))
return mask;
}
+#if ENABLE_FEATURE_TASKSET_CPULIST
+/*
+ * Parse the CPU list and set the mask accordingly.
+ *
+ * The list element can be either a CPU index or a range of CPU indices.
+ * Example: "1,3,5-7".
+ *
+ * note1: pattern specifiers after a range (e.g. 0-255:2/64) are not supported
+ * note2: leading/trailing white-spaces are not allowed
+ */
+static void parse_cpulist(ul *mask, unsigned max, char *s)
+{
+ char *aff = s;
+ for (;;) {
+ unsigned bit, end;
+
+ bit = end = bb_strtou(s, &s, 10);
+ if (*s == '-') {
+ s++;
+ end = bb_strtou(s, &s, 10);
+ }
+ if ((*s != ',' && *s != '\0')
+ || bit > end
+ || end == UINT_MAX /* bb_strtou returns this on malformed / ERANGE numbers */
+ ) {
+ bb_error_msg_and_die("bad affinity '%s'", aff);
+ }
+ while (bit <= end && bit < max) {
+ mask[bit / BITS_UL] |= (1UL << (bit & MASK_UL));
+ bit++;
+ }
+ if (*s == '\0')
+ break;
+ s++;
+ }
+}
+static void print_cpulist(const ul *mask, unsigned mask_size_in_bytes)
+{
+ const ul *mask_end;
+ const char *delim;
+ unsigned pos;
+ ul bit;
+
+ mask_end = mask + mask_size_in_bytes / sizeof(mask[0]);
+ delim = "";
+ pos = 0;
+ bit = 1;
+ for (;;) {
+ if (*mask & bit) {
+ unsigned onebit = pos + 1;
+ printf("%s%u", delim, pos);
+ do {
+ pos++;
+ bit <<= 1;
+ if (bit == 0) {
+ mask++;
+ if (mask >= mask_end)
+ break;
+ bit = 1;
+ }
+ } while (*mask & bit);
+ if (onebit != pos)
+ printf("-%u", pos - 1);
+ delim = ",";
+ }
+ pos++;
+ bit <<= 1;
+ if (bit == 0) {
+ mask++;
+ if (mask >= mask_end)
+ break;
+ bit = 1;
+ }
+ }
+ bb_putchar('\n');
+}
+#endif
+
int taskset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int taskset_main(int argc UNUSED_PARAM, char **argv)
{
ul *mask;
unsigned mask_size_in_bytes;
pid_t pid = 0;
- unsigned opt_p;
const char *current_new;
char *aff;
+ unsigned opts;
+ enum {
+ OPT_p = 1 << 0,
+ OPT_c = (1 << 1) * ENABLE_FEATURE_TASKSET_CPULIST,
+ };
/* NB: we mimic util-linux's taskset: -p does not take
* an argument, i.e., "-pN" is NOT valid, only "-p N"!
* Indeed, util-linux-2.13-pre7 uses:
* getopt_long(argc, argv, "+pchV", ...), not "...p:..." */
- opt_p = getopt32(argv, "^+" "p" "\0" "-1" /* at least 1 arg */);
+ opts = getopt32(argv, "^+" "p"IF_FEATURE_TASKSET_CPULIST("c")
+ "\0" "-1" /* at least 1 arg */);
argv += optind;
aff = *argv++;
- if (opt_p) {
+ if (opts & OPT_p) {
char *pid_str = aff;
if (*argv) { /* "-p <aff> <pid> ...rest.is.ignored..." */
pid_str = *argv; /* NB: *argv != NULL in this case */
current_new = "current";
print_aff:
mask = get_aff(pid, &mask_size_in_bytes);
- if (opt_p) {
- printf("pid %d's %s affinity mask: "TASKSET_PRINTF_MASK"\n",
+ if (opts & OPT_p) {
+#if ENABLE_FEATURE_TASKSET_CPULIST
+ if (opts & OPT_c) {
+ printf("pid %d's %s affinity list: ", pid, current_new);
+ print_cpulist(mask, mask_size_in_bytes);
+ } else
+#endif
+ printf("pid %d's %s affinity mask: "TASKSET_PRINTF_MASK"\n",
pid, current_new, from_mask(mask, mask_size_in_bytes));
if (*argv == NULL) {
/* Either it was just "-p <pid>",
}
memset(mask, 0, mask_size_in_bytes);
- /* Affinity was specified, translate it into mask */
- /* it is always in hex, skip "0x" if it exists */
- if (aff[0] == '0' && (aff[1]|0x20) == 'x')
- aff += 2;
-
if (!ENABLE_FEATURE_TASKSET_FANCY) {
+ /* Affinity was specified, translate it into mask */
+ /* it is always in hex, skip "0x" if it exists */
+ if (aff[0] == '0' && (aff[1]|0x20) == 'x')
+ aff += 2;
mask[0] = xstrtoul(aff, 16);
- } else {
+ }
+#if ENABLE_FEATURE_TASKSET_CPULIST
+ else if (opts & OPT_c) {
+ parse_cpulist(mask, mask_size_in_bytes * 8, aff);
+ }
+#endif
+ else {
unsigned i;
char *last_char;
+ /* Affinity was specified, translate it into mask */
+ /* it is always in hex, skip "0x" if it exists */
+ if (aff[0] == '0' && (aff[1]|0x20) == 'x')
+ aff += 2;
+
i = 0; /* bit pos in mask[] */
/* aff is ASCII hex string, accept very long masks in this form.