*
* Based on code from taskset.c and Linux kernel.
*
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
* Copyright (C) 2010 Karel Zak <kzak@redhat.com>
*/
#include <sys/syscall.h>
#include "cpuset.h"
+#include "c.h"
static inline int val_to_char(int v)
{
if (v >= 0 && v < 10)
return '0' + v;
- else if (v >= 10 && v < 16)
+ if (v >= 10 && v < 16)
return ('a' - 10) + v;
- else
- return -1;
+ return -1;
}
static inline int char_to_val(int c)
{
int cl;
- cl = tolower(c);
if (c >= '0' && c <= '9')
return c - '0';
- else if (cl >= 'a' && cl <= 'f')
+ cl = tolower(c);
+ if (cl >= 'a' && cl <= 'f')
return cl + (10 - 'a');
- else
- return -1;
+ return -1;
}
static const char *nexttoken(const char *q, int sep)
*/
int get_max_number_of_cpus(void)
{
+#ifdef SYS_sched_getaffinity
int n, cpus = 2048;
size_t setsize;
cpu_set_t *set = cpuset_alloc(cpus, &setsize, NULL);
cpuset_free(set);
return n * 8;
}
+#endif
return -1;
}
char *cpulist_create(char *str, size_t len,
cpu_set_t *set, size_t setsize)
{
- int i;
+ size_t i;
char *ptr = str;
int entry_made = 0;
size_t max = cpuset_nbits(setsize);
for (i = 0; i < max; i++) {
if (CPU_ISSET_S(i, setsize, set)) {
- int j, rlen;
- int run = 0;
+ int rlen;
+ size_t j, run = 0;
entry_made = 1;
for (j = i + 1; j < max; j++) {
if (CPU_ISSET_S(j, setsize, set))
break;
}
if (!run)
- rlen = snprintf(ptr, len, "%d,", i);
+ rlen = snprintf(ptr, len, "%zu,", i);
else if (run == 1) {
- rlen = snprintf(ptr, len, "%d,%d,", i, i + 1);
+ rlen = snprintf(ptr, len, "%zu,%zu,", i, i + 1);
i++;
} else {
- rlen = snprintf(ptr, len, "%d-%d,", i, i + run);
+ rlen = snprintf(ptr, len, "%zu-%zu,", i, i + run);
i += run;
}
- if (rlen < 0 || rlen + 1 > len)
+ if (rlen < 0 || (size_t) rlen >= len)
return NULL;
ptr += rlen;
len -= rlen;
for (cpu = cpuset_nbits(setsize) - 4; cpu >= 0; cpu -= 4) {
char val = 0;
- if (len == (ptr - str))
+ if (len == (size_t) (ptr - str))
break;
if (CPU_ISSET_S(cpu, setsize, set))
}
/*
- * Parses string with list of CPU ranges.
+ * Parses string with CPUs mask.
*/
int cpumask_parse(const char *str, cpu_set_t *set, size_t setsize)
{
CPU_SET_S(cpu + 2, setsize, set);
if (val & 8)
CPU_SET_S(cpu + 3, setsize, set);
- len--;
ptr--;
cpu += 4;
}
return 0;
}
+static int nextnumber(const char *str, char **end, unsigned int *result)
+{
+ errno = 0;
+ if (str == NULL || *str == '\0' || !isdigit(*str))
+ return -EINVAL;
+ *result = (unsigned int) strtoul(str, end, 10);
+ if (errno)
+ return -errno;
+ if (str == *end)
+ return -EINVAL;
+ return 0;
+}
+
/*
- * Parses string with CPUs mask.
+ * Parses string with list of CPU ranges.
+ * Returns 0 on success.
+ * Returns 1 on error.
+ * Returns 2 if fail is set and a cpu number passed in the list doesn't fit
+ * into the cpu_set. If fail is not set cpu numbers that do not fit are
+ * ignored and 0 is returned instead.
*/
-int cpulist_parse(const char *str, cpu_set_t *set, size_t setsize)
+int cpulist_parse(const char *str, cpu_set_t *set, size_t setsize, int fail)
{
+ size_t max = cpuset_nbits(setsize);
const char *p, *q;
- q = str;
+ char *end = NULL;
+ q = str;
CPU_ZERO_S(setsize, set);
while (p = q, q = nexttoken(q, ','), p) {
unsigned int s; /* stride */
const char *c1, *c2;
- if (sscanf(p, "%u", &a) < 1)
+ if (nextnumber(p, &end, &a) != 0)
return 1;
b = a;
s = 1;
+ p = end;
c1 = nexttoken(p, '-');
c2 = nexttoken(p, ',');
+
if (c1 != NULL && (c2 == NULL || c1 < c2)) {
- if (sscanf(c1, "%u", &b) < 1)
+ if (nextnumber(c1, &end, &b) != 0)
return 1;
- c1 = nexttoken(c1, ':');
- if (c1 != NULL && (c2 == NULL || c1 < c2))
- if (sscanf(c1, "%u", &s) < 1) {
+
+ c1 = end && *end ? nexttoken(end, ':') : NULL;
+
+ if (c1 != NULL && (c2 == NULL || c1 < c2)) {
+ if (nextnumber(c1, &end, &s) != 0)
+ return 1;
+ if (s == 0)
return 1;
}
}
if (!(a <= b))
return 1;
while (a <= b) {
+ if (fail && (a >= max))
+ return 2;
CPU_SET_S(a, setsize, set);
a += s;
}
}
+ if (end && *end)
+ return 1;
return 0;
}
-#ifdef TEST_PROGRAM
+#ifdef TEST_PROGRAM_CPUSET
-#include <err.h>
#include <getopt.h>
int main(int argc, char *argv[])
char *buf, *mask = NULL, *range = NULL;
int ncpus = 2048, rc, c;
- struct option longopts[] = {
- { "ncpus", 1, 0, 'n' },
- { "mask", 1, 0, 'm' },
- { "range", 1, 0, 'r' },
- { NULL, 0, 0, 0 }
+ static const struct option longopts[] = {
+ { "ncpus", 1, NULL, 'n' },
+ { "mask", 1, NULL, 'm' },
+ { "range", 1, NULL, 'r' },
+ { NULL, 0, NULL, 0 }
};
while ((c = getopt_long(argc, argv, "n:m:r:", longopts, NULL)) != -1) {
if (mask)
rc = cpumask_parse(mask, set, setsize);
else
- rc = cpulist_parse(range, set, setsize);
+ rc = cpulist_parse(range, set, setsize, 0);
if (rc)
errx(EXIT_FAILURE, "failed to parse string: %s", mask ? : range);
printf("[%s]\n", cpulist_create(buf, buflen, set, setsize));
free(buf);
+ free(mask);
+ free(range);
cpuset_free(set);
return EXIT_SUCCESS;
usage_err:
fprintf(stderr,
- "usage: %s [--ncpus <num>] --mask <mask> | --range <list>",
+ "usage: %s [--ncpus <num>] --mask <mask> | --range <list>\n",
program_invocation_short_name);
exit(EXIT_FAILURE);
}