diff --git a/include/villas/utils.h b/include/villas/utils.h index ce3b630a4..6664b2232 100644 --- a/include/villas/utils.h +++ b/include/villas/utils.h @@ -47,6 +47,10 @@ #define XSTR(x) STR(x) #define STR(x) #x +#define CONCAT_DETAIL(x, y) x##y +#define CONCAT(x, y) CONCAT_DETAIL(x, y) +#define UNIQUE(x) CONCAT(x, __COUNTER__) + #define ALIGN(x, a) ALIGN_MASK(x, (uintptr_t) (a) - 1) #define ALIGN_MASK(x, m) (((uintptr_t) (x) + (m)) & ~(m)) #define IS_ALIGNED(x, a) (ALIGN(x, a) == (uintptr_t) x) @@ -127,10 +131,30 @@ int strftimespec(char *s, size_t max, const char *format, struct timespec *ts) /** Convert integer to cpu_set_t. * - * @param set A cpu bitmask - * @return The opaque cpu_set_t datatype + * @param set An integer number which is used as the mask + * @param cset A pointer to the cpu_set_t datastructure */ -cpu_set_t integer_to_cpuset(uintmax_t set); +void cpuset_from_integer(uintmax_t set, cpu_set_t *cset); + +/** Parses string with list of CPU ranges. + * + * From: https://github.com/mmalecki/util-linux/blob/master/lib/cpuset.c + * + * @retval 0 On success. + * @retval 1 On error. + * @retval 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, int fail); + +/** Returns human readable representation of the cpuset. + * + * From: https://github.com/mmalecki/util-linux/blob/master/lib/cpuset.c + * + * The output format is a list of CPUs with ranges (for example, "0,1,3-9"). + */ +char * cpulist_create(char *str, size_t len, cpu_set_t *set); #ifdef WITH_JANSSON #include diff --git a/lib/utils.c b/lib/utils.c index 5e16a235e..eab323d11 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -135,18 +135,113 @@ char * vstrcatf(char **dest, const char *fmt, va_list ap) return *dest; } -cpu_set_t integer_to_cpuset(uintmax_t set) +void cpuset_from_integer(uintmax_t set, cpu_set_t *cset) { - cpu_set_t cset; - - CPU_ZERO(&cset); - - for (int i = 0; i < sizeof(set) * 8; i++) { + CPU_ZERO(cset); + for (int i = 0; i < MIN(sizeof(set), CPU_SETSIZE) * 8; i++) { if (set & (1L << i)) - CPU_SET(i, &cset); + CPU_SET(i, cset); + } +} + +/* From: https://github.com/mmalecki/util-linux/blob/master/lib/cpuset.c */ +static const char *nexttoken(const char *q, int sep) +{ + if (q) + q = strchr(q, sep); + if (q) + q++; + return q; +} + +int cpulist_parse(const char *str, cpu_set_t *set, int fail) +{ + const char *p, *q; + int r = 0; + + q = str; + CPU_ZERO(set); + + while (p = q, q = nexttoken(q, ','), p) { + unsigned int a; /* beginning of range */ + unsigned int b; /* end of range */ + unsigned int s; /* stride */ + const char *c1, *c2; + char c; + + if ((r = sscanf(p, "%u%c", &a, &c)) < 1) + return 1; + b = a; + s = 1; + + c1 = nexttoken(p, '-'); + c2 = nexttoken(p, ','); + if (c1 != NULL && (c2 == NULL || c1 < c2)) { + if ((r = sscanf(c1, "%u%c", &b, &c)) < 1) + return 1; + c1 = nexttoken(c1, ':'); + if (c1 != NULL && (c2 == NULL || c1 < c2)) { + if ((r = sscanf(c1, "%u%c", &s, &c)) < 1) + return 1; + if (s == 0) + return 1; + } + } + + if (!(a <= b)) + return 1; + while (a <= b) { + if (fail && (a >= CPU_SETSIZE)) + return 2; + CPU_SET(a, set); + a += s; + } } - return cset; + if (r == 2) + return 1; + return 0; +} + +char *cpulist_create(char *str, size_t len, cpu_set_t *set) +{ + size_t i; + char *ptr = str; + int entry_made = 0; + + for (i = 0; i < CPU_SETSIZE; i++) { + if (CPU_ISSET(i, set)) { + int rlen; + size_t j, run = 0; + entry_made = 1; + for (j = i + 1; j < CPU_SETSIZE; j++) { + if (CPU_ISSET(j, set)) + run++; + else + break; + } + if (!run) + rlen = snprintf(ptr, len, "%zd,", i); + else if (run == 1) { + rlen = snprintf(ptr, len, "%zd,%zd,", i, i + 1); + i++; + } else { + rlen = snprintf(ptr, len, "%zd-%zd,", i, i + run); + i += run; + } + if (rlen < 0 || (size_t) rlen + 1 > len) + return NULL; + ptr += rlen; + if (rlen > 0 && len > (size_t) rlen) + len -= rlen; + else + len = 0; + } + } + ptr -= entry_made; + *ptr = '\0'; + + return str; } #ifdef WITH_JANSSON