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.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +3 -4
  3. data/CHANGELOG.md +32 -1
  4. data/TODO.md +0 -39
  5. data/examples/bm_fileno.rb +33 -0
  6. data/examples/bm_mutex.rb +85 -0
  7. data/examples/bm_mutex_single.rb +33 -0
  8. data/examples/bm_queue.rb +29 -29
  9. data/examples/bm_send.rb +2 -5
  10. data/examples/bm_snooze.rb +20 -42
  11. data/examples/bm_write.rb +4 -1
  12. data/examples/fiber_scheduler_demo.rb +15 -51
  13. data/examples/fiber_scheduler_fork.rb +24 -0
  14. data/examples/nc_ssl.rb +71 -0
  15. data/ext/um/extconf.rb +5 -15
  16. data/ext/um/um.c +310 -74
  17. data/ext/um/um.h +66 -29
  18. data/ext/um/um_async_op.c +1 -1
  19. data/ext/um/um_async_op_class.c +2 -2
  20. data/ext/um/um_buffer.c +1 -1
  21. data/ext/um/um_class.c +178 -31
  22. data/ext/um/um_const.c +51 -3
  23. data/ext/um/um_mutex_class.c +1 -1
  24. data/ext/um/um_op.c +37 -0
  25. data/ext/um/um_queue_class.c +1 -1
  26. data/ext/um/um_stream.c +5 -5
  27. data/ext/um/um_stream_class.c +3 -0
  28. data/ext/um/um_sync.c +28 -39
  29. data/ext/um/um_utils.c +59 -19
  30. data/grant-2025/journal.md +353 -0
  31. data/grant-2025/tasks.md +135 -0
  32. data/lib/uringmachine/fiber_scheduler.rb +316 -57
  33. data/lib/uringmachine/version.rb +1 -1
  34. data/lib/uringmachine.rb +6 -0
  35. data/test/test_fiber_scheduler.rb +640 -0
  36. data/test/test_stream.rb +2 -2
  37. data/test/test_um.rb +722 -54
  38. data/uringmachine.gemspec +5 -5
  39. data/vendor/liburing/.github/workflows/ci.yml +94 -1
  40. data/vendor/liburing/.github/workflows/test_build.c +9 -0
  41. data/vendor/liburing/configure +27 -0
  42. data/vendor/liburing/examples/Makefile +6 -0
  43. data/vendor/liburing/examples/helpers.c +8 -0
  44. data/vendor/liburing/examples/helpers.h +5 -0
  45. data/vendor/liburing/liburing.spec +1 -1
  46. data/vendor/liburing/src/Makefile +9 -3
  47. data/vendor/liburing/src/include/liburing/barrier.h +11 -5
  48. data/vendor/liburing/src/include/liburing/io_uring/query.h +41 -0
  49. data/vendor/liburing/src/include/liburing/io_uring.h +51 -0
  50. data/vendor/liburing/src/include/liburing/sanitize.h +16 -4
  51. data/vendor/liburing/src/include/liburing.h +458 -121
  52. data/vendor/liburing/src/liburing-ffi.map +16 -0
  53. data/vendor/liburing/src/liburing.map +8 -0
  54. data/vendor/liburing/src/sanitize.c +4 -1
  55. data/vendor/liburing/src/setup.c +7 -4
  56. data/vendor/liburing/test/232c93d07b74.c +4 -16
  57. data/vendor/liburing/test/Makefile +15 -1
  58. data/vendor/liburing/test/accept.c +2 -13
  59. data/vendor/liburing/test/bind-listen.c +175 -13
  60. data/vendor/liburing/test/conn-unreach.c +132 -0
  61. data/vendor/liburing/test/fd-pass.c +32 -7
  62. data/vendor/liburing/test/fdinfo.c +39 -12
  63. data/vendor/liburing/test/fifo-futex-poll.c +114 -0
  64. data/vendor/liburing/test/fifo-nonblock-read.c +1 -12
  65. data/vendor/liburing/test/futex.c +1 -1
  66. data/vendor/liburing/test/helpers.c +99 -2
  67. data/vendor/liburing/test/helpers.h +9 -0
  68. data/vendor/liburing/test/io_uring_passthrough.c +6 -12
  69. data/vendor/liburing/test/mock_file.c +379 -0
  70. data/vendor/liburing/test/mock_file.h +47 -0
  71. data/vendor/liburing/test/nop.c +2 -2
  72. data/vendor/liburing/test/nop32-overflow.c +150 -0
  73. data/vendor/liburing/test/nop32.c +126 -0
  74. data/vendor/liburing/test/pipe.c +166 -0
  75. data/vendor/liburing/test/poll-race-mshot.c +13 -1
  76. data/vendor/liburing/test/read-write.c +4 -4
  77. data/vendor/liburing/test/recv-mshot-fair.c +81 -34
  78. data/vendor/liburing/test/recvsend_bundle.c +1 -1
  79. data/vendor/liburing/test/resize-rings.c +2 -0
  80. data/vendor/liburing/test/ring-query.c +322 -0
  81. data/vendor/liburing/test/ringbuf-loop.c +87 -0
  82. data/vendor/liburing/test/ringbuf-read.c +4 -4
  83. data/vendor/liburing/test/runtests.sh +2 -2
  84. data/vendor/liburing/test/send-zerocopy.c +43 -5
  85. data/vendor/liburing/test/send_recv.c +103 -32
  86. data/vendor/liburing/test/shutdown.c +2 -12
  87. data/vendor/liburing/test/socket-nb.c +3 -14
  88. data/vendor/liburing/test/socket-rw-eagain.c +2 -12
  89. data/vendor/liburing/test/socket-rw-offset.c +2 -12
  90. data/vendor/liburing/test/socket-rw.c +2 -12
  91. data/vendor/liburing/test/sqe-mixed-bad-wrap.c +87 -0
  92. data/vendor/liburing/test/sqe-mixed-nop.c +82 -0
  93. data/vendor/liburing/test/sqe-mixed-uring_cmd.c +153 -0
  94. data/vendor/liburing/test/timestamp.c +56 -19
  95. data/vendor/liburing/test/vec-regbuf.c +2 -4
  96. data/vendor/liburing/test/wq-aff.c +7 -0
  97. metadata +37 -15
@@ -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
+ }
@@ -14,7 +14,7 @@
14
14
  #include "helpers.h"
15
15
 
16
16
  #define BUF_SIZE 4096
17
- #define NR_BUFS 64
17
+ #define NR_BUFS 128
18
18
  #define FSIZE (BUF_SIZE * NR_BUFS)
19
19
 
20
20
  #define BR_MASK (NR_BUFS - 1)
@@ -87,7 +87,7 @@ static int test(const char *filename, int dio, int async)
87
87
  }
88
88
  io_uring_buf_ring_advance(br, NR_BUFS);
89
89
 
90
- for (i = 0; i < NR_BUFS; i++) {
90
+ for (i = 0; i < NR_BUFS / 2; i++) {
91
91
  sqe = io_uring_get_sqe(&ring);
92
92
  io_uring_prep_read(sqe, fd, NULL, BUF_SIZE, i * BUF_SIZE);
93
93
  sqe->buf_group = 1;
@@ -98,12 +98,12 @@ static int test(const char *filename, int dio, int async)
98
98
  }
99
99
 
100
100
  ret = io_uring_submit(&ring);
101
- if (ret != NR_BUFS) {
101
+ if (ret != NR_BUFS / 2) {
102
102
  fprintf(stderr, "submit: %d\n", ret);
103
103
  return 1;
104
104
  }
105
105
 
106
- for (i = 0; i < NR_BUFS; i++) {
106
+ for (i = 0; i < NR_BUFS / 2; i++) {
107
107
  int bid, ud;
108
108
 
109
109
  ret = io_uring_wait_cqe(&ring, &cqe);
@@ -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