uringmachine 0.19.1 → 0.21.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/.github/workflows/test.yml +3 -4
- data/CHANGELOG.md +32 -1
- data/TODO.md +0 -39
- 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 +29 -29
- data/examples/bm_send.rb +2 -5
- data/examples/bm_snooze.rb +20 -42
- data/examples/bm_write.rb +4 -1
- 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 +310 -74
- data/ext/um/um.h +66 -29
- data/ext/um/um_async_op.c +1 -1
- data/ext/um/um_async_op_class.c +2 -2
- data/ext/um/um_buffer.c +1 -1
- data/ext/um/um_class.c +178 -31
- data/ext/um/um_const.c +51 -3
- data/ext/um/um_mutex_class.c +1 -1
- data/ext/um/um_op.c +37 -0
- 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 +28 -39
- data/ext/um/um_utils.c +59 -19
- data/grant-2025/journal.md +353 -0
- data/grant-2025/tasks.md +135 -0
- data/lib/uringmachine/fiber_scheduler.rb +316 -57
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +6 -0
- data/test/test_fiber_scheduler.rb +640 -0
- data/test/test_stream.rb +2 -2
- data/test/test_um.rb +722 -54
- data/uringmachine.gemspec +5 -5
- 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 +51 -0
- data/vendor/liburing/src/include/liburing/sanitize.h +16 -4
- data/vendor/liburing/src/include/liburing.h +458 -121
- data/vendor/liburing/src/liburing-ffi.map +16 -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/bind-listen.c +175 -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/read-write.c +4 -4
- 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/ringbuf-read.c +4 -4
- data/vendor/liburing/test/runtests.sh +2 -2
- data/vendor/liburing/test/send-zerocopy.c +43 -5
- data/vendor/liburing/test/send_recv.c +103 -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 +37 -15
|
@@ -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) {
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/* SPDX-License-Identifier: MIT */
|
|
2
|
+
/*
|
|
3
|
+
* Description: run various nop tests
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
#include <errno.h>
|
|
7
|
+
#include <stdio.h>
|
|
8
|
+
#include <unistd.h>
|
|
9
|
+
#include <stdlib.h>
|
|
10
|
+
#include <string.h>
|
|
11
|
+
#include <fcntl.h>
|
|
12
|
+
|
|
13
|
+
#include "liburing.h"
|
|
14
|
+
#include "helpers.h"
|
|
15
|
+
#include "test.h"
|
|
16
|
+
|
|
17
|
+
static int seq;
|
|
18
|
+
|
|
19
|
+
static int fail_cqe(struct io_uring_cqe *cqe, int off, const char *msg)
|
|
20
|
+
{
|
|
21
|
+
fprintf(stderr, "Bad cqe at off %d: %s\n", off, msg);
|
|
22
|
+
fprintf(stderr, "CQE ud=%lu, res=%u, flags=%x\n", (long) cqe->user_data, cqe->res, cqe->flags);
|
|
23
|
+
return T_EXIT_FAIL;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
static int test_ring(unsigned flags)
|
|
27
|
+
{
|
|
28
|
+
struct io_uring_sqe *sqe;
|
|
29
|
+
struct io_uring_cqe *cqe;
|
|
30
|
+
struct io_uring ring;
|
|
31
|
+
struct io_uring_params p = { };
|
|
32
|
+
unsigned head;
|
|
33
|
+
int ret, i, cqe_nr;
|
|
34
|
+
|
|
35
|
+
p.flags = flags | IORING_SETUP_CQSIZE;
|
|
36
|
+
p.cq_entries = 8;
|
|
37
|
+
ret = io_uring_queue_init_params(8, &ring, &p);
|
|
38
|
+
if (ret) {
|
|
39
|
+
if (ret == -EINVAL)
|
|
40
|
+
return T_EXIT_SKIP;
|
|
41
|
+
fprintf(stderr, "ring setup failed: %d\n", ret);
|
|
42
|
+
return T_EXIT_FAIL;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/*
|
|
46
|
+
* Prep 8 NOP requests, with the first being a 16b one to
|
|
47
|
+
* unalign the ring. The 4 latter ones will hit overflow,
|
|
48
|
+
* and after the first 4 we should see a SKIP cqe.
|
|
49
|
+
*/
|
|
50
|
+
for (i = 0; i < 8; i++) {
|
|
51
|
+
sqe = io_uring_get_sqe(&ring);
|
|
52
|
+
io_uring_prep_nop(sqe);
|
|
53
|
+
if (i)
|
|
54
|
+
sqe->nop_flags = IORING_NOP_CQE32;
|
|
55
|
+
sqe->user_data = ++seq;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
io_uring_submit(&ring);
|
|
59
|
+
|
|
60
|
+
/*
|
|
61
|
+
* Should find the following CQEs:
|
|
62
|
+
*
|
|
63
|
+
* 1: 16b with ud 1
|
|
64
|
+
* 2: 32b with ud 2
|
|
65
|
+
* 3: 32b with ud 3
|
|
66
|
+
* 4: 32b with ud 4
|
|
67
|
+
* 5: 16b skip CQE
|
|
68
|
+
*
|
|
69
|
+
* And then we should have overflow pending to flush the rest
|
|
70
|
+
*/
|
|
71
|
+
i = cqe_nr = 0;
|
|
72
|
+
io_uring_for_each_cqe(&ring, head, cqe) {
|
|
73
|
+
switch (i) {
|
|
74
|
+
case 0:
|
|
75
|
+
if (cqe->user_data != 1)
|
|
76
|
+
return fail_cqe(cqe, i, "Non-overflow UD");
|
|
77
|
+
if (cqe->flags & IORING_CQE_F_32)
|
|
78
|
+
return fail_cqe(cqe, i, "Non-overflow flags");
|
|
79
|
+
break;
|
|
80
|
+
case 1:
|
|
81
|
+
case 2:
|
|
82
|
+
case 3:
|
|
83
|
+
if (cqe->user_data != i + 1)
|
|
84
|
+
return fail_cqe(cqe, i, "Non-overflow 32b UD");
|
|
85
|
+
if (!(cqe->flags & IORING_CQE_F_32))
|
|
86
|
+
return fail_cqe(cqe, i, "Non-overflow 32b flags");
|
|
87
|
+
break;
|
|
88
|
+
case 4:
|
|
89
|
+
if (!(cqe->flags & IORING_CQE_F_SKIP))
|
|
90
|
+
return fail_cqe(cqe, i, "Non-overflow skip");
|
|
91
|
+
break;
|
|
92
|
+
default:
|
|
93
|
+
return fail_cqe(cqe, i, "Bogus CQE");
|
|
94
|
+
}
|
|
95
|
+
i++;
|
|
96
|
+
cqe_nr += io_uring_cqe_nr(cqe);
|
|
97
|
+
}
|
|
98
|
+
io_uring_cq_advance(&ring, cqe_nr);
|
|
99
|
+
|
|
100
|
+
/*
|
|
101
|
+
* This should flush overflow, and we should see:
|
|
102
|
+
*
|
|
103
|
+
* 1: 32b with ud 5
|
|
104
|
+
* 2: 32b with ud 6
|
|
105
|
+
* 3: 32b with ud 7
|
|
106
|
+
* 4: 32b with ud 8
|
|
107
|
+
*/
|
|
108
|
+
for (i = 0; i < 4; i++) {
|
|
109
|
+
ret = io_uring_wait_cqe(&ring, &cqe);
|
|
110
|
+
if (ret) {
|
|
111
|
+
fprintf(stderr, "wait ret %d\n", ret);
|
|
112
|
+
return T_EXIT_FAIL;
|
|
113
|
+
}
|
|
114
|
+
switch (i) {
|
|
115
|
+
case 0:
|
|
116
|
+
case 1:
|
|
117
|
+
case 2:
|
|
118
|
+
case 3:
|
|
119
|
+
if (cqe->user_data != i + 5)
|
|
120
|
+
return fail_cqe(cqe, i + 5, "Overflow UD");
|
|
121
|
+
if (!(cqe->flags & IORING_CQE_F_32))
|
|
122
|
+
return fail_cqe(cqe, i + 5, "Overflow flags");
|
|
123
|
+
break;
|
|
124
|
+
default:
|
|
125
|
+
return fail_cqe(cqe, i + 5, "Bogus CQE");
|
|
126
|
+
}
|
|
127
|
+
io_uring_cqe_seen(&ring, cqe);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
io_uring_queue_exit(&ring);
|
|
131
|
+
return ret;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
int main(int argc, char *argv[])
|
|
135
|
+
{
|
|
136
|
+
int ret;
|
|
137
|
+
|
|
138
|
+
if (argc > 1)
|
|
139
|
+
return T_EXIT_SKIP;
|
|
140
|
+
|
|
141
|
+
ret = test_ring(IORING_SETUP_CQE_MIXED);
|
|
142
|
+
if (ret == T_EXIT_SKIP) {
|
|
143
|
+
return T_EXIT_SKIP;
|
|
144
|
+
} else if (ret != T_EXIT_PASS) {
|
|
145
|
+
fprintf(stderr, "Mixed ring test failed\n");
|
|
146
|
+
return ret;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return T_EXIT_PASS;
|
|
150
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/* SPDX-License-Identifier: MIT */
|
|
2
|
+
/*
|
|
3
|
+
* Description: run various nop tests
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
#include <errno.h>
|
|
7
|
+
#include <stdio.h>
|
|
8
|
+
#include <unistd.h>
|
|
9
|
+
#include <stdlib.h>
|
|
10
|
+
#include <string.h>
|
|
11
|
+
#include <fcntl.h>
|
|
12
|
+
|
|
13
|
+
#include "liburing.h"
|
|
14
|
+
#include "helpers.h"
|
|
15
|
+
#include "test.h"
|
|
16
|
+
|
|
17
|
+
static int seq;
|
|
18
|
+
static int extra1 = 100, extra2 = 200;
|
|
19
|
+
static int want_extra1 = 100, want_extra2 = 200;
|
|
20
|
+
|
|
21
|
+
static int test_single_nop(struct io_uring *ring, unsigned req_flags, bool cqe32)
|
|
22
|
+
{
|
|
23
|
+
struct io_uring_cqe *cqe;
|
|
24
|
+
struct io_uring_sqe *sqe;
|
|
25
|
+
int ret;
|
|
26
|
+
|
|
27
|
+
sqe = io_uring_get_sqe(ring);
|
|
28
|
+
if (!sqe) {
|
|
29
|
+
fprintf(stderr, "get sqe failed\n");
|
|
30
|
+
goto err;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
io_uring_prep_nop(sqe);
|
|
34
|
+
sqe->user_data = ++seq;
|
|
35
|
+
sqe->flags |= req_flags;
|
|
36
|
+
if (cqe32) {
|
|
37
|
+
sqe->nop_flags = IORING_NOP_CQE32;
|
|
38
|
+
sqe->off = extra1++;
|
|
39
|
+
sqe->addr = extra2++;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
ret = io_uring_submit(ring);
|
|
43
|
+
if (ret <= 0) {
|
|
44
|
+
fprintf(stderr, "sqe submit failed: %d\n", ret);
|
|
45
|
+
goto err;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
ret = io_uring_wait_cqe(ring, &cqe);
|
|
49
|
+
if (ret < 0) {
|
|
50
|
+
fprintf(stderr, "wait completion %d\n", ret);
|
|
51
|
+
goto err;
|
|
52
|
+
}
|
|
53
|
+
if (!cqe->user_data) {
|
|
54
|
+
fprintf(stderr, "Unexpected 0 user_data: %ld\n", (long) cqe->user_data);
|
|
55
|
+
goto err;
|
|
56
|
+
}
|
|
57
|
+
if (cqe32) {
|
|
58
|
+
if (!(cqe->flags & IORING_CQE_F_32)) {
|
|
59
|
+
fprintf(stderr, "CQE_F_32 not set\n");
|
|
60
|
+
goto err;
|
|
61
|
+
}
|
|
62
|
+
if (cqe->big_cqe[0] != want_extra1) {
|
|
63
|
+
fprintf(stderr, "Unexpected extra1: %ld, want %d\n", (long) cqe->big_cqe[0], want_extra1);
|
|
64
|
+
goto err;
|
|
65
|
+
|
|
66
|
+
}
|
|
67
|
+
want_extra1++;
|
|
68
|
+
if (cqe->big_cqe[1] != want_extra2) {
|
|
69
|
+
fprintf(stderr, "Unexpected extra2: %ld, want %d\n", (long) cqe->big_cqe[1], want_extra2);
|
|
70
|
+
goto err;
|
|
71
|
+
}
|
|
72
|
+
want_extra2++;
|
|
73
|
+
}
|
|
74
|
+
io_uring_cqe_seen(ring, cqe);
|
|
75
|
+
return T_EXIT_PASS;
|
|
76
|
+
err:
|
|
77
|
+
return T_EXIT_FAIL;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
static int test_ring(unsigned flags)
|
|
81
|
+
{
|
|
82
|
+
struct io_uring ring;
|
|
83
|
+
struct io_uring_params p = { };
|
|
84
|
+
int ret, i;
|
|
85
|
+
|
|
86
|
+
p.flags = flags;
|
|
87
|
+
ret = io_uring_queue_init_params(8, &ring, &p);
|
|
88
|
+
if (ret) {
|
|
89
|
+
if (ret == -EINVAL)
|
|
90
|
+
return T_EXIT_SKIP;
|
|
91
|
+
fprintf(stderr, "ring setup failed: %d\n", ret);
|
|
92
|
+
return T_EXIT_FAIL;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
test_single_nop(&ring, 0, 0);
|
|
96
|
+
|
|
97
|
+
for (i = 0; i < 16; i++) {
|
|
98
|
+
ret = test_single_nop(&ring, 0, 1);
|
|
99
|
+
if (ret) {
|
|
100
|
+
printf("fail off %d\n", i);
|
|
101
|
+
fprintf(stderr, "test_single_nop failed\n");
|
|
102
|
+
goto err;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
err:
|
|
106
|
+
io_uring_queue_exit(&ring);
|
|
107
|
+
return ret;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
int main(int argc, char *argv[])
|
|
111
|
+
{
|
|
112
|
+
int ret;
|
|
113
|
+
|
|
114
|
+
if (argc > 1)
|
|
115
|
+
return T_EXIT_SKIP;
|
|
116
|
+
|
|
117
|
+
ret = test_ring(IORING_SETUP_CQE_MIXED);
|
|
118
|
+
if (ret == T_EXIT_SKIP) {
|
|
119
|
+
return T_EXIT_SKIP;
|
|
120
|
+
} else if (ret != T_EXIT_PASS) {
|
|
121
|
+
fprintf(stderr, "Mixed ring test failed\n");
|
|
122
|
+
return ret;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return T_EXIT_PASS;
|
|
126
|
+
}
|