]>
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"
23 char* cpu_set_to_string(const CPUSet
*a
) {
24 _cleanup_free_
char *str
= NULL
;
28 for (i
= 0; (size_t) i
< a
->allocated
* 8; i
++) {
29 if (!CPU_ISSET_S(i
, a
->allocated
, a
->set
))
32 if (!GREEDY_REALLOC(str
, len
+ 1 + DECIMAL_STR_MAX(int)))
35 r
= sprintf(str
+ len
, len
> 0 ? " %d" : "%d", i
);
40 return TAKE_PTR(str
) ?: strdup("");
43 char *cpu_set_to_range_string(const CPUSet
*set
) {
44 unsigned range_start
= 0, range_end
;
45 _cleanup_free_
char *str
= NULL
;
46 bool in_range
= false;
50 for (unsigned i
= 0; i
< set
->allocated
* 8; i
++)
51 if (CPU_ISSET_S(i
, set
->allocated
, set
->set
)) {
55 range_start
= range_end
= i
;
58 } else if (in_range
) {
61 if (!GREEDY_REALLOC(str
, len
+ 2 + 2 * DECIMAL_STR_MAX(unsigned)))
64 if (range_end
> range_start
)
65 r
= sprintf(str
+ len
, len
> 0 ? " %d-%d" : "%d-%d", range_start
, range_end
);
67 r
= sprintf(str
+ len
, len
> 0 ? " %d" : "%d", range_start
);
73 if (!GREEDY_REALLOC(str
, len
+ 2 + 2 * DECIMAL_STR_MAX(int)))
76 if (range_end
> range_start
)
77 r
= sprintf(str
+ len
, len
> 0 ? " %d-%d" : "%d-%d", range_start
, range_end
);
79 r
= sprintf(str
+ len
, len
> 0 ? " %d" : "%d", range_start
);
83 return TAKE_PTR(str
) ?: strdup("");
86 int cpu_set_realloc(CPUSet
*cpu_set
, unsigned ncpus
) {
91 need
= CPU_ALLOC_SIZE(ncpus
);
92 if (need
> cpu_set
->allocated
) {
95 t
= realloc(cpu_set
->set
, need
);
99 memzero((uint8_t*) t
+ cpu_set
->allocated
, need
- cpu_set
->allocated
);
102 cpu_set
->allocated
= need
;
108 int cpu_set_add(CPUSet
*cpu_set
, unsigned cpu
) {
112 /* As of kernel 5.1, CONFIG_NR_CPUS can be set to 8192 on PowerPC */
115 r
= cpu_set_realloc(cpu_set
, cpu
+ 1);
119 CPU_SET_S(cpu
, cpu_set
->allocated
, cpu_set
->set
);
123 int cpu_set_add_all(CPUSet
*a
, const CPUSet
*b
) {
126 /* Do this backwards, so if we fail, we fail before changing anything. */
127 for (unsigned cpu_p1
= b
->allocated
* 8; cpu_p1
> 0; cpu_p1
--)
128 if (CPU_ISSET_S(cpu_p1
- 1, b
->allocated
, b
->set
)) {
129 r
= cpu_set_add(a
, cpu_p1
- 1);
137 int parse_cpu_set_full(
142 const char *filename
,
144 const char *lvalue
) {
146 _cleanup_(cpu_set_reset
) CPUSet c
= {};
147 const char *p
= rvalue
;
152 _cleanup_free_
char *word
= NULL
;
153 unsigned cpu_lower
, cpu_upper
;
156 r
= extract_first_word(&p
, &word
, WHITESPACE
",", EXTRACT_UNQUOTE
);
158 return warn
? log_oom() : -ENOMEM
;
160 return warn
? log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid value for %s: %s", lvalue
, rvalue
) : r
;
164 r
= parse_range(word
, &cpu_lower
, &cpu_upper
);
166 return warn
? log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse CPU affinity '%s'", word
) : r
;
168 if (cpu_lower
> cpu_upper
) {
170 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Range '%s' is invalid, %u > %u, ignoring.",
171 word
, cpu_lower
, cpu_upper
);
173 /* Make sure something is allocated, to distinguish this from the empty case */
174 r
= cpu_set_realloc(&c
, 1);
179 for (unsigned cpu_p1
= MIN(cpu_upper
, UINT_MAX
-1) + 1; cpu_p1
> cpu_lower
; cpu_p1
--) {
180 r
= cpu_set_add(&c
, cpu_p1
- 1);
182 return warn
? log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
183 "Cannot add CPU %u to set: %m", cpu_p1
- 1) : r
;
187 /* On success, transfer ownership to the output variable */
194 int parse_cpu_set_extend(
199 const char *filename
,
201 const char *lvalue
) {
203 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
206 r
= parse_cpu_set_full(rvalue
, &cpuset
, true, unit
, filename
, line
, lvalue
);
211 /* An empty assignment resets the CPU list */
218 cpuset
= (CPUSet
) {};
222 return cpu_set_add_all(old
, &cpuset
);
225 int cpus_in_affinity_mask(void) {
236 if (sched_getaffinity(0, CPU_ALLOC_SIZE(n
), c
) >= 0) {
239 k
= CPU_COUNT_S(CPU_ALLOC_SIZE(n
), c
);
259 int cpu_set_to_dbus(const CPUSet
*set
, uint8_t **ret
, size_t *allocated
) {
265 out
= new0(uint8_t, set
->allocated
);
269 for (unsigned cpu
= 0; cpu
< set
->allocated
* 8; cpu
++)
270 if (CPU_ISSET_S(cpu
, set
->allocated
, set
->set
))
271 out
[cpu
/ 8] |= 1u << (cpu
% 8);
274 *allocated
= set
->allocated
;
278 int cpu_set_from_dbus(const uint8_t *bits
, size_t size
, CPUSet
*set
) {
279 _cleanup_(cpu_set_reset
) CPUSet s
= {};
285 for (unsigned cpu
= size
* 8; cpu
> 0; cpu
--)
286 if (bits
[(cpu
- 1) / 8] & (1u << ((cpu
- 1) % 8))) {
287 r
= cpu_set_add(&s
, cpu
- 1);