uringmachine 0.19.1 → 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 +12 -1
  3. data/TODO.md +0 -1
  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 +57 -41
  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 +427 -34
  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
@@ -21,7 +21,7 @@ static int nr_msgs;
21
21
  static int use_tcp;
22
22
  static int classic_buffers;
23
23
 
24
- #define RECV_BIDS 8192
24
+ #define RECV_BIDS 16384
25
25
  #define RECV_BID_MASK (RECV_BIDS - 1)
26
26
 
27
27
  #include "liburing.h"
@@ -657,6 +657,8 @@ try_defer:
657
657
  ret = test(IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN, fd, 0);
658
658
  if (ret == T_EXIT_FAIL)
659
659
  return T_EXIT_FAIL;
660
+ else if (ret == T_EXIT_SKIP)
661
+ return T_EXIT_SKIP;
660
662
 
661
663
  ret = test(IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN, fd, 1);
662
664
  if (ret == T_EXIT_FAIL)
@@ -0,0 +1,322 @@
1
+ /* SPDX-License-Identifier: MIT */
2
+ #include <errno.h>
3
+ #include <stdio.h>
4
+ #include <unistd.h>
5
+ #include <stdlib.h>
6
+ #include <string.h>
7
+ #include <fcntl.h>
8
+
9
+ #include "liburing.h"
10
+ #include "test.h"
11
+ #include "helpers.h"
12
+
13
+ struct io_uring_query_opcode_short {
14
+ __u32 nr_request_opcodes;
15
+ __u32 nr_register_opcodes;
16
+ };
17
+
18
+ struct io_uring_query_opcode_large {
19
+ __u32 nr_request_opcodes;
20
+ __u32 nr_register_opcodes;
21
+ __u64 feature_flags;
22
+ __u64 ring_setup_flags;
23
+ __u64 enter_flags;
24
+ __u64 sqe_flags;
25
+ __u64 placeholder[8];
26
+ };
27
+
28
+ static struct io_uring_query_opcode sys_ops;
29
+
30
+ static int io_uring_query(struct io_uring *ring, struct io_uring_query_hdr *arg)
31
+ {
32
+ int fd = ring ? ring->ring_fd : -1;
33
+
34
+ return io_uring_register(fd, IORING_REGISTER_QUERY, arg, 0);
35
+ }
36
+
37
+ static int test_basic_query(void)
38
+ {
39
+ struct io_uring_query_opcode op;
40
+ struct io_uring_query_hdr hdr = {
41
+ .query_op = IO_URING_QUERY_OPCODES,
42
+ .query_data = uring_ptr_to_u64(&op),
43
+ .size = sizeof(op),
44
+ };
45
+ int ret;
46
+
47
+ ret = io_uring_query(NULL, &hdr);
48
+ if (ret == -EINVAL)
49
+ return T_EXIT_SKIP;
50
+
51
+ if (ret != 0) {
52
+ fprintf(stderr, "query failed %d\n", ret);
53
+ return T_EXIT_FAIL;
54
+ }
55
+
56
+ if (hdr.size != sizeof(op)) {
57
+ fprintf(stderr, "unexpected size %i vs %i\n",
58
+ (int)hdr.size, (int)sizeof(op));
59
+ return T_EXIT_FAIL;
60
+ }
61
+
62
+ if (hdr.result) {
63
+ fprintf(stderr, "unexpected result %i\n", hdr.result);
64
+ return T_EXIT_FAIL;
65
+ }
66
+
67
+ if (op.nr_register_opcodes <= IORING_REGISTER_QUERY) {
68
+ fprintf(stderr, "too few opcodes (%i)\n", op.nr_register_opcodes);
69
+ return T_EXIT_FAIL;
70
+ }
71
+
72
+ memcpy(&sys_ops, &op, sizeof(sys_ops));
73
+ return T_EXIT_PASS;
74
+ }
75
+
76
+ static int test_invalid(void)
77
+ {
78
+ int ret;
79
+ struct io_uring_query_opcode op;
80
+ struct io_uring_query_hdr invalid_hdr = {
81
+ .query_op = -1U,
82
+ .query_data = uring_ptr_to_u64(&op),
83
+ .size = sizeof(struct io_uring_query_opcode),
84
+ };
85
+ struct io_uring_query_hdr invalid_next_hdr = {
86
+ .query_op = IO_URING_QUERY_OPCODES,
87
+ .query_data = uring_ptr_to_u64(&op),
88
+ .size = sizeof(struct io_uring_query_opcode),
89
+ .next_entry = 0xdeadbeefUL,
90
+ };
91
+ struct io_uring_query_hdr invalid_data_hdr = {
92
+ .query_op = IO_URING_QUERY_OPCODES,
93
+ .query_data = 0xdeadbeefUL,
94
+ .size = sizeof(struct io_uring_query_opcode),
95
+ };
96
+
97
+ ret = io_uring_query(NULL, &invalid_hdr);
98
+ if (ret || invalid_hdr.result != -EOPNOTSUPP) {
99
+ fprintf(stderr, "failed invalid opcode %i (%i)\n",
100
+ ret, invalid_hdr.result);
101
+ return T_EXIT_FAIL;
102
+ }
103
+
104
+ ret = io_uring_query(NULL, &invalid_next_hdr);
105
+ if (ret != -EFAULT) {
106
+ fprintf(stderr, "invalid next %i\n", ret);
107
+ return T_EXIT_FAIL;
108
+ }
109
+
110
+ ret = io_uring_query(NULL, &invalid_data_hdr);
111
+ if (ret != -EFAULT) {
112
+ fprintf(stderr, "invalid next %i\n", ret);
113
+ return T_EXIT_FAIL;
114
+ }
115
+
116
+ return T_EXIT_PASS;
117
+ }
118
+
119
+ static int test_chain(void)
120
+ {
121
+ int ret;
122
+ struct io_uring_query_opcode op1, op2, op3;
123
+ struct io_uring_query_hdr hdr3 = {
124
+ .query_op = IO_URING_QUERY_OPCODES,
125
+ .query_data = uring_ptr_to_u64(&op3),
126
+ .size = sizeof(struct io_uring_query_opcode),
127
+ };
128
+ struct io_uring_query_hdr hdr2 = {
129
+ .query_op = IO_URING_QUERY_OPCODES,
130
+ .query_data = uring_ptr_to_u64(&op2),
131
+ .size = sizeof(struct io_uring_query_opcode),
132
+ .next_entry = uring_ptr_to_u64(&hdr3),
133
+ };
134
+ struct io_uring_query_hdr hdr1 = {
135
+ .query_op = IO_URING_QUERY_OPCODES,
136
+ .query_data = uring_ptr_to_u64(&op1),
137
+ .size = sizeof(struct io_uring_query_opcode),
138
+ .next_entry = uring_ptr_to_u64(&hdr2),
139
+ };
140
+
141
+ ret = io_uring_query(NULL, &hdr1);
142
+ if (ret) {
143
+ fprintf(stderr, "chain failed %i\n", ret);
144
+ return T_EXIT_FAIL;
145
+ }
146
+
147
+ if (hdr1.result || hdr2.result || hdr3.result) {
148
+ fprintf(stderr, "chain invalid result entries %i %i %i\n",
149
+ hdr1.result, hdr2.result, hdr3.result);
150
+ return T_EXIT_FAIL;
151
+ }
152
+
153
+ if (op1.nr_register_opcodes != sys_ops.nr_register_opcodes ||
154
+ op2.nr_register_opcodes != sys_ops.nr_register_opcodes ||
155
+ op3.nr_register_opcodes != sys_ops.nr_register_opcodes) {
156
+ fprintf(stderr, "chain invalid register opcodes\n");
157
+ return T_EXIT_FAIL;
158
+ }
159
+
160
+ return T_EXIT_PASS;
161
+ }
162
+
163
+ static int test_chain_loop(void)
164
+ {
165
+ int ret;
166
+ struct io_uring_query_opcode op1, op2;
167
+ struct io_uring_query_hdr hdr2 = {
168
+ .query_op = IO_URING_QUERY_OPCODES,
169
+ .query_data = uring_ptr_to_u64(&op2),
170
+ .size = sizeof(struct io_uring_query_opcode),
171
+ };
172
+ struct io_uring_query_hdr hdr1 = {
173
+ .query_op = IO_URING_QUERY_OPCODES,
174
+ .query_data = uring_ptr_to_u64(&op1),
175
+ .size = sizeof(struct io_uring_query_opcode),
176
+ };
177
+ struct io_uring_query_hdr hdr_self_circular = {
178
+ .query_op = IO_URING_QUERY_OPCODES,
179
+ .query_data = uring_ptr_to_u64(&op1),
180
+ .size = sizeof(struct io_uring_query_opcode),
181
+ .next_entry = uring_ptr_to_u64(&hdr_self_circular),
182
+ };
183
+
184
+ hdr1.next_entry = uring_ptr_to_u64(&hdr2);
185
+ hdr2.next_entry = uring_ptr_to_u64(&hdr1);
186
+ ret = io_uring_query(NULL, &hdr1);
187
+ if (!ret) {
188
+ fprintf(stderr, "chain loop failed %i\n", ret);
189
+ return T_EXIT_FAIL;
190
+ }
191
+
192
+ ret = io_uring_query(NULL, &hdr_self_circular);
193
+ if (!ret) {
194
+ fprintf(stderr, "chain loop failed %i\n", ret);
195
+ return T_EXIT_FAIL;
196
+ }
197
+
198
+ return T_EXIT_PASS;
199
+ }
200
+
201
+ static int test_compatibile_shorter(void)
202
+ {
203
+ int ret;
204
+ struct io_uring_query_opcode_short op;
205
+ struct io_uring_query_hdr hdr = {
206
+ .query_op = IO_URING_QUERY_OPCODES,
207
+ .query_data = uring_ptr_to_u64(&op),
208
+ .size = sizeof(op),
209
+ };
210
+
211
+ ret = io_uring_query(NULL, &hdr);
212
+ if (ret || hdr.result) {
213
+ fprintf(stderr, "failed invalid short result %i (%i)\n",
214
+ ret, hdr.result);
215
+ return T_EXIT_FAIL;
216
+ }
217
+
218
+ if (hdr.size != sizeof(struct io_uring_query_opcode_short)) {
219
+ fprintf(stderr, "unexpected short query size %i %i\n",
220
+ (int)hdr.size,
221
+ (int)sizeof(struct io_uring_query_opcode_short));
222
+ return T_EXIT_FAIL;
223
+ }
224
+
225
+ if (sys_ops.nr_register_opcodes != op.nr_register_opcodes ||
226
+ sys_ops.nr_request_opcodes != op.nr_request_opcodes) {
227
+ fprintf(stderr, "invalid short data\n");
228
+ return T_EXIT_FAIL;
229
+ }
230
+
231
+ return T_EXIT_PASS;
232
+ }
233
+
234
+ static int test_compatibile_larger(void)
235
+ {
236
+ int ret;
237
+ struct io_uring_query_opcode_large op;
238
+ struct io_uring_query_hdr hdr = {
239
+ .query_op = IO_URING_QUERY_OPCODES,
240
+ .query_data = uring_ptr_to_u64(&op),
241
+ .size = sizeof(op),
242
+ };
243
+
244
+ ret = io_uring_query(NULL, &hdr);
245
+ if (ret || hdr.result) {
246
+ fprintf(stderr, "failed invalid large result %i (%i)\n",
247
+ ret, hdr.result);
248
+ return T_EXIT_FAIL;
249
+ }
250
+
251
+ if (hdr.size < sizeof(struct io_uring_query_opcode)) {
252
+ fprintf(stderr, "unexpected large query size %i %i\n",
253
+ (int)hdr.size,
254
+ (int)sizeof(struct io_uring_query_opcode));
255
+ return T_EXIT_FAIL;
256
+ }
257
+
258
+ if (sys_ops.nr_register_opcodes != op.nr_register_opcodes ||
259
+ sys_ops.nr_request_opcodes != op.nr_request_opcodes ||
260
+ sys_ops.ring_setup_flags != op.ring_setup_flags ||
261
+ sys_ops.feature_flags != op.feature_flags) {
262
+ fprintf(stderr, "invalid large data\n");
263
+ return T_EXIT_FAIL;
264
+ }
265
+
266
+ return T_EXIT_PASS;
267
+ }
268
+
269
+ int main(int argc, char *argv[])
270
+ {
271
+ struct io_uring ring;
272
+ int ret;
273
+
274
+ if (argc > 1)
275
+ return T_EXIT_SKIP;
276
+
277
+ ret = test_basic_query();
278
+ if (ret != T_EXIT_PASS) {
279
+ if (ret == T_EXIT_SKIP)
280
+ fprintf(stderr, "ring query not supported, skip\n");
281
+ else
282
+ fprintf(stderr, "test_basic_query failed\n");
283
+
284
+ return T_EXIT_SKIP;
285
+ }
286
+
287
+ ret = io_uring_queue_init(8, &ring, 0);
288
+ if (ret) {
289
+ fprintf(stderr, "init failed\n");
290
+ return T_EXIT_FAIL;
291
+ }
292
+
293
+ ret = test_invalid();
294
+ if (ret)
295
+ return T_EXIT_FAIL;
296
+
297
+ ret = test_chain();
298
+ if (ret) {
299
+ fprintf(stderr, "test_chain failed\n");
300
+ return T_EXIT_FAIL;
301
+ }
302
+
303
+ ret = test_chain_loop();
304
+ if (ret) {
305
+ fprintf(stderr, "test_chain_loop failed\n");
306
+ return T_EXIT_FAIL;
307
+ }
308
+
309
+ ret = test_compatibile_shorter();
310
+ if (ret) {
311
+ fprintf(stderr, "test_compatibile_shorter failed\n");
312
+ return T_EXIT_FAIL;
313
+ }
314
+
315
+ ret = test_compatibile_larger();
316
+ if (ret) {
317
+ fprintf(stderr, "test_compatibile_larger failed\n");
318
+ return T_EXIT_FAIL;
319
+ }
320
+
321
+ return 0;
322
+ }
@@ -0,0 +1,87 @@
1
+ /* SPDX-License-Identifier: MIT */
2
+ /*
3
+ * Description: test that having a command overwrite the provided ring
4
+ * buffer itself doesn't impact committing of the received
5
+ * length at completion time. Based on a test case posted
6
+ * here:
7
+ *
8
+ * https://lore.kernel.org/io-uring/tencent_2DEFFED135071FB225305A65D1688B303A09@qq.com/
9
+ *
10
+ */
11
+ #include <stdlib.h>
12
+ #include <stdio.h>
13
+ #include <string.h>
14
+ #include <sys/socket.h>
15
+
16
+ #include "liburing.h"
17
+ #include "helpers.h"
18
+
19
+ #define BGID 0
20
+ #define RENTRIES 2
21
+ #define RMASK (RENTRIES - 1)
22
+
23
+ int main(int argc, char *argv[])
24
+ {
25
+ struct io_uring_buf_ring *br;
26
+ struct io_uring_sqe *sqe;
27
+ struct io_uring ring;
28
+ void *send_buf;
29
+ int ret, fds[2];
30
+
31
+ if (argc > 1)
32
+ return T_EXIT_SKIP;
33
+
34
+ ret = io_uring_queue_init(1, &ring, IORING_SETUP_NO_SQARRAY);
35
+ if (ret) {
36
+ if (ret == -EINVAL)
37
+ return T_EXIT_SKIP;
38
+ fprintf(stderr, "ring setup: %d\n", ret);
39
+ return T_EXIT_FAIL;
40
+ }
41
+
42
+ br = io_uring_setup_buf_ring(&ring, RENTRIES, BGID, IOU_PBUF_RING_INC, &ret);
43
+ if (!br) {
44
+ if (ret == -EINVAL)
45
+ return T_EXIT_SKIP;
46
+ fprintf(stderr, "buf ring setup: %d\n", ret);
47
+ return T_EXIT_FAIL;
48
+ }
49
+
50
+ /*
51
+ * Use the buffer ring itself as the provided buffer address. Once the
52
+ * recv completes, it will have zero filled the buffer addr/len.
53
+ */
54
+ io_uring_buf_ring_add(br, br, 4096, 0, RMASK, 0);
55
+ io_uring_buf_ring_advance(br, 1);
56
+
57
+ if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) < 0) {
58
+ perror("socketpair");
59
+ return T_EXIT_FAIL;
60
+ }
61
+
62
+ /*
63
+ * Send zeroes, overwriting the buffer ring
64
+ */
65
+ send_buf = calloc(1, 32);
66
+ ret = send(fds[0], send_buf, 32, MSG_DONTWAIT);
67
+ if (ret < 0) {
68
+ perror("send");
69
+ return T_EXIT_FAIL;
70
+ }
71
+
72
+ /*
73
+ * Do recv, picking the first buffer. When buffer is picked,
74
+ * it's still fully valid. By the time it needs to get committed,
75
+ * it will have invalid addr/len fields (all zeroes from the recv)
76
+ */
77
+ sqe = io_uring_get_sqe(&ring);
78
+ io_uring_prep_recv(sqe, fds[1], NULL, 0, 0);
79
+ sqe->flags |= IOSQE_BUFFER_SELECT;
80
+ sqe->buf_index = BGID;
81
+ io_uring_submit_and_wait(&ring, 1);
82
+
83
+ io_uring_free_buf_ring(&ring, br, RENTRIES, BGID);
84
+ io_uring_queue_exit(&ring);
85
+ free(send_buf);
86
+ return T_EXIT_PASS;
87
+ }
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bash
2
2
 
