]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/cpu-set-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
8 #include "alloc-util.h"
9 #include "cpu-set-util.h"
10 #include "extract-word.h"
13 #include "memory-util.h"
14 #include "parse-util.h"
15 #include "string-util.h"
17 char* cpu_set_to_string(const CPUSet
*a
) {
18 _cleanup_free_
char *str
= NULL
;
19 size_t allocated
= 0, len
= 0;
22 for (i
= 0; (size_t) i
< a
->allocated
* 8; i
++) {
23 if (!CPU_ISSET_S(i
, a
->allocated
, a
->set
))
26 if (!GREEDY_REALLOC(str
, allocated
, len
+ 1 + DECIMAL_STR_MAX(int)))
29 r
= sprintf(str
+ len
, len
> 0 ? " %d" : "%d", i
);
34 return TAKE_PTR(str
) ?: strdup("");
37 cpu_set_t
* cpu_set_malloc(unsigned *ncpus
) {
41 /* Allocates the cpuset in the right size */
48 if (sched_getaffinity(0, CPU_ALLOC_SIZE(n
), c
) >= 0) {
49 CPU_ZERO_S(CPU_ALLOC_SIZE(n
), c
);
66 static int cpu_set_realloc(CPUSet
*cpu_set
, unsigned ncpus
) {
71 need
= CPU_ALLOC_SIZE(ncpus
);
72 if (need
> cpu_set
->allocated
) {
75 t
= realloc(cpu_set
->set
, need
);
79 memzero((uint8_t*) t
+ cpu_set
->allocated
, need
- cpu_set
->allocated
);
82 cpu_set
->allocated
= need
;
88 static int cpu_set_add(CPUSet
*cpu_set
, unsigned cpu
) {
92 /* As of kernel 5.1, CONFIG_NR_CPUS can be set to 8192 on PowerPC */
95 r
= cpu_set_realloc(cpu_set
, cpu
+ 1);
99 CPU_SET_S(cpu
, cpu_set
->allocated
, cpu_set
->set
);
103 int cpu_set_add_all(CPUSet
*a
, const CPUSet
*b
) {
106 /* Do this backwards, so if we fail, we fail before changing anything. */
107 for (unsigned cpu_p1
= b
->allocated
* 8; cpu_p1
> 0; cpu_p1
--)
108 if (CPU_ISSET_S(cpu_p1
- 1, b
->allocated
, b
->set
)) {
109 r
= cpu_set_add(a
, cpu_p1
- 1);
117 int parse_cpu_set_full(
122 const char *filename
,
124 const char *lvalue
) {
126 _cleanup_(cpu_set_reset
) CPUSet c
= {};
127 const char *p
= rvalue
;
132 _cleanup_free_
char *word
= NULL
;
133 unsigned cpu_lower
, cpu_upper
;
136 r
= extract_first_word(&p
, &word
, WHITESPACE
",", EXTRACT_QUOTES
);
138 return warn
? log_oom() : -ENOMEM
;
140 return warn
? log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid value for %s: %s", lvalue
, rvalue
) : r
;
144 r
= parse_range(word
, &cpu_lower
, &cpu_upper
);
146 return warn
? log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse CPU affinity '%s'", word
) : r
;
148 if (cpu_lower
> cpu_upper
) {
150 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Range '%s' is invalid, %u > %u, ignoring.",
151 word
, cpu_lower
, cpu_upper
);
153 /* Make sure something is allocated, to distinguish this from the empty case */
154 r
= cpu_set_realloc(&c
, 1);
159 for (unsigned cpu_p1
= MIN(cpu_upper
, UINT_MAX
-1) + 1; cpu_p1
> cpu_lower
; cpu_p1
--) {
160 r
= cpu_set_add(&c
, cpu_p1
- 1);
162 return warn
? log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
163 "Cannot add CPU %u to set: %m", cpu_p1
- 1) : r
;
167 /* On success, transfer ownership to the output variable */
174 int parse_cpu_set_extend(
179 const char *filename
,
181 const char *lvalue
) {
183 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
186 r
= parse_cpu_set_full(rvalue
, &cpuset
, true, unit
, filename
, line
, lvalue
);
191 /* An empty assignment resets the CPU list */
198 cpuset
= (CPUSet
) {};
202 return cpu_set_add_all(old
, &cpuset
);
205 int cpus_in_affinity_mask(void) {
216 if (sched_getaffinity(0, CPU_ALLOC_SIZE(n
), c
) >= 0) {
219 k
= CPU_COUNT_S(CPU_ALLOC_SIZE(n
), c
);