xref: /spdk/lib/util/cpuset.c (revision 6f338d4bf3a8a91b7abe377a605a321ea2b05bf7)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright(c) Intel Corporation. All rights reserved.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/cpuset.h"
7 #include "spdk/log.h"
8 
9 struct spdk_cpuset *
10 spdk_cpuset_alloc(void)
11 {
12 	return (struct spdk_cpuset *)calloc(sizeof(struct spdk_cpuset), 1);
13 }
14 
15 void
16 spdk_cpuset_free(struct spdk_cpuset *set)
17 {
18 	free(set);
19 }
20 
21 bool
22 spdk_cpuset_equal(const struct spdk_cpuset *set1, const struct spdk_cpuset *set2)
23 {
24 	assert(set1 != NULL);
25 	assert(set2 != NULL);
26 	return memcmp(set1->cpus, set2->cpus, sizeof(set2->cpus)) == 0;
27 }
28 
29 void
30 spdk_cpuset_copy(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
31 {
32 	assert(dst != NULL);
33 	assert(src != NULL);
34 	memcpy(&dst->cpus, &src->cpus, sizeof(src->cpus));
35 }
36 
37 void
38 spdk_cpuset_negate(struct spdk_cpuset *set)
39 {
40 	unsigned int i;
41 	assert(set != NULL);
42 	for (i = 0; i < sizeof(set->cpus); i++) {
43 		set->cpus[i] = ~set->cpus[i];
44 	}
45 }
46 
47 void
48 spdk_cpuset_and(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
49 {
50 	unsigned int i;
51 	assert(dst != NULL);
52 	assert(src != NULL);
53 	for (i = 0; i < sizeof(src->cpus); i++) {
54 		dst->cpus[i] &= src->cpus[i];
55 	}
56 }
57 
58 void
59 spdk_cpuset_or(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
60 {
61 	unsigned int i;
62 	assert(dst != NULL);
63 	assert(src != NULL);
64 	for (i = 0; i < sizeof(src->cpus); i++) {
65 		dst->cpus[i] |= src->cpus[i];
66 	}
67 }
68 
69 void
70 spdk_cpuset_xor(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
71 {
72 	unsigned int i;
73 	assert(dst != NULL);
74 	assert(src != NULL);
75 	for (i = 0; i < sizeof(src->cpus); i++) {
76 		dst->cpus[i] ^= src->cpus[i];
77 	}
78 }
79 
80 void
81 spdk_cpuset_zero(struct spdk_cpuset *set)
82 {
83 	assert(set != NULL);
84 	memset(set->cpus, 0, sizeof(set->cpus));
85 }
86 
87 void
88 spdk_cpuset_set_cpu(struct spdk_cpuset *set, uint32_t cpu, bool state)
89 {
90 	assert(set != NULL);
91 	assert(cpu < sizeof(set->cpus) * 8);
92 	if (state) {
93 		set->cpus[cpu / 8] |= (1U << (cpu % 8));
94 	} else {
95 		set->cpus[cpu / 8] &= ~(1U << (cpu % 8));
96 	}
97 }
98 
99 bool
100 spdk_cpuset_get_cpu(const struct spdk_cpuset *set, uint32_t cpu)
101 {
102 	assert(set != NULL);
103 	assert(cpu < sizeof(set->cpus) * 8);
104 	return (set->cpus[cpu / 8] >> (cpu % 8)) & 1U;
105 }
106 
107 uint32_t
108 spdk_cpuset_count(const struct spdk_cpuset *set)
109 {
110 	uint32_t count = 0;
111 	uint8_t n;
112 	unsigned int i;
113 	for (i = 0; i < sizeof(set->cpus); i++) {
114 		n = set->cpus[i];
115 		while (n) {
116 			n &= (n - 1);
117 			count++;
118 		}
119 	}
120 	return count;
121 }
122 
123 const char *
124 spdk_cpuset_fmt(struct spdk_cpuset *set)
125 {
126 	uint32_t lcore, lcore_max = 0;
127 	int val, i, n;
128 	char *ptr;
129 	static const char *hex = "0123456789abcdef";
130 
131 	assert(set != NULL);
132 
133 	for (lcore = 0; lcore < sizeof(set->cpus) * 8; lcore++) {
134 		if (spdk_cpuset_get_cpu(set, lcore)) {
135 			lcore_max = lcore;
136 		}
137 	}
138 
139 	ptr = set->str;
140 	n = lcore_max / 8;
141 	val = set->cpus[n];
142 
143 	/* Store first number only if it is not leading zero */
144 	if ((val & 0xf0) != 0) {
145 		*(ptr++) = hex[(val & 0xf0) >> 4];
146 	}
147 	*(ptr++) = hex[val & 0x0f];
148 
149 	for (i = n - 1; i >= 0; i--) {
150 		val = set->cpus[i];
151 		*(ptr++) = hex[(val & 0xf0) >> 4];
152 		*(ptr++) = hex[val & 0x0f];
153 	}
154 	*ptr = '\0';
155 
156 	return set->str;
157 }
158 
159 static int
160 hex_value(uint8_t c)
161 {
162 #define V(x, y) [x] = y + 1
163 	static const int8_t val[256] = {
164 		V('0', 0), V('1', 1), V('2', 2), V('3', 3), V('4', 4),
165 		V('5', 5), V('6', 6), V('7', 7), V('8', 8), V('9', 9),
166 		V('A', 0xA), V('B', 0xB), V('C', 0xC), V('D', 0xD), V('E', 0xE), V('F', 0xF),
167 		V('a', 0xA), V('b', 0xB), V('c', 0xC), V('d', 0xD), V('e', 0xE), V('f', 0xF),
168 	};
169 #undef V
170 
171 	return val[c] - 1;
172 }
173 
174 static int
175 parse_list(const char *mask, struct spdk_cpuset *set)
176 {
177 	char *end;
178 	const char *ptr = mask;
179 	uint32_t lcore;
180 	uint32_t lcore_min, lcore_max;
181 
182 	spdk_cpuset_zero(set);
183 	lcore_min = UINT32_MAX;
184 
185 	ptr++;
186 	end = (char *)ptr;
187 	do {
188 		while (isblank(*ptr)) {
189 			ptr++;
190 		}
191 		if (*ptr == '\0' || *ptr == ']' || *ptr == '-' || *ptr == ',') {
192 			goto invalid_character;
193 		}
194 
195 		errno = 0;
196 		lcore = strtoul(ptr, &end, 10);
197 		if (errno) {
198 			SPDK_ERRLOG("Conversion of core mask in '%s' failed\n", mask);
199 			return -1;
200 		}
201 
202 		if (lcore >= sizeof(set->cpus) * 8) {
203 			SPDK_ERRLOG("Core number %" PRIu32 " is out of range in '%s'\n", lcore, mask);
204 			return -1;
205 		}
206 
207 		while (isblank(*end)) {
208 			end++;
209 		}
210 
211 		if (*end == '-') {
212 			lcore_min = lcore;
213 		} else if (*end == ',' || *end == ']') {
214 			lcore_max = lcore;
215 			if (lcore_min == UINT32_MAX) {
216 				lcore_min = lcore;
217 			}
218 			if (lcore_min > lcore_max) {
219 				SPDK_ERRLOG("Invalid range of CPUs (%" PRIu32 " > %" PRIu32 ")\n",
220 					    lcore_min, lcore_max);
221 				return -1;
222 			}
223 			for (lcore = lcore_min; lcore <= lcore_max; lcore++) {
224 				spdk_cpuset_set_cpu(set, lcore, true);
225 			}
226 			lcore_min = UINT32_MAX;
227 		} else {
228 			goto invalid_character;
229 		}
230 
231 		ptr = end + 1;
232 
233 	} while (*end != ']');
234 
235 	return 0;
236 
237 invalid_character:
238 	if (*end == '\0') {
239 		SPDK_ERRLOG("Unexpected end of core list '%s'\n", mask);
240 	} else {
241 		SPDK_ERRLOG("Parsing of core list '%s' failed on character '%c'\n", mask, *end);
242 	}
243 	return -1;
244 }
245 
246 static int
247 parse_mask(const char *mask, struct spdk_cpuset *set, size_t len)
248 {
249 	int i, j;
250 	char c;
251 	int val;
252 	uint32_t lcore = 0;
253 
254 	if (mask[0] == '0' && (mask[1] == 'x' || mask[1] == 'X')) {
255 		mask += 2;
256 		len -= 2;
257 	}
258 
259 	spdk_cpuset_zero(set);
260 	for (i = len - 1; i >= 0; i--) {
261 		c = mask[i];
262 		val = hex_value(c);
263 		if (val < 0) {
264 			/* Invalid character */
265 			SPDK_ERRLOG("Invalid character in core mask '%s' (%c)\n", mask, c);
266 			return -1;
267 		}
268 		for (j = 0; j < 4 && lcore < SPDK_CPUSET_SIZE; j++, lcore++) {
269 			if ((1 << j) & val) {
270 				spdk_cpuset_set_cpu(set, lcore, true);
271 			}
272 		}
273 	}
274 
275 	return 0;
276 }
277 
278 int
279 spdk_cpuset_parse(struct spdk_cpuset *set, const char *mask)
280 {
281 	int ret;
282 	size_t len;
283 
284 	if (mask == NULL || set == NULL) {
285 		return -1;
286 	}
287 
288 	while (isblank(*mask)) {
289 		mask++;
290 	}
291 
292 	len = strlen(mask);
293 	while (len > 0 && isblank(mask[len - 1])) {
294 		len--;
295 	}
296 
297 	if (len == 0) {
298 		return -1;
299 	}
300 
301 	if (mask[0] == '[') {
302 		ret = parse_list(mask, set);
303 	} else {
304 		ret = parse_mask(mask, set, len);
305 	}
306 
307 	return ret;
308 }
309