uringmachine 0.4 → 0.5.1

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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +2 -1
  3. data/CHANGELOG.md +16 -0
  4. data/README.md +44 -1
  5. data/TODO.md +12 -3
  6. data/examples/bm_snooze.rb +89 -0
  7. data/examples/bm_sqlite.rb +89 -0
  8. data/examples/bm_write.rb +56 -0
  9. data/examples/dns_client.rb +12 -0
  10. data/examples/http_server.rb +42 -43
  11. data/examples/pg.rb +85 -0
  12. data/examples/server_client.rb +64 -0
  13. data/examples/snooze.rb +44 -0
  14. data/examples/stream.rb +85 -0
  15. data/examples/write_dev_null.rb +16 -0
  16. data/ext/um/extconf.rb +81 -14
  17. data/ext/um/um.c +468 -414
  18. data/ext/um/um.h +149 -40
  19. data/ext/um/um_async_op.c +40 -0
  20. data/ext/um/um_async_op_class.c +136 -0
  21. data/ext/um/um_buffer.c +49 -0
  22. data/ext/um/um_class.c +176 -44
  23. data/ext/um/um_const.c +174 -9
  24. data/ext/um/um_ext.c +8 -0
  25. data/ext/um/um_mutex_class.c +47 -0
  26. data/ext/um/um_op.c +89 -111
  27. data/ext/um/um_queue_class.c +58 -0
  28. data/ext/um/um_ssl.c +850 -0
  29. data/ext/um/um_ssl.h +22 -0
  30. data/ext/um/um_ssl_class.c +138 -0
  31. data/ext/um/um_sync.c +273 -0
  32. data/ext/um/um_utils.c +1 -1
  33. data/lib/uringmachine/dns_resolver.rb +84 -0
  34. data/lib/uringmachine/ssl/context_builder.rb +96 -0
  35. data/lib/uringmachine/ssl.rb +394 -0
  36. data/lib/uringmachine/version.rb +1 -1
  37. data/lib/uringmachine.rb +27 -3
  38. data/supressions/ruby.supp +71 -0
  39. data/test/helper.rb +6 -0
  40. data/test/test_async_op.rb +119 -0
  41. data/test/test_ssl.rb +155 -0
  42. data/test/test_um.rb +464 -47
  43. data/uringmachine.gemspec +3 -2
  44. data/vendor/liburing/.gitignore +5 -0
  45. data/vendor/liburing/CHANGELOG +1 -0
  46. data/vendor/liburing/configure +32 -0
  47. data/vendor/liburing/examples/Makefile +1 -0
  48. data/vendor/liburing/examples/reg-wait.c +159 -0
  49. data/vendor/liburing/liburing.spec +1 -1
  50. data/vendor/liburing/src/include/liburing/io_uring.h +48 -2
  51. data/vendor/liburing/src/include/liburing.h +28 -2
  52. data/vendor/liburing/src/int_flags.h +10 -3
  53. data/vendor/liburing/src/liburing-ffi.map +13 -2
  54. data/vendor/liburing/src/liburing.map +9 -0
  55. data/vendor/liburing/src/queue.c +25 -16
  56. data/vendor/liburing/src/register.c +73 -4
  57. data/vendor/liburing/src/setup.c +46 -18
  58. data/vendor/liburing/src/setup.h +6 -0
  59. data/vendor/liburing/test/Makefile +7 -0
  60. data/vendor/liburing/test/cmd-discard.c +427 -0
  61. data/vendor/liburing/test/fifo-nonblock-read.c +69 -0
  62. data/vendor/liburing/test/file-exit-unreg.c +48 -0
  63. data/vendor/liburing/test/io_uring_passthrough.c +2 -0
  64. data/vendor/liburing/test/io_uring_register.c +13 -2
  65. data/vendor/liburing/test/napi-test.c +1 -1
  66. data/vendor/liburing/test/no-mmap-inval.c +1 -1
  67. data/vendor/liburing/test/read-mshot-empty.c +2 -0
  68. data/vendor/liburing/test/read-mshot-stdin.c +121 -0
  69. data/vendor/liburing/test/read-mshot.c +6 -0
  70. data/vendor/liburing/test/recvsend_bundle.c +2 -2
  71. data/vendor/liburing/test/reg-fd-only.c +1 -1
  72. data/vendor/liburing/test/reg-wait.c +251 -0
  73. data/vendor/liburing/test/regbuf-clone.c +458 -0
  74. data/vendor/liburing/test/resize-rings.c +643 -0
  75. data/vendor/liburing/test/rsrc_tags.c +1 -1
  76. data/vendor/liburing/test/sqpoll-sleep.c +39 -8
  77. data/vendor/liburing/test/sqwait.c +136 -0
  78. data/vendor/liburing/test/sync-cancel.c +8 -1
  79. data/vendor/liburing/test/timeout.c +13 -8
  80. metadata +52 -8
  81. data/examples/http_server_multishot.rb +0 -57
  82. data/examples/http_server_simpler.rb +0 -34
