1c8b5c478SDmitry Chagin /*-
2c8b5c478SDmitry Chagin * Copyright (c) 2022 Dmitry Chagin <dchagin@FreeBSD.org>
3c8b5c478SDmitry Chagin *
4c8b5c478SDmitry Chagin * SPDX-License-Identifier: BSD-2-Clause
5c8b5c478SDmitry Chagin */
66dced2c6SWarner Losh
7c8b5c478SDmitry Chagin #include <sys/types.h>
8c8b5c478SDmitry Chagin #include <sys/stdint.h>
9c8b5c478SDmitry Chagin #include <sys/sysctl.h>
10c8b5c478SDmitry Chagin
11c8b5c478SDmitry Chagin #include <errno.h>
12c8b5c478SDmitry Chagin #include <sched.h>
13c8b5c478SDmitry Chagin
14c8b5c478SDmitry Chagin #include <atf-c.h>
15c8b5c478SDmitry Chagin
16c8b5c478SDmitry Chagin static uint32_t maxcpuid;
17c8b5c478SDmitry Chagin static uint32_t maxcpus;
18c8b5c478SDmitry Chagin static uint32_t cpus;
19c8b5c478SDmitry Chagin
20c8b5c478SDmitry Chagin static uint32_t
support_getcpus(void)21c8b5c478SDmitry Chagin support_getcpus(void)
22c8b5c478SDmitry Chagin {
23c8b5c478SDmitry Chagin uint32_t val;
24c8b5c478SDmitry Chagin size_t sz = sizeof(val);
25c8b5c478SDmitry Chagin
26c8b5c478SDmitry Chagin ATF_REQUIRE(sysctlbyname("kern.smp.cpus", &val, &sz, NULL, 0) == 0);
27c8b5c478SDmitry Chagin return (val);
28c8b5c478SDmitry Chagin }
29c8b5c478SDmitry Chagin
30c8b5c478SDmitry Chagin static uint32_t
support_getmaxcpus(void)31c8b5c478SDmitry Chagin support_getmaxcpus(void)
32c8b5c478SDmitry Chagin {
33c8b5c478SDmitry Chagin uint32_t val;
34c8b5c478SDmitry Chagin size_t sz = sizeof(val);
35c8b5c478SDmitry Chagin
36c8b5c478SDmitry Chagin ATF_REQUIRE(sysctlbyname("kern.smp.maxcpus", &val, &sz, NULL, 0) == 0);
37c8b5c478SDmitry Chagin return (val);
38c8b5c478SDmitry Chagin }
39c8b5c478SDmitry Chagin
40c8b5c478SDmitry Chagin static uint32_t
support_getmaxcpuid(void)41c8b5c478SDmitry Chagin support_getmaxcpuid(void)
42c8b5c478SDmitry Chagin {
43c8b5c478SDmitry Chagin cpuset_t *set;
44c8b5c478SDmitry Chagin int setsize, rv;
45c8b5c478SDmitry Chagin uint32_t i, id;
46c8b5c478SDmitry Chagin
47c8b5c478SDmitry Chagin for (i = 1; i < maxcpus; i++) {
48c8b5c478SDmitry Chagin setsize = CPU_ALLOC_SIZE(i);
49c8b5c478SDmitry Chagin set = CPU_ALLOC(i);
50c8b5c478SDmitry Chagin ATF_REQUIRE(set != NULL);
5102f7670eSDmitry Chagin CPU_ZERO_S(setsize, set);
52c8b5c478SDmitry Chagin rv = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
53c8b5c478SDmitry Chagin -1, setsize, set);
54c8b5c478SDmitry Chagin if (rv == 0) {
55c8b5c478SDmitry Chagin id = __BIT_FLS(i, set) - 1;
56c8b5c478SDmitry Chagin CPU_FREE(set);
57c8b5c478SDmitry Chagin break;
58c8b5c478SDmitry Chagin }
59c8b5c478SDmitry Chagin CPU_FREE(set);
60c8b5c478SDmitry Chagin }
61c8b5c478SDmitry Chagin ATF_REQUIRE(rv == 0);
62c8b5c478SDmitry Chagin return (id);
63c8b5c478SDmitry Chagin }
64c8b5c478SDmitry Chagin
65c8b5c478SDmitry Chagin ATF_TC_WITHOUT_HEAD(test_setinvalidcpu);
ATF_TC_BODY(test_setinvalidcpu,tc)66c8b5c478SDmitry Chagin ATF_TC_BODY(test_setinvalidcpu, tc)
67c8b5c478SDmitry Chagin {
68c8b5c478SDmitry Chagin size_t cpusetsize;
69c8b5c478SDmitry Chagin cpuset_t *set;
70*5b98bd30SMark Johnston int cpu;
71*5b98bd30SMark Johnston
72*5b98bd30SMark Johnston cpu = maxcpuid > 1 ? maxcpuid - 1 : 0;
73c8b5c478SDmitry Chagin
74c8b5c478SDmitry Chagin cpusetsize = CPU_ALLOC_SIZE(maxcpuid + 1);
75c8b5c478SDmitry Chagin set = CPU_ALLOC(maxcpuid + 1);
76c8b5c478SDmitry Chagin ATF_REQUIRE(set != NULL);
7702f7670eSDmitry Chagin CPU_ZERO_S(cpusetsize, set);
7802f7670eSDmitry Chagin CPU_SET_S(maxcpuid + 1, cpusetsize, set);
79*5b98bd30SMark Johnston CPU_SET_S(cpu, cpusetsize, set);
80c8b5c478SDmitry Chagin ATF_REQUIRE(sched_setaffinity(0, cpusetsize, set) == 0);
81c8b5c478SDmitry Chagin CPU_FREE(set);
82c8b5c478SDmitry Chagin
83c8b5c478SDmitry Chagin cpusetsize = CPU_ALLOC_SIZE(maxcpus + 1);
84c8b5c478SDmitry Chagin set = CPU_ALLOC(maxcpus + 1);
85c8b5c478SDmitry Chagin ATF_REQUIRE(set != NULL);
8602f7670eSDmitry Chagin CPU_ZERO_S(cpusetsize, set);
8702f7670eSDmitry Chagin CPU_SET_S(maxcpuid + 1, cpusetsize, set);
88*5b98bd30SMark Johnston CPU_SET_S(cpu, cpusetsize, set);
89c8b5c478SDmitry Chagin ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
90c8b5c478SDmitry Chagin -1, cpusetsize, set) == -1);
91c8b5c478SDmitry Chagin ATF_REQUIRE_EQ(errno, EINVAL);
92c8b5c478SDmitry Chagin CPU_FREE(set);
93c8b5c478SDmitry Chagin }
94c8b5c478SDmitry Chagin
95c8b5c478SDmitry Chagin ATF_TC_WITHOUT_HEAD(test_setvalidcpu);
ATF_TC_BODY(test_setvalidcpu,tc)96c8b5c478SDmitry Chagin ATF_TC_BODY(test_setvalidcpu, tc)
97c8b5c478SDmitry Chagin {
98c8b5c478SDmitry Chagin size_t cpusetsize;
99c8b5c478SDmitry Chagin cpuset_t *set;
100c8b5c478SDmitry Chagin int cpu;
101c8b5c478SDmitry Chagin
102c8b5c478SDmitry Chagin ATF_REQUIRE(maxcpuid < maxcpus);
103c8b5c478SDmitry Chagin cpu = maxcpuid > 1 ? maxcpuid - 1 : 0;
104c8b5c478SDmitry Chagin
105c8b5c478SDmitry Chagin cpusetsize = CPU_ALLOC_SIZE(maxcpus + 1);
106c8b5c478SDmitry Chagin set = CPU_ALLOC(maxcpus + 1);
107c8b5c478SDmitry Chagin ATF_REQUIRE(set != NULL);
10802f7670eSDmitry Chagin CPU_ZERO_S(cpusetsize, set);
10902f7670eSDmitry Chagin CPU_SET_S(cpu, cpusetsize, set);
110c8b5c478SDmitry Chagin ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
111c8b5c478SDmitry Chagin -1, cpusetsize, set) == 0);
112c8b5c478SDmitry Chagin ATF_REQUIRE_EQ(cpu, sched_getcpu());
113c8b5c478SDmitry Chagin CPU_FREE(set);
114c8b5c478SDmitry Chagin }
115c8b5c478SDmitry Chagin
116c8b5c478SDmitry Chagin ATF_TC_WITHOUT_HEAD(test_setzeroset1);
ATF_TC_BODY(test_setzeroset1,tc)117c8b5c478SDmitry Chagin ATF_TC_BODY(test_setzeroset1, tc)
118c8b5c478SDmitry Chagin {
119c8b5c478SDmitry Chagin size_t cpusetsize;
120c8b5c478SDmitry Chagin cpuset_t *set;
121c8b5c478SDmitry Chagin
122c8b5c478SDmitry Chagin cpusetsize = CPU_ALLOC_SIZE(maxcpuid + 1);
123c8b5c478SDmitry Chagin set = CPU_ALLOC(maxcpuid + 1);
124c8b5c478SDmitry Chagin ATF_REQUIRE(set != NULL);
12502f7670eSDmitry Chagin CPU_ZERO_S(cpusetsize, set);
126c8b5c478SDmitry Chagin ATF_REQUIRE(sched_setaffinity(0, cpusetsize, set) == -1);
127c8b5c478SDmitry Chagin ATF_REQUIRE_EQ(errno, EINVAL);
128c8b5c478SDmitry Chagin CPU_FREE(set);
129c8b5c478SDmitry Chagin }
130c8b5c478SDmitry Chagin
131c8b5c478SDmitry Chagin ATF_TC_WITHOUT_HEAD(test_setzeroset2);
ATF_TC_BODY(test_setzeroset2,tc)132c8b5c478SDmitry Chagin ATF_TC_BODY(test_setzeroset2, tc)
133c8b5c478SDmitry Chagin {
134c8b5c478SDmitry Chagin size_t cpusetsize;
135c8b5c478SDmitry Chagin cpuset_t *set;
136c8b5c478SDmitry Chagin
137c8b5c478SDmitry Chagin cpusetsize = CPU_ALLOC_SIZE(maxcpuid + 1);
138c8b5c478SDmitry Chagin set = CPU_ALLOC(maxcpuid + 1);
139c8b5c478SDmitry Chagin ATF_REQUIRE(set != NULL);
14002f7670eSDmitry Chagin CPU_ZERO_S(cpusetsize, set);
141c8b5c478SDmitry Chagin ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
142c8b5c478SDmitry Chagin -1, cpusetsize, set) == -1);
143c8b5c478SDmitry Chagin ATF_REQUIRE_EQ(errno, EDEADLK);
144c8b5c478SDmitry Chagin CPU_FREE(set);
145c8b5c478SDmitry Chagin }
146c8b5c478SDmitry Chagin
147c8b5c478SDmitry Chagin ATF_TC_WITHOUT_HEAD(test_setmaxsetsize);
ATF_TC_BODY(test_setmaxsetsize,tc)148c8b5c478SDmitry Chagin ATF_TC_BODY(test_setmaxsetsize, tc)
149c8b5c478SDmitry Chagin {
150c8b5c478SDmitry Chagin size_t cpusetsize;
151c8b5c478SDmitry Chagin cpuset_t *set;
152c8b5c478SDmitry Chagin
153c8b5c478SDmitry Chagin cpusetsize = CPU_ALLOC_SIZE(maxcpus * 2);
154c8b5c478SDmitry Chagin set = CPU_ALLOC(maxcpus * 2);
155c8b5c478SDmitry Chagin ATF_REQUIRE(set != NULL);
15602f7670eSDmitry Chagin CPU_ZERO_S(cpusetsize, set);
15702f7670eSDmitry Chagin ATF_REQUIRE(CPU_COUNT_S(cpusetsize, set) == 0);
15802f7670eSDmitry Chagin CPU_SET_S(0, cpusetsize, set);
15902f7670eSDmitry Chagin ATF_REQUIRE(CPU_COUNT_S(cpusetsize, set) == 1);
160c8b5c478SDmitry Chagin ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
161c8b5c478SDmitry Chagin -1, cpusetsize, set) == 0);
162c8b5c478SDmitry Chagin
16302f7670eSDmitry Chagin CPU_ZERO_S(cpusetsize, set);
16402f7670eSDmitry Chagin CPU_SET_S(maxcpuid, cpusetsize, set);
165c8b5c478SDmitry Chagin ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
166c8b5c478SDmitry Chagin -1, cpusetsize, set) == 0);
167c8b5c478SDmitry Chagin
16802f7670eSDmitry Chagin CPU_ZERO_S(cpusetsize, set);
16902f7670eSDmitry Chagin CPU_SET_S(maxcpuid + 1, cpusetsize, set);
170c8b5c478SDmitry Chagin ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
171c8b5c478SDmitry Chagin -1, cpusetsize, set) == -1);
172c8b5c478SDmitry Chagin ATF_REQUIRE_EQ(errno, EINVAL);
173c8b5c478SDmitry Chagin CPU_FREE(set);
174c8b5c478SDmitry Chagin }
175c8b5c478SDmitry Chagin
176c8b5c478SDmitry Chagin ATF_TC_WITHOUT_HEAD(test_setminsetsize);
ATF_TC_BODY(test_setminsetsize,tc)177c8b5c478SDmitry Chagin ATF_TC_BODY(test_setminsetsize, tc)
178c8b5c478SDmitry Chagin {
179c8b5c478SDmitry Chagin size_t cpusetsize = 1;
180c8b5c478SDmitry Chagin int8_t set;
181c8b5c478SDmitry Chagin
182c8b5c478SDmitry Chagin if (cpus <= 8)
183c8b5c478SDmitry Chagin return;
184c8b5c478SDmitry Chagin
185c8b5c478SDmitry Chagin set = 1;
186c8b5c478SDmitry Chagin ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
187c8b5c478SDmitry Chagin -1, cpusetsize, (const cpuset_t *)&set) == 0);
188c8b5c478SDmitry Chagin set = 0;
189c8b5c478SDmitry Chagin ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
190c8b5c478SDmitry Chagin -1, cpusetsize, (const cpuset_t *)&set) == -1);
191c8b5c478SDmitry Chagin ATF_REQUIRE_EQ(errno, EDEADLK);
192c8b5c478SDmitry Chagin }
193c8b5c478SDmitry Chagin
194c8b5c478SDmitry Chagin ATF_TC_WITHOUT_HEAD(test_getminsetsize);
ATF_TC_BODY(test_getminsetsize,tc)195c8b5c478SDmitry Chagin ATF_TC_BODY(test_getminsetsize, tc)
196c8b5c478SDmitry Chagin {
197c8b5c478SDmitry Chagin size_t cpusetsize = 1;
198c8b5c478SDmitry Chagin int8_t set = 0;
199c8b5c478SDmitry Chagin
200c8b5c478SDmitry Chagin if (cpus < 9)
201c8b5c478SDmitry Chagin return;
202c8b5c478SDmitry Chagin ATF_REQUIRE(cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
203c8b5c478SDmitry Chagin -1, cpusetsize, (cpuset_t *)&set) == -1);
204c8b5c478SDmitry Chagin ATF_REQUIRE_EQ(errno, ERANGE);
205c8b5c478SDmitry Chagin }
206c8b5c478SDmitry Chagin
207c8b5c478SDmitry Chagin ATF_TC_WITHOUT_HEAD(test_getsetsize);
ATF_TC_BODY(test_getsetsize,tc)208c8b5c478SDmitry Chagin ATF_TC_BODY(test_getsetsize, tc)
209c8b5c478SDmitry Chagin {
210c8b5c478SDmitry Chagin size_t cpusetsize;
211c8b5c478SDmitry Chagin cpuset_t *set;
212c8b5c478SDmitry Chagin
213c8b5c478SDmitry Chagin cpusetsize = CPU_ALLOC_SIZE(maxcpuid + 1);
214c8b5c478SDmitry Chagin set = CPU_ALLOC(maxcpuid + 1);
215c8b5c478SDmitry Chagin ATF_REQUIRE(set != NULL);
21602f7670eSDmitry Chagin CPU_ZERO_S(cpusetsize, set);
217c8b5c478SDmitry Chagin ATF_REQUIRE(cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
218c8b5c478SDmitry Chagin -1, cpusetsize, set) == 0);
219c8b5c478SDmitry Chagin CPU_FREE(set);
220c8b5c478SDmitry Chagin }
221c8b5c478SDmitry Chagin
222c8b5c478SDmitry Chagin ATF_TC_WITHOUT_HEAD(test_holes);
ATF_TC_BODY(test_holes,tc)223c8b5c478SDmitry Chagin ATF_TC_BODY(test_holes, tc)
224c8b5c478SDmitry Chagin {
225c8b5c478SDmitry Chagin cpuset_t *set;
226c8b5c478SDmitry Chagin int cpusetsize;
227c8b5c478SDmitry Chagin
228c8b5c478SDmitry Chagin cpusetsize = CPU_ALLOC_SIZE(maxcpus * 2);
229c8b5c478SDmitry Chagin set = CPU_ALLOC(maxcpus * 2);
230c8b5c478SDmitry Chagin ATF_REQUIRE(set != NULL);
23102f7670eSDmitry Chagin CPU_ZERO_S(cpusetsize, set);
23202f7670eSDmitry Chagin ATF_REQUIRE(CPU_COUNT_S(cpusetsize, set) == 0);
23302f7670eSDmitry Chagin CPU_SET_S(maxcpuid, cpusetsize, set);
23402f7670eSDmitry Chagin ATF_REQUIRE(CPU_COUNT_S(cpusetsize, set) == 1);
235c8b5c478SDmitry Chagin ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
236c8b5c478SDmitry Chagin -1, cpusetsize, set) == 0);
237c8b5c478SDmitry Chagin
23802f7670eSDmitry Chagin CPU_ZERO_S(cpusetsize, set);
23902f7670eSDmitry Chagin ATF_REQUIRE(CPU_COUNT_S(cpusetsize, set) == 0);
24002f7670eSDmitry Chagin CPU_SET_S(maxcpuid + 1, cpusetsize, set);
24102f7670eSDmitry Chagin ATF_REQUIRE(CPU_COUNT_S(cpusetsize, set) == 1);
242c8b5c478SDmitry Chagin ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
243c8b5c478SDmitry Chagin -1, cpusetsize, set) == -1);
244c8b5c478SDmitry Chagin ATF_REQUIRE_EQ(errno, EINVAL);
245c8b5c478SDmitry Chagin
24602f7670eSDmitry Chagin ATF_REQUIRE(CPU_COUNT_S(cpusetsize, set) == 1);
247c8b5c478SDmitry Chagin ATF_REQUIRE(cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
248c8b5c478SDmitry Chagin -1, cpusetsize, set) == 0);
24902f7670eSDmitry Chagin ATF_REQUIRE(CPU_ISSET_S(maxcpuid + 1, cpusetsize, set) == false);
25002f7670eSDmitry Chagin ATF_REQUIRE(CPU_ISSET_S(maxcpuid, cpusetsize, set) == true);
251c8b5c478SDmitry Chagin ATF_REQUIRE_EQ(maxcpuid, (uint32_t)sched_getcpu());
252c8b5c478SDmitry Chagin }
253c8b5c478SDmitry Chagin
ATF_TP_ADD_TCS(tp)254c8b5c478SDmitry Chagin ATF_TP_ADD_TCS(tp)
255c8b5c478SDmitry Chagin {
256c8b5c478SDmitry Chagin
257c8b5c478SDmitry Chagin cpus = support_getcpus();
258c8b5c478SDmitry Chagin maxcpus = support_getmaxcpus();
259c8b5c478SDmitry Chagin maxcpuid = support_getmaxcpuid();
260c8b5c478SDmitry Chagin
261c8b5c478SDmitry Chagin ATF_TP_ADD_TC(tp, test_setinvalidcpu);
262c8b5c478SDmitry Chagin ATF_TP_ADD_TC(tp, test_setvalidcpu);
263c8b5c478SDmitry Chagin ATF_TP_ADD_TC(tp, test_setzeroset1);
264c8b5c478SDmitry Chagin ATF_TP_ADD_TC(tp, test_setzeroset2);
265c8b5c478SDmitry Chagin
266c8b5c478SDmitry Chagin ATF_TP_ADD_TC(tp, test_setminsetsize);
267c8b5c478SDmitry Chagin ATF_TP_ADD_TC(tp, test_setmaxsetsize);
268c8b5c478SDmitry Chagin
269c8b5c478SDmitry Chagin ATF_TP_ADD_TC(tp, test_getminsetsize);
270c8b5c478SDmitry Chagin ATF_TP_ADD_TC(tp, test_getsetsize);
271c8b5c478SDmitry Chagin
272c8b5c478SDmitry Chagin ATF_TP_ADD_TC(tp, test_holes);
273c8b5c478SDmitry Chagin
274c8b5c478SDmitry Chagin return (atf_no_error());
275c8b5c478SDmitry Chagin }
276