1/* @title: CPU Mask */
2#pragma once
3#include <compiler/diagnostic.h>
4#include <math/align.h>
5#include <stdbool.h>
6#include <stddef.h>
7#include <stdint.h>
8#include <string.h>
9#include <structures/bitmap.h>
10
11#ifndef CPU_MASK_BITS
12#define CPU_MASK_BITS 128
13#endif
14
15#define CPU_MASK_WORD_BITS 64
16#define CPU_MASK_WORDS BITMAP_WORDS_CONST(CPU_MASK_BITS)
17
18struct cpu_mask {
19 BITMAP_DECLARE(bits, CPU_MASK_BITS);
20};
21
22#define CPU_MASK_INIT \
23 (struct cpu_mask) { \
24 .bits = {0} \
25 }
26
27#define CPU_MASK_LAST_WORD_BITS ((CPU_MASK_BITS) % CPU_MASK_WORD_BITS)
28
29#define CPU_MASK_INIT_ALL \
30 cc_wno_override_init_expr( \
31 struct cpu_mask, \
32 ((struct cpu_mask) { \
33 .bits = { \
34 [0 ...(CPU_MASK_WORDS - 1)] = ~(bitmap_word_t) 0, \
35 [CPU_MASK_WORDS - 1] = \
36 (CPU_MASK_LAST_WORD_BITS == 0) \
37 ? ~(bitmap_word_t) 0 \
38 : (((bitmap_word_t) 1 << CPU_MASK_LAST_WORD_BITS) - \
39 1)}}))
40
41/* Used to overload cpu_mask to carry an error at times */
42#define CPU_MASK_ERR(e) \
43 (struct cpu_mask) { \
44 .bits = {(bitmap_word_t) (e) } \
45 }
46
47static inline void cpu_mask_init(struct cpu_mask *m, size_t nbits) {
48 cc_ignore(nbits);
49 memset(m->bits, 0, sizeof(m->bits));
50}
51
52struct cpu_mask *cpu_mask_create(void);
53void cpu_mask_free(struct cpu_mask *m);
54
55static inline void cpu_mask_copy(struct cpu_mask *dst,
56 const struct cpu_mask *src) {
57 *dst = *src;
58}
59
60static inline void cpu_mask_set(struct cpu_mask *m, size_t cpu) {
61 if (cpu < CPU_MASK_BITS) {
62 bitmap_set(map: m->bits, bit: cpu);
63 }
64}
65
66/* Mask with only `cpu` set, usable as a runtime initializer */
67static inline struct cpu_mask cpu_mask_of(size_t cpu) {
68 struct cpu_mask m = CPU_MASK_INIT;
69 cpu_mask_set(m: &m, cpu);
70 return m;
71}
72
73static inline void cpu_mask_clear(struct cpu_mask *m, size_t cpu) {
74 if (cpu < CPU_MASK_BITS) {
75 bitmap_clear(map: m->bits, bit: cpu);
76 }
77}
78
79static inline void cpu_mask_toggle(struct cpu_mask *m, size_t cpu) {
80 if (cpu < CPU_MASK_BITS) {
81 bitmap_toggle(map: m->bits, bit: cpu);
82 }
83}
84
85static inline bool cpu_mask_test(const struct cpu_mask *m, size_t cpu) {
86 return (cpu < CPU_MASK_BITS) ? bitmap_test(map: m->bits, bit: cpu) : false;
87}
88
89static inline bool cpu_mask_test_and_set(struct cpu_mask *m, size_t cpu) {
90 return (cpu < CPU_MASK_BITS) ? bitmap_test_and_set(map: m->bits, bit: cpu) : false;
91}
92
93static inline bool cpu_mask_test_and_clear(struct cpu_mask *m, size_t cpu) {
94 return (cpu < CPU_MASK_BITS) ? bitmap_test_and_clear(map: m->bits, bit: cpu) : false;
95}
96
97static inline void cpu_mask_set_atomic(struct cpu_mask *m, size_t cpu) {
98 if (cpu < CPU_MASK_BITS) {
99 bitmap_atomic_set(map: m->bits, bit: cpu);
100 }
101}
102
103static inline void cpu_mask_clear_atomic(struct cpu_mask *m, size_t cpu) {
104 if (cpu < CPU_MASK_BITS) {
105 bitmap_atomic_clear(map: m->bits, bit: cpu);
106 }
107}
108
109static inline void cpu_mask_toggle_atomic(struct cpu_mask *m, size_t cpu) {
110 if (cpu < CPU_MASK_BITS) {
111 bitmap_atomic_toggle(map: m->bits, bit: cpu);
112 }
113}
114
115static inline bool cpu_mask_test_atomic(const struct cpu_mask *m, size_t cpu) {
116 return (cpu < CPU_MASK_BITS) ? bitmap_atomic_test(map: m->bits, bit: cpu) : false;
117}
118
119static inline bool cpu_mask_test_and_set_atomic(struct cpu_mask *m,
120 size_t cpu) {
121 return (cpu < CPU_MASK_BITS) ? bitmap_atomic_test_and_set(map: m->bits, bit: cpu)
122 : false;
123}
124
125static inline bool cpu_mask_test_and_clear_atomic(struct cpu_mask *m,
126 size_t cpu) {
127 return (cpu < CPU_MASK_BITS) ? bitmap_atomic_test_and_clear(map: m->bits, bit: cpu)
128 : false;
129}
130
131static inline void cpu_mask_clear_all(struct cpu_mask *m) {
132 bitmap_zero(map: m->bits, CPU_MASK_BITS);
133}
134
135static inline void cpu_mask_zero(struct cpu_mask *m) {
136 bitmap_zero(map: m->bits, CPU_MASK_BITS);
137}
138
139static inline void cpu_mask_fill(struct cpu_mask *m) {
140 bitmap_fill(map: m->bits, CPU_MASK_BITS);
141}
142
143#define cpu_mask_active_bits \
144 (global.core_count && global.core_count <= CPU_MASK_BITS \
145 ? global.core_count \
146 : CPU_MASK_BITS)
147
148#define cpu_mask_set_all(m) bitmap_fill((m)->bits, cpu_mask_active_bits)
149
150static inline void cpu_mask_set_range(struct cpu_mask *m, size_t start,
151 size_t len) {
152 bitmap_set_range(map: m->bits, start, len);
153}
154
155static inline void cpu_mask_clear_range(struct cpu_mask *m, size_t start,
156 size_t len) {
157 bitmap_clear_range(map: m->bits, start, len);
158}
159
160static inline void cpu_mask_or(struct cpu_mask *dst, const struct cpu_mask *b) {
161 bitmap_or(dst: dst->bits, src1: dst->bits, src2: b->bits, CPU_MASK_BITS);
162}
163
164static inline void cpu_mask_or2(struct cpu_mask *dst, const struct cpu_mask *a,
165 const struct cpu_mask *b) {
166 bitmap_or(dst: dst->bits, src1: a->bits, src2: b->bits, CPU_MASK_BITS);
167}
168
169static inline void cpu_mask_and(struct cpu_mask *dst, const struct cpu_mask *a,
170 const struct cpu_mask *b) {
171 bitmap_and(dst: dst->bits, src1: a->bits, src2: b->bits, CPU_MASK_BITS);
172}
173
174static inline void cpu_mask_xor(struct cpu_mask *dst, const struct cpu_mask *a,
175 const struct cpu_mask *b) {
176 bitmap_xor(dst: dst->bits, src1: a->bits, src2: b->bits, CPU_MASK_BITS);
177}
178
179static inline void cpu_mask_andnot(struct cpu_mask *dst,
180 const struct cpu_mask *a,
181 const struct cpu_mask *b) {
182 bitmap_andnot(dst: dst->bits, src1: a->bits, src2: b->bits, CPU_MASK_BITS);
183}
184
185static inline bool cpu_mask_intersects(const struct cpu_mask *a,
186 const struct cpu_mask *b) {
187 return bitmap_intersects(src1: a->bits, src2: b->bits, CPU_MASK_BITS);
188}
189
190static inline bool cpu_mask_equal(const struct cpu_mask *a,
191 const struct cpu_mask *b) {
192 return bitmap_equal(src1: a->bits, src2: b->bits, CPU_MASK_BITS);
193}
194
195static inline bool cpu_mask_subset(const struct cpu_mask *subset,
196 const struct cpu_mask *superset) {
197 return bitmap_subset(subset: subset->bits, superset: superset->bits, CPU_MASK_BITS);
198}
199
200static inline size_t cpu_mask_popcount(const struct cpu_mask *m) {
201 return bitmap_weight(map: m->bits, CPU_MASK_BITS);
202}
203
204static inline size_t cpu_mask_weight(const struct cpu_mask *m) {
205 return bitmap_weight(map: m->bits, CPU_MASK_BITS);
206}
207
208static inline bool cpu_mask_empty(const struct cpu_mask *m) {
209 return bitmap_empty(map: m->bits, CPU_MASK_BITS);
210}
211
212static inline bool cpu_mask_full(const struct cpu_mask *m) {
213 return bitmap_full(map: m->bits, CPU_MASK_BITS);
214}
215
216static inline size_t cpu_mask_first_set(const struct cpu_mask *m) {
217 return bitmap_find_first_set(map: m->bits, CPU_MASK_BITS);
218}
219
220static inline size_t cpu_mask_first_clear(const struct cpu_mask *m) {
221 return bitmap_find_first_zero(map: m->bits, CPU_MASK_BITS);
222}
223
224static inline size_t cpu_mask_next_set(const struct cpu_mask *m, size_t start) {
225 return bitmap_find_next_bit(map: m->bits, CPU_MASK_BITS, start);
226}
227
228static inline size_t cpu_mask_next_clear(const struct cpu_mask *m,
229 size_t start) {
230 return bitmap_find_next_zero_bit(map: m->bits, CPU_MASK_BITS, start);
231}
232
233#define for_each_cpu(cpu, mask_ptr) \
234 for ((cpu) = \
235 bitmap_find_first_set((mask_ptr)->bits, cpu_mask_active_bits); \
236 (cpu) < cpu_mask_active_bits; \
237 (cpu) = bitmap_find_next_bit((mask_ptr)->bits, cpu_mask_active_bits, \
238 (cpu) + 1))
239
240#define cpu_mask_for_each(iter, mask) \
241 for (iter = 0; iter < cpu_mask_active_bits; iter++) \
242 if (bitmap_test((mask).bits, iter))
243
244#define cpu_mask_for_each_atomic(iter, mask) \
245 for (iter = 0; iter < cpu_mask_active_bits; iter++) \
246 if (bitmap_atomic_test((mask).bits, iter))
247
248#define cpu_mask_for_each_clear(iter, mask) \
249 for (iter = 0; iter < cpu_mask_active_bits; iter++) \
250 if (!bitmap_test((mask).bits, iter))
251
252#define cpu_mask_for_all(iter, mask) \
253 for (iter = 0; iter < cpu_mask_active_bits; iter++)
254
255#define cpu_mask_for_each_in(iter, mask, start, end) \
256 for (iter = (start); iter < cpu_mask_active_bits && iter <= (end); iter++) \
257 if (bitmap_test((mask).bits, iter))
258
259#define cpu_mask_for_each_clear_in(iter, mask, start, end) \
260 for (iter = (start); iter < cpu_mask_active_bits && iter <= (end); iter++) \
261 if (!bitmap_test((mask).bits, iter))
262