3
3
  TESTS=("$@")
4
- TIMEOUT=60
4
+ : "${TIMEOUT:=60}"
5
5
  DMESG_FILTER="cat"
6
6
  TEST_DIR=$(dirname "$0")
7
7
  FAILED=()
@@ -99,7 +99,7 @@ run_test()
99
99
 
100
100
  # Run the test
101
101
  T_START=$(date +%s)
102
- timeout -s INT -k $TIMEOUT $TIMEOUT "${test_exec[@]}"
102
+ timeout -s INT -k "${TIMEOUT}" "${TIMEOUT}" "${test_exec[@]}"
103
103
  local status=$?
104
104
  T_END=$(date +%s)
105
105
 
@@ -74,6 +74,7 @@ static bool has_sendzc;
74
74
  static bool has_sendmsg;
75
75
  static bool hit_enomem;
76
76
  static bool try_hugepages = 1;
77
+ static bool no_send_vec;
77
78
 
78
79
  static int probe_zc_support(void)
79
80
  {
@@ -112,18 +113,34 @@ static bool check_cq_empty(struct io_uring *ring)
112
113
  return ret == -EAGAIN;
113
114
  }
114
115
 
115
- static int test_basic_send(struct io_uring *ring, int sock_tx, int sock_rx)
116
+ static int test_basic_send(struct io_uring *ring, int sock_tx, int sock_rx,
117
+ int vec)
116
118
  {
117
119
  struct io_uring_sqe *sqe;
118
120
  struct io_uring_cqe *cqe;
121
+ struct iovec vecs[2];
119
122
  int msg_flags = 0;
120
123
  unsigned zc_flags = 0;
121
124
  int payload_size = 100;
122
125
  int ret;
123
126
 
127
+ if (vec && no_send_vec)
128
+ return 0;
129
+
124
130
  sqe = io_uring_get_sqe(ring);
125
- io_uring_prep_send_zc(sqe, sock_tx, tx_buffer, payload_size,
126
- msg_flags, zc_flags);
131
+ if (vec) {
132
+ size_t split = payload_size / 2;
133
+
134
+ vecs[0].iov_base = tx_buffer;
135
+ vecs[0].iov_len = split;
136
+ vecs[1].iov_base = tx_buffer + split;
137
+ vecs[1].iov_len = split;
138
+ io_uring_prep_send_zc(sqe, sock_tx, vecs, 2, msg_flags, zc_flags);
139
+ sqe->ioprio |= (1U << 5);
140
+ } else {
141
+ io_uring_prep_send_zc(sqe, sock_tx, tx_buffer, payload_size,
142
+ msg_flags, zc_flags);
143
+ }
127
144
  sqe->user_data = 1;
128
145
 
129
146
  ret = io_uring_submit(ring);
@@ -132,6 +149,21 @@ static int test_basic_send(struct io_uring *ring, int sock_tx, int sock_rx)
132
149
  ret = io_uring_wait_cqe(ring, &cqe);
133
150
  assert(!ret && cqe->user_data == 1);
134
151
  if (cqe->res != payload_size) {
152
+ if (cqe->res == -EINVAL && vec) {
153
+ int has_more = cqe->flags & IORING_CQE_F_MORE;
154
+
155
+ no_send_vec = 1;
156
+ io_uring_cqe_seen(ring, cqe);
157
+ if (has_more) {
158
+ ret = io_uring_peek_cqe(ring, &cqe);
159
+ if (ret) {
160
+ fprintf(stderr, "peek failed\n");
161
+ return T_EXIT_FAIL;
162
+ }
163
+ io_uring_cqe_seen(ring, cqe);
164
+ }
165
+ return T_EXIT_PASS;
166
+ }
135
167
  fprintf(stderr, "send failed %i\n", cqe->res);
136
168
  return T_EXIT_FAIL;
137
169
  }
@@ -773,9 +805,15 @@ static int run_basic_tests(void)
773
805
  return -1;
774
806
  }
775
807
 
776
- ret = test_basic_send(&ring, sp[0], sp[1]);
808
+ ret = test_basic_send(&ring, sp[0], sp[1], 0);
809
+ if (ret) {
810
+ fprintf(stderr, "test_basic_send() nonvec failed\n");
811
+ return -1;
812
+ }
813
+
814
+ ret = test_basic_send(&ring, sp[0], sp[1], 1);
777
815
  if (ret) {
778
- fprintf(stderr, "test_basic_send() failed\n");
816
+ fprintf(stderr, "test_basic_send() vec failed\n");
779
817
  return -1;
780
818
  }
781
819