diff options
author | Daniel Mack <github@zonque.org> | 2015-09-25 13:27:11 +0200 |
---|---|---|
committer | Daniel Mack <github@zonque.org> | 2015-09-25 13:27:11 +0200 |
commit | 2c995032e8089114d22f0be4a81325a867d320c1 (patch) | |
tree | f7b005b5de2ed93b225fbd931eadc7c53738ec7e | |
parent | 54e56acafef1458d7baa08658c6ca06245215488 (diff) | |
parent | 9d5ca7f882d3c65f6d85e9fc727a0eea3262aaf9 (diff) |
Merge pull request #1382 from filbranden/cpuaffinity2
Use parse_cpu_set in CPUAffinity support (for units)
-rw-r--r-- | src/basic/util.c | 56 | ||||
-rw-r--r-- | src/basic/util.h | 1 | ||||
-rw-r--r-- | src/core/load-fragment.c | 48 | ||||
-rw-r--r-- | src/core/main.c | 44 | ||||
-rw-r--r-- | src/test/test-util.c | 59 |
5 files changed, 136 insertions, 72 deletions
diff --git a/src/basic/util.c b/src/basic/util.c index 40a4b8fbec..bc61ec0115 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -2578,6 +2578,62 @@ cpu_set_t* cpu_set_malloc(unsigned *ncpus) { } } +int parse_cpu_set( + 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(filename); + assert(lvalue); + assert(rvalue); + + for (;;) { + _cleanup_free_ char *word = NULL; + unsigned cpu; + int r; + + r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Invalid value for %s: %s", lvalue, whole_rvalue); + return r; + } + if (r == 0) + break; + + r = safe_atou(word, &cpu); + + if (!c) + if (!(c = cpu_set_malloc(&ncpus))) + return log_oom(); + + if (r < 0 || cpu >= ncpus) { + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to parse CPU affinity '%s'", rvalue); + return -EBADMSG; + } + + CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c); + } + if (!isempty(rvalue)) + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Trailing garbage, ignoring."); + + /* On success, sets *cpu_set and returns ncpus for the system. */ + if (c) { + *cpu_set = c; + c = NULL; + } + return (int) ncpus; +} + int files_same(const char *filea, const char *fileb) { struct stat a, b; diff --git a/src/basic/util.h b/src/basic/util.h index d53e15e6e6..56d9f037bf 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -375,6 +375,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE); #define _cleanup_cpu_free_ _cleanup_(CPU_FREEp) cpu_set_t* cpu_set_malloc(unsigned *ncpus); +int parse_cpu_set(const char *rvalue, cpu_set_t **cpu_set, const char *unit, const char *filename, unsigned line, const char *lvalue); #define xsprintf(buf, fmt, ...) \ assert_message_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf), \ diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index f42bee4fa9..a13f42b5e0 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -875,50 +875,30 @@ 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; - } + ncpus = parse_cpu_set(rvalue, &cpuset, unit, filename, line, lvalue); - FOREACH_WORD_QUOTED(word, l, rvalue, state) { - _cleanup_free_ char *t = NULL; - int r; - unsigned cpu; + if (ncpus < 0) + return ncpus; - t = strndup(word, l); - if (!t) - return log_oom(); + if (c->cpuset) + CPU_FREE(c->cpuset); - r = safe_atou(t, &cpu); - - if (!c->cpuset) { - c->cpuset = cpu_set_malloc(&c->cpuset_ncpus); - if (!c->cpuset) - return log_oom(); - } - - 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 b57f4c1b7a..bc72a2b00b 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -434,48 +434,16 @@ static int config_parse_cpu_affinity2( void *data, void *userdata) { - const char *whole_rvalue = rvalue; _cleanup_cpu_free_ cpu_set_t *c = NULL; - unsigned ncpus = 0; + int ncpus; - assert(filename); - assert(lvalue); - assert(rvalue); + ncpus = parse_cpu_set(rvalue, &c, unit, filename, line, lvalue); - for (;;) { - _cleanup_free_ char *word = NULL; - unsigned cpu; - int r; - - r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue); - return r; - } - if (r == 0) - break; - - r = safe_atou(word, &cpu); - - if (!c) - if (!(c = cpu_set_malloc(&ncpus))) - return log_oom(); - - if (r < 0 || cpu >= ncpus) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse CPU affinity '%s'", rvalue); - return -EBADMSG; - } - - CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c); - } - if (!isempty(rvalue)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); + if (ncpus < 0) + return ncpus; - if (c) - if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0) - log_warning("Failed to set CPU affinity: %m"); + if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0) + log_warning("Failed to set CPU affinity: %m"); return 0; } diff --git a/src/test/test-util.c b/src/test/test-util.c index 7935442dbb..f434c5ceba 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -960,6 +960,64 @@ static void test_parse_size(void) { assert_se(parse_size("-10B 20K", 1024, &bytes) == -ERANGE); } +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("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("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("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("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus < 0); + assert_se(!c); + + /* Ranges */ + ncpus = parse_cpu_set("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus < 0); + assert_se(!c); + + /* Garbage */ + ncpus = parse_cpu_set("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus < 0); + assert_se(!c); + + /* Empty string */ + c = NULL; + ncpus = parse_cpu_set("", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus == 0); /* empty string returns 0 */ + assert_se(!c); + + /* Runnaway quoted string */ + ncpus = parse_cpu_set("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_uint64(void) { uint64_t offset = 0; assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4M", &offset, NULL) == 0); @@ -2250,6 +2308,7 @@ int main(int argc, char *argv[]) { test_u64log2(); test_protect_errno(); test_parse_size(); + test_parse_cpu_set(); test_config_parse_iec_uint64(); test_strextend(); test_strrep(); |