@@ -8,6 +8,10 @@
8
8
  #include <unistd.h>
9
9
  #include <stdlib.h>
10
10
  #include <sys/uio.h>
11
+ #include <string.h>
12
+ #include <limits.h>
13
+ #include <sys/mman.h>
14
+ #include <linux/mman.h>
11
15
 
12
16
  #include "liburing.h"
13
17
  #include "helpers.h"
@@ -15,6 +19,295 @@
15
19
  #define NR_VECS 64
16
20
  #define BUF_SIZE 8192
17
21
 
22
+ static int no_buf_clone;
23
+ static int no_buf_offset;
24
+
25
+ static void fdinfo_read(struct io_uring *ring)
26
+ {
27
+ char fd_name[128];
28
+ char *buf;
29
+ int fd;
30
+
31
+ buf = malloc(4096);
32
+
33
+ sprintf(fd_name, "/proc/self/fdinfo/%d", ring->ring_fd);
34
+ fd = open(fd_name, O_RDONLY);
35
+ if (fd < 0) {
36
+ perror("open");
37
+ return;
38
+ }
39
+
40
+ do {
41
+ int ret = read(fd, buf, 4096);
42
+
43
+ if (ret < 0) {
44
+ perror("fdinfo read");
45
+ break;
46
+ } else if (ret == 4096) {
47
+ continue;
48
+ }
49
+ break;
50
+ } while (1);
51
+
52
+ close(fd);
53
+ free(buf);
54
+ }
55
+
56
+ static int use_buf(struct io_uring *ring, void *addr, int index)
57
+ {
58
+ struct io_uring_sqe *sqe;
59
+ struct io_uring_cqe *cqe;
60
+ char src_buf[32];
61
+ int fds[2], ret;
62
+
63
+ fdinfo_read(ring);
64
+
65
+ if (pipe(fds) < 0)
66
+ return -errno;
67
+
68
+ memset(src_buf, 0xbb, sizeof(src_buf));
69
+
70
+ sqe = io_uring_get_sqe(ring);
71
+ io_uring_prep_read_fixed(sqe, fds[0], addr, sizeof(src_buf), 0, index);
72
+ io_uring_submit(ring);
73
+
74
+ ret = write(fds[1], src_buf, sizeof(src_buf));
75
+ if (ret < 0)
76
+ return -errno;
77
+
78
+ ret = io_uring_wait_cqe(ring, &cqe);
79
+ if (ret) {
80
+ fprintf(stderr, "wait_cqe: %d\n", ret);
81
+ return ret;
82
+ }
83
+
84
+ ret = cqe->res;
85
+ io_uring_cqe_seen(ring, cqe);
86
+ if (ret < 0)
87
+ return ret;
88
+ close(fds[0]);
89
+ close(fds[1]);
90
+ return 0;
91
+ }
92
+
93
+ static int test_offsets(void)
94
+ {
95
+ struct iovec vecs[NR_VECS];
96
+ struct io_uring src, dst;
97
+ unsigned int i, offset, nr;
98
+ int ret;
99
+
100
+ ret = io_uring_queue_init(1, &src, 0);
101
+ if (ret) {
102
+ fprintf(stderr, "ring_init: %d\n", ret);
103
+ return T_EXIT_FAIL;
104
+ }
105
+ ret = io_uring_queue_init(1, &dst, 0);
106
+ if (ret) {
107
+ fprintf(stderr, "ring_init: %d\n", ret);
108
+ return T_EXIT_FAIL;
109
+ }
110
+
111
+ for (i = 0; i < NR_VECS; i++) {
112
+ if (posix_memalign(&vecs[i].iov_base, 4096, BUF_SIZE))
113
+ return T_EXIT_FAIL;
114
+ vecs[i].iov_len = BUF_SIZE;
115
+ }
116
+
117
+ ret = io_uring_register_buffers(&src, vecs, NR_VECS);
118
+ if (ret < 0) {
119
+ if (ret == -ENOMEM)
120
+ return T_EXIT_SKIP;
121
+ return T_EXIT_FAIL;
122
+ }
123
+
124
+ /* clone half the buffers, src offset 0, but ask for too many */
125
+ offset = NR_VECS / 2;
126
+ nr = NR_VECS;
127
+ ret = io_uring_clone_buffers_offset(&dst, &src, 0, offset, nr, 0);
128
+ if (ret != -EOVERFLOW) {
129
+ if (ret == -EINVAL) {
130
+ no_buf_offset = 1;
131
+ return T_EXIT_SKIP;
132
+ }
133
+ fprintf(stderr, "Offset and too big total failed: %d\n", ret);
134
+ return T_EXIT_FAIL;
135
+ }
136
+
137
+ /* ask for too many buffers */
138
+ nr = NR_VECS + 1;
139
+ ret = io_uring_clone_buffers_offset(&dst, &src, 0, 0, nr, 0);
140
+ if (ret != -EINVAL) {
141
+ fprintf(stderr, "Too many buffers total failed: %d\n", ret);
142
+ return T_EXIT_FAIL;
143
+ }
144
+
145
+ /* clone half the buffers into start of src offset */
146
+ nr = NR_VECS / 2;
147
+ ret = io_uring_clone_buffers_offset(&dst, &src, 0, nr, nr, 0);
148
+ if (ret) {
149
+ fprintf(stderr, "Half clone with offset failed: %d\n", ret);
150
+ return T_EXIT_FAIL;
151
+ }
152
+
153
+ /* 'nr' offset should be 0 on the src side */
154
+ ret = use_buf(&dst, vecs[nr].iov_base, 0);
155
+ if (ret) {
156
+ fprintf(stderr, "1 use_buf=%d\n", ret);
157
+ return T_EXIT_FAIL;
158
+ }
159
+
160
+ ret = io_uring_unregister_buffers(&dst);
161
+ if (ret) {
162
+ fprintf(stderr, "Failed to unregister partial dst: %d\n", ret);
163
+ return T_EXIT_FAIL;
164
+ }
165
+
166
+ ret = use_buf(&dst, vecs[0].iov_base, 0);
167
+ if (ret != -EFAULT) {
168
+ fprintf(stderr, "2 use_buf=%d\n", ret);
169
+ return T_EXIT_FAIL;
170
+ }
171
+
172
+ /* clone half the buffers into middle of src offset */
173
+ nr = NR_VECS / 2;
174
+ ret = io_uring_clone_buffers_offset(&dst, &src, nr, nr, nr, 0);
175
+ if (ret) {
176
+ fprintf(stderr, "Half buffers and middle offset failed: %d\n", ret);
177
+ return T_EXIT_FAIL;
178
+ }
179
+
180
+ ret = use_buf(&dst, vecs[0].iov_base, 0);
181
+ if (ret != -EFAULT) {
182
+ fprintf(stderr, "3 use_buf=%d\n", ret);
183
+ return T_EXIT_FAIL;
184
+ }
185
+
186
+ ret = use_buf(&dst, vecs[nr].iov_base, nr);
187
+ if (ret) {
188
+ fprintf(stderr, "4 use_buf=%d\n", ret);
189
+ return T_EXIT_FAIL;
190
+ }
191
+
192
+ ret = io_uring_unregister_buffers(&dst);
193
+ if (ret) {
194
+ fprintf(stderr, "Failed to unregister partial dst: %d\n", ret);
195
+ return T_EXIT_FAIL;
196
+ }
197
+
198
+ /* clone buffers, but specify overflowing dst offset */
199
+ offset = UINT_MAX - 32;
200
+ nr = NR_VECS;
201
+ ret = io_uring_clone_buffers_offset(&dst, &src, 0, offset, nr, 0);
202
+ if (ret != -EOVERFLOW) {
203
+ fprintf(stderr, "Overflow dst offset failed: %d\n", ret);
204
+ return T_EXIT_FAIL;
205
+ }
206
+
207
+ /* clone half the buffers into middle of src offset */
208
+ nr = NR_VECS / 2;
209
+ ret = io_uring_clone_buffers_offset(&dst, &src, nr, nr, nr, 0);
210
+ if (ret) {
211
+ fprintf(stderr, "Clone half middle src offset failed: %d\n", ret);
212
+ return T_EXIT_FAIL;
213
+ }
214
+
215
+ ret = use_buf(&dst, vecs[nr].iov_base, nr);
216
+ if (ret) {
217
+ fprintf(stderr, "5 use_buf=%d\n", ret);
218
+ return T_EXIT_FAIL;
219
+ }
220
+
221
+ ret = use_buf(&dst, vecs[0].iov_base, 0);
222
+ if (ret != -EFAULT) {
223
+ fprintf(stderr, "5 use_buf=%d\n", ret);
224
+ return T_EXIT_FAIL;
225
+ }
226
+
227
+ /* should get -EBUSY now, REPLACE not set */
228
+ nr = NR_VECS / 2;
229
+ ret = io_uring_clone_buffers_offset(&dst, &src, nr, nr, nr, 0);
230
+ if (ret != -EBUSY) {
231
+ fprintf(stderr, "Replace buffers failed: %d\n", ret);
232
+ return T_EXIT_FAIL;
233
+ }
234
+
235
+ /* now replace the initial 0..n in dst (which are dummy nodes) */
236
+ ret = io_uring_clone_buffers_offset(&dst, &src, 0, 0, nr, IORING_REGISTER_DST_REPLACE);
237
+ if (ret) {
238
+ fprintf(stderr, "Buffer replace failed: %d\n", ret);
239
+ return T_EXIT_FAIL;
240
+ }
241
+
242
+ ret = use_buf(&dst, vecs[0].iov_base, 0);
243
+ if (ret) {
244
+ fprintf(stderr, "6 use_buf=%d\n", ret);
245
+ return T_EXIT_FAIL;
246
+ }
247
+
248
+ ret = io_uring_unregister_buffers(&dst);
249
+ if (ret) {
250
+ fprintf(stderr, "Failed to unregister partial dst: %d\n", ret);
251
+ return T_EXIT_FAIL;
252
+ }
253
+
254
+ ret = io_uring_register_buffers_sparse(&dst, NR_VECS);
255
+ if (ret) {
256
+ fprintf(stderr, "Register sparse buffers failed: %d\n", ret);
257
+ return T_EXIT_FAIL;
258
+ }
259
+
260
+ /* dst has a full sparse table, replace first NR_VECS / 2 with bufs */
261
+ nr = NR_VECS / 2;
262
+ ret = io_uring_clone_buffers_offset(&dst, &src, 0, 0, nr, 0);
263
+ if (ret != -EBUSY) {
264
+ fprintf(stderr, "Buffer replace failed: %d\n", ret);
265
+ return T_EXIT_FAIL;
266
+ }
267
+
268
+ ret = io_uring_clone_buffers_offset(&dst, &src, 0, 0, nr, IORING_REGISTER_DST_REPLACE);
269
+ if (ret) {
270
+ fprintf(stderr, "Buffer replace failed: %d\n", ret);
271
+ return T_EXIT_FAIL;
272
+ }
273
+
274
+ ret = use_buf(&dst, vecs[0].iov_base, 0);
275
+ if (ret) {
276
+ fprintf(stderr, "7 use_buf=%d\n", ret);
277
+ return T_EXIT_FAIL;
278
+ }
279
+
280
+ /* now expand existing dst table, from to NR_VECS + NR_VECS / 2 */
281
+ nr = NR_VECS;
282
+ offset = NR_VECS / 2;
283
+ ret = io_uring_clone_buffers_offset(&dst, &src, offset, 0, nr, IORING_REGISTER_DST_REPLACE);
284
+ if (ret) {
285
+ fprintf(stderr, "Buffer replace failed: %d\n", ret);
286
+ return T_EXIT_FAIL;
287
+ }
288
+
289
+ ret = use_buf(&dst, vecs[0].iov_base, 0);
290
+ if (ret) {
291
+ fprintf(stderr, "8 use_buf=%d\n", ret);
292
+ return T_EXIT_FAIL;
293
+ }
294
+
295
+ offset = NR_VECS + (NR_VECS / 2) - 1;
296
+ ret = use_buf(&dst, vecs[NR_VECS - 1].iov_base, offset);
297
+ if (ret) {
298
+ fprintf(stderr, "8b use_buf=%d\n", ret);
299
+ return T_EXIT_FAIL;
300
+ }
301
+
302
+ ret = use_buf(&dst, vecs[NR_VECS / 2].iov_base, NR_VECS);
303
+ if (ret) {
304
+ fprintf(stderr, "9 use_buf=%d\n", ret);
305
+ return T_EXIT_FAIL;
306
+ }
307
+
308
+ return T_EXIT_PASS;
309
+ }
310
+
18
311
  static int test(int reg_src, int reg_dst)
19
312
  {
20
313
  struct iovec vecs[NR_VECS];
@@ -54,6 +347,7 @@ static int test(int reg_src, int reg_dst)
54
347
  ret = io_uring_clone_buffers(&dst, &src);
55
348
  if (ret == -EINVAL) {
56
349
  /* no buffer copy support */
350
+ no_buf_clone = true;
57
351
  return T_EXIT_SKIP;
58
352
  } else if (ret != -ENXIO) {
59
353
  fprintf(stderr, "empty copy: %d\n", ret);
@@ -73,6 +367,18 @@ static int test(int reg_src, int reg_dst)
73
367
  return T_EXIT_FAIL;
74
368
  }
75
369
 
370
+ ret = use_buf(&src, vecs[0].iov_base, 0);
371
+ if (ret) {
372
+ fprintf(stderr, "use_buf=%d\n", ret);
373
+ return T_EXIT_FAIL;
374
+ }
375
+
376
+ ret = use_buf(&dst, vecs[0].iov_base, 0);
377
+ if (ret != -EFAULT) {
378
+ fprintf(stderr, "use_buf=%d\n", ret);
379
+ return T_EXIT_FAIL;
380
+ }
381
+
76
382
  /* copy should work now */
77
383
  ret = io_uring_clone_buffers(&dst, &src);
78
384
  if (ret) {
@@ -80,6 +386,12 @@ static int test(int reg_src, int reg_dst)
80
386
  return T_EXIT_FAIL;
81
387
  }
82
388
 
389
+ ret = use_buf(&dst, vecs[NR_VECS / 2].iov_base, NR_VECS / 2);
390
+ if (ret) {
391
+ fprintf(stderr, "use_buf=%d\n", ret);
392
+ return T_EXIT_FAIL;
393
+ }
394
+
83
395
  /* try copy again, should get -EBUSY */
84
396
  ret = io_uring_clone_buffers(&dst, &src);
85
397
  if (ret != -EBUSY) {
@@ -93,18 +405,36 @@ static int test(int reg_src, int reg_dst)
93
405
  return T_EXIT_FAIL;
94
406
  }
95
407
 
408
+ ret = use_buf(&dst, vecs[NR_VECS / 2].iov_base, NR_VECS / 2);
409
+ if (ret != -EFAULT) {
410
+ fprintf(stderr, "use_buf=%d\n", ret);
411
+ return T_EXIT_FAIL;
412
+ }
413
+
96
414
  ret = io_uring_unregister_buffers(&dst);
97
415
  if (ret != -ENXIO) {
98
416
  fprintf(stderr, "dst unregister empty buffers: %d\n", ret);
99
417
  return T_EXIT_FAIL;
100
418
  }
101
419
 
420
+ ret = use_buf(&src, vecs[NR_VECS / 2].iov_base, NR_VECS / 2);
421
+ if (ret) {
422
+ fprintf(stderr, "use_buf=%d\n", ret);
423
+ return T_EXIT_FAIL;
424
+ }
425
+
102
426
  ret = io_uring_unregister_buffers(&src);
103
427
  if (ret) {
104
428
  fprintf(stderr, "src unregister buffers: %d\n", ret);
105
429
  return T_EXIT_FAIL;
106
430
  }
107
431
 
432
+ ret = use_buf(&src, vecs[NR_VECS / 2].iov_base, NR_VECS / 2);
433
+ if (ret != -EFAULT) {
434
+ fprintf(stderr, "use_buf=%d\n", ret);
435
+ return T_EXIT_FAIL;
436
+ }
437
+
108
438
  ret = io_uring_register_buffers(&dst, vecs, NR_VECS);
109
439
  if (ret < 0) {
110
440
  fprintf(stderr, "register buffers dst; %d\n", ret);
@@ -144,6 +474,108 @@ static int test(int reg_src, int reg_dst)
144
474
  return T_EXIT_PASS;
145
475
  }
146
476
 
477
+ static int test_dummy(void)
478
+ {
479
+ struct iovec vec = { };
480
+ struct io_uring src, dst;
481
+ int ret;
482
+
483
+ ret = io_uring_queue_init(1, &src, 0);
484
+ if (ret) {
485
+ fprintf(stderr, "ring_init: %d\n", ret);
486
+ return T_EXIT_FAIL;
487
+ }
488
+ ret = io_uring_queue_init(1, &dst, 0);
489
+ if (ret) {
490
+ fprintf(stderr, "ring_init: %d\n", ret);
491
+ return T_EXIT_FAIL;
492
+ }
493
+
494
+ ret = io_uring_register_buffers(&src, &vec, 1);
495
+ if (ret < 0) {
496
+ fprintf(stderr, "failed to register dummy buffer: %d\n", ret);
497
+ return T_EXIT_FAIL;
498
+ }
499
+
500
+ ret = io_uring_clone_buffers(&dst, &src);
501
+ if (ret) {
502
+ fprintf(stderr, "clone dummy buf: %d\n", ret);
503
+ return T_EXIT_FAIL;
504
+ }
505
+
506
+ ret = io_uring_unregister_buffers(&src);
507
+ if (ret) {
508
+ fprintf(stderr, "rsc unregister buffers: %d\n", ret);
509
+ return T_EXIT_FAIL;
510
+ }
511
+
512
+ ret = io_uring_unregister_buffers(&dst);
513
+ if (ret) {
514
+ fprintf(stderr, "dst unregister buffers: %d\n", ret);
515
+ return T_EXIT_FAIL;
516
+ }
517
+
518
+ io_uring_queue_exit(&src);
519
+ io_uring_queue_exit(&dst);
520
+
521
+ return T_EXIT_PASS;
522
+ }
523
+
524
+ /*
525
+ * Register sparse buffer table, then try updating that with a few huge
526
+ * page entries.
527
+ */
528
+ static int test_merge(void)
529
+ {
530
+ int ret, res = T_EXIT_SKIP;
531
+ struct iovec vecs[8];
532
+ struct io_uring ring;
533
+ __u64 tags[2];
534
+ void *p1;
535
+
536
+ p1 = mmap(NULL, 2*1024*1024, PROT_READ|PROT_WRITE,
537
+ MAP_PRIVATE|MAP_HUGETLB | MAP_HUGE_2MB | MAP_ANONYMOUS,
538
+ -1, 0);
539
+ if (p1 == MAP_FAILED)
540
+ return T_EXIT_SKIP;
541
+
542
+ ret = io_uring_queue_init(1, &ring, 0);
543
+ if (ret) {
544
+ fprintf(stderr, "ring_init: %d\n", ret);
545
+ return T_EXIT_FAIL;
546
+ }
547
+
548
+ memset(vecs, 0, sizeof(vecs));
549
+
550
+ ret = io_uring_register_buffers(&ring, vecs, 8);
551
+ if (ret < 0) {
552
+ if (ret == -EINVAL)
553
+ goto skip;
554
+ fprintf(stderr, "failed to register initial buffers: %d\n", ret);
555
+ return T_EXIT_FAIL;
556
+ }
557
+
558
+ vecs[0].iov_base = p1;
559
+ vecs[0].iov_len = 4096;
560
+ vecs[1].iov_base = p1 + 4096;
561
+ vecs[1].iov_len = 4096;
562
+
563
+ tags[0] = 1;
564
+ tags[1] = 2;
565
+ ret = io_uring_register_buffers_update_tag(&ring, 4, vecs, tags, 2);
566
+ if (ret < 0) {
567
+ if (ret == -EINVAL)
568
+ goto skip;
569
+ fprintf(stderr, "failed to register merge buffers: %d\n", ret);
570
+ return T_EXIT_FAIL;
571
+ }
572
+ res = T_EXIT_PASS;
573
+ skip:
574
+ munmap(p1, 2*1024*1024);
575
+ io_uring_queue_exit(&ring);
576
+ return res;
577
+ }
578
+
147
579
  int main(int argc, char *argv[])
148
580
  {
149
581
  int ret;
@@ -151,6 +583,12 @@ int main(int argc, char *argv[])
151
583
  if (argc > 1)
152
584
  return T_EXIT_SKIP;
153
585
 
586
+ ret = test_merge();
587
+ if (ret == T_EXIT_FAIL) {
588
+ fprintf(stderr, "test_merge failed\n");
589
+ return T_EXIT_FAIL;
590
+ }
591
+
154
592
  ret = test(0, 0);
155
593
  if (ret == T_EXIT_SKIP) {
156
594
  return T_EXIT_SKIP;
@@ -158,6 +596,8 @@ int main(int argc, char *argv[])
158
596
  fprintf(stderr, "test 0 0 failed\n");
159
597
  return T_EXIT_FAIL;
160
598
  }
599
+ if (no_buf_clone)
600
+ return T_EXIT_SKIP;
161
601
 
162
602
  ret = test(0, 1);
163
603
  if (ret == T_EXIT_SKIP) {
@@ -183,5 +623,23 @@ int main(int argc, char *argv[])
183
623
  return T_EXIT_FAIL;
184
624
  }
185
625
 
626
+ ret = test_dummy();
627
+ if (ret == T_EXIT_SKIP) {
628
+ return T_EXIT_SKIP;
629
+ } else if (ret != T_EXIT_PASS) {
630
+ fprintf(stderr, "test_dummy failed\n");
631
+ return T_EXIT_FAIL;
632
+ }
633
+
634
+ ret = test_offsets();
635
+ if (ret == T_EXIT_SKIP) {
636
+ return T_EXIT_PASS;
637
+ } else if (ret != T_EXIT_PASS) {
638
+ fprintf(stderr, "test_offset failed\n");
639
+ return T_EXIT_FAIL;
640
+ }
641
+ if (no_buf_offset)
642
+ return T_EXIT_PASS;
643
+
186
644
  return T_EXIT_PASS;
187
645
  }