1 /*
2 * Copyright (c) 2016-2024 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <assert.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <uuid/uuid.h>
35 #include <sys/select.h>
36 #include <poll.h>
37 #include <sys/event.h>
38 #include <darwintest.h>
39 #include "skywalk_test_driver.h"
40 #include "skywalk_test_common.h"
41 #include "skywalk_test_utils.h"
42
43 int
skt_nslots_common(int argc,char * argv[],uint32_t nslots,uint32_t interval,int method)44 skt_nslots_common(int argc, char *argv[], uint32_t nslots, uint32_t interval, int method)
45 {
46 int error;
47 channel_t channel;
48 uuid_t channel_uuid;
49 ring_id_t ringid;
50 channel_ring_t ring;
51 channel_slot_t prev, slot;
52 channel_attr_t attr;
53 uint32_t avail;
54 slot_prop_t prop;
55 int channelfd;
56 uint32_t sendcount;
57 uint32_t recvcount;
58 uint64_t slotsize;
59 fd_set fdset, efdset;
60 struct pollfd fds;
61 int kq;
62 struct kevent kev;
63 time_t start = time(NULL);
64 time_t now, then = start;
65
66 sendcount = 0;
67 recvcount = 0;
68
69 error = uuid_parse(argv[3], channel_uuid);
70 SKTC_ASSERT_ERR(!error);
71
72 channel = sktu_channel_create_extended(channel_uuid, 0,
73 CHANNEL_DIR_TX_RX, CHANNEL_RING_ID_ANY, NULL,
74 -1, -1, -1, -1, -1, -1, -1, 1, -1, -1);
75 assert(channel);
76
77 channelfd = os_channel_get_fd(channel);
78 assert(channelfd != -1);
79
80 switch (method) {
81 case 0:
82 FD_ZERO(&fdset);
83 FD_ZERO(&efdset);
84 break;
85 case 1:
86 fds.fd = channelfd;
87 break;
88 case 2:
89 kq = kqueue();
90 assert(kq != -1);
91 break;
92 default:
93 abort();
94 }
95
96 attr = os_channel_attr_create();
97
98 error = os_channel_read_attr(channel, attr);
99 SKTC_ASSERT_ERR(!error);
100
101 if (nslots == -1) {
102 uint64_t attrval = -1;
103 error = os_channel_attr_get(attr, CHANNEL_ATTR_TX_SLOTS, &attrval);
104 SKTC_ASSERT_ERR(!error);
105 assert(attrval != -1);
106 nslots = attrval;
107 }
108
109 slotsize = -1;
110 error = os_channel_attr_get(attr, CHANNEL_ATTR_SLOT_BUF_SIZE, &slotsize);
111 SKTC_ASSERT_ERR(!error);
112 assert(slotsize != -1);
113 assert(slotsize >= sizeof(sendcount));
114
115 os_channel_attr_destroy(attr);
116
117 while (recvcount < nslots) {
118 now = time(NULL);
119 if (now > then) {
120 T_LOG("time %ld send %d recv %d of %d (%2.2f%%, est %ld secs left)\n",
121 now - start, sendcount, recvcount, nslots,
122 (double)recvcount * 100 / nslots,
123 (long)((double)(now - start) * nslots / recvcount) - (now - start));
124 then = now;
125 }
126
127 if (sendcount < nslots) {
128 ringid = os_channel_ring_id(channel, CHANNEL_FIRST_TX_RING);
129 ring = os_channel_tx_ring(channel, ringid);
130 assert(ring);
131
132 switch (method) {
133 case 0:
134 FD_SET(channelfd, &fdset);
135 FD_SET(channelfd, &efdset);
136 error = select(channelfd + 1, NULL, &fdset, &efdset, NULL);
137 SKTC_ASSERT_ERR(error != -1);
138 SKTC_ASSERT_ERR(error == 1);
139 assert(FD_ISSET(channelfd, &fdset));
140 assert(!FD_ISSET(channelfd, &efdset));
141 break;
142 case 1:
143 fds.events = POLLWRNORM;
144 error = poll(&fds, 1, -1);
145 SKTC_ASSERT_ERR(error != -1);
146 SKTC_ASSERT_ERR(error == 1);
147 assert(fds.fd == channelfd);
148 assert(fds.events == POLLWRNORM);
149 assert(fds.revents == POLLWRNORM);
150 break;
151 case 2:
152 EV_SET(&kev, channelfd, EVFILT_WRITE, EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 0, NULL);
153 error = kevent(kq, &kev, 1, &kev, 1, NULL);
154 SKTC_ASSERT_ERR(error != -1);
155 SKTC_ASSERT_ERR(error == 1);
156 assert(kev.filter == EVFILT_WRITE);
157 assert(kev.ident == channelfd);
158 assert(kev.udata == NULL);
159 break;
160 default:
161 abort();
162 }
163
164 avail = os_channel_available_slot_count(ring);
165 assert(avail);
166
167 prev = NULL;
168 slot = os_channel_get_next_slot(ring, NULL, &prop);
169 assert(slot);
170
171 for (uint32_t i = 0; i < avail; i++) {
172 assert(slot);
173
174 if (sendcount == nslots || i == interval) {
175 slot = NULL;
176 break;
177 }
178
179 assert(prop.sp_len == slotsize);
180 memcpy((void *)prop.sp_buf_ptr, &sendcount, sizeof(sendcount));
181 prop.sp_len = sizeof(sendcount);
182 os_channel_set_slot_properties(ring, slot, &prop);
183 sendcount++;
184
185 prev = slot;
186 slot = os_channel_get_next_slot(ring, slot, &prop);
187 }
188 assert(!slot);
189 assert(prev);
190
191 error = os_channel_advance_slot(ring, prev);
192 SKTC_ASSERT_ERR(!error);
193
194 error = os_channel_sync(channel, CHANNEL_SYNC_TX);
195 SKTC_ASSERT_ERR(!error);
196 }
197
198 ringid = os_channel_ring_id(channel, CHANNEL_FIRST_RX_RING);
199 ring = os_channel_rx_ring(channel, ringid);
200 assert(ring);
201
202 switch (method) {
203 case 0:
204 FD_SET(channelfd, &fdset);
205 FD_SET(channelfd, &efdset);
206 error = select(channelfd + 1, &fdset, NULL, &efdset, NULL);
207 SKTC_ASSERT_ERR(error != -1);
208 SKTC_ASSERT_ERR(error == 1);
209 assert(FD_ISSET(channelfd, &fdset));
210 assert(!FD_ISSET(channelfd, &efdset));
211 break;
212 case 1:
213 fds.events = POLLRDNORM;
214 error = poll(&fds, 1, -1);
215 SKTC_ASSERT_ERR(error != -1);
216 SKTC_ASSERT_ERR(error == 1);
217 assert(fds.fd == channelfd);
218 assert(fds.events == POLLRDNORM);
219 assert(fds.revents == POLLRDNORM);
220 break;
221 case 2:
222 EV_SET(&kev, channelfd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 0, NULL);
223 error = kevent(kq, &kev, 1, &kev, 1, NULL);
224 SKTC_ASSERT_ERR(error != -1);
225 SKTC_ASSERT_ERR(error == 1);
226 assert(kev.filter == EVFILT_READ);
227 assert(kev.ident == channelfd);
228 assert(kev.udata == NULL);
229 break;
230 default:
231 abort();
232 }
233
234 avail = os_channel_available_slot_count(ring);
235 assert(avail);
236
237 prev = NULL;
238 slot = os_channel_get_next_slot(ring, NULL, &prop);
239
240 for (uint32_t i = 0; i < avail; i++) {
241 assert(slot);
242
243 assert(prop.sp_len == sizeof(recvcount));
244 uint32_t count;
245 memcpy(&count, (void *)prop.sp_buf_ptr, sizeof(count));
246 assert(!memcmp(&recvcount, (void *)prop.sp_buf_ptr, sizeof(recvcount)));
247 recvcount++;
248
249 prev = slot;
250 slot = os_channel_get_next_slot(ring, slot, &prop);
251 }
252 assert(!slot);
253 assert(prev);
254
255 error = os_channel_advance_slot(ring, prev);
256 SKTC_ASSERT_ERR(!error);
257
258 //T_LOG("rx sync %d\n", avail);
259
260 // Unnecessary
261 //error = os_channel_sync(channel, CHANNEL_SYNC_RX);
262 //SKTC_ASSERT_ERR(!error);
263 }
264
265 now = time(NULL);
266 T_LOG("total time %ld for %d slots (rate %.2f)\n",
267 now - start, nslots, (double)nslots / (now - start));
268
269 switch (method) {
270 case 0:
271 break;
272 case 1:
273 break;
274 case 2:
275 error = close(kq);
276 SKTC_ASSERT_ERR(!error);
277 break;
278 default:
279 abort();
280 }
281
282 os_channel_destroy(channel);
283
284 return 0;
285 }
286
287 int
skt_nslots_select_main(int argc,char * argv[])288 skt_nslots_select_main(int argc, char *argv[])
289 {
290 return skt_nslots_common(argc, argv, -1, -1, 0);
291 }
292
293 int
skt_nslots_poll_main(int argc,char * argv[])294 skt_nslots_poll_main(int argc, char *argv[])
295 {
296 return skt_nslots_common(argc, argv, -1, -1, 1);
297 }
298
299 int
skt_nslots_kqueue_main(int argc,char * argv[])300 skt_nslots_kqueue_main(int argc, char *argv[])
301 {
302 return skt_nslots_common(argc, argv, -1, -1, 2);
303 }
304
305 struct skywalk_test skt_nslotsus = {
306 "nslotsus", "test sends TX_SLOTS of data on user pipe loopback using select",
307 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE,
308 skt_nslots_select_main, SKTC_GENERIC_UPIPE_ARGV,
309 sktc_generic_upipe_echo_init, sktc_generic_upipe_fini,
310 };
311
312 struct skywalk_test skt_nslotsks = {
313 "nslotsks", "test sends TX_SLOTS of data on kpipe loopback using select",
314 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE | SK_FEATURE_NEXUS_KERNEL_PIPE_LOOPBACK,
315 skt_nslots_select_main, SKTC_GENERIC_KPIPE_ARGV,
316 sktc_generic_kpipe_init, sktc_generic_kpipe_fini,
317 };
318
319 struct skywalk_test skt_nslotsup = {
320 "nslotsup", "test sends TX_SLOTS of data on user pipe loopback using poll",
321 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE,
322 skt_nslots_poll_main, SKTC_GENERIC_UPIPE_ARGV,
323 sktc_generic_upipe_echo_init, sktc_generic_upipe_fini,
324 };
325
326 struct skywalk_test skt_nslotskp = {
327 "nslotskp", "test sends TX_SLOTS of data on kpipe loopback using poll",
328 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE | SK_FEATURE_NEXUS_KERNEL_PIPE_LOOPBACK,
329 skt_nslots_poll_main, SKTC_GENERIC_KPIPE_ARGV,
330 sktc_generic_kpipe_init, sktc_generic_kpipe_fini,
331 };
332
333 struct skywalk_test skt_nslotsuk = {
334 "nslotsuk", "test sends TX_SLOTS of data on user pipe loopback using kqueue",
335 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE,
336 skt_nslots_kqueue_main, SKTC_GENERIC_UPIPE_ARGV,
337 sktc_generic_upipe_echo_init, sktc_generic_upipe_fini,
338 };
339
340 struct skywalk_test skt_nslotskk = {
341 "nslotskk", "test sends TX_SLOTS of data on kpipe loopback using kqueue",
342 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE | SK_FEATURE_NEXUS_KERNEL_PIPE_LOOPBACK,
343 skt_nslots_kqueue_main, SKTC_GENERIC_KPIPE_ARGV,
344 sktc_generic_kpipe_init, sktc_generic_kpipe_fini,
345 };
346
347 /****************************************************************/
348 // <rdar://problem/25995625> Need skywalk unit test that streams packets over upipe for a long time
349
350 #define MSLOTS 1000000
351 int
skt_mslots_select_main(int argc,char * argv[])352 skt_mslots_select_main(int argc, char *argv[])
353 {
354 return skt_nslots_common(argc, argv, MSLOTS, -1, 0);
355 }
356
357 int
skt_mslots_poll_main(int argc,char * argv[])358 skt_mslots_poll_main(int argc, char *argv[])
359 {
360 return skt_nslots_common(argc, argv, MSLOTS, -1, 1);
361 }
362
363 int
skt_mslots_kqueue_main(int argc,char * argv[])364 skt_mslots_kqueue_main(int argc, char *argv[])
365 {
366 return skt_nslots_common(argc, argv, MSLOTS, -1, 2);
367 }
368
369 struct skywalk_test skt_mslotsus = {
370 "mslotsus", "test sends 1000000 slots of data on user pipe loopback using select",
371 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE,
372 skt_mslots_select_main, SKTC_GENERIC_UPIPE_ARGV,
373 sktc_generic_upipe_echo_init, sktc_generic_upipe_fini,
374 };
375
376 struct skywalk_test skt_mslotsks = {
377 "mslotsks", "test sends 1000000 slots of data on kpipe loopback using select",
378 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE | SK_FEATURE_NEXUS_KERNEL_PIPE_LOOPBACK,
379 skt_mslots_select_main, SKTC_GENERIC_KPIPE_ARGV,
380 sktc_generic_kpipe_init, sktc_generic_kpipe_fini,
381 };
382
383 struct skywalk_test skt_mslotsup = {
384 "mslotsup", "test sends 1000000 slots of data on user pipe loopback using poll",
385 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE,
386 skt_mslots_poll_main, SKTC_GENERIC_UPIPE_ARGV,
387 sktc_generic_upipe_echo_init, sktc_generic_upipe_fini,
388 };
389
390 struct skywalk_test skt_mslotskp = {
391 "mslotskp", "test sends 1000000 slots of data on kpipe loopback using poll",
392 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE | SK_FEATURE_NEXUS_KERNEL_PIPE_LOOPBACK,
393 skt_mslots_poll_main, SKTC_GENERIC_KPIPE_ARGV,
394 sktc_generic_kpipe_init, sktc_generic_kpipe_fini,
395 };
396
397 struct skywalk_test skt_mslotsuk = {
398 "mslotsuk", "test sends 1000000 slots of data on user pipe loopback using kqueue",
399 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE,
400 skt_mslots_kqueue_main, SKTC_GENERIC_UPIPE_ARGV,
401 sktc_generic_upipe_echo_init, sktc_generic_upipe_fini,
402 };
403
404 struct skywalk_test skt_mslotskk = {
405 "mslotskk", "test sends 1000000 slots of data on kpipe loopback using kqueue",
406 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE | SK_FEATURE_NEXUS_KERNEL_PIPE_LOOPBACK,
407 skt_mslots_kqueue_main, SKTC_GENERIC_KPIPE_ARGV,
408 sktc_generic_kpipe_init, sktc_generic_kpipe_fini,
409 };
410
411 /****************************************************************/
412
413 #define MMSLOTS 10000000
414 int
skt_mmslots_select_main(int argc,char * argv[])415 skt_mmslots_select_main(int argc, char *argv[])
416 {
417 return skt_nslots_common(argc, argv, MMSLOTS, -1, 0);
418 }
419
420 int
skt_mmslots_poll_main(int argc,char * argv[])421 skt_mmslots_poll_main(int argc, char *argv[])
422 {
423 return skt_nslots_common(argc, argv, MMSLOTS, -1, 1);
424 }
425
426 int
skt_mmslots_kqueue_main(int argc,char * argv[])427 skt_mmslots_kqueue_main(int argc, char *argv[])
428 {
429 return skt_nslots_common(argc, argv, MMSLOTS, -1, 2);
430 }
431
432 struct skywalk_test skt_mmslotsus = {
433 "mmslotsus", "test sends 10000000 slots of data on user pipe loopback using select",
434 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE,
435 skt_mmslots_select_main, SKTC_GENERIC_UPIPE_ARGV,
436 sktc_generic_upipe_echo_init, sktc_generic_upipe_fini,
437 };
438
439 struct skywalk_test skt_mmslotsks = {
440 "mmslotsks", "test sends 10000000 slots of data on kpipe loopback using select",
441 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE | SK_FEATURE_NEXUS_KERNEL_PIPE_LOOPBACK,
442 skt_mmslots_select_main, SKTC_GENERIC_KPIPE_ARGV,
443 sktc_generic_kpipe_init, sktc_generic_kpipe_fini,
444 };
445
446 struct skywalk_test skt_mmslotsup = {
447 "mmslotsup", "test sends 10000000 slots of data on user pipe loopback using poll",
448 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE,
449 skt_mmslots_poll_main, SKTC_GENERIC_UPIPE_ARGV,
450 sktc_generic_upipe_echo_init, sktc_generic_upipe_fini,
451 };
452
453 struct skywalk_test skt_mmslotskp = {
454 "mmslotskp", "test sends 10000000 slots of data on kpipe loopback using poll",
455 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE | SK_FEATURE_NEXUS_KERNEL_PIPE_LOOPBACK,
456 skt_mmslots_poll_main, SKTC_GENERIC_KPIPE_ARGV,
457 sktc_generic_kpipe_init, sktc_generic_kpipe_fini,
458 };
459
460 struct skywalk_test skt_mmslotsuk = {
461 "mmslotsuk", "test sends 10000000 slots of data on user pipe loopback using kqueue",
462 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE,
463 skt_mmslots_kqueue_main, SKTC_GENERIC_UPIPE_ARGV,
464 sktc_generic_upipe_echo_init, sktc_generic_upipe_fini,
465 };
466
467 struct skywalk_test skt_mmslotskk = {
468 "mmslotskk", "test sends 10000000 slots of data on kpipe loopback using kqueue",
469 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE | SK_FEATURE_NEXUS_KERNEL_PIPE_LOOPBACK,
470 skt_mmslots_kqueue_main, SKTC_GENERIC_KPIPE_ARGV,
471 sktc_generic_kpipe_init, sktc_generic_kpipe_fini,
472 };
473
474 /****************************************************************/
475