1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-01-10 01:17:44 +03:00

Merge pull request #1382 from filbranden/cpuaffinity2

Use parse_cpu_set in CPUAffinity support (for units)
This commit is contained in:
Daniel Mack 2015-09-25 13:27:11 +02:00
commit 2c995032e8
5 changed files with 137 additions and 73 deletions

View File

@ -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;

View File

@ -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), \

View File

@ -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)) {
ncpus = parse_cpu_set(rvalue, &cpuset, unit, filename, line, lvalue);
if (ncpus < 0)
return ncpus;
if (c->cpuset)
CPU_FREE(c->cpuset);
if (ncpus == 0)
/* An empty assignment resets the CPU list */
if (c->cpuset)
CPU_FREE(c->cpuset);
c->cpuset = NULL;
return 0;
else {
c->cpuset = cpuset;
cpuset = NULL;
}
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);
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 (!isempty(state))
log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
"Trailing garbage, ignoring.");
c->cpuset_ncpus = ncpus;
return 0;
}

View File

@ -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;
if (ncpus < 0)
return ncpus;
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 (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;
}

View File

@ -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();