You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
621 lines
22 KiB
621 lines
22 KiB
From 6e00430563108b98230abd7407ac54fde61ae93c Mon Sep 17 00:00:00 2001 |
|
From: Jan Synacek <jsynacek@redhat.com> |
|
Date: Tue, 26 Sep 2017 12:34:19 +0200 |
|
Subject: [PATCH] support ranges when parsing CPUAffinity |
|
|
|
The functionality was implemented in https://github.com/systemd/systemd/pull/1699/. |
|
However, it is not backportable without considerable code changes. |
|
|
|
Implement parse_range() and parse_cpu_set_and_warn() from the upstream master |
|
branch and use them in appropriate places. Also introduce relevant tests. |
|
|
|
Resolves: #1493976 |
|
--- |
|
src/core/load-fragment.c | 49 +++----- |
|
src/core/main.c | 48 ++------ |
|
src/shared/util.c | 91 +++++++++++++++ |
|
src/shared/util.h | 9 ++ |
|
src/test/test-util.c | 296 +++++++++++++++++++++++++++++++++++++++++++++++ |
|
5 files changed, 417 insertions(+), 76 deletions(-) |
|
|
|
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c |
|
index 0c0fa0f50..a10e1903a 100644 |
|
--- a/src/core/load-fragment.c |
|
+++ b/src/core/load-fragment.c |
|
@@ -884,50 +884,29 @@ int config_parse_exec_cpu_affinity(const char *unit, |
|
void *userdata) { |
|
|
|
ExecContext *c = data; |
|
- const char *word, *state; |
|
- size_t l; |
|
+ _cleanup_cpu_free_ cpu_set_t *cpuset = NULL; |
|
+ int ncpus; |
|
|
|
assert(filename); |
|
assert(lvalue); |
|
assert(rvalue); |
|
assert(data); |
|
|
|
- if (isempty(rvalue)) { |
|
- /* An empty assignment resets the CPU list */ |
|
- if (c->cpuset) |
|
- CPU_FREE(c->cpuset); |
|
- c->cpuset = NULL; |
|
- return 0; |
|
- } |
|
- |
|
- FOREACH_WORD_QUOTED(word, l, rvalue, state) { |
|
- _cleanup_free_ char *t = NULL; |
|
- int r; |
|
- unsigned cpu; |
|
- |
|
- t = strndup(word, l); |
|
- if (!t) |
|
- return log_oom(); |
|
- |
|
- r = safe_atou(t, &cpu); |
|
+ ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue); |
|
+ if (ncpus < 0) |
|
+ return ncpus; |
|
|
|
- if (!c->cpuset) { |
|
- c->cpuset = cpu_set_malloc(&c->cpuset_ncpus); |
|
- if (!c->cpuset) |
|
- return log_oom(); |
|
- } |
|
+ if (c->cpuset) |
|
+ CPU_FREE(c->cpuset); |
|
|
|
- if (r < 0 || cpu >= c->cpuset_ncpus) { |
|
- log_syntax(unit, LOG_ERR, filename, line, ERANGE, |
|
- "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue); |
|
- return 0; |
|
- } |
|
- |
|
- CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset); |
|
+ if (ncpus == 0) |
|
+ /* An empty assignment resets the CPU list */ |
|
+ c->cpuset = NULL; |
|
+ else { |
|
+ c->cpuset = cpuset; |
|
+ cpuset = NULL; |
|
} |
|
- if (!isempty(state)) |
|
- log_syntax(unit, LOG_WARNING, filename, line, EINVAL, |
|
- "Trailing garbage, ignoring."); |
|
+ c->cpuset_ncpus = ncpus; |
|
|
|
return 0; |
|
} |
|
diff --git a/src/core/main.c b/src/core/main.c |
|
index 66393ed6a..5554ef468 100644 |
|
--- a/src/core/main.c |
|
+++ b/src/core/main.c |
|
@@ -438,49 +438,15 @@ static int config_parse_cpu_affinity2( |
|
void *data, |
|
void *userdata) { |
|
|
|
- const char *word, *state; |
|
- size_t l; |
|
- cpu_set_t *c = NULL; |
|
- unsigned ncpus = 0; |
|
- |
|
- assert(filename); |
|
- assert(lvalue); |
|
- assert(rvalue); |
|
+ _cleanup_cpu_free_ cpu_set_t *c = NULL; |
|
+ int ncpus; |
|
|
|
- FOREACH_WORD_QUOTED(word, l, rvalue, state) { |
|
- char *t; |
|
- int r; |
|
- unsigned cpu; |
|
- |
|
- if (!(t = strndup(word, l))) |
|
- return log_oom(); |
|
- |
|
- r = safe_atou(t, &cpu); |
|
- free(t); |
|
- |
|
- if (!c) |
|
- if (!(c = cpu_set_malloc(&ncpus))) |
|
- return log_oom(); |
|
+ ncpus = parse_cpu_set_and_warn(rvalue, &c, unit, filename, line, lvalue); |
|
+ if (ncpus < 0) |
|
+ return ncpus; |
|
|
|
- if (r < 0 || cpu >= ncpus) { |
|
- log_syntax(unit, LOG_ERR, filename, line, -r, |
|
- "Failed to parse CPU affinity '%s'", rvalue); |
|
- CPU_FREE(c); |
|
- return -EBADMSG; |
|
- } |
|
- |
|
- CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c); |
|
- } |
|
- if (!isempty(state)) |
|
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, |
|
- "Trailing garbage, ignoring."); |
|
- |
|
- if (c) { |
|
- if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0) |
|
- log_unit_warning(unit, "Failed to set CPU affinity: %m"); |
|
- |
|
- CPU_FREE(c); |
|
- } |
|
+ if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0) |
|
+ log_warning_errno(errno, "Failed to set CPU affinity: %m"); |
|
|
|
return 0; |
|
} |
|
diff --git a/src/shared/util.c b/src/shared/util.c |
|
index bbb457759..39359fcc8 100644 |
|
--- a/src/shared/util.c |
|
+++ b/src/shared/util.c |
|
@@ -2727,6 +2727,43 @@ int parse_size(const char *t, off_t base, off_t *size) { |
|
return 0; |
|
} |
|
|
|
+int parse_range(const char *t, unsigned *lower, unsigned *upper) { |
|
+ _cleanup_free_ char *word = NULL; |
|
+ unsigned l, u; |
|
+ int r; |
|
+ |
|
+ assert(lower); |
|
+ assert(upper); |
|
+ |
|
+ /* Extract the lower bound. */ |
|
+ r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS); |
|
+ if (r < 0) |
|
+ return r; |
|
+ if (r == 0) |
|
+ return -EINVAL; |
|
+ |
|
+ r = safe_atou(word, &l); |
|
+ if (r < 0) |
|
+ return r; |
|
+ |
|
+ /* Check for the upper bound and extract it if needed */ |
|
+ if (!t) |
|
+ /* Single number with no dashes. */ |
|
+ u = l; |
|
+ else if (!*t) |
|
+ /* Trailing dash is an error. */ |
|
+ return -EINVAL; |
|
+ else { |
|
+ r = safe_atou(t, &u); |
|
+ if (r < 0) |
|
+ return r; |
|
+ } |
|
+ |
|
+ *lower = l; |
|
+ *upper = u; |
|
+ return 0; |
|
+} |
|
+ |
|
int make_stdio(int fd) { |
|
int r, s, t; |
|
|
|
@@ -3460,6 +3497,60 @@ cpu_set_t* cpu_set_malloc(unsigned *ncpus) { |
|
} |
|
} |
|
|
|
+int parse_cpu_set_and_warn( |
|
+ const char *rvalue, |
|
+ cpu_set_t **cpu_set, |
|
+ const char *unit, |
|
+ const char *filename, |
|
+ unsigned line, |
|
+ const char *lvalue) { |
|
+ |
|
+ const char *whole_rvalue = rvalue; |
|
+ _cleanup_cpu_free_ cpu_set_t *c = NULL; |
|
+ unsigned ncpus = 0; |
|
+ |
|
+ assert(lvalue); |
|
+ assert(rvalue); |
|
+ |
|
+ for (;;) { |
|
+ _cleanup_free_ char *word = NULL; |
|
+ unsigned cpu, cpu_lower, cpu_upper; |
|
+ int r; |
|
+ |
|
+ r = extract_first_word(&rvalue, &word, WHITESPACE ",", EXTRACT_QUOTES); |
|
+ if (r < 0) |
|
+ return log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue); |
|
+ if (r == 0) |
|
+ break; |
|
+ |
|
+ if (!c) { |
|
+ c = cpu_set_malloc(&ncpus); |
|
+ if (!c) |
|
+ return log_oom(); |
|
+ } |
|
+ |
|
+ r = parse_range(word, &cpu_lower, &cpu_upper); |
|
+ if (r < 0) |
|
+ return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU affinity '%s'", word); |
|
+ if (cpu_lower >= ncpus || cpu_upper >= ncpus) |
|
+ return log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU out of range '%s' ncpus is %u", word, ncpus); |
|
+ |
|
+ if (cpu_lower > cpu_upper) |
|
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Range '%s' is invalid, %u > %u", word, cpu_lower, cpu_upper); |
|
+ else |
|
+ for (cpu = cpu_lower; cpu <= cpu_upper; cpu++) |
|
+ CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c); |
|
+ } |
|
+ |
|
+ /* On success, sets *cpu_set and returns ncpus for the system. */ |
|
+ if (c) { |
|
+ *cpu_set = c; |
|
+ c = NULL; |
|
+ } |
|
+ |
|
+ return (int) ncpus; |
|
+} |
|
+ |
|
int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) { |
|
static const char status_indent[] = " "; /* "[" STATUS "] " */ |
|
_cleanup_free_ char *s = NULL; |
|
diff --git a/src/shared/util.h b/src/shared/util.h |
|
index 80ad18c0a..526a6fe84 100644 |
|
--- a/src/shared/util.h |
|
+++ b/src/shared/util.h |
|
@@ -136,6 +136,11 @@ bool streq_ptr(const char *a, const char *b) _pure_; |
|
|
|
#define malloc0(n) (calloc((n), 1)) |
|
|
|
+static inline void *mfree(void *memory) { |
|
+ free(memory); |
|
+ return NULL; |
|
+} |
|
+ |
|
static inline const char* yes_no(bool b) { |
|
return b ? "yes" : "no"; |
|
} |
|
@@ -195,6 +200,7 @@ void safe_close_pair(int p[]); |
|
void close_many(const int fds[], unsigned n_fd); |
|
|
|
int parse_size(const char *t, off_t base, off_t *size); |
|
+int parse_range(const char *t, unsigned *lower, unsigned *upper); |
|
|
|
int parse_boolean(const char *v) _pure_; |
|
int parse_pid(const char *s, pid_t* ret_pid); |
|
@@ -474,6 +480,7 @@ int rm_rf_dangerous(const char *path, bool only_dirs, bool delete_root, bool hon |
|
int pipe_eof(int fd); |
|
|
|
cpu_set_t* cpu_set_malloc(unsigned *ncpus); |
|
+int parse_cpu_set_and_warn(const char *rvalue, cpu_set_t **cpu_set, const char *unit, const char *filename, unsigned line, const char *lvalue); |
|
|
|
int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0); |
|
int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_(4,5); |
|
@@ -692,6 +699,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, fclose); |
|
DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose); |
|
DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); |
|
DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent); |
|
+DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE); |
|
|
|
#define _cleanup_free_ _cleanup_(freep) |
|
#define _cleanup_close_ _cleanup_(closep) |
|
@@ -702,6 +710,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent); |
|
#define _cleanup_closedir_ _cleanup_(closedirp) |
|
#define _cleanup_endmntent_ _cleanup_(endmntentp) |
|
#define _cleanup_close_pair_ _cleanup_(close_pairp) |
|
+#define _cleanup_cpu_free_ _cleanup_(CPU_FREEp) |
|
|
|
_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) { |
|
if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) |
|
diff --git a/src/test/test-util.c b/src/test/test-util.c |
|
index 971f97d7c..fcf5416c0 100644 |
|
--- a/src/test/test-util.c |
|
+++ b/src/test/test-util.c |
|
@@ -689,6 +689,300 @@ static void test_parse_size(void) { |
|
assert_se(parse_size("-10B 20K", 1024, &bytes) == -ERANGE); |
|
} |
|
|
|
+static void test_parse_range(void) { |
|
+ unsigned lower, upper; |
|
+ |
|
+ /* Successful cases */ |
|
+ assert_se(parse_range("111", &lower, &upper) == 0); |
|
+ assert_se(lower == 111); |
|
+ assert_se(upper == 111); |
|
+ |
|
+ assert_se(parse_range("111-123", &lower, &upper) == 0); |
|
+ assert_se(lower == 111); |
|
+ assert_se(upper == 123); |
|
+ |
|
+ assert_se(parse_range("123-111", &lower, &upper) == 0); |
|
+ assert_se(lower == 123); |
|
+ assert_se(upper == 111); |
|
+ |
|
+ assert_se(parse_range("123-123", &lower, &upper) == 0); |
|
+ assert_se(lower == 123); |
|
+ assert_se(upper == 123); |
|
+ |
|
+ assert_se(parse_range("0", &lower, &upper) == 0); |
|
+ assert_se(lower == 0); |
|
+ assert_se(upper == 0); |
|
+ |
|
+ assert_se(parse_range("0-15", &lower, &upper) == 0); |
|
+ assert_se(lower == 0); |
|
+ assert_se(upper == 15); |
|
+ |
|
+ assert_se(parse_range("15-0", &lower, &upper) == 0); |
|
+ assert_se(lower == 15); |
|
+ assert_se(upper == 0); |
|
+ |
|
+ assert_se(parse_range("128-65535", &lower, &upper) == 0); |
|
+ assert_se(lower == 128); |
|
+ assert_se(upper == 65535); |
|
+ |
|
+ assert_se(parse_range("1024-4294967295", &lower, &upper) == 0); |
|
+ assert_se(lower == 1024); |
|
+ assert_se(upper == 4294967295); |
|
+ |
|
+ /* Leading whitespace is acceptable */ |
|
+ assert_se(parse_range(" 111", &lower, &upper) == 0); |
|
+ assert_se(lower == 111); |
|
+ assert_se(upper == 111); |
|
+ |
|
+ assert_se(parse_range(" 111-123", &lower, &upper) == 0); |
|
+ assert_se(lower == 111); |
|
+ assert_se(upper == 123); |
|
+ |
|
+ assert_se(parse_range("111- 123", &lower, &upper) == 0); |
|
+ assert_se(lower == 111); |
|
+ assert_se(upper == 123); |
|
+ |
|
+ assert_se(parse_range("\t111-\t123", &lower, &upper) == 0); |
|
+ assert_se(lower == 111); |
|
+ assert_se(upper == 123); |
|
+ |
|
+ assert_se(parse_range(" \t 111- \t 123", &lower, &upper) == 0); |
|
+ assert_se(lower == 111); |
|
+ assert_se(upper == 123); |
|
+ |
|
+ /* Error cases, make sure they fail as expected */ |
|
+ lower = upper = 9999; |
|
+ assert_se(parse_range("111garbage", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ assert_se(parse_range("garbage111", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ assert_se(parse_range("garbage", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ assert_se(parse_range("111-123garbage", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ assert_se(parse_range("111garbage-123", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ /* Empty string */ |
|
+ lower = upper = 9999; |
|
+ assert_se(parse_range("", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ /* 111--123 will pass -123 to safe_atou which returns -ERANGE for negative */ |
|
+ assert_se(parse_range("111--123", &lower, &upper) == -ERANGE); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ assert_se(parse_range("-111-123", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ assert_se(parse_range("111-123-", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ assert_se(parse_range("111.4-123", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ assert_se(parse_range("111-123.4", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ assert_se(parse_range("111,4-123", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ assert_se(parse_range("111-123,4", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ /* Error on trailing dash */ |
|
+ assert_se(parse_range("111-", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ assert_se(parse_range("111-123-", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ assert_se(parse_range("111--", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ assert_se(parse_range("111- ", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ /* Whitespace is not a separator */ |
|
+ assert_se(parse_range("111 123", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ assert_se(parse_range("111\t123", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ assert_se(parse_range("111 \t 123", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ /* Trailing whitespace is invalid (from safe_atou) */ |
|
+ assert_se(parse_range("111 ", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ assert_se(parse_range("111-123 ", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ assert_se(parse_range("111 -123", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ assert_se(parse_range("111 -123 ", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ assert_se(parse_range("111\t-123\t", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ assert_se(parse_range("111 \t -123 \t ", &lower, &upper) == -EINVAL); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+ |
|
+ /* Out of the "unsigned" range, this is 1<<64 */ |
|
+ assert_se(parse_range("0-18446744073709551616", &lower, &upper) == -ERANGE); |
|
+ assert_se(lower == 9999); |
|
+ assert_se(upper == 9999); |
|
+} |
|
+ |
|
+static void test_parse_cpu_set(void) { |
|
+ cpu_set_t *c = NULL; |
|
+ int ncpus; |
|
+ int cpu; |
|
+ |
|
+ /* Simple range (from CPUAffinity example) */ |
|
+ ncpus = parse_cpu_set_and_warn("1 2", &c, NULL, "fake", 1, "CPUAffinity"); |
|
+ assert_se(ncpus >= 1024); |
|
+ assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); |
|
+ assert_se(CPU_ISSET_S(2, CPU_ALLOC_SIZE(ncpus), c)); |
|
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 2); |
|
+ c = mfree(c); |
|
+ |
|
+ /* A more interesting range */ |
|
+ ncpus = parse_cpu_set_and_warn("0 1 2 3 8 9 10 11", &c, NULL, "fake", 1, "CPUAffinity"); |
|
+ assert_se(ncpus >= 1024); |
|
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); |
|
+ for (cpu = 0; cpu < 4; cpu++) |
|
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); |
|
+ for (cpu = 8; cpu < 12; cpu++) |
|
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); |
|
+ c = mfree(c); |
|
+ |
|
+ /* Quoted strings */ |
|
+ ncpus = parse_cpu_set_and_warn("8 '9' 10 \"11\"", &c, NULL, "fake", 1, "CPUAffinity"); |
|
+ assert_se(ncpus >= 1024); |
|
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 4); |
|
+ for (cpu = 8; cpu < 12; cpu++) |
|
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); |
|
+ c = mfree(c); |
|
+ |
|
+ /* Use commas as separators */ |
|
+ ncpus = parse_cpu_set_and_warn("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity"); |
|
+ assert_se(ncpus >= 1024); |
|
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); |
|
+ for (cpu = 0; cpu < 4; cpu++) |
|
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); |
|
+ for (cpu = 8; cpu < 12; cpu++) |
|
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); |
|
+ c = mfree(c); |
|
+ |
|
+ /* Commas with spaces (and trailing comma, space) */ |
|
+ ncpus = parse_cpu_set_and_warn("0, 1, 2, 3, 4, 5, 6, 7, ", &c, NULL, "fake", 1, "CPUAffinity"); |
|
+ assert_se(ncpus >= 1024); |
|
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); |
|
+ for (cpu = 0; cpu < 8; cpu++) |
|
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); |
|
+ c = mfree(c); |
|
+ |
|
+ /* Ranges */ |
|
+ ncpus = parse_cpu_set_and_warn("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity"); |
|
+ assert_se(ncpus >= 1024); |
|
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); |
|
+ for (cpu = 0; cpu < 4; cpu++) |
|
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); |
|
+ for (cpu = 8; cpu < 12; cpu++) |
|
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); |
|
+ c = mfree(c); |
|
+ |
|
+ /* Ranges with trailing comma, space */ |
|
+ ncpus = parse_cpu_set_and_warn("0-3 8-11, ", &c, NULL, "fake", 1, "CPUAffinity"); |
|
+ assert_se(ncpus >= 1024); |
|
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); |
|
+ for (cpu = 0; cpu < 4; cpu++) |
|
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); |
|
+ for (cpu = 8; cpu < 12; cpu++) |
|
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); |
|
+ c = mfree(c); |
|
+ |
|
+ /* Negative range (returns empty cpu_set) */ |
|
+ ncpus = parse_cpu_set_and_warn("3-0", &c, NULL, "fake", 1, "CPUAffinity"); |
|
+ assert_se(ncpus >= 1024); |
|
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 0); |
|
+ c = mfree(c); |
|
+ |
|
+ /* Overlapping ranges */ |
|
+ ncpus = parse_cpu_set_and_warn("0-7 4-11", &c, NULL, "fake", 1, "CPUAffinity"); |
|
+ assert_se(ncpus >= 1024); |
|
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 12); |
|
+ for (cpu = 0; cpu < 12; cpu++) |
|
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); |
|
+ c = mfree(c); |
|
+ |
|
+ /* Mix ranges and individual CPUs */ |
|
+ ncpus = parse_cpu_set_and_warn("0,1 4-11", &c, NULL, "fake", 1, "CPUAffinity"); |
|
+ assert_se(ncpus >= 1024); |
|
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 10); |
|
+ assert_se(CPU_ISSET_S(0, CPU_ALLOC_SIZE(ncpus), c)); |
|
+ assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); |
|
+ for (cpu = 4; cpu < 12; cpu++) |
|
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); |
|
+ c = mfree(c); |
|
+ |
|
+ /* Garbage */ |
|
+ ncpus = parse_cpu_set_and_warn("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity"); |
|
+ assert_se(ncpus < 0); |
|
+ assert_se(!c); |
|
+ |
|
+ /* Range with garbage */ |
|
+ ncpus = parse_cpu_set_and_warn("0-3 8-garbage", &c, NULL, "fake", 1, "CPUAffinity"); |
|
+ assert_se(ncpus < 0); |
|
+ assert_se(!c); |
|
+ |
|
+ /* Empty string */ |
|
+ c = NULL; |
|
+ ncpus = parse_cpu_set_and_warn("", &c, NULL, "fake", 1, "CPUAffinity"); |
|
+ assert_se(ncpus == 0); /* empty string returns 0 */ |
|
+ assert_se(!c); |
|
+ |
|
+ /* Runaway quoted string */ |
|
+ ncpus = parse_cpu_set_and_warn("0 1 2 3 \"4 5 6 7 ", &c, NULL, "fake", 1, "CPUAffinity"); |
|
+ assert_se(ncpus < 0); |
|
+ assert_se(!c); |
|
+} |
|
+ |
|
static void test_config_parse_iec_off(void) { |
|
off_t offset = 0; |
|
assert_se(config_parse_iec_off(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4M", &offset, NULL) == 0); |
|
@@ -1605,6 +1899,8 @@ int main(int argc, char *argv[]) { |
|
test_get_process_comm(); |
|
test_protect_errno(); |
|
test_parse_size(); |
|
+ test_parse_range(); |
|
+ test_parse_cpu_set(); |
|
test_config_parse_iec_off(); |
|
test_strextend(); |
|
test_strrep();
|
|
|