uringmachine 0.8.2 → 0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/TODO.md +0 -1
- data/examples/bm_side_running.rb +83 -0
- data/examples/bm_sqlite.rb +1 -1
- data/ext/um/um.c +66 -4
- data/ext/um/um.h +36 -0
- data/ext/um/um_class.c +6 -0
- data/ext/um/um_const.c +36 -0
- data/ext/um/um_ext.c +2 -0
- data/ext/um/um_stream.c +344 -0
- data/ext/um/um_stream_class.c +140 -0
- data/ext/um/um_utils.c +4 -0
- data/lib/uringmachine/actor.rb +1 -1
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +35 -17
- data/test/test_fiber.rb +23 -3
- data/test/test_stream.rb +133 -0
- data/test/test_um.rb +109 -2
- data/uringmachine.gemspec +0 -2
- data/vendor/liburing/.github/workflows/{build.yml → ci.yml} +107 -42
- data/vendor/liburing/.gitignore +1 -0
- data/vendor/liburing/CHANGELOG +10 -0
- data/vendor/liburing/README +5 -0
- data/vendor/liburing/configure +1 -1
- data/vendor/liburing/examples/Makefile +1 -0
- data/vendor/liburing/examples/helpers.c +25 -0
- data/vendor/liburing/examples/helpers.h +13 -0
- data/vendor/liburing/examples/io_uring-test.c +3 -0
- data/vendor/liburing/examples/proxy.c +1 -1
- data/vendor/liburing/examples/reg-wait.c +41 -6
- data/vendor/liburing/examples/send-zerocopy.c +79 -32
- data/vendor/liburing/examples/zcrx.c +436 -0
- data/vendor/liburing/liburing.spec +1 -1
- data/vendor/liburing/src/Makefile +0 -1
- data/vendor/liburing/src/arch/generic/syscall.h +2 -2
- data/vendor/liburing/src/arch/syscall-defs.h +2 -2
- data/vendor/liburing/src/include/liburing/io_uring.h +101 -17
- data/vendor/liburing/src/include/liburing.h +179 -59
- data/vendor/liburing/src/int_flags.h +4 -1
- data/vendor/liburing/src/liburing-ffi.map +14 -2
- data/vendor/liburing/src/liburing.map +9 -2
- data/vendor/liburing/src/queue.c +35 -30
- data/vendor/liburing/src/register.c +46 -15
- data/vendor/liburing/src/sanitize.c +6 -9
- data/vendor/liburing/src/setup.c +37 -71
- data/vendor/liburing/src/syscall.c +2 -2
- data/vendor/liburing/test/232c93d07b74.c +1 -0
- data/vendor/liburing/test/Makefile +9 -0
- data/vendor/liburing/test/accept-test.c +1 -0
- data/vendor/liburing/test/cmd-discard.c +16 -8
- data/vendor/liburing/test/connect.c +11 -7
- data/vendor/liburing/test/epwait.c +420 -0
- data/vendor/liburing/test/eventfd-ring.c +30 -5
- data/vendor/liburing/test/fallocate.c +1 -1
- data/vendor/liburing/test/fixed-hugepage.c +10 -7
- data/vendor/liburing/test/fixed-seg.c +187 -0
- data/vendor/liburing/test/helpers.c +121 -0
- data/vendor/liburing/test/helpers.h +13 -0
- data/vendor/liburing/test/init-mem.c +2 -0
- data/vendor/liburing/test/io_uring_passthrough.c +78 -62
- data/vendor/liburing/test/iopoll-overflow.c +5 -4
- data/vendor/liburing/test/iopoll.c +20 -10
- data/vendor/liburing/test/iowait.c +141 -0
- data/vendor/liburing/test/nvme.h +2 -0
- data/vendor/liburing/test/pipe-bug.c +11 -5
- data/vendor/liburing/test/pipe-eof.c +11 -1
- data/vendor/liburing/test/read-inc-file.c +150 -0
- data/vendor/liburing/test/read-write.c +21 -14
- data/vendor/liburing/test/recv-bundle-short-ooo.c +435 -0
- data/vendor/liburing/test/recv-multishot.c +2 -2
- data/vendor/liburing/test/reg-wait.c +449 -120
- data/vendor/liburing/test/regbuf-clone.c +53 -0
- data/vendor/liburing/test/resize-rings.c +25 -2
- data/vendor/liburing/test/rsrc_tags.c +67 -14
- data/vendor/liburing/test/send-zerocopy.c +52 -130
- data/vendor/liburing/test/sendmsg_iov_clean.c +216 -0
- data/vendor/liburing/test/socket-nb.c +158 -0
- data/vendor/liburing/test/sqwait.c +9 -11
- data/vendor/liburing/test/timeout.c +198 -0
- data/vendor/liburing/test/vec-regbuf.c +609 -0
- data/vendor/liburing/test/wait-timeout.c +1 -1
- data/vendor/liburing/test/wq-aff.c +5 -1
- data/vendor/liburing/test/zcrx.c +928 -0
- metadata +16 -32
- data/vendor/liburing/.github/workflows/codespell.yml +0 -25
- data/vendor/liburing/.github/workflows/shellcheck.yml +0 -20
@@ -14,6 +14,8 @@
|
|
14
14
|
#include "liburing.h"
|
15
15
|
#include "helpers.h"
|
16
16
|
|
17
|
+
static bool only_defer, no_defer;
|
18
|
+
|
17
19
|
#define NVECS 128
|
18
20
|
|
19
21
|
#define min(a, b) ((a) < (b) ? (a) : (b))
|
@@ -286,6 +288,9 @@ static int test_reads(struct io_uring *ring, int fd, int async)
|
|
286
288
|
}
|
287
289
|
}
|
288
290
|
|
291
|
+
for (i = 0; i < NVECS; i++)
|
292
|
+
free(vecs[i].iov_base);
|
293
|
+
|
289
294
|
return 0;
|
290
295
|
}
|
291
296
|
|
@@ -306,8 +311,12 @@ static int test_basic(struct io_uring *ring, int async)
|
|
306
311
|
p.sq_entries = 32;
|
307
312
|
p.cq_entries = 64;
|
308
313
|
ret = io_uring_resize_rings(ring, &p);
|
309
|
-
if (ret == -EINVAL)
|
314
|
+
if (ret == -EINVAL || ret == -ENOMEM) {
|
310
315
|
return T_EXIT_SKIP;
|
316
|
+
} else if (ret < 0) {
|
317
|
+
fprintf(stderr, "resize=%d\n", ret);
|
318
|
+
return T_EXIT_FAIL;
|
319
|
+
}
|
311
320
|
|
312
321
|
sqe = io_uring_get_sqe(ring);
|
313
322
|
io_uring_prep_nop(sqe);
|
@@ -548,7 +557,14 @@ static int test(int flags, int fd, int async)
|
|
548
557
|
struct io_uring ring;
|
549
558
|
int ret;
|
550
559
|
|
560
|
+
if (no_defer)
|
561
|
+
return T_EXIT_SKIP;
|
562
|
+
if (!(flags & IORING_SETUP_DEFER_TASKRUN) && only_defer)
|
563
|
+
return T_EXIT_SKIP;
|
564
|
+
|
551
565
|
ret = io_uring_queue_init_params(8, &ring, &p);
|
566
|
+
if (ret == -EINVAL)
|
567
|
+
return T_EXIT_SKIP;
|
552
568
|
if (ret < 0) {
|
553
569
|
fprintf(stderr, "ring setup failed: %d\n", ret);
|
554
570
|
return T_EXIT_FAIL;
|
@@ -556,6 +572,12 @@ static int test(int flags, int fd, int async)
|
|
556
572
|
|
557
573
|
ret = test_basic(&ring, async);
|
558
574
|
if (ret == T_EXIT_SKIP) {
|
575
|
+
if (!(flags & IORING_SETUP_DEFER_TASKRUN)) {
|
576
|
+
io_uring_queue_exit(&ring);
|
577
|
+
only_defer = true;
|
578
|
+
} else {
|
579
|
+
no_defer = true;
|
580
|
+
}
|
559
581
|
return T_EXIT_SKIP;
|
560
582
|
} else if (ret == T_EXIT_FAIL) {
|
561
583
|
fprintf(stderr, "test_basic %x failed\n", flags);
|
@@ -615,7 +637,7 @@ int main(int argc, char *argv[])
|
|
615
637
|
|
616
638
|
ret = test(0, fd, 0);
|
617
639
|
if (ret == T_EXIT_SKIP)
|
618
|
-
|
640
|
+
goto try_defer;
|
619
641
|
else if (ret == T_EXIT_FAIL)
|
620
642
|
return T_EXIT_FAIL;
|
621
643
|
|
@@ -631,6 +653,7 @@ int main(int argc, char *argv[])
|
|
631
653
|
if (ret == T_EXIT_FAIL)
|
632
654
|
return T_EXIT_FAIL;
|
633
655
|
|
656
|
+
try_defer:
|
634
657
|
ret = test(IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN, fd, 0);
|
635
658
|
if (ret == T_EXIT_FAIL)
|
636
659
|
return T_EXIT_FAIL;
|
@@ -151,7 +151,7 @@ static int test_buffers_update(void)
|
|
151
151
|
struct io_uring ring;
|
152
152
|
const int nr = 5;
|
153
153
|
int buf_idx = 1, i, ret;
|
154
|
-
int
|
154
|
+
int fds[2];
|
155
155
|
char tmp_buf[1024];
|
156
156
|
char tmp_buf2[1024];
|
157
157
|
struct iovec vecs[nr];
|
@@ -172,7 +172,7 @@ static int test_buffers_update(void)
|
|
172
172
|
printf("ring setup failed\n");
|
173
173
|
return 1;
|
174
174
|
}
|
175
|
-
if (pipe(
|
175
|
+
if (pipe(fds) < 0) {
|
176
176
|
perror("pipe");
|
177
177
|
return 1;
|
178
178
|
}
|
@@ -184,7 +184,7 @@ static int test_buffers_update(void)
|
|
184
184
|
|
185
185
|
/* test that CQE is not emitted before we're done with a buffer */
|
186
186
|
sqe = io_uring_get_sqe(&ring);
|
187
|
-
io_uring_prep_read_fixed(sqe,
|
187
|
+
io_uring_prep_read_fixed(sqe, fds[0], tmp_buf, 10, 0, 1);
|
188
188
|
sqe->user_data = 100;
|
189
189
|
ret = io_uring_submit(&ring);
|
190
190
|
if (ret != 1) {
|
@@ -204,8 +204,8 @@ static int test_buffers_update(void)
|
|
204
204
|
|
205
205
|
ret = io_uring_peek_cqe(&ring, &cqe); /* nothing should be there */
|
206
206
|
assert(ret == -EAGAIN);
|
207
|
-
close(
|
208
|
-
close(
|
207
|
+
close(fds[0]);
|
208
|
+
close(fds[1]);
|
209
209
|
|
210
210
|
ret = io_uring_wait_cqe(&ring, &cqe);
|
211
211
|
assert(!ret && cqe->user_data == 100);
|
@@ -312,7 +312,6 @@ static int test_buffers_empty_buffers(void)
|
|
312
312
|
return 0;
|
313
313
|
}
|
314
314
|
|
315
|
-
|
316
315
|
static int test_files(int ring_flags)
|
317
316
|
{
|
318
317
|
struct io_uring_cqe *cqe = NULL;
|
@@ -408,6 +407,53 @@ static int test_notag(void)
|
|
408
407
|
return 0;
|
409
408
|
}
|
410
409
|
|
410
|
+
static char buffer[16];
|
411
|
+
|
412
|
+
static int test_tagged_register_partial_fail(void)
|
413
|
+
{
|
414
|
+
__u64 tags[2] = { 1, 2 };
|
415
|
+
int fds[2] = { pipes[0], -1 };
|
416
|
+
struct iovec iovec[2];
|
417
|
+
struct io_uring ring;
|
418
|
+
int ret;
|
419
|
+
|
420
|
+
iovec[0].iov_base = buffer;
|
421
|
+
iovec[0].iov_len = 1;
|
422
|
+
iovec[1].iov_base = (void *)1UL;
|
423
|
+
iovec[1].iov_len = 1;
|
424
|
+
|
425
|
+
ret = io_uring_queue_init(1, &ring, 0);
|
426
|
+
if (ret) {
|
427
|
+
printf("ring setup failed\n");
|
428
|
+
return 1;
|
429
|
+
}
|
430
|
+
|
431
|
+
ret = io_uring_register_buffers_tags(&ring, iovec, tags, 2);
|
432
|
+
if (ret >= 0) {
|
433
|
+
fprintf(stderr, "io_uring_register_buffers_tags returned %i\n", ret);
|
434
|
+
return -EFAULT;
|
435
|
+
}
|
436
|
+
|
437
|
+
if (!check_cq_empty(&ring)) {
|
438
|
+
fprintf(stderr, "stray buffer CQEs found\n");
|
439
|
+
return -EFAULT;
|
440
|
+
}
|
441
|
+
|
442
|
+
ret = io_uring_register_files_tags(&ring, fds, tags, 2);
|
443
|
+
if (ret >= 0) {
|
444
|
+
fprintf(stderr, "io_uring_register_files_tags returned %i\n", ret);
|
445
|
+
return -EFAULT;
|
446
|
+
}
|
447
|
+
|
448
|
+
if (!check_cq_empty(&ring)) {
|
449
|
+
fprintf(stderr, "stray file CQEs found\n");
|
450
|
+
return -EFAULT;
|
451
|
+
}
|
452
|
+
|
453
|
+
io_uring_queue_exit(&ring);
|
454
|
+
return 0;
|
455
|
+
}
|
456
|
+
|
411
457
|
int main(int argc, char *argv[])
|
412
458
|
{
|
413
459
|
int ring_flags[] = {0, IORING_SETUP_IOPOLL, IORING_SETUP_SQPOLL,
|
@@ -415,21 +461,28 @@ int main(int argc, char *argv[])
|
|
415
461
|
int i, ret;
|
416
462
|
|
417
463
|
if (argc > 1)
|
418
|
-
return
|
464
|
+
return T_EXIT_SKIP;
|
465
|
+
|
419
466
|
if (!has_rsrc_update()) {
|
420
467
|
fprintf(stderr, "doesn't support rsrc tags, skip\n");
|
421
|
-
return
|
468
|
+
return T_EXIT_SKIP;
|
422
469
|
}
|
423
470
|
|
424
471
|
if (pipe(pipes) < 0) {
|
425
472
|
perror("pipe");
|
426
|
-
return
|
473
|
+
return T_EXIT_FAIL;
|
474
|
+
}
|
475
|
+
|
476
|
+
ret = test_tagged_register_partial_fail();
|
477
|
+
if (ret) {
|
478
|
+
printf("test_tagged_register_partial_fail() failed\n");
|
479
|
+
return T_EXIT_FAIL;
|
427
480
|
}
|
428
481
|
|
429
482
|
ret = test_notag();
|
430
483
|
if (ret) {
|
431
484
|
printf("test_notag failed\n");
|
432
|
-
return
|
485
|
+
return T_EXIT_FAIL;
|
433
486
|
}
|
434
487
|
|
435
488
|
for (i = 0; i < sizeof(ring_flags) / sizeof(ring_flags[0]); i++) {
|
@@ -441,21 +494,21 @@ int main(int argc, char *argv[])
|
|
441
494
|
ret = test_files(flag);
|
442
495
|
if (ret) {
|
443
496
|
printf("test_tag failed, type %i\n", i);
|
444
|
-
return
|
497
|
+
return T_EXIT_FAIL;
|
445
498
|
}
|
446
499
|
}
|
447
500
|
|
448
501
|
ret = test_buffers_update();
|
449
502
|
if (ret) {
|
450
503
|
printf("test_buffers_update failed\n");
|
451
|
-
return
|
504
|
+
return T_EXIT_FAIL;
|
452
505
|
}
|
453
506
|
|
454
507
|
ret = test_buffers_empty_buffers();
|
455
508
|
if (ret) {
|
456
509
|
printf("test_buffers_empty_buffers failed\n");
|
457
|
-
return
|
510
|
+
return T_EXIT_FAIL;
|
458
511
|
}
|
459
512
|
|
460
|
-
return
|
513
|
+
return T_EXIT_PASS;
|
461
514
|
}
|
@@ -69,9 +69,11 @@ static size_t page_sz;
|
|
69
69
|
static char *tx_buffer, *rx_buffer;
|
70
70
|
static struct iovec buffers_iov[__BUF_NR];
|
71
71
|
|
72
|
+
static bool has_regvec;
|
72
73
|
static bool has_sendzc;
|
73
74
|
static bool has_sendmsg;
|
74
75
|
static bool hit_enomem;
|
76
|
+
static bool try_hugepages = 1;
|
75
77
|
|
76
78
|
static int probe_zc_support(void)
|
77
79
|
{
|
@@ -95,6 +97,7 @@ static int probe_zc_support(void)
|
|
95
97
|
|
96
98
|
has_sendzc = p->ops_len > IORING_OP_SEND_ZC;
|
97
99
|
has_sendmsg = p->ops_len > IORING_OP_SENDMSG_ZC;
|
100
|
+
has_regvec = p->ops_len > IORING_OP_READV_FIXED;
|
98
101
|
io_uring_queue_exit(&ring);
|
99
102
|
free(p);
|
100
103
|
return 0;
|
@@ -255,117 +258,6 @@ static int test_send_faults(int sock_tx, int sock_rx)
|
|
255
258
|
return T_EXIT_PASS;
|
256
259
|
}
|
257
260
|
|
258
|
-
static int create_socketpair_ip(struct sockaddr_storage *addr,
|
259
|
-
int *sock_client, int *sock_server,
|
260
|
-
bool ipv6, bool client_connect,
|
261
|
-
bool msg_zc, bool tcp)
|
262
|
-
{
|
263
|
-
socklen_t addr_size;
|
264
|
-
int family, sock, listen_sock = -1;
|
265
|
-
int ret;
|
266
|
-
|
267
|
-
memset(addr, 0, sizeof(*addr));
|
268
|
-
if (ipv6) {
|
269
|
-
struct sockaddr_in6 *saddr = (struct sockaddr_in6 *)addr;
|
270
|
-
|
271
|
-
family = AF_INET6;
|
272
|
-
saddr->sin6_family = family;
|
273
|
-
saddr->sin6_port = htons(0);
|
274
|
-
addr_size = sizeof(*saddr);
|
275
|
-
} else {
|
276
|
-
struct sockaddr_in *saddr = (struct sockaddr_in *)addr;
|
277
|
-
|
278
|
-
family = AF_INET;
|
279
|
-
saddr->sin_family = family;
|
280
|
-
saddr->sin_port = htons(0);
|
281
|
-
saddr->sin_addr.s_addr = htonl(INADDR_ANY);
|
282
|
-
addr_size = sizeof(*saddr);
|
283
|
-
}
|
284
|
-
|
285
|
-
/* server sock setup */
|
286
|
-
if (tcp) {
|
287
|
-
sock = listen_sock = socket(family, SOCK_STREAM, IPPROTO_TCP);
|
288
|
-
} else {
|
289
|
-
sock = *sock_server = socket(family, SOCK_DGRAM, 0);
|
290
|
-
}
|
291
|
-
if (sock < 0) {
|
292
|
-
perror("socket");
|
293
|
-
return 1;
|
294
|
-
}
|
295
|
-
|
296
|
-
ret = bind(sock, (struct sockaddr *)addr, addr_size);
|
297
|
-
if (ret < 0) {
|
298
|
-
perror("bind");
|
299
|
-
return 1;
|
300
|
-
}
|
301
|
-
|
302
|
-
ret = getsockname(sock, (struct sockaddr *)addr, &addr_size);
|
303
|
-
if (ret < 0) {
|
304
|
-
fprintf(stderr, "getsockname failed %i\n", errno);
|
305
|
-
return 1;
|
306
|
-
}
|
307
|
-
|
308
|
-
if (tcp) {
|
309
|
-
ret = listen(sock, 128);
|
310
|
-
assert(ret != -1);
|
311
|
-
}
|
312
|
-
|
313
|
-
if (ipv6) {
|
314
|
-
struct sockaddr_in6 *saddr = (struct sockaddr_in6 *)addr;
|
315
|
-
|
316
|
-
inet_pton(AF_INET6, HOSTV6, &(saddr->sin6_addr));
|
317
|
-
} else {
|
318
|
-
struct sockaddr_in *saddr = (struct sockaddr_in *)addr;
|
319
|
-
|
320
|
-
inet_pton(AF_INET, HOST, &saddr->sin_addr);
|
321
|
-
}
|
322
|
-
|
323
|
-
/* client sock setup */
|
324
|
-
if (tcp) {
|
325
|
-
*sock_client = socket(family, SOCK_STREAM, IPPROTO_TCP);
|
326
|
-
assert(client_connect);
|
327
|
-
} else {
|
328
|
-
*sock_client = socket(family, SOCK_DGRAM, 0);
|
329
|
-
}
|
330
|
-
if (*sock_client < 0) {
|
331
|
-
perror("socket");
|
332
|
-
return 1;
|
333
|
-
}
|
334
|
-
if (client_connect) {
|
335
|
-
ret = connect(*sock_client, (struct sockaddr *)addr, addr_size);
|
336
|
-
if (ret < 0) {
|
337
|
-
perror("connect");
|
338
|
-
return 1;
|
339
|
-
}
|
340
|
-
}
|
341
|
-
if (msg_zc) {
|
342
|
-
#ifdef SO_ZEROCOPY
|
343
|
-
int val = 1;
|
344
|
-
|
345
|
-
/*
|
346
|
-
* NOTE: apps must not set SO_ZEROCOPY when using io_uring zc.
|
347
|
-
* It's only here to test interactions with MSG_ZEROCOPY.
|
348
|
-
*/
|
349
|
-
if (setsockopt(*sock_client, SOL_SOCKET, SO_ZEROCOPY, &val, sizeof(val))) {
|
350
|
-
perror("setsockopt zc");
|
351
|
-
return 1;
|
352
|
-
}
|
353
|
-
#else
|
354
|
-
fprintf(stderr, "no SO_ZEROCOPY\n");
|
355
|
-
return 1;
|
356
|
-
#endif
|
357
|
-
}
|
358
|
-
if (tcp) {
|
359
|
-
*sock_server = accept(listen_sock, NULL, NULL);
|
360
|
-
if (!*sock_server) {
|
361
|
-
fprintf(stderr, "can't accept\n");
|
362
|
-
return 1;
|
363
|
-
}
|
364
|
-
close(listen_sock);
|
365
|
-
}
|
366
|
-
return 0;
|
367
|
-
}
|
368
|
-
|
369
261
|
struct send_conf {
|
370
262
|
bool fixed_buf;
|
371
263
|
bool mix_register;
|
@@ -447,6 +339,11 @@ static int do_test_inet_send(struct io_uring *ring, int sock_client, int sock_se
|
|
447
339
|
else
|
448
340
|
io_uring_prep_sendmsg(sqe, sock_client, &msghdr[i], msg_flags);
|
449
341
|
|
342
|
+
if (real_fixed_buf) {
|
343
|
+
sqe->ioprio |= IORING_RECVSEND_FIXED_BUF;
|
344
|
+
sqe->buf_index = conf->buf_index;
|
345
|
+
}
|
346
|
+
|
450
347
|
if (!conf->iovec) {
|
451
348
|
io = &iov[i];
|
452
349
|
iov_len = 1;
|
@@ -566,6 +463,16 @@ static int do_test_inet_send(struct io_uring *ring, int sock_client, int sock_se
|
|
566
463
|
return 0;
|
567
464
|
}
|
568
465
|
|
466
|
+
static int create_socketpair_ip(struct sockaddr_storage *addr,
|
467
|
+
int *sock_client, int *sock_server,
|
468
|
+
bool ipv6, bool client_connect,
|
469
|
+
bool msg_zc, bool tcp)
|
470
|
+
{
|
471
|
+
return t_create_socketpair_ip(addr, sock_client, sock_server, ipv6,
|
472
|
+
client_connect, msg_zc, tcp,
|
473
|
+
ipv6 ? HOSTV6 : HOST);
|
474
|
+
}
|
475
|
+
|
569
476
|
static int test_inet_send(struct io_uring *ring)
|
570
477
|
{
|
571
478
|
struct send_conf conf;
|
@@ -590,7 +497,7 @@ static int test_inet_send(struct io_uring *ring)
|
|
590
497
|
continue;
|
591
498
|
#endif
|
592
499
|
ret = create_socketpair_ip(&addr, &sock_client, &sock_server, ipv6,
|
593
|
-
|
500
|
+
client_connect, msg_zc_set, tcp);
|
594
501
|
if (ret) {
|
595
502
|
fprintf(stderr, "sock prep failed %d\n", ret);
|
596
503
|
return 1;
|
@@ -618,7 +525,11 @@ static int test_inet_send(struct io_uring *ring)
|
|
618
525
|
conf.tcp = tcp;
|
619
526
|
regbuf = conf.mix_register || conf.fixed_buf;
|
620
527
|
|
621
|
-
if (
|
528
|
+
if (!tcp && conf.long_iovec)
|
529
|
+
continue;
|
530
|
+
if (conf.use_sendmsg && regbuf && !has_regvec)
|
531
|
+
continue;
|
532
|
+
if (conf.iovec && (!conf.use_sendmsg || conf.cork))
|
622
533
|
continue;
|
623
534
|
if (!conf.zc) {
|
624
535
|
if (regbuf)
|
@@ -636,7 +547,7 @@ static int test_inet_send(struct io_uring *ring)
|
|
636
547
|
continue;
|
637
548
|
if (!client_connect && conf.addr == NULL)
|
638
549
|
continue;
|
639
|
-
if (conf.use_sendmsg &&
|
550
|
+
if (conf.use_sendmsg && !has_sendmsg)
|
640
551
|
continue;
|
641
552
|
if (msg_zc_set && !conf.zc)
|
642
553
|
continue;
|
@@ -900,6 +811,15 @@ static int run_basic_tests(void)
|
|
900
811
|
return 0;
|
901
812
|
}
|
902
813
|
|
814
|
+
static void free_buffers(void)
|
815
|
+
{
|
816
|
+
if (tx_buffer)
|
817
|
+
free(tx_buffer);
|
818
|
+
if (rx_buffer)
|
819
|
+
free(rx_buffer);
|
820
|
+
tx_buffer = rx_buffer = NULL;
|
821
|
+
}
|
822
|
+
|
903
823
|
int main(int argc, char *argv[])
|
904
824
|
{
|
905
825
|
size_t len;
|
@@ -920,27 +840,29 @@ int main(int argc, char *argv[])
|
|
920
840
|
|
921
841
|
page_sz = sysconf(_SC_PAGESIZE);
|
922
842
|
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
buffers_iov[BUF_T_LARGE].iov_base = tx_buffer;
|
928
|
-
buffers_iov[BUF_T_LARGE].iov_len = len;
|
929
|
-
} else {
|
930
|
-
if (tx_buffer)
|
931
|
-
free(tx_buffer);
|
932
|
-
if (rx_buffer)
|
933
|
-
free(rx_buffer);
|
843
|
+
if (try_hugepages) {
|
844
|
+
len = LARGE_BUF_SIZE;
|
845
|
+
tx_buffer = aligned_alloc(page_sz, len);
|
846
|
+
rx_buffer = aligned_alloc(page_sz, len);
|
934
847
|
|
935
|
-
|
848
|
+
if (tx_buffer && rx_buffer) {
|
849
|
+
buffers_iov[BUF_T_LARGE].iov_base = tx_buffer;
|
850
|
+
buffers_iov[BUF_T_LARGE].iov_len = len;
|
851
|
+
} else {
|
852
|
+
printf("skip large buffer tests, can't alloc\n");
|
853
|
+
free_buffers();
|
854
|
+
}
|
855
|
+
}
|
936
856
|
|
857
|
+
if (!tx_buffer) {
|
937
858
|
len = 2 * page_sz;
|
938
859
|
tx_buffer = aligned_alloc(page_sz, len);
|
939
860
|
rx_buffer = aligned_alloc(page_sz, len);
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
861
|
+
|
862
|
+
if (!tx_buffer || !rx_buffer) {
|
863
|
+
fprintf(stderr, "can't allocate buffers\n");
|
864
|
+
return T_EXIT_FAIL;
|
865
|
+
}
|
944
866
|
}
|
945
867
|
|
946
868
|
srand((unsigned)time(NULL));
|
@@ -0,0 +1,216 @@
|
|
1
|
+
/* SPDX-License-Identifier: MIT */
|
2
|
+
/*
|
3
|
+
* Description: Test non-immediate sendmsg completion with non-static iovec
|
4
|
+
*/
|
5
|
+
#include <stdio.h>
|
6
|
+
#include <stdlib.h>
|
7
|
+
#include <string.h>
|
8
|
+
#include <unistd.h>
|
9
|
+
#include <errno.h>
|
10
|
+
#include <arpa/inet.h>
|
11
|
+
#include <sys/socket.h>
|
12
|
+
#include <pthread.h>
|
13
|
+
#include "liburing.h"
|
14
|
+
#include "helpers.h"
|
15
|
+
|
16
|
+
/* anything > 1 should be fine, do bigger than FAST_IOV to be sure */
|
17
|
+
#define IOVS 16
|
18
|
+
#define INFLIGHT 256
|
19
|
+
|
20
|
+
enum {
|
21
|
+
IS_ACCEPT = 0x89,
|
22
|
+
IS_SENDMSG = 0x91,
|
23
|
+
};
|
24
|
+
|
25
|
+
struct thread_data {
|
26
|
+
pthread_t thread;
|
27
|
+
pthread_barrier_t barrier;
|
28
|
+
int parent_pid;
|
29
|
+
};
|
30
|
+
|
31
|
+
static void *thread_fn(void *__data)
|
32
|
+
{
|
33
|
+
struct thread_data *data = __data;
|
34
|
+
struct sockaddr_in saddr;
|
35
|
+
int sockfd, ret;
|
36
|
+
char msg[64];
|
37
|
+
|
38
|
+
memset(&saddr, 0, sizeof(saddr));
|
39
|
+
saddr.sin_family = AF_INET;
|
40
|
+
saddr.sin_port = htons(9999);
|
41
|
+
inet_pton(AF_INET, "127.0.0.1", &saddr.sin_addr);
|
42
|
+
|
43
|
+
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
44
|
+
if (sockfd < 0) {
|
45
|
+
perror("socket");
|
46
|
+
goto done;
|
47
|
+
}
|
48
|
+
|
49
|
+
ret = connect(sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
|
50
|
+
if (ret < 0) {
|
51
|
+
perror("connect");
|
52
|
+
close(sockfd);
|
53
|
+
goto done;
|
54
|
+
}
|
55
|
+
|
56
|
+
pthread_barrier_wait(&data->barrier);
|
57
|
+
do {
|
58
|
+
usleep(100);
|
59
|
+
memset(msg, 0, sizeof(msg));
|
60
|
+
ret = recv(sockfd, msg, sizeof(msg), 0);
|
61
|
+
} while (ret > 0);
|
62
|
+
|
63
|
+
close(sockfd);
|
64
|
+
done:
|
65
|
+
kill(data->parent_pid, SIGUSR1);
|
66
|
+
return NULL;
|
67
|
+
}
|
68
|
+
|
69
|
+
static int queue_sends(struct io_uring *ring, int send_fd, struct thread_data *td, struct msghdr *msghdr)
|
70
|
+
{
|
71
|
+
struct io_uring_sqe *sqe;
|
72
|
+
char buf[64];
|
73
|
+
int i, ret, sbuf;
|
74
|
+
struct iovec *iovs = msghdr->msg_iov;
|
75
|
+
|
76
|
+
sbuf = 8 * 1024;
|
77
|
+
ret = setsockopt(send_fd, SOL_SOCKET, SO_SNDBUF, &sbuf, sizeof(sbuf));
|
78
|
+
if (ret < 0) {
|
79
|
+
perror("setsockopt");
|
80
|
+
return 1;
|
81
|
+
}
|
82
|
+
|
83
|
+
memset(buf, 0xaa, sizeof(buf));
|
84
|
+
for (i = 0; i < IOVS; i++) {
|
85
|
+
iovs[i].iov_base = buf;
|
86
|
+
iovs[i].iov_len = sizeof(buf);
|
87
|
+
}
|
88
|
+
|
89
|
+
/* fill send buffer */
|
90
|
+
for (i = 0;; i++) {
|
91
|
+
ret = sendmsg(send_fd, msghdr, MSG_DONTWAIT);
|
92
|
+
if (ret == -1) {
|
93
|
+
if (errno == EAGAIN)
|
94
|
+
break;
|
95
|
+
perror("sendmsg");
|
96
|
+
return 1;
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
/* kick receiver, start sendmsg */
|
101
|
+
msghdr->msg_iovlen = IOVS;
|
102
|
+
pthread_barrier_wait(&td->barrier);
|
103
|
+
for (i = 0; i < INFLIGHT; i++) {
|
104
|
+
sqe = io_uring_get_sqe(ring);
|
105
|
+
io_uring_prep_sendmsg(sqe, send_fd, msghdr, 0);
|
106
|
+
sqe->user_data = IS_SENDMSG;
|
107
|
+
}
|
108
|
+
|
109
|
+
return 0;
|
110
|
+
}
|
111
|
+
|
112
|
+
int main(int argc, char *argv[])
|
113
|
+
{
|
114
|
+
struct io_uring ring;
|
115
|
+
struct io_uring_sqe *sqe;
|
116
|
+
struct io_uring_cqe *cqe;
|
117
|
+
struct sockaddr_in saddr;
|
118
|
+
int val, send_fd, ret, sockfd, seen_sends = 0;
|
119
|
+
struct thread_data td;
|
120
|
+
struct iovec iovs[IOVS];
|
121
|
+
struct msghdr msghdr = {
|
122
|
+
.msg_iov = iovs,
|
123
|
+
.msg_iovlen = 1,
|
124
|
+
};
|
125
|
+
|
126
|
+
if (argc > 1)
|
127
|
+
return T_EXIT_SKIP;
|
128
|
+
|
129
|
+
memset(&saddr, 0, sizeof(saddr));
|
130
|
+
saddr.sin_family = AF_INET;
|
131
|
+
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
132
|
+
saddr.sin_port = htons(9999);
|
133
|
+
|
134
|
+
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
135
|
+
if (sockfd < 0) {
|
136
|
+
perror("socket");
|
137
|
+
return T_EXIT_FAIL;
|
138
|
+
}
|
139
|
+
|
140
|
+
val = 1;
|
141
|
+
setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));
|
142
|
+
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
|
143
|
+
|
144
|
+
ret = bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr));
|
145
|
+
if (ret < 0) {
|
146
|
+
perror("bind");
|
147
|
+
close(sockfd);
|
148
|
+
return T_EXIT_FAIL;
|
149
|
+
}
|
150
|
+
|
151
|
+
ret = listen(sockfd, 1);
|
152
|
+
if (ret < 0) {
|
153
|
+
perror("listen");
|
154
|
+
close(sockfd);
|
155
|
+
return T_EXIT_FAIL;
|
156
|
+
}
|
157
|
+
|
158
|
+
ret = io_uring_queue_init(INFLIGHT, &ring, IORING_SETUP_SINGLE_ISSUER |
|
159
|
+
IORING_SETUP_DEFER_TASKRUN);
|
160
|
+
if (ret == -EINVAL) {
|
161
|
+
close(sockfd);
|
162
|
+
return T_EXIT_SKIP;
|
163
|
+
}
|
164
|
+
|
165
|
+
sqe = io_uring_get_sqe(&ring);
|
166
|
+
io_uring_prep_multishot_accept(sqe, sockfd, NULL, NULL, 0);
|
167
|
+
sqe->user_data = IS_ACCEPT;
|
168
|
+
io_uring_submit(&ring);
|
169
|
+
|
170
|
+
/* check for no multishot accept */
|
171
|
+
ret = io_uring_peek_cqe(&ring, &cqe);
|
172
|
+
if (!ret && cqe->res == -EINVAL) {
|
173
|
+
close(sockfd);
|
174
|
+
return T_EXIT_SKIP;
|
175
|
+
}
|
176
|
+
|
177
|
+
/* start receiver */
|
178
|
+
td.parent_pid = getpid();
|
179
|
+
pthread_barrier_init(&td.barrier, NULL, 2);
|
180
|
+
pthread_create(&td.thread, NULL, thread_fn, &td);
|
181
|
+
|
182
|
+
do {
|
183
|
+
ret = io_uring_submit_and_wait(&ring, 1);
|
184
|
+
if (ret < 0) {
|
185
|
+
fprintf(stderr, "submit: %d\n", ret);
|
186
|
+
break;
|
187
|
+
}
|
188
|
+
ret = io_uring_peek_cqe(&ring, &cqe);
|
189
|
+
if (ret) {
|
190
|
+
fprintf(stderr, "peek: %d\n", ret);
|
191
|
+
break;
|
192
|
+
}
|
193
|
+
|
194
|
+
switch (cqe->user_data) {
|
195
|
+
case IS_ACCEPT:
|
196
|
+
send_fd = cqe->res;
|
197
|
+
io_uring_cqe_seen(&ring, cqe);
|
198
|
+
|
199
|
+
ret = queue_sends(&ring, send_fd, &td, &msghdr);
|
200
|
+
if (ret)
|
201
|
+
exit(T_EXIT_FAIL);
|
202
|
+
break;
|
203
|
+
case IS_SENDMSG:
|
204
|
+
io_uring_cqe_seen(&ring, cqe);
|
205
|
+
seen_sends++;
|
206
|
+
if (seen_sends == INFLIGHT)
|
207
|
+
exit(0);
|
208
|
+
break;
|
209
|
+
default:
|
210
|
+
fprintf(stderr, "got unknown cqe\n");
|
211
|
+
return T_EXIT_FAIL;
|
212
|
+
}
|
213
|
+
} while (1);
|
214
|
+
|
215
|
+
return T_EXIT_FAIL;
|
216
|
+
}
|