]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/cpu-set-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
8 #include "alloc-util.h"
9 #include "cpu-set-util.h"
10 #include "dirent-util.h"
11 #include "errno-util.h"
12 #include "extract-word.h"
16 #include "memory-util.h"
17 #include "parse-util.h"
18 #include "stat-util.h"
19 #include "string-util.h"
22 char* cpu_set_to_string(const CPUSet
*a
) {
23 _cleanup_free_
char *str
= NULL
;
27 for (i
= 0; (size_t) i
< a
->allocated
* 8; i
++) {
28 if (!CPU_ISSET_S(i
, a
->allocated
, a
->set
))
31 if (!GREEDY_REALLOC(str
, len
+ 1 + DECIMAL_STR_MAX(int)))
34 r
= sprintf(str
+ len
, len
> 0 ? " %d" : "%d", i
);
39 return TAKE_PTR(str
) ?: strdup("");
42 char *cpu_set_to_range_string(const CPUSet
*set
) {
43 unsigned range_start
= 0, range_end
;
44 _cleanup_free_
char *str
= NULL
;
45 bool in_range
= false;
49 for (unsigned i
= 0; i
< set
->allocated
* 8; i
++)
50 if (CPU_ISSET_S(i
, set
->allocated
, set
->set
)) {
54 range_start
= range_end
= i
;
57 } else if (in_range
) {
60 if (!GREEDY_REALLOC(str
, len
+ 2 + 2 * DECIMAL_STR_MAX(unsigned)))
63 if (range_end
> range_start
)
64 r
= sprintf(str
+ len
, len
> 0 ? " %u-%u" : "%u-%u", range_start
, range_end
);
66 r
= sprintf(str
+ len
, len
> 0 ? " %u" : "%u", range_start
);
72 if (!GREEDY_REALLOC(str
, len
+ 2 + 2 * DECIMAL_STR_MAX(int)))
75 if (range_end
> range_start
)
76 r
= sprintf(str
+ len
, len
> 0 ? " %u-%u" : "%u-%u", range_start
, range_end
);
78 r
= sprintf(str
+ len
, len
> 0 ? " %u" : "%u", range_start
);
82 return TAKE_PTR(str
) ?: strdup("");
85 int cpu_set_realloc(CPUSet
*cpu_set
, unsigned ncpus
) {
90 need
= CPU_ALLOC_SIZE(ncpus
);
91 if (need
> cpu_set
->allocated
) {
94 t
= realloc(cpu_set
->set
, need
);
98 memzero((uint8_t*) t
+ cpu_set
->allocated
, need
- cpu_set
->allocated
);
101 cpu_set
->allocated
= need
;
107 int cpu_set_add(CPUSet
*cpu_set
, unsigned cpu
) {
111 /* As of kernel 5.1, CONFIG_NR_CPUS can be set to 8192 on PowerPC */
114 r
= cpu_set_realloc(cpu_set
, cpu
+ 1);
118 CPU_SET_S(cpu
, cpu_set
->allocated
, cpu_set
->set
);
122 int cpu_set_add_all(CPUSet
*a
, const CPUSet
*b
) {
125 /* Do this backwards, so if we fail, we fail before changing anything. */
126 for (unsigned cpu_p1
= b
->allocated
* 8; cpu_p1
> 0; cpu_p1
--)
127 if (CPU_ISSET_S(cpu_p1
- 1, b
->allocated
, b
->set
)) {
128 r
= cpu_set_add(a
, cpu_p1
- 1);
136 int parse_cpu_set_full(
141 const char *filename
,
143 const char *lvalue
) {
145 _cleanup_(cpu_set_reset
) CPUSet c
= {};
146 const char *p
= ASSERT_PTR(rvalue
);
151 _cleanup_free_
char *word
= NULL
;
152 unsigned cpu_lower
, cpu_upper
;
155 r
= extract_first_word(&p
, &word
, WHITESPACE
",", EXTRACT_UNQUOTE
);
157 return warn
? log_oom() : -ENOMEM
;
159 return warn
? log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid value for %s: %s", lvalue
, rvalue
) : r
;
163 r
= parse_range(word
, &cpu_lower
, &cpu_upper
);
165 return warn
? log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse CPU affinity '%s'", word
) : r
;
167 if (cpu_lower
> cpu_upper
) {
169 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Range '%s' is invalid, %u > %u, ignoring.",
170 word
, cpu_lower
, cpu_upper
);
172 /* Make sure something is allocated, to distinguish this from the empty case */
173 r
= cpu_set_realloc(&c
, 1);
178 for (unsigned cpu_p1
= MIN(cpu_upper
, UINT_MAX
-1) + 1; cpu_p1
> cpu_lower
; cpu_p1
--) {
179 r
= cpu_set_add(&c
, cpu_p1
- 1);
181 return warn
? log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
182 "Cannot add CPU %u to set: %m", cpu_p1
- 1) : r
;
186 *cpu_set
= TAKE_STRUCT(c
);
191 int parse_cpu_set_extend(
196 const char *filename
,
198 const char *lvalue
) {
200 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
205 r
= parse_cpu_set_full(rvalue
, &cpuset
, true, unit
, filename
, line
, lvalue
);
210 /* An empty assignment resets the CPU list */
216 *old
= TAKE_STRUCT(cpuset
);
220 return cpu_set_add_all(old
, &cpuset
);
223 int cpus_in_affinity_mask(void) {
234 if (sched_getaffinity(0, CPU_ALLOC_SIZE(n
), c
) >= 0) {
237 k
= CPU_COUNT_S(CPU_ALLOC_SIZE(n
), c
);
257 int cpu_set_to_dbus(const CPUSet
*set
, uint8_t **ret
, size_t *allocated
) {
263 out
= new0(uint8_t, set
->allocated
);
267 for (unsigned cpu
= 0; cpu
< set
->allocated
* 8; cpu
++)
268 if (CPU_ISSET_S(cpu
, set
->allocated
, set
->set
))
269 out
[cpu
/ 8] |= 1u << (cpu
% 8);
272 *allocated
= set
->allocated
;
276 int cpu_set_from_dbus(const uint8_t *bits
, size_t size
, CPUSet
*set
) {
277 _cleanup_(cpu_set_reset
) CPUSet s
= {};
283 for (unsigned cpu
= size
* 8; cpu
> 0; cpu
--)
284 if (bits
[(cpu
- 1) / 8] & (1u << ((cpu
- 1) % 8))) {
285 r
= cpu_set_add(&s
, cpu
- 1);
290 *set
= TAKE_STRUCT(s
);