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.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/TODO.md +40 -0
  4. data/examples/bm_fileno.rb +33 -0
  5. data/examples/bm_mutex.rb +85 -0
  6. data/examples/bm_mutex_single.rb +33 -0
  7. data/examples/bm_queue.rb +27 -28
  8. data/examples/bm_send.rb +2 -5
  9. data/examples/bm_snooze.rb +20 -42
  10. data/examples/fiber_scheduler_demo.rb +15 -51
  11. data/examples/fiber_scheduler_fork.rb +24 -0
  12. data/examples/nc_ssl.rb +71 -0
  13. data/ext/um/extconf.rb +5 -15
  14. data/ext/um/um.c +73 -42
  15. data/ext/um/um.h +21 -11
  16. data/ext/um/um_async_op_class.c +2 -2
  17. data/ext/um/um_buffer.c +1 -1
  18. data/ext/um/um_class.c +94 -23
  19. data/ext/um/um_const.c +51 -3
  20. data/ext/um/um_mutex_class.c +1 -1
  21. data/ext/um/um_queue_class.c +1 -1
  22. data/ext/um/um_stream.c +5 -5
  23. data/ext/um/um_stream_class.c +3 -0
  24. data/ext/um/um_sync.c +22 -27
  25. data/ext/um/um_utils.c +59 -19
  26. data/grant-2025/journal.md +229 -0
  27. data/grant-2025/tasks.md +66 -0
  28. data/lib/uringmachine/fiber_scheduler.rb +180 -48
  29. data/lib/uringmachine/version.rb +1 -1
  30. data/lib/uringmachine.rb +6 -0
  31. data/test/test_fiber_scheduler.rb +138 -0
  32. data/test/test_stream.rb +2 -2
  33. data/test/test_um.rb +451 -33
  34. data/vendor/liburing/.github/workflows/ci.yml +94 -1
  35. data/vendor/liburing/.github/workflows/test_build.c +9 -0
  36. data/vendor/liburing/configure +27 -0
  37. data/vendor/liburing/examples/Makefile +6 -0
  38. data/vendor/liburing/examples/helpers.c +8 -0
  39. data/vendor/liburing/examples/helpers.h +5 -0
  40. data/vendor/liburing/liburing.spec +1 -1
  41. data/vendor/liburing/src/Makefile +9 -3
  42. data/vendor/liburing/src/include/liburing/barrier.h +11 -5
  43. data/vendor/liburing/src/include/liburing/io_uring/query.h +41 -0
  44. data/vendor/liburing/src/include/liburing/io_uring.h +50 -0
  45. data/vendor/liburing/src/include/liburing/sanitize.h +16 -4
  46. data/vendor/liburing/src/include/liburing.h +445 -121
  47. data/vendor/liburing/src/liburing-ffi.map +15 -0
  48. data/vendor/liburing/src/liburing.map +8 -0
  49. data/vendor/liburing/src/sanitize.c +4 -1
  50. data/vendor/liburing/src/setup.c +7 -4
  51. data/vendor/liburing/test/232c93d07b74.c +4 -16
  52. data/vendor/liburing/test/Makefile +15 -1
  53. data/vendor/liburing/test/accept.c +2 -13
  54. data/vendor/liburing/test/conn-unreach.c +132 -0
  55. data/vendor/liburing/test/fd-pass.c +32 -7
  56. data/vendor/liburing/test/fdinfo.c +39 -12
  57. data/vendor/liburing/test/fifo-futex-poll.c +114 -0
  58. data/vendor/liburing/test/fifo-nonblock-read.c +1 -12
  59. data/vendor/liburing/test/futex.c +1 -1
  60. data/vendor/liburing/test/helpers.c +99 -2
  61. data/vendor/liburing/test/helpers.h +9 -0
  62. data/vendor/liburing/test/io_uring_passthrough.c +6 -12
  63. data/vendor/liburing/test/mock_file.c +379 -0
  64. data/vendor/liburing/test/mock_file.h +47 -0
  65. data/vendor/liburing/test/nop.c +2 -2
  66. data/vendor/liburing/test/nop32-overflow.c +150 -0
  67. data/vendor/liburing/test/nop32.c +126 -0
  68. data/vendor/liburing/test/pipe.c +166 -0
  69. data/vendor/liburing/test/poll-race-mshot.c +13 -1
  70. data/vendor/liburing/test/recv-mshot-fair.c +81 -34
  71. data/vendor/liburing/test/recvsend_bundle.c +1 -1
  72. data/vendor/liburing/test/resize-rings.c +2 -0
  73. data/vendor/liburing/test/ring-query.c +322 -0
  74. data/vendor/liburing/test/ringbuf-loop.c +87 -0
  75. data/vendor/liburing/test/runtests.sh +2 -2
  76. data/vendor/liburing/test/send-zerocopy.c +43 -5
  77. data/vendor/liburing/test/send_recv.c +102 -32
  78. data/vendor/liburing/test/shutdown.c +2 -12
  79. data/vendor/liburing/test/socket-nb.c +3 -14
  80. data/vendor/liburing/test/socket-rw-eagain.c +2 -12
  81. data/vendor/liburing/test/socket-rw-offset.c +2 -12
  82. data/vendor/liburing/test/socket-rw.c +2 -12
  83. data/vendor/liburing/test/sqe-mixed-bad-wrap.c +87 -0
  84. data/vendor/liburing/test/sqe-mixed-nop.c +82 -0
  85. data/vendor/liburing/test/sqe-mixed-uring_cmd.c +153 -0
  86. data/vendor/liburing/test/timestamp.c +56 -19
  87. data/vendor/liburing/test/vec-regbuf.c +2 -4
  88. data/vendor/liburing/test/wq-aff.c +7 -0
  89. 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
- flags = fcntl(fds[0], F_GETFL, 0);
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 = (!i % 2);
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
- if (ret != -EINVAL)
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
- io_uring_prep_read(sqe, fd, vecs[0].iov_base, vecs[0].iov_len, 0);
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
- io_uring_prep_readv(sqe, fd, &vecs[i], 1, offset);
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)&mp;
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
@@ -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) {