uringmachine 0.19 → 0.20.0
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 +15 -0
- data/TODO.md +40 -0
- data/examples/bm_fileno.rb +33 -0
- data/examples/bm_mutex.rb +85 -0
- data/examples/bm_mutex_single.rb +33 -0
- data/examples/bm_queue.rb +27 -28
- data/examples/bm_send.rb +2 -5
- data/examples/bm_snooze.rb +20 -42
- data/examples/fiber_scheduler_demo.rb +15 -51
- data/examples/fiber_scheduler_fork.rb +24 -0
- data/examples/nc_ssl.rb +71 -0
- data/ext/um/extconf.rb +5 -15
- data/ext/um/um.c +73 -42
- data/ext/um/um.h +21 -11
- data/ext/um/um_async_op_class.c +2 -2
- data/ext/um/um_buffer.c +1 -1
- data/ext/um/um_class.c +94 -23
- data/ext/um/um_const.c +51 -3
- data/ext/um/um_mutex_class.c +1 -1
- data/ext/um/um_queue_class.c +1 -1
- data/ext/um/um_stream.c +5 -5
- data/ext/um/um_stream_class.c +3 -0
- data/ext/um/um_sync.c +22 -27
- data/ext/um/um_utils.c +59 -19
- data/grant-2025/journal.md +229 -0
- data/grant-2025/tasks.md +66 -0
- data/lib/uringmachine/fiber_scheduler.rb +180 -48
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +6 -0
- data/test/test_fiber_scheduler.rb +138 -0
- data/test/test_stream.rb +2 -2
- data/test/test_um.rb +451 -33
- data/vendor/liburing/.github/workflows/ci.yml +94 -1
- data/vendor/liburing/.github/workflows/test_build.c +9 -0
- data/vendor/liburing/configure +27 -0
- data/vendor/liburing/examples/Makefile +6 -0
- data/vendor/liburing/examples/helpers.c +8 -0
- data/vendor/liburing/examples/helpers.h +5 -0
- data/vendor/liburing/liburing.spec +1 -1
- data/vendor/liburing/src/Makefile +9 -3
- data/vendor/liburing/src/include/liburing/barrier.h +11 -5
- data/vendor/liburing/src/include/liburing/io_uring/query.h +41 -0
- data/vendor/liburing/src/include/liburing/io_uring.h +50 -0
- data/vendor/liburing/src/include/liburing/sanitize.h +16 -4
- data/vendor/liburing/src/include/liburing.h +445 -121
- data/vendor/liburing/src/liburing-ffi.map +15 -0
- data/vendor/liburing/src/liburing.map +8 -0
- data/vendor/liburing/src/sanitize.c +4 -1
- data/vendor/liburing/src/setup.c +7 -4
- data/vendor/liburing/test/232c93d07b74.c +4 -16
- data/vendor/liburing/test/Makefile +15 -1
- data/vendor/liburing/test/accept.c +2 -13
- data/vendor/liburing/test/conn-unreach.c +132 -0
- data/vendor/liburing/test/fd-pass.c +32 -7
- data/vendor/liburing/test/fdinfo.c +39 -12
- data/vendor/liburing/test/fifo-futex-poll.c +114 -0
- data/vendor/liburing/test/fifo-nonblock-read.c +1 -12
- data/vendor/liburing/test/futex.c +1 -1
- data/vendor/liburing/test/helpers.c +99 -2
- data/vendor/liburing/test/helpers.h +9 -0
- data/vendor/liburing/test/io_uring_passthrough.c +6 -12
- data/vendor/liburing/test/mock_file.c +379 -0
- data/vendor/liburing/test/mock_file.h +47 -0
- data/vendor/liburing/test/nop.c +2 -2
- data/vendor/liburing/test/nop32-overflow.c +150 -0
- data/vendor/liburing/test/nop32.c +126 -0
- data/vendor/liburing/test/pipe.c +166 -0
- data/vendor/liburing/test/poll-race-mshot.c +13 -1
- data/vendor/liburing/test/recv-mshot-fair.c +81 -34
- data/vendor/liburing/test/recvsend_bundle.c +1 -1
- data/vendor/liburing/test/resize-rings.c +2 -0
- data/vendor/liburing/test/ring-query.c +322 -0
- data/vendor/liburing/test/ringbuf-loop.c +87 -0
- data/vendor/liburing/test/runtests.sh +2 -2
- data/vendor/liburing/test/send-zerocopy.c +43 -5
- data/vendor/liburing/test/send_recv.c +102 -32
- data/vendor/liburing/test/shutdown.c +2 -12
- data/vendor/liburing/test/socket-nb.c +3 -14
- data/vendor/liburing/test/socket-rw-eagain.c +2 -12
- data/vendor/liburing/test/socket-rw-offset.c +2 -12
- data/vendor/liburing/test/socket-rw.c +2 -12
- data/vendor/liburing/test/sqe-mixed-bad-wrap.c +87 -0
- data/vendor/liburing/test/sqe-mixed-nop.c +82 -0
- data/vendor/liburing/test/sqe-mixed-uring_cmd.c +153 -0
- data/vendor/liburing/test/timestamp.c +56 -19
- data/vendor/liburing/test/vec-regbuf.c +2 -4
- data/vendor/liburing/test/wq-aff.c +7 -0
- metadata +24 -2
|
@@ -18,7 +18,6 @@ int main(int argc, char *argv[])
|
|
|
18
18
|
struct io_uring ring;
|
|
19
19
|
char buf[32];
|
|
20
20
|
int fds[2];
|
|
21
|
-
int flags;
|
|
22
21
|
int ret;
|
|
23
22
|
|
|
24
23
|
io_uring_queue_init(1, &ring, 0);
|
|
@@ -28,17 +27,7 @@ int main(int argc, char *argv[])
|
|
|
28
27
|
return T_EXIT_FAIL;
|
|
29
28
|
}
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
if (flags < 0) {
|
|
33
|
-
perror("fcntl get");
|
|
34
|
-
return T_EXIT_FAIL;
|
|
35
|
-
}
|
|
36
|
-
flags |= O_NONBLOCK;
|
|
37
|
-
ret = fcntl(fds[0], F_SETFL, flags);
|
|
38
|
-
if (ret < 0) {
|
|
39
|
-
perror("fcntl set");
|
|
40
|
-
return T_EXIT_FAIL;
|
|
41
|
-
}
|
|
30
|
+
t_set_nonblock(fds[0]);
|
|
42
31
|
|
|
43
32
|
sqe = io_uring_get_sqe(&ring);
|
|
44
33
|
io_uring_prep_read(sqe, fds[0], buf, sizeof(buf), 0);
|
|
@@ -149,7 +149,7 @@ static int test(int flags, int vectored)
|
|
|
149
149
|
return ret;
|
|
150
150
|
|
|
151
151
|
for (i = 0; i < LOOPS; i++) {
|
|
152
|
-
int async_cancel = (
|
|
152
|
+
int async_cancel = !(i % 2);
|
|
153
153
|
int async_wait = !(i % 3);
|
|
154
154
|
ret = __test(&ring, vectored, async_wait, async_cancel);
|
|
155
155
|
if (ret) {
|
|
@@ -136,9 +136,10 @@ enum t_setup_ret t_create_ring_params(int depth, struct io_uring *ring,
|
|
|
136
136
|
fprintf(stdout, "SQPOLL skipped for regular user\n");
|
|
137
137
|
return T_SETUP_SKIP;
|
|
138
138
|
}
|
|
139
|
+
if (ret == -EINVAL)
|
|
140
|
+
return T_SETUP_SKIP;
|
|
139
141
|
|
|
140
|
-
|
|
141
|
-
fprintf(stderr, "queue_init: %s\n", strerror(-ret));
|
|
142
|
+
fprintf(stderr, "queue_init: %s\n", strerror(-ret));
|
|
142
143
|
return ret;
|
|
143
144
|
}
|
|
144
145
|
|
|
@@ -484,3 +485,99 @@ int t_create_socketpair_ip(struct sockaddr_storage *addr,
|
|
|
484
485
|
}
|
|
485
486
|
return 0;
|
|
486
487
|
}
|
|
488
|
+
|
|
489
|
+
static void __t_toggle_nonblock(int fd, int set)
|
|
490
|
+
{
|
|
491
|
+
int flags;
|
|
492
|
+
|
|
493
|
+
flags = fcntl(fd, F_GETFL, 0);
|
|
494
|
+
if (flags < 0)
|
|
495
|
+
t_error(1, errno, "fcntl F_GETFL");
|
|
496
|
+
if (set)
|
|
497
|
+
flags |= O_NONBLOCK;
|
|
498
|
+
else
|
|
499
|
+
flags &= ~O_NONBLOCK;
|
|
500
|
+
if (fcntl(fd, F_SETFL, flags) < 0)
|
|
501
|
+
t_error(1, errno, "fcntl F_SETFL");
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
void t_set_nonblock(int fd)
|
|
505
|
+
{
|
|
506
|
+
__t_toggle_nonblock(fd, 1);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
void t_clear_nonblock(int fd)
|
|
510
|
+
{
|
|
511
|
+
__t_toggle_nonblock(fd, 0);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
int t_submit_and_wait_single(struct io_uring *ring, struct io_uring_cqe **cqe)
|
|
515
|
+
{
|
|
516
|
+
int ret;
|
|
517
|
+
|
|
518
|
+
ret = io_uring_submit(ring);
|
|
519
|
+
if (ret <= 0) {
|
|
520
|
+
fprintf(stderr, "sqe submit failed: %d\n", ret);
|
|
521
|
+
return -1;
|
|
522
|
+
}
|
|
523
|
+
ret = io_uring_wait_cqe(ring, cqe);
|
|
524
|
+
if (ret < 0) {
|
|
525
|
+
fprintf(stderr, "wait completion %d\n", ret);
|
|
526
|
+
return ret;
|
|
527
|
+
}
|
|
528
|
+
return 0;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
size_t t_iovec_data_length(struct iovec *iov, unsigned iov_len)
|
|
532
|
+
{
|
|
533
|
+
size_t sz = 0;
|
|
534
|
+
int i;
|
|
535
|
+
|
|
536
|
+
for (i = 0; i < iov_len; i++)
|
|
537
|
+
sz += iov[i].iov_len;
|
|
538
|
+
return sz;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
#define t_min(a, b) ((a) < (b) ? (a) : (b))
|
|
542
|
+
|
|
543
|
+
unsigned long t_compare_data_iovec(struct iovec *iov_src, unsigned nr_src,
|
|
544
|
+
struct iovec *iov_dst, unsigned nr_dst)
|
|
545
|
+
{
|
|
546
|
+
size_t src_len = t_iovec_data_length(iov_src, nr_src);
|
|
547
|
+
size_t dst_len = t_iovec_data_length(iov_dst, nr_dst);
|
|
548
|
+
size_t len_left = t_min(src_len, dst_len);
|
|
549
|
+
unsigned long src_off = 0, dst_off = 0;
|
|
550
|
+
unsigned long offset = 0;
|
|
551
|
+
|
|
552
|
+
while (offset != len_left) {
|
|
553
|
+
size_t len = len_left - offset;
|
|
554
|
+
unsigned long i;
|
|
555
|
+
|
|
556
|
+
len = t_min(len, iov_src->iov_len - src_off);
|
|
557
|
+
len = t_min(len, iov_dst->iov_len - dst_off);
|
|
558
|
+
|
|
559
|
+
for (i = 0; i < len; i++) {
|
|
560
|
+
char csrc = ((char *)iov_src->iov_base)[src_off + i];
|
|
561
|
+
char cdst = ((char *)iov_dst->iov_base)[dst_off + i];
|
|
562
|
+
|
|
563
|
+
if (csrc != cdst) {
|
|
564
|
+
fprintf(stderr, "data mismatch, %i vs %i\n",
|
|
565
|
+
csrc, cdst);
|
|
566
|
+
return -EINVAL;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
src_off += len;
|
|
571
|
+
dst_off += len;
|
|
572
|
+
if (src_off == iov_src->iov_len) {
|
|
573
|
+
src_off = 0;
|
|
574
|
+
iov_src++;
|
|
575
|
+
}
|
|
576
|
+
if (dst_off == iov_dst->iov_len) {
|
|
577
|
+
dst_off = 0;
|
|
578
|
+
iov_dst++;
|
|
579
|
+
}
|
|
580
|
+
offset += len;
|
|
581
|
+
}
|
|
582
|
+
return 0;
|
|
583
|
+
}
|
|
@@ -99,6 +99,8 @@ enum t_setup_ret t_register_buffers(struct io_uring *ring,
|
|
|
99
99
|
unsigned nr_iovecs);
|
|
100
100
|
|
|
101
101
|
bool t_probe_defer_taskrun(void);
|
|
102
|
+
void t_set_nonblock(int fd);
|
|
103
|
+
void t_clear_nonblock(int fd);
|
|
102
104
|
|
|
103
105
|
unsigned __io_uring_flush_sq(struct io_uring *ring);
|
|
104
106
|
|
|
@@ -120,6 +122,13 @@ unsigned long long mtime_since_now(struct timeval *tv);
|
|
|
120
122
|
unsigned long long utime_since(const struct timeval *s, const struct timeval *e);
|
|
121
123
|
unsigned long long utime_since_now(struct timeval *tv);
|
|
122
124
|
|
|
125
|
+
int t_submit_and_wait_single(struct io_uring *ring, struct io_uring_cqe **cqe);
|
|
126
|
+
|
|
127
|
+
size_t t_iovec_data_length(struct iovec *iov, unsigned iov_len);
|
|
128
|
+
|
|
129
|
+
unsigned long t_compare_data_iovec(struct iovec *iov_src, unsigned nr_src,
|
|
130
|
+
struct iovec *iov_dst, unsigned nr_dst);
|
|
131
|
+
|
|
123
132
|
#ifdef __cplusplus
|
|
124
133
|
}
|
|
125
134
|
#endif
|
|
@@ -141,18 +141,16 @@ static int __test_io(const char *file, struct io_uring *ring, int tc, int read,
|
|
|
141
141
|
|
|
142
142
|
if (sqthread)
|
|
143
143
|
use_fd = 0;
|
|
144
|
+
if (nonvec)
|
|
145
|
+
io_uring_prep_uring_cmd(sqe, NVME_URING_CMD_IO, use_fd);
|
|
146
|
+
else
|
|
147
|
+
io_uring_prep_uring_cmd(sqe, NVME_URING_CMD_IO_VEC, use_fd);
|
|
144
148
|
if (fixed && (i & 1))
|
|
145
149
|
do_fixed = 0;
|
|
146
150
|
if (do_fixed)
|
|
147
151
|
sqe->buf_index = 0;
|
|
148
152
|
if (async)
|
|
149
153
|
sqe->flags |= IOSQE_ASYNC;
|
|
150
|
-
if (nonvec)
|
|
151
|
-
sqe->cmd_op = NVME_URING_CMD_IO;
|
|
152
|
-
else
|
|
153
|
-
sqe->cmd_op = NVME_URING_CMD_IO_VEC;
|
|
154
|
-
sqe->fd = use_fd;
|
|
155
|
-
sqe->opcode = IORING_OP_URING_CMD;
|
|
156
154
|
if (do_fixed)
|
|
157
155
|
sqe->uring_cmd_flags |= IORING_URING_CMD_FIXED;
|
|
158
156
|
sqe->user_data = ((uint64_t)offset << 32) | i;
|
|
@@ -328,9 +326,7 @@ static int test_invalid_passthru_submit(const char *file)
|
|
|
328
326
|
}
|
|
329
327
|
|
|
330
328
|
sqe = io_uring_get_sqe(&ring);
|
|
331
|
-
|
|
332
|
-
sqe->cmd_op = NVME_URING_CMD_IO;
|
|
333
|
-
sqe->opcode = IORING_OP_URING_CMD;
|
|
329
|
+
io_uring_prep_uring_cmd(sqe, NVME_URING_CMD_IO, fd);
|
|
334
330
|
sqe->user_data = 1;
|
|
335
331
|
cmd = (struct nvme_uring_cmd *)sqe->cmd;
|
|
336
332
|
memset(cmd, 0, sizeof(struct nvme_uring_cmd));
|
|
@@ -401,10 +397,8 @@ static int test_io_uring_submit_enters(const char *file)
|
|
|
401
397
|
__u32 nlb;
|
|
402
398
|
|
|
403
399
|
sqe = io_uring_get_sqe(&ring);
|
|
404
|
-
|
|
400
|
+
io_uring_prep_uring_cmd(sqe, NVME_URING_CMD_IO, fd);
|
|
405
401
|
sqe->user_data = i;
|
|
406
|
-
sqe->opcode = IORING_OP_URING_CMD;
|
|
407
|
-
sqe->cmd_op = NVME_URING_CMD_IO;
|
|
408
402
|
cmd = (struct nvme_uring_cmd *)sqe->cmd;
|
|
409
403
|
memset(cmd, 0, sizeof(struct nvme_uring_cmd));
|
|
410
404
|
|
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
#include <errno.h>
|
|
2
|
+
#include <stdio.h>
|
|
3
|
+
#include <unistd.h>
|
|
4
|
+
#include <stdlib.h>
|
|
5
|
+
#include <string.h>
|
|
6
|
+
#include <fcntl.h>
|
|
7
|
+
#include <poll.h>
|
|
8
|
+
#include <assert.h>
|
|
9
|
+
|
|
10
|
+
#include "liburing.h"
|
|
11
|
+
#include "test.h"
|
|
12
|
+
#include "helpers.h"
|
|
13
|
+
|
|
14
|
+
#include "mock_file.h"
|
|
15
|
+
|
|
16
|
+
static struct io_uring mgr_ring;
|
|
17
|
+
static __u64 mock_features;
|
|
18
|
+
static int mgr_fd;
|
|
19
|
+
|
|
20
|
+
static bool has_feature(int feature)
|
|
21
|
+
{
|
|
22
|
+
return mock_features >= feature;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static int setup_mgr(void)
|
|
26
|
+
{
|
|
27
|
+
struct io_uring_mock_probe mp;
|
|
28
|
+
struct io_uring_cqe *cqe;
|
|
29
|
+
struct io_uring_sqe *sqe;
|
|
30
|
+
int ret;
|
|
31
|
+
|
|
32
|
+
ret = mgr_fd = open("/dev/io_uring_mock", O_RDWR);
|
|
33
|
+
if (mgr_fd < 0) {
|
|
34
|
+
if (errno == EACCES)
|
|
35
|
+
printf("No permission to open /dev/io_uring_mock, skipping\n");
|
|
36
|
+
else
|
|
37
|
+
printf("no io_uring mock files, skip\n");
|
|
38
|
+
return T_EXIT_SKIP;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
ret = io_uring_queue_init(8, &mgr_ring, 0);
|
|
42
|
+
if (ret) {
|
|
43
|
+
fprintf(stderr, "mgr ring setup failed %i\n", ret);
|
|
44
|
+
return T_EXIT_FAIL;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
memset(&mp, 0, sizeof(mp));
|
|
48
|
+
sqe = io_uring_get_sqe(&mgr_ring);
|
|
49
|
+
io_uring_prep_uring_cmd(sqe, IORING_MOCK_MGR_CMD_PROBE, mgr_fd);
|
|
50
|
+
sqe->addr = (__u64)(unsigned long)∓
|
|
51
|
+
sqe->len = sizeof(mp);
|
|
52
|
+
|
|
53
|
+
ret = t_submit_and_wait_single(&mgr_ring, &cqe);
|
|
54
|
+
if (ret || cqe->res) {
|
|
55
|
+
fprintf(stderr, "probe cmd failed %i %i\n", ret, cqe->res);
|
|
56
|
+
return T_EXIT_FAIL;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
io_uring_cqe_seen(&mgr_ring, cqe);
|
|
60
|
+
mock_features = mp.features;
|
|
61
|
+
return 0;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static int create_mock_file(struct io_uring_mock_create *mc)
|
|
65
|
+
{
|
|
66
|
+
struct io_uring_cqe *cqe;
|
|
67
|
+
struct io_uring_sqe *sqe;
|
|
68
|
+
int ret;
|
|
69
|
+
|
|
70
|
+
sqe = io_uring_get_sqe(&mgr_ring);
|
|
71
|
+
io_uring_prep_uring_cmd(sqe, IORING_MOCK_MGR_CMD_CREATE, mgr_fd);
|
|
72
|
+
sqe->addr = (__u64)(unsigned long)mc;
|
|
73
|
+
sqe->len = sizeof(*mc);
|
|
74
|
+
|
|
75
|
+
ret = t_submit_and_wait_single(&mgr_ring, &cqe);
|
|
76
|
+
if (ret || cqe->res) {
|
|
77
|
+
fprintf(stderr, "file create cmd failed %i %i\n", ret, cqe->res);
|
|
78
|
+
return T_EXIT_FAIL;
|
|
79
|
+
}
|
|
80
|
+
io_uring_cqe_seen(&mgr_ring, cqe);
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
static int t_copy_regvec(struct io_uring *ring, int mock_fd,
|
|
85
|
+
struct iovec *iov, unsigned iov_len, char *buf,
|
|
86
|
+
bool from_iov)
|
|
87
|
+
{
|
|
88
|
+
struct io_uring_cqe *cqe;
|
|
89
|
+
struct io_uring_sqe *sqe;
|
|
90
|
+
int ret;
|
|
91
|
+
|
|
92
|
+
sqe = io_uring_get_sqe(ring);
|
|
93
|
+
io_uring_prep_uring_cmd(sqe, IORING_MOCK_CMD_COPY_REGBUF, mock_fd);
|
|
94
|
+
sqe->addr3 = (__u64)(unsigned long)buf;
|
|
95
|
+
sqe->addr = (__u64)(unsigned long)iov;
|
|
96
|
+
sqe->len = iov_len;
|
|
97
|
+
if (from_iov)
|
|
98
|
+
sqe->file_index = IORING_MOCK_COPY_FROM;
|
|
99
|
+
sqe->buf_index = from_iov ? 0 : 1;
|
|
100
|
+
sqe->user_data = 43;
|
|
101
|
+
sqe->uring_cmd_flags |= IORING_URING_CMD_FIXED;
|
|
102
|
+
|
|
103
|
+
ret = t_submit_and_wait_single(ring, &cqe);
|
|
104
|
+
if (ret)
|
|
105
|
+
t_error(1, ret, "submit/wait failed");
|
|
106
|
+
|
|
107
|
+
ret = cqe->res;
|
|
108
|
+
io_uring_cqe_seen(ring, cqe);
|
|
109
|
+
return ret;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
static int t_copy_verify_regvec(struct io_uring *ring, int mock_fd,
|
|
113
|
+
struct iovec *iov, unsigned iov_len, char *buf,
|
|
114
|
+
bool from_iov)
|
|
115
|
+
{
|
|
116
|
+
struct iovec iov2;
|
|
117
|
+
int ret;
|
|
118
|
+
|
|
119
|
+
ret = t_copy_regvec(ring, mock_fd, iov, iov_len, buf, from_iov);
|
|
120
|
+
if (ret < 0 || ret != t_iovec_data_length(iov, iov_len))
|
|
121
|
+
return ret < 0 ? ret : -1;
|
|
122
|
+
|
|
123
|
+
iov2.iov_base = buf;
|
|
124
|
+
iov2.iov_len = -1U;
|
|
125
|
+
|
|
126
|
+
ret = t_compare_data_iovec(iov, iov_len, &iov2, 1);
|
|
127
|
+
if (ret) {
|
|
128
|
+
fprintf(stderr, "iovec1 data mismatch %i\n", ret);
|
|
129
|
+
return -1;
|
|
130
|
+
}
|
|
131
|
+
return 0;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
static int test_regvec_cmd(struct io_uring *ring, int mock_fd)
|
|
135
|
+
{
|
|
136
|
+
struct iovec buf_iovec[2];
|
|
137
|
+
struct iovec iov[8];
|
|
138
|
+
size_t size = 4096 * 32;
|
|
139
|
+
char *buf_src, *buf_dst;
|
|
140
|
+
int i, ret;
|
|
141
|
+
|
|
142
|
+
buf_src = aligned_alloc(4096, size);
|
|
143
|
+
buf_dst = aligned_alloc(4096, size);
|
|
144
|
+
if (!buf_src || !buf_dst)
|
|
145
|
+
t_error(0, -ENOMEM, "can't allocate buffers");
|
|
146
|
+
|
|
147
|
+
for (i = 0; i < size; i++)
|
|
148
|
+
buf_src[i] = 'a' + (i % 26);
|
|
149
|
+
|
|
150
|
+
buf_iovec[0].iov_base = buf_src;
|
|
151
|
+
buf_iovec[0].iov_len = size;
|
|
152
|
+
buf_iovec[1].iov_base = buf_dst;
|
|
153
|
+
buf_iovec[1].iov_len = size;
|
|
154
|
+
ret = t_register_buffers(ring, buf_iovec, 2);
|
|
155
|
+
if (ret) {
|
|
156
|
+
free(buf_src);
|
|
157
|
+
free(buf_dst);
|
|
158
|
+
return ret == T_SETUP_SKIP ? 0 : T_EXIT_FAIL;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
memset(buf_dst, 0, size);
|
|
162
|
+
iov[0].iov_len = size;
|
|
163
|
+
iov[0].iov_base = buf_src;
|
|
164
|
+
ret = t_copy_verify_regvec(ring, mock_fd, iov, 1, buf_dst, true);
|
|
165
|
+
if (ret < 0) {
|
|
166
|
+
fprintf(stderr, "t_copy_verify_regvec iovec1 failed %i\n", ret);
|
|
167
|
+
return T_EXIT_FAIL;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
memset(buf_dst, 0, size);
|
|
171
|
+
iov[0].iov_len = size;
|
|
172
|
+
iov[0].iov_base = buf_dst;
|
|
173
|
+
ret = t_copy_verify_regvec(ring, mock_fd, iov, 1, buf_src, false);
|
|
174
|
+
if (ret < 0) {
|
|
175
|
+
fprintf(stderr, "t_copy_verify_regvec iovec1 reverse failed %i\n", ret);
|
|
176
|
+
return T_EXIT_FAIL;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
memset(buf_dst, 0, size);
|
|
180
|
+
iov[0].iov_base = buf_src;
|
|
181
|
+
iov[0].iov_len = 5;
|
|
182
|
+
iov[1].iov_base = buf_src + 5;
|
|
183
|
+
iov[1].iov_len = 11;
|
|
184
|
+
iov[2].iov_base = buf_src + (4096 - 127);
|
|
185
|
+
iov[2].iov_len = 127;
|
|
186
|
+
iov[3].iov_base = buf_src + (4096 - 127);
|
|
187
|
+
iov[3].iov_len = 127 + 4096 + 13;
|
|
188
|
+
iov[4].iov_base = buf_src + 4 * 4096;
|
|
189
|
+
iov[4].iov_len = 4096 + 73;
|
|
190
|
+
iov[5].iov_base = buf_src + 7 * 4096 + 127;
|
|
191
|
+
iov[5].iov_len = 4096 * 11 + 132;
|
|
192
|
+
assert(t_iovec_data_length(iov, 6) <= size);
|
|
193
|
+
ret = t_copy_verify_regvec(ring, mock_fd, iov, 6, buf_dst, true);
|
|
194
|
+
if (ret < 0) {
|
|
195
|
+
fprintf(stderr, "t_copy_verify_regvec iovec6 failed %i\n", ret);
|
|
196
|
+
return T_EXIT_FAIL;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
memset(buf_dst, 0, size);
|
|
200
|
+
iov[0].iov_base = buf_dst;
|
|
201
|
+
iov[0].iov_len = 5;
|
|
202
|
+
iov[1].iov_base = buf_dst + 5;
|
|
203
|
+
iov[1].iov_len = 11;
|
|
204
|
+
iov[2].iov_base = buf_dst + (4096 - 127);
|
|
205
|
+
iov[2].iov_len = 127;
|
|
206
|
+
iov[3].iov_base = buf_dst + 4 * 4096;
|
|
207
|
+
iov[3].iov_len = 4096 + 73;
|
|
208
|
+
iov[4].iov_base = buf_dst + 7 * 4096 + 127;
|
|
209
|
+
iov[4].iov_len = 4096 * 11 + 132;
|
|
210
|
+
assert(t_iovec_data_length(iov, 5) <= size);
|
|
211
|
+
ret = t_copy_verify_regvec(ring, mock_fd, iov, 5, buf_src, false);
|
|
212
|
+
if (ret < 0) {
|
|
213
|
+
fprintf(stderr, "t_copy_verify_regvec iovec6 reverse failed %i\n", ret);
|
|
214
|
+
return T_EXIT_FAIL;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
free(buf_src);
|
|
218
|
+
free(buf_dst);
|
|
219
|
+
return 0;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
static int test_cmds(void)
|
|
223
|
+
{
|
|
224
|
+
struct io_uring_mock_create mc;
|
|
225
|
+
struct io_uring ring;
|
|
226
|
+
int ret, mock_fd;
|
|
227
|
+
|
|
228
|
+
memset(&mc, 0, sizeof(mc));
|
|
229
|
+
if (create_mock_file(&mc))
|
|
230
|
+
return T_EXIT_FAIL;
|
|
231
|
+
mock_fd = mc.out_fd;
|
|
232
|
+
|
|
233
|
+
ret = io_uring_queue_init(8, &ring, 0);
|
|
234
|
+
if (ret) {
|
|
235
|
+
fprintf(stderr, "ring setup failed: %d\n", ret);
|
|
236
|
+
return 1;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (has_feature(IORING_MOCK_FEAT_CMD_COPY)) {
|
|
240
|
+
ret = test_regvec_cmd(&ring, mock_fd);
|
|
241
|
+
if (ret) {
|
|
242
|
+
fprintf(stderr, "test_regvec_cmd() failed\n");
|
|
243
|
+
return T_EXIT_FAIL;
|
|
244
|
+
}
|
|
245
|
+
} else {
|
|
246
|
+
printf("skip test_regvec_cmd()\n");
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
io_uring_queue_exit(&ring);
|
|
250
|
+
return 0;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
static int test_reads(struct io_uring *ring, int mock_fd, void *buffer)
|
|
254
|
+
{
|
|
255
|
+
struct io_uring_cqe *cqe;
|
|
256
|
+
struct io_uring_sqe *sqe;
|
|
257
|
+
int io_len = 4096;
|
|
258
|
+
int nr_reqs = 16;
|
|
259
|
+
int i, ret;
|
|
260
|
+
|
|
261
|
+
for (i = 0; i < nr_reqs; i++) {
|
|
262
|
+
sqe = io_uring_get_sqe(ring);
|
|
263
|
+
io_uring_prep_read(sqe, mock_fd, buffer, io_len, 0);
|
|
264
|
+
sqe->user_data = i;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
ret = io_uring_submit(ring);
|
|
268
|
+
if (ret != nr_reqs) {
|
|
269
|
+
fprintf(stderr, "submit got %d, wanted %d\n", ret, nr_reqs);
|
|
270
|
+
return T_EXIT_FAIL;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
for (i = 0; i < nr_reqs; i++) {
|
|
274
|
+
ret = io_uring_wait_cqe(ring, &cqe);
|
|
275
|
+
if (ret) {
|
|
276
|
+
fprintf(stderr, "wait_cqe=%d\n", ret);
|
|
277
|
+
return T_EXIT_FAIL;
|
|
278
|
+
}
|
|
279
|
+
if (cqe->res != io_len) {
|
|
280
|
+
fprintf(stderr, "unexpected cqe res %i, data %i\n",
|
|
281
|
+
cqe->res, (int)cqe->user_data);
|
|
282
|
+
return T_EXIT_FAIL;
|
|
283
|
+
}
|
|
284
|
+
io_uring_cqe_seen(ring, cqe);
|
|
285
|
+
}
|
|
286
|
+
return 0;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
static int test_rw(void)
|
|
290
|
+
{
|
|
291
|
+
void *buffer;
|
|
292
|
+
struct io_uring ring;
|
|
293
|
+
int ret, i;
|
|
294
|
+
|
|
295
|
+
if (!has_feature(IORING_MOCK_FEAT_RW_ZERO)) {
|
|
296
|
+
printf("no mock read-write support, skip\n");
|
|
297
|
+
return T_EXIT_SKIP;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
buffer = malloc(4096);
|
|
301
|
+
if (!buffer) {
|
|
302
|
+
fprintf(stderr, "can't allocate buffers\n");
|
|
303
|
+
return T_EXIT_FAIL;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
ret = io_uring_queue_init(32, &ring, 0);
|
|
307
|
+
if (ret) {
|
|
308
|
+
fprintf(stderr, "ring setup failed: %d\n", ret);
|
|
309
|
+
return 1;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
for (i = 0; i < 8; i++) {
|
|
313
|
+
struct io_uring_mock_create mc;
|
|
314
|
+
bool nowait = i & 1;
|
|
315
|
+
bool async = i & 2;
|
|
316
|
+
bool poll = i & 4;
|
|
317
|
+
int mock_fd;
|
|
318
|
+
|
|
319
|
+
memset(&mc, 0, sizeof(mc));
|
|
320
|
+
if (poll) {
|
|
321
|
+
if (!has_feature(IORING_MOCK_FEAT_POLL))
|
|
322
|
+
continue;
|
|
323
|
+
mc.flags |= IORING_MOCK_CREATE_F_POLL;
|
|
324
|
+
}
|
|
325
|
+
if (nowait) {
|
|
326
|
+
if (!has_feature(IORING_MOCK_FEAT_RW_NOWAIT))
|
|
327
|
+
continue;
|
|
328
|
+
mc.flags |= IORING_MOCK_CREATE_F_SUPPORT_NOWAIT;
|
|
329
|
+
}
|
|
330
|
+
if (async) {
|
|
331
|
+
if (!has_feature(IORING_MOCK_FEAT_RW_ASYNC))
|
|
332
|
+
continue;
|
|
333
|
+
mc.rw_delay_ns = 1000 * 1000 * 50;
|
|
334
|
+
}
|
|
335
|
+
mc.file_size = 10 * (1UL << 20);
|
|
336
|
+
if (create_mock_file(&mc))
|
|
337
|
+
return T_EXIT_FAIL;
|
|
338
|
+
mock_fd = mc.out_fd;
|
|
339
|
+
|
|
340
|
+
ret = test_reads(&ring, mock_fd, buffer);
|
|
341
|
+
if (ret) {
|
|
342
|
+
fprintf(stderr, "rw failed %i/%i/%i\n",
|
|
343
|
+
nowait, async, poll);
|
|
344
|
+
return T_EXIT_FAIL;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
close(mock_fd);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
free(buffer);
|
|
351
|
+
io_uring_queue_exit(&ring);
|
|
352
|
+
return 0;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
int main(int argc, char *argv[])
|
|
356
|
+
{
|
|
357
|
+
int ret;
|
|
358
|
+
|
|
359
|
+
if (argc > 1)
|
|
360
|
+
return T_EXIT_SKIP;
|
|
361
|
+
|
|
362
|
+
ret = setup_mgr();
|
|
363
|
+
if (ret)
|
|
364
|
+
return ret;
|
|
365
|
+
|
|
366
|
+
ret = test_cmds();
|
|
367
|
+
if (ret)
|
|
368
|
+
return T_EXIT_FAIL;
|
|
369
|
+
|
|
370
|
+
ret = test_rw();
|
|
371
|
+
if (ret) {
|
|
372
|
+
fprintf(stderr, "test_rw failed %i\n", ret);
|
|
373
|
+
return T_EXIT_FAIL;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
io_uring_queue_exit(&mgr_ring);
|
|
377
|
+
close(mgr_fd);
|
|
378
|
+
return 0;
|
|
379
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#ifndef LINUX_IO_URING_MOCK_FILE_H
|
|
2
|
+
#define LINUX_IO_URING_MOCK_FILE_H
|
|
3
|
+
|
|
4
|
+
#include <linux/types.h>
|
|
5
|
+
|
|
6
|
+
enum {
|
|
7
|
+
IORING_MOCK_FEAT_CMD_COPY,
|
|
8
|
+
IORING_MOCK_FEAT_RW_ZERO,
|
|
9
|
+
IORING_MOCK_FEAT_RW_NOWAIT,
|
|
10
|
+
IORING_MOCK_FEAT_RW_ASYNC,
|
|
11
|
+
IORING_MOCK_FEAT_POLL,
|
|
12
|
+
|
|
13
|
+
IORING_MOCK_FEAT_END,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
struct io_uring_mock_probe {
|
|
17
|
+
__u64 features;
|
|
18
|
+
__u64 __resv[9];
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
enum {
|
|
22
|
+
IORING_MOCK_CREATE_F_SUPPORT_NOWAIT = 1,
|
|
23
|
+
IORING_MOCK_CREATE_F_POLL = 2,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
struct io_uring_mock_create {
|
|
27
|
+
__u32 out_fd;
|
|
28
|
+
__u32 flags;
|
|
29
|
+
__u64 file_size;
|
|
30
|
+
__u64 rw_delay_ns;
|
|
31
|
+
__u64 __resv[13];
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
enum {
|
|
35
|
+
IORING_MOCK_MGR_CMD_PROBE,
|
|
36
|
+
IORING_MOCK_MGR_CMD_CREATE,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
enum {
|
|
40
|
+
IORING_MOCK_CMD_COPY_REGBUF,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
enum {
|
|
44
|
+
IORING_MOCK_COPY_FROM = 1,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
#endif
|
data/vendor/liburing/test/nop.c
CHANGED
|
@@ -83,7 +83,7 @@ static int test_single_nop(struct io_uring *ring, unsigned req_flags)
|
|
|
83
83
|
goto err;
|
|
84
84
|
}
|
|
85
85
|
if (!cqe->user_data) {
|
|
86
|
-
fprintf(stderr, "Unexpected 0 user_data\n");
|
|
86
|
+
fprintf(stderr, "Unexpected 0 user_data: %ld\n", (long) cqe->user_data);
|
|
87
87
|
goto err;
|
|
88
88
|
}
|
|
89
89
|
if (cqe32) {
|
|
@@ -140,7 +140,7 @@ static int test_barrier_nop(struct io_uring *ring, unsigned req_flags)
|
|
|
140
140
|
goto err;
|
|
141
141
|
}
|
|
142
142
|
if (!cqe->user_data) {
|
|
143
|
-
fprintf(stderr, "Unexpected 0 user_data\n");
|
|
143
|
+
fprintf(stderr, "Unexpected 0 user_data: %ld\n", (long) cqe->user_data);
|
|
144
144
|
goto err;
|
|
145
145
|
}
|
|
146
146
|
if (cqe32) {
|