uringmachine 0.4 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +2 -1
  3. data/CHANGELOG.md +14 -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_write.rb +56 -0
  8. data/examples/dns_client.rb +12 -0
  9. data/examples/http_server.rb +42 -43
  10. data/examples/server_client.rb +64 -0
  11. data/examples/snooze.rb +44 -0
  12. data/examples/write_dev_null.rb +16 -0
  13. data/ext/um/extconf.rb +24 -14
  14. data/ext/um/um.c +468 -414
  15. data/ext/um/um.h +129 -39
  16. data/ext/um/um_buffer.c +49 -0
  17. data/ext/um/um_class.c +148 -24
  18. data/ext/um/um_const.c +30 -1
  19. data/ext/um/um_ext.c +4 -0
  20. data/ext/um/um_mutex_class.c +47 -0
  21. data/ext/um/um_op.c +86 -111
  22. data/ext/um/um_queue_class.c +58 -0
  23. data/ext/um/um_sync.c +273 -0
  24. data/ext/um/um_utils.c +1 -1
  25. data/lib/uringmachine/dns_resolver.rb +84 -0
  26. data/lib/uringmachine/version.rb +1 -1
  27. data/lib/uringmachine.rb +19 -3
  28. data/supressions/ruby.supp +71 -0
  29. data/test/test_um.rb +466 -47
  30. data/vendor/liburing/.gitignore +5 -0
  31. data/vendor/liburing/CHANGELOG +1 -0
  32. data/vendor/liburing/configure +32 -0
  33. data/vendor/liburing/examples/Makefile +1 -0
  34. data/vendor/liburing/examples/reg-wait.c +159 -0
  35. data/vendor/liburing/liburing.spec +1 -1
  36. data/vendor/liburing/src/include/liburing/io_uring.h +48 -2
  37. data/vendor/liburing/src/include/liburing.h +28 -2
  38. data/vendor/liburing/src/int_flags.h +10 -3
  39. data/vendor/liburing/src/liburing-ffi.map +13 -2
  40. data/vendor/liburing/src/liburing.map +9 -0
  41. data/vendor/liburing/src/queue.c +25 -16
  42. data/vendor/liburing/src/register.c +73 -4
  43. data/vendor/liburing/src/setup.c +46 -18
  44. data/vendor/liburing/src/setup.h +6 -0
  45. data/vendor/liburing/test/Makefile +7 -0
  46. data/vendor/liburing/test/cmd-discard.c +427 -0
  47. data/vendor/liburing/test/fifo-nonblock-read.c +69 -0
  48. data/vendor/liburing/test/file-exit-unreg.c +48 -0
  49. data/vendor/liburing/test/io_uring_passthrough.c +2 -0
  50. data/vendor/liburing/test/io_uring_register.c +13 -2
  51. data/vendor/liburing/test/napi-test.c +1 -1
  52. data/vendor/liburing/test/no-mmap-inval.c +1 -1
  53. data/vendor/liburing/test/read-mshot-empty.c +2 -0
  54. data/vendor/liburing/test/read-mshot-stdin.c +121 -0
  55. data/vendor/liburing/test/read-mshot.c +6 -0
  56. data/vendor/liburing/test/recvsend_bundle.c +2 -2
  57. data/vendor/liburing/test/reg-fd-only.c +1 -1
  58. data/vendor/liburing/test/reg-wait.c +251 -0
  59. data/vendor/liburing/test/regbuf-clone.c +458 -0
  60. data/vendor/liburing/test/resize-rings.c +643 -0
  61. data/vendor/liburing/test/rsrc_tags.c +1 -1
  62. data/vendor/liburing/test/sqpoll-sleep.c +39 -8
  63. data/vendor/liburing/test/sqwait.c +136 -0
  64. data/vendor/liburing/test/sync-cancel.c +8 -1
  65. data/vendor/liburing/test/timeout.c +13 -8
  66. metadata +22 -4
  67. data/examples/http_server_multishot.rb +0 -57
  68. 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
  }