summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/dbus-execute.c35
-rw-r--r--src/core/execute.c12
-rw-r--r--src/core/execute.h4
-rw-r--r--src/core/load-fragment.c31
-rw-r--r--src/core/main.c14
-rw-r--r--src/nspawn/nspawn-oci.c25
-rw-r--r--src/nspawn/nspawn-settings.c33
-rw-r--r--src/nspawn/nspawn-settings.h4
-rw-r--r--src/nspawn/nspawn.c29
-rw-r--r--src/shared/bus-unit-util.c4
-rw-r--r--src/shared/cpu-set-util.c133
-rw-r--r--src/shared/cpu-set-util.h47
-rw-r--r--src/test/test-cpu-set-util.c177
-rw-r--r--src/test/test-sizeof.c3
14 files changed, 295 insertions, 256 deletions
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 5a56aad592..326e451b9a 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -219,7 +219,7 @@ static int property_get_cpu_affinity(
assert(reply);
assert(c);
- return sd_bus_message_append_array(reply, 'y', c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus));
+ return sd_bus_message_append_array(reply, 'y', c->cpu_set.set, c->cpu_set.allocated);
}
static int property_get_timer_slack_nsec(
@@ -1566,37 +1566,22 @@ int bus_exec_context_set_transient_property(
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (n == 0) {
- c->cpuset = cpu_set_mfree(c->cpuset);
- c->cpuset_ncpus = 0;
+ cpu_set_reset(&c->cpu_set);
unit_write_settingf(u, flags, name, "%s=", name);
} else {
_cleanup_free_ char *str = NULL;
- size_t ncpus;
+ const CPUSet set = {(cpu_set_t*) a, n};
- str = cpu_set_to_string(a, n);
+ str = cpu_set_to_string(&set);
if (!str)
return -ENOMEM;
- ncpus = CPU_SIZE_TO_NUM(n);
-
- if (!c->cpuset || c->cpuset_ncpus < ncpus) {
- cpu_set_t *cpuset;
-
- cpuset = CPU_ALLOC(ncpus);
- if (!cpuset)
- return -ENOMEM;
-
- CPU_ZERO_S(n, cpuset);
- if (c->cpuset) {
- CPU_OR_S(CPU_ALLOC_SIZE(c->cpuset_ncpus), cpuset, c->cpuset, (cpu_set_t*) a);
- CPU_FREE(c->cpuset);
- } else
- CPU_OR_S(n, cpuset, cpuset, (cpu_set_t*) a);
-
- c->cpuset = cpuset;
- c->cpuset_ncpus = ncpus;
- } else
- CPU_OR_S(n, c->cpuset, c->cpuset, (cpu_set_t*) a);
+ /* We forego any optimizations here, and always create the structure using
+ * cpu_set_add_all(), because we don't want to care if the existing size we
+ * got over dbus is appropriate. */
+ r = cpu_set_add_all(&c->cpu_set, &set);
+ if (r < 0)
+ return r;
unit_write_settingf(u, flags, name, "%s=%s", name, str);
}
diff --git a/src/core/execute.c b/src/core/execute.c
index a8b6c92873..01d36c1831 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -3144,8 +3144,8 @@ static int exec_child(
}
}
- if (context->cpuset)
- if (sched_setaffinity(0, CPU_ALLOC_SIZE(context->cpuset_ncpus), context->cpuset) < 0) {
+ if (context->cpu_set.set)
+ if (sched_setaffinity(0, context->cpu_set.allocated, context->cpu_set.set) < 0) {
*exit_status = EXIT_CPUAFFINITY;
return log_unit_error_errno(unit, errno, "Failed to set up CPU affinity: %m");
}
@@ -3896,7 +3896,7 @@ void exec_context_done(ExecContext *c) {
c->temporary_filesystems = NULL;
c->n_temporary_filesystems = 0;
- c->cpuset = cpu_set_mfree(c->cpuset);
+ cpu_set_reset(&c->cpu_set);
c->utmp_id = mfree(c->utmp_id);
c->selinux_context = mfree(c->selinux_context);
@@ -4328,10 +4328,10 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
prefix, yes_no(c->cpu_sched_reset_on_fork));
}
- if (c->cpuset) {
+ if (c->cpu_set.set) {
fprintf(f, "%sCPUAffinity:", prefix);
- for (i = 0; i < c->cpuset_ncpus; i++)
- if (CPU_ISSET_S(i, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset))
+ for (i = 0; i < c->cpu_set.allocated * 8; i++)
+ if (CPU_ISSET_S(i, c->cpu_set.allocated, c->cpu_set.set))
fprintf(f, " %u", i);
fputs("\n", f);
}
diff --git a/src/core/execute.h b/src/core/execute.h
index 23bf3b546a..7ddc36e6f3 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -14,6 +14,7 @@ typedef struct Manager Manager;
#include <sys/capability.h>
#include "cgroup-util.h"
+#include "cpu-set-util.h"
#include "fdset.h"
#include "list.h"
#include "missing_resource.h"
@@ -172,8 +173,7 @@ struct ExecContext {
int cpu_sched_policy;
int cpu_sched_priority;
- unsigned cpuset_ncpus;
- cpu_set_t *cpuset;
+ CPUSet cpu_set;
ExecInput std_input;
ExecOutput std_output;
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 11a9a7bdeb..bf414e62f1 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -1263,42 +1263,13 @@ int config_parse_exec_cpu_affinity(const char *unit,
void *userdata) {
ExecContext *c = data;
- _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
- int ncpus;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
- ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue);
- if (ncpus < 0)
- return ncpus;
-
- if (ncpus == 0) {
- /* An empty assignment resets the CPU list */
- c->cpuset = cpu_set_mfree(c->cpuset);
- c->cpuset_ncpus = 0;
- return 0;
- }
-
- if (!c->cpuset) {
- c->cpuset = TAKE_PTR(cpuset);
- c->cpuset_ncpus = (unsigned) ncpus;
- return 0;
- }
-
- if (c->cpuset_ncpus < (unsigned) ncpus) {
- CPU_OR_S(CPU_ALLOC_SIZE(c->cpuset_ncpus), cpuset, c->cpuset, cpuset);
- CPU_FREE(c->cpuset);
- c->cpuset = TAKE_PTR(cpuset);
- c->cpuset_ncpus = (unsigned) ncpus;
- return 0;
- }
-
- CPU_OR_S(CPU_ALLOC_SIZE((unsigned) ncpus), c->cpuset, c->cpuset, cpuset);
-
- return 0;
+ return parse_cpu_set_extend(rvalue, &c->cpu_set, true, unit, filename, line, lvalue);
}
int config_parse_capability_set(
diff --git a/src/core/main.c b/src/core/main.c
index e34da11984..67a62a5ad2 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -567,16 +567,18 @@ static int config_parse_cpu_affinity2(
void *data,
void *userdata) {
- _cleanup_cpu_free_ cpu_set_t *c = NULL;
- int ncpus;
+ _cleanup_(cpu_set_reset) CPUSet c = {};
+ int r;
- ncpus = parse_cpu_set_and_warn(rvalue, &c, unit, filename, line, lvalue);
- if (ncpus < 0)
- return ncpus;
+ r = parse_cpu_set_full(rvalue, &c, true, unit, filename, line, lvalue);
+ if (r < 0)
+ return r;
- if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0)
+ if (sched_setaffinity(0, c.allocated, c.set) < 0)
log_warning_errno(errno, "Failed to set CPU affinity: %m");
+ // FIXME: parsing and execution should be seperated.
+
return 0;
}
diff --git a/src/nspawn/nspawn-oci.c b/src/nspawn/nspawn-oci.c
index 97323f31dd..f5e52bef5e 100644
--- a/src/nspawn/nspawn-oci.c
+++ b/src/nspawn/nspawn-oci.c
@@ -1266,8 +1266,7 @@ struct cpu_data {
uint64_t shares;
uint64_t quota;
uint64_t period;
- cpu_set_t *cpuset;
- unsigned ncpus;
+ CPUSet cpu_set;
};
static int oci_cgroup_cpu_shares(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
@@ -1302,21 +1301,20 @@ static int oci_cgroup_cpu_quota(const char *name, JsonVariant *v, JsonDispatchFl
static int oci_cgroup_cpu_cpus(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
struct cpu_data *data = userdata;
- cpu_set_t *set;
+ CPUSet set;
const char *n;
- int ncpus;
+ int r;
assert(data);
assert_se(n = json_variant_string(v));
- ncpus = parse_cpu_set(n, &set);
- if (ncpus < 0)
- return json_log(v, flags, ncpus, "Failed to parse CPU set specification: %s", n);
+ r = parse_cpu_set(n, &set);
+ if (r < 0)
+ return json_log(v, flags, r, "Failed to parse CPU set specification: %s", n);
- CPU_FREE(data->cpuset);
- data->cpuset = set;
- data->ncpus = ncpus;
+ cpu_set_reset(&data->cpu_set);
+ data->cpu_set = set;
return 0;
}
@@ -1345,13 +1343,12 @@ static int oci_cgroup_cpu(const char *name, JsonVariant *v, JsonDispatchFlags fl
r = json_dispatch(v, table, oci_unexpected, flags, &data);
if (r < 0) {
- CPU_FREE(data.cpuset);
+ cpu_set_reset(&data.cpu_set);
return r;
}
- CPU_FREE(s->cpuset);
- s->cpuset = data.cpuset;
- s->cpuset_ncpus = data.ncpus;
+ cpu_set_reset(&s->cpu_set);
+ s->cpu_set = data.cpu_set;
if (data.shares != UINT64_MAX) {
r = settings_allocate_properties(s);
diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c
index 476cb0779e..9ff37c6dbd 100644
--- a/src/nspawn/nspawn-settings.c
+++ b/src/nspawn/nspawn-settings.c
@@ -133,7 +133,7 @@ Settings* settings_free(Settings *s) {
strv_free(s->syscall_blacklist);
rlimit_free_all(s->rlimit);
free(s->hostname);
- s->cpuset = cpu_set_mfree(s->cpuset);
+ cpu_set_reset(&s->cpu_set);
strv_free(s->network_interfaces);
strv_free(s->network_macvlan);
@@ -803,41 +803,12 @@ int config_parse_cpu_affinity(
void *data,
void *userdata) {
- _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
Settings *settings = data;
- int ncpus;
assert(rvalue);
assert(settings);
- ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue);
- if (ncpus < 0)
- return ncpus;
-
- if (ncpus == 0) {
- /* An empty assignment resets the CPU list */
- settings->cpuset = cpu_set_mfree(settings->cpuset);
- settings->cpuset_ncpus = 0;
- return 0;
- }
-
- if (!settings->cpuset) {
- settings->cpuset = TAKE_PTR(cpuset);
- settings->cpuset_ncpus = (unsigned) ncpus;
- return 0;
- }
-
- if (settings->cpuset_ncpus < (unsigned) ncpus) {
- CPU_OR_S(CPU_ALLOC_SIZE(settings->cpuset_ncpus), cpuset, settings->cpuset, cpuset);
- CPU_FREE(settings->cpuset);
- settings->cpuset = TAKE_PTR(cpuset);
- settings->cpuset_ncpus = (unsigned) ncpus;
- return 0;
- }
-
- CPU_OR_S(CPU_ALLOC_SIZE((unsigned) ncpus), settings->cpuset, settings->cpuset, cpuset);
-
- return 0;
+ return parse_cpu_set_extend(rvalue, &settings->cpu_set, true, unit, filename, line, lvalue);
}
DEFINE_CONFIG_PARSE_ENUM(config_parse_resolv_conf, resolv_conf_mode, ResolvConfMode, "Failed to parse resolv.conf mode");
diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h
index 64910c3ecc..f1a1a75466 100644
--- a/src/nspawn/nspawn-settings.h
+++ b/src/nspawn/nspawn-settings.h
@@ -13,6 +13,7 @@
#include "capability-util.h"
#include "conf-parser.h"
+#include "cpu-set-util.h"
#include "macro.h"
#include "missing_resource.h"
#include "nspawn-expose-ports.h"
@@ -163,8 +164,7 @@ typedef struct Settings {
int no_new_privileges;
int oom_score_adjust;
bool oom_score_adjust_set;
- cpu_set_t *cpuset;
- unsigned cpuset_ncpus;
+ CPUSet cpu_set;
ResolvConfMode resolv_conf;
LinkJournal link_journal;
bool link_journal_try;
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 27829431ac..25184e11e9 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -220,8 +220,7 @@ static struct rlimit *arg_rlimit[_RLIMIT_MAX] = {};
static bool arg_no_new_privileges = false;
static int arg_oom_score_adjust = 0;
static bool arg_oom_score_adjust_set = false;
-static cpu_set_t *arg_cpuset = NULL;
-static unsigned arg_cpuset_ncpus = 0;
+static CPUSet arg_cpu_set = {};
static ResolvConfMode arg_resolv_conf = RESOLV_CONF_AUTO;
static TimezoneMode arg_timezone = TIMEZONE_AUTO;
static unsigned arg_console_width = (unsigned) -1, arg_console_height = (unsigned) -1;
@@ -259,7 +258,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_syscall_blacklist, strv_freep);
#if HAVE_SECCOMP
STATIC_DESTRUCTOR_REGISTER(arg_seccomp, seccomp_releasep);
#endif
-STATIC_DESTRUCTOR_REGISTER(arg_cpuset, CPU_FREEp);
+STATIC_DESTRUCTOR_REGISTER(arg_cpu_set, cpu_set_reset);
STATIC_DESTRUCTOR_REGISTER(arg_sysctl, strv_freep);
static int help(void) {
@@ -1329,17 +1328,14 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_CPU_AFFINITY: {
- _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
+ CPUSet cpuset;
r = parse_cpu_set(optarg, &cpuset);
if (r < 0)
- return log_error_errno(r, "Failed to parse CPU affinity mask: %s", optarg);
+ return log_error_errno(r, "Failed to parse CPU affinity mask %s: %m", optarg);
- if (arg_cpuset)
- CPU_FREE(arg_cpuset);
-
- arg_cpuset = TAKE_PTR(cpuset);
- arg_cpuset_ncpus = r;
+ cpu_set_reset(&arg_cpu_set);
+ arg_cpu_set = cpuset;
arg_settings_mask |= SETTING_CPU_AFFINITY;
break;
}
@@ -2922,8 +2918,8 @@ static int inner_child(
return log_error_errno(r, "Failed to adjust OOM score: %m");
}
- if (arg_cpuset)
- if (sched_setaffinity(0, CPU_ALLOC_SIZE(arg_cpuset_ncpus), arg_cpuset) < 0)
+ if (arg_cpu_set.set)
+ if (sched_setaffinity(0, arg_cpu_set.allocated, arg_cpu_set.set) < 0)
return log_error_errno(errno, "Failed to set CPU affinity: %m");
(void) setup_hostname();
@@ -3869,15 +3865,14 @@ static int merge_settings(Settings *settings, const char *path) {
}
if ((arg_settings_mask & SETTING_CPU_AFFINITY) == 0 &&
- settings->cpuset) {
+ settings->cpu_set.set) {
if (!arg_settings_trusted)
log_warning("Ignoring CPUAffinity= setting, file '%s' is not trusted.", path);
else {
- if (arg_cpuset)
- CPU_FREE(arg_cpuset);
- arg_cpuset = TAKE_PTR(settings->cpuset);
- arg_cpuset_ncpus = settings->cpuset_ncpus;
+ cpu_set_reset(&arg_cpu_set);
+ arg_cpu_set = settings->cpu_set;
+ settings->cpu_set = (CPUSet) {};
}
}
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 2b425efc9c..e4889dc55d 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -992,13 +992,13 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
}
if (streq(field, "CPUAffinity")) {
- _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
+ _cleanup_(cpu_set_reset) CPUSet cpuset = {};
r = parse_cpu_set(eq, &cpuset);
if (r < 0)
return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
- return bus_append_byte_array(m, field, cpuset, CPU_ALLOC_SIZE(r));
+ return bus_append_byte_array(m, field, cpuset.set, cpuset.allocated);
}
if (STR_IN_SET(field, "RestrictAddressFamilies", "SystemCallFilter")) {
diff --git a/src/shared/cpu-set-util.c b/src/shared/cpu-set-util.c
index aa5c4d110d..b8d13a2ba6 100644
--- a/src/shared/cpu-set-util.c
+++ b/src/shared/cpu-set-util.c
@@ -10,16 +10,17 @@
#include "extract-word.h"
#include "log.h"
#include "macro.h"
+#include "memory-util.h"
#include "parse-util.h"
#include "string-util.h"
-char* cpu_set_to_string(const cpu_set_t *set, size_t setsize) {
+char* cpu_set_to_string(const CPUSet *a) {
_cleanup_free_ char *str = NULL;
size_t allocated = 0, len = 0;
int i, r;
- for (i = 0; (size_t) i < setsize * 8; i++) {
- if (!CPU_ISSET_S(i, setsize, set))
+ for (i = 0; (size_t) i < a->allocated * 8; i++) {
+ if (!CPU_ISSET_S(i, a->allocated, a->set))
continue;
if (!GREEDY_REALLOC(str, allocated, len + 1 + DECIMAL_STR_MAX(int)))
@@ -62,24 +63,74 @@ cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
}
}
-int parse_cpu_set_internal(
+static int cpu_set_realloc(CPUSet *cpu_set, unsigned ncpus) {
+ size_t need;
+
+ assert(cpu_set);
+
+ need = CPU_ALLOC_SIZE(ncpus);
+ if (need > cpu_set->allocated) {
+ cpu_set_t *t;
+
+ t = realloc(cpu_set->set, need);
+ if (!t)
+ return -ENOMEM;
+
+ memzero((uint8_t*) t + cpu_set->allocated, need - cpu_set->allocated);
+
+ cpu_set->set = t;
+ cpu_set->allocated = need;
+ }
+
+ return 0;
+}
+
+static int cpu_set_add(CPUSet *cpu_set, unsigned cpu) {
+ int r;
+
+ if (cpu >= 8192)
+ /* As of kernel 5.1, CONFIG_NR_CPUS can be set to 8192 on PowerPC */
+ return -ERANGE;
+
+ r = cpu_set_realloc(cpu_set, cpu + 1);
+ if (r < 0)
+ return r;
+
+ CPU_SET_S(cpu, cpu_set->allocated, cpu_set->set);
+ return 0;
+}
+
+int cpu_set_add_all(CPUSet *a, const CPUSet *b) {
+ int r;
+
+ /* Do this backwards, so if we fail, we fail before changing anything. */
+ for (unsigned cpu_p1 = b->allocated * 8; cpu_p1 > 0; cpu_p1--)
+ if (CPU_ISSET_S(cpu_p1 - 1, b->allocated, b->set)) {
+ r = cpu_set_add(a, cpu_p1 - 1);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+int parse_cpu_set_full(
const char *rvalue,
- cpu_set_t **cpu_set,
+ CPUSet *cpu_set,
bool warn,
const char *unit,
const char *filename,
unsigned line,
const char *lvalue) {
- _cleanup_cpu_free_ cpu_set_t *c = NULL;
+ _cleanup_(cpu_set_reset) CPUSet c = {};
const char *p = rvalue;
- unsigned ncpus = 0;
- assert(rvalue);
+ assert(p);
for (;;) {
_cleanup_free_ char *word = NULL;
- unsigned cpu, cpu_lower, cpu_upper;
+ unsigned cpu_lower, cpu_upper;
int r;
r = extract_first_word(&p, &word, WHITESPACE ",", EXTRACT_QUOTES);
@@ -90,31 +141,63 @@ int parse_cpu_set_internal(
if (r == 0)
break;
- if (!c) {
- c = cpu_set_malloc(&ncpus);
- if (!c)
- return warn ? log_oom() : -ENOMEM;
- }
-
r = parse_range(word, &cpu_lower, &cpu_upper);
if (r < 0)
return warn ? log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU affinity '%s'", word) : r;
- if (cpu_lower >= ncpus || cpu_upper >= ncpus)
- return warn ? log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU out of range '%s' ncpus is %u", word, ncpus) : -EINVAL;
if (cpu_lower > cpu_upper) {
if (warn)
- log_syntax(unit, LOG_WARNING, filename, line, 0, "Range '%s' is invalid, %u > %u, ignoring", word, cpu_lower, cpu_upper);
- continue;
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Range '%s' is invalid, %u > %u, ignoring.",
+ word, cpu_lower, cpu_upper);
+
+ /* Make sure something is allocated, to distinguish this from the empty case */
+ r = cpu_set_realloc(&c, 1);
+ if (r < 0)
+ return r;
}
- for (cpu = cpu_lower; cpu <= cpu_upper; cpu++)
- CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c);
+ for (unsigned cpu_p1 = MIN(cpu_upper, UINT_MAX-1) + 1; cpu_p1 > cpu_lower; cpu_p1--) {
+ r = cpu_set_add(&c, cpu_p1 - 1);
+ if (r < 0)
+ return warn ? log_syntax(unit, LOG_ERR, filename, line, r,
+ "Cannot add CPU %u to set: %m", cpu_p1 - 1) : r;
+ }
}
- /* On success, sets *cpu_set and returns ncpus for the system. */
- if (c)
- *cpu_set = TAKE_PTR(c);
+ /* On success, transfer ownership to the output variable */
+ *cpu_set = c;
+ c = (CPUSet) {};
+
+ return 0;
+}
+
+int parse_cpu_set_extend(
+ const char *rvalue,
+ CPUSet *old,
+ bool warn,
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *lvalue) {
+
+ _cleanup_(cpu_set_reset) CPUSet cpuset = {};
+ int r;
+
+ r = parse_cpu_set_full(rvalue, &cpuset, true, unit, filename, line, lvalue);
+ if (r < 0)
+ return r;
+
+ if (!cpuset.set) {
+ /* An empty assignment resets the CPU list */
+ cpu_set_reset(old);
+ return 0;
+ }
+
+ if (!old->set) {
+ *old = cpuset;
+ cpuset = (CPUSet) {};
+ return 0;
+ }
- return (int) ncpus;
+ return cpu_set_add_all(old, &cpuset);
}
diff --git a/src/shared/cpu-set-util.h b/src/shared/cpu-set-util.h
index 9574b81582..4c1c81fc59 100644
--- a/src/shared/cpu-set-util.h
+++ b/src/shared/cpu-set-util.h
@@ -8,23 +8,40 @@
DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE);
#define _cleanup_cpu_free_ _cleanup_(CPU_FREEp)
-static inline cpu_set_t* cpu_set_mfree(cpu_set_t *p) {
- if (p)
- CPU_FREE(p);
- return NULL;
-}
-
cpu_set_t* cpu_set_malloc(unsigned *ncpus);
-char* cpu_set_to_string(const cpu_set_t *set, size_t setsize);
-int parse_cpu_set_internal(const char *rvalue, cpu_set_t **cpu_set, bool warn, const char *unit, const char *filename, unsigned line, const char *lvalue);
-
-static inline 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) {
- assert(lvalue);
-
- return parse_cpu_set_internal(rvalue, cpu_set, true, unit, filename, line, lvalue);
+/* This wraps the libc interface with a variable to keep the allocated size. */
+typedef struct CPUSet {
+ cpu_set_t *set;
+ size_t allocated; /* in bytes */
+} CPUSet;
+
+static inline void cpu_set_reset(CPUSet *a) {
+ assert((a->allocated > 0) == !!a->set);
+ if (a->set)
+ CPU_FREE(a->set);
+ *a = (CPUSet) {};
}
-static inline int parse_cpu_set(const char *rvalue, cpu_set_t **cpu_set){
- return parse_cpu_set_internal(rvalue, cpu_set, false, NULL, NULL, 0, NULL);
+int cpu_set_add_all(CPUSet *a, const CPUSet *b);
+
+char* cpu_set_to_string(const CPUSet *a);
+int parse_cpu_set_full(
+ const char *rvalue,
+ CPUSet *cpu_set,
+ bool warn,
+ const char *unit,
+ const char *filename, unsigned line,
+ const char *lvalue);
+int parse_cpu_set_extend(
+ const char *rvalue,
+ CPUSet *old,
+ bool warn,
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *lvalue);
+
+static inline int parse_cpu_set(const char *rvalue, CPUSet *cpu_set){
+ return parse_cpu_set_full(rvalue, cpu_set, false, NULL, NULL, 0, NULL);
}
diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c
index ff5edb2a69..8c17931f84 100644
--- a/src/test/test-cpu-set-util.c
+++ b/src/test/test-cpu-set-util.c
@@ -5,150 +5,165 @@
#include "macro.h"
static void test_parse_cpu_set(void) {
- cpu_set_t *c = NULL;
+ CPUSet c = {};
_cleanup_free_ char *str = 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);
-
- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ assert_se(parse_cpu_set_full("1 2", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(c.set);
+ assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(CPU_ISSET_S(1, c.allocated, c.set));
+ assert_se(CPU_ISSET_S(2, c.allocated, c.set));
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 2);
+
+ assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
- c = cpu_set_mfree(c);
+ cpu_set_reset(&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);
+ assert_se(parse_cpu_set_full("0 1 2 3 8 9 10 11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
for (cpu = 0; cpu < 4; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
for (cpu = 8; cpu < 12; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
+ assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
- c = cpu_set_mfree(c);
+ cpu_set_reset(&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);
+ assert_se(parse_cpu_set_full("8 '9' 10 \"11\"", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 4);
for (cpu = 8; cpu < 12; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
+ assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
- c = cpu_set_mfree(c);
+ cpu_set_reset(&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);
+ assert_se(parse_cpu_set_full("0,1,2,3 8,9,10,11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
for (cpu = 0; cpu < 4; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
for (cpu = 8; cpu < 12; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
+ assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
- c = cpu_set_mfree(c);
+ cpu_set_reset(&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);
+ assert_se(parse_cpu_set_full("0, 1, 2, 3, 4, 5, 6, 7, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
for (cpu = 0; cpu < 8; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
+ assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
- c = cpu_set_mfree(c);
+ cpu_set_reset(&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);
+ assert_se(parse_cpu_set_full("0-3,8-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
for (cpu = 0; cpu < 4; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
for (cpu = 8; cpu < 12; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
+ assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
- c = cpu_set_mfree(c);
+ cpu_set_reset(&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);
+ assert_se(parse_cpu_set_full("0-3 8-11, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
for (cpu = 0; cpu < 4; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
for (cpu = 8; cpu < 12; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
+ assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
- c = cpu_set_mfree(c);
+ cpu_set_reset(&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 = cpu_set_mfree(c);
+ assert_se(parse_cpu_set_full("3-0", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 0);
+ cpu_set_reset(&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);
+ assert_se(parse_cpu_set_full("0-7 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 12);
for (cpu = 0; cpu < 12; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
+ assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
- c = cpu_set_mfree(c);
+ cpu_set_reset(&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));
+ assert_se(parse_cpu_set_full("0,1 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 10);
+ assert_se(CPU_ISSET_S(0, c.allocated, c.set));
+ assert_se(CPU_ISSET_S(1, c.allocated, c.set));
for (cpu = 4; cpu < 12; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
+ assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
- c = cpu_set_mfree(c);
+ cpu_set_reset(&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);
+ assert_se(parse_cpu_set_full("0 1 2 3 garbage", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL);
+ assert_se(!c.set);
+ assert_se(c.allocated == 0);
/* 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);
+ assert_se(parse_cpu_set_full("0-3 8-garbage", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL);
+ assert_se(!c.set);
+ assert_se(c.allocated == 0);
/* 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);
+ assert_se(parse_cpu_set_full("", &c, true, NULL, "fake", 1, "CPUAffinity") == 0);
+ assert_se(!c.set); /* empty string returns NULL */
+ assert_se(c.allocated == 0);
/* 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);
+ assert_se(parse_cpu_set_full("0 1 2 3 \"4 5 6 7 ", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL);
+ assert_se(!c.set);
+ assert_se(c.allocated == 0);
+
+ /* Maximum allocation */
+ assert_se(parse_cpu_set_full("8000-8191", &c, true, NULL, "fake", 1, "CPUAffinity") == 0);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 192);
+ assert_se(str = cpu_set_to_string(&c));
+ log_info("cpu_set_to_string: %s", str);
+ str = mfree(str);
+ cpu_set_reset(&c);
}
int main(int argc, char *argv[]) {
+ log_info("CPU_ALLOC_SIZE(1) = %zu", CPU_ALLOC_SIZE(1));
+ log_info("CPU_ALLOC_SIZE(9) = %zu", CPU_ALLOC_SIZE(9));
+ log_info("CPU_ALLOC_SIZE(64) = %zu", CPU_ALLOC_SIZE(64));
+ log_info("CPU_ALLOC_SIZE(65) = %zu", CPU_ALLOC_SIZE(65));
+ log_info("CPU_ALLOC_SIZE(1024) = %zu", CPU_ALLOC_SIZE(1024));
+ log_info("CPU_ALLOC_SIZE(1025) = %zu", CPU_ALLOC_SIZE(1025));
+ log_info("CPU_ALLOC_SIZE(8191) = %zu", CPU_ALLOC_SIZE(8191));
+
test_parse_cpu_set();
return 0;
diff --git a/src/test/test-sizeof.c b/src/test/test-sizeof.c
index 35b087653e..7fc16a62b6 100644
--- a/src/test/test-sizeof.c
+++ b/src/test/test-sizeof.c
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <sched.h>
#include <stdio.h>
#include <string.h>
@@ -65,6 +66,8 @@ int main(void) {
info(uid_t);
info(gid_t);
+ info(__cpu_mask);
+
info(enum Enum);
info(enum BigEnum);
info(enum BigEnum2);