uringmachine 0.3 → 0.4

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 (138) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -0
  3. data/README.md +85 -0
  4. data/TODO.md +5 -0
  5. data/examples/echo_server.rb +18 -40
  6. data/examples/inout.rb +19 -0
  7. data/examples/nc.rb +36 -0
  8. data/ext/um/extconf.rb +6 -15
  9. data/ext/um/um.c +245 -53
  10. data/ext/um/um.h +21 -9
  11. data/ext/um/um_class.c +74 -87
  12. data/ext/um/um_const.c +184 -0
  13. data/ext/um/um_op.c +10 -13
  14. data/ext/um/um_utils.c +48 -3
  15. data/lib/uringmachine/version.rb +1 -1
  16. data/lib/uringmachine.rb +12 -0
  17. data/test/helper.rb +8 -0
  18. data/test/test_um.rb +227 -7
  19. data/vendor/liburing/.github/workflows/build.yml +29 -1
  20. data/vendor/liburing/.gitignore +1 -0
  21. data/vendor/liburing/CHANGELOG +15 -0
  22. data/vendor/liburing/CONTRIBUTING.md +165 -0
  23. data/vendor/liburing/configure +32 -0
  24. data/vendor/liburing/examples/Makefile +8 -1
  25. data/vendor/liburing/examples/kdigest.c +405 -0
  26. data/vendor/liburing/examples/proxy.c +75 -8
  27. data/vendor/liburing/liburing.pc.in +1 -1
  28. data/vendor/liburing/src/Makefile +16 -2
  29. data/vendor/liburing/src/include/liburing/io_uring.h +31 -0
  30. data/vendor/liburing/src/include/liburing/sanitize.h +39 -0
  31. data/vendor/liburing/src/include/liburing.h +31 -4
  32. data/vendor/liburing/src/liburing-ffi.map +5 -0
  33. data/vendor/liburing/src/liburing.map +1 -0
  34. data/vendor/liburing/src/queue.c +3 -0
  35. data/vendor/liburing/src/register.c +36 -0
  36. data/vendor/liburing/src/sanitize.c +176 -0
  37. data/vendor/liburing/src/setup.c +1 -1
  38. data/vendor/liburing/test/35fa71a030ca.c +7 -0
  39. data/vendor/liburing/test/500f9fbadef8.c +2 -0
  40. data/vendor/liburing/test/7ad0e4b2f83c.c +0 -25
  41. data/vendor/liburing/test/917257daa0fe.c +7 -0
  42. data/vendor/liburing/test/Makefile +31 -4
  43. data/vendor/liburing/test/a0908ae19763.c +7 -0
  44. data/vendor/liburing/test/a4c0b3decb33.c +7 -0
  45. data/vendor/liburing/test/accept.c +14 -4
  46. data/vendor/liburing/test/b19062a56726.c +7 -0
  47. data/vendor/liburing/test/bind-listen.c +2 -2
  48. data/vendor/liburing/test/buf-ring-nommap.c +10 -3
  49. data/vendor/liburing/test/buf-ring.c +2 -0
  50. data/vendor/liburing/test/coredump.c +7 -0
  51. data/vendor/liburing/test/cq-overflow.c +13 -1
  52. data/vendor/liburing/test/d4ae271dfaae.c +11 -3
  53. data/vendor/liburing/test/defer-taskrun.c +2 -2
  54. data/vendor/liburing/test/defer-tw-timeout.c +4 -1
  55. data/vendor/liburing/test/defer.c +2 -2
  56. data/vendor/liburing/test/double-poll-crash.c +1 -1
  57. data/vendor/liburing/test/eeed8b54e0df.c +2 -0
  58. data/vendor/liburing/test/eventfd.c +0 -1
  59. data/vendor/liburing/test/exit-no-cleanup.c +11 -0
  60. data/vendor/liburing/test/fadvise.c +9 -26
  61. data/vendor/liburing/test/fdinfo.c +9 -1
  62. data/vendor/liburing/test/file-register.c +14 -2
  63. data/vendor/liburing/test/file-update.c +1 -1
  64. data/vendor/liburing/test/file-verify.c +27 -16
  65. data/vendor/liburing/test/files-exit-hang-timeout.c +1 -2
  66. data/vendor/liburing/test/fixed-buf-iter.c +3 -1
  67. data/vendor/liburing/test/fixed-hugepage.c +12 -1
  68. data/vendor/liburing/test/fsnotify.c +1 -0
  69. data/vendor/liburing/test/futex.c +16 -4
  70. data/vendor/liburing/test/helpers.c +47 -0
  71. data/vendor/liburing/test/helpers.h +6 -0
  72. data/vendor/liburing/test/init-mem.c +5 -3
  73. data/vendor/liburing/test/io-cancel.c +0 -24
  74. data/vendor/liburing/test/io_uring_passthrough.c +2 -0
  75. data/vendor/liburing/test/io_uring_register.c +25 -6
  76. data/vendor/liburing/test/iopoll-leak.c +4 -0
  77. data/vendor/liburing/test/iopoll-overflow.c +1 -1
  78. data/vendor/liburing/test/iopoll.c +3 -3
  79. data/vendor/liburing/test/kallsyms.c +203 -0
  80. data/vendor/liburing/test/link-timeout.c +159 -0
  81. data/vendor/liburing/test/linked-defer-close.c +224 -0
  82. data/vendor/liburing/test/madvise.c +12 -25
  83. data/vendor/liburing/test/min-timeout-wait.c +0 -25
  84. data/vendor/liburing/test/min-timeout.c +0 -25
  85. data/vendor/liburing/test/mkdir.c +6 -0
  86. data/vendor/liburing/test/msg-ring.c +8 -2
  87. data/vendor/liburing/test/napi-test.c +15 -2
  88. data/vendor/liburing/test/no-mmap-inval.c +2 -0
  89. data/vendor/liburing/test/nop.c +44 -0
  90. data/vendor/liburing/test/ooo-file-unreg.c +1 -1
  91. data/vendor/liburing/test/open-close.c +40 -0
  92. data/vendor/liburing/test/openat2.c +37 -14
  93. data/vendor/liburing/test/poll-many.c +13 -7
  94. data/vendor/liburing/test/poll-mshot-update.c +17 -10
  95. data/vendor/liburing/test/poll-v-poll.c +6 -3
  96. data/vendor/liburing/test/pollfree.c +148 -0
  97. data/vendor/liburing/test/read-mshot-empty.c +156 -153
  98. data/vendor/liburing/test/read-mshot.c +276 -27
  99. data/vendor/liburing/test/read-write.c +78 -13
  100. data/vendor/liburing/test/recv-msgall-stream.c +3 -0
  101. data/vendor/liburing/test/recv-msgall.c +5 -0
  102. data/vendor/liburing/test/recvsend_bundle-inc.c +680 -0
  103. data/vendor/liburing/test/recvsend_bundle.c +92 -29
  104. data/vendor/liburing/test/reg-fd-only.c +14 -4
  105. data/vendor/liburing/test/regbuf-clone.c +187 -0
  106. data/vendor/liburing/test/regbuf-merge.c +7 -0
  107. data/vendor/liburing/test/register-restrictions.c +86 -85
  108. data/vendor/liburing/test/rename.c +59 -1
  109. data/vendor/liburing/test/ringbuf-read.c +5 -0
  110. data/vendor/liburing/test/ringbuf-status.c +5 -1
  111. data/vendor/liburing/test/runtests.sh +16 -1
  112. data/vendor/liburing/test/send-zerocopy.c +59 -0
  113. data/vendor/liburing/test/short-read.c +1 -0
  114. data/vendor/liburing/test/socket.c +43 -0
  115. data/vendor/liburing/test/splice.c +3 -1
  116. data/vendor/liburing/test/sq-poll-dup.c +1 -1
  117. data/vendor/liburing/test/sq-poll-share.c +2 -0
  118. data/vendor/liburing/test/sqpoll-disable-exit.c +8 -0
  119. data/vendor/liburing/test/sqpoll-exit-hang.c +1 -25
  120. data/vendor/liburing/test/sqpoll-sleep.c +1 -25
  121. data/vendor/liburing/test/statx.c +89 -0
  122. data/vendor/liburing/test/stdout.c +2 -0
  123. data/vendor/liburing/test/submit-and-wait.c +1 -25
  124. data/vendor/liburing/test/submit-reuse.c +4 -26
  125. data/vendor/liburing/test/symlink.c +12 -1
  126. data/vendor/liburing/test/sync-cancel.c +48 -21
  127. data/vendor/liburing/test/thread-exit.c +5 -0
  128. data/vendor/liburing/test/timeout-new.c +1 -26
  129. data/vendor/liburing/test/timeout.c +12 -26
  130. data/vendor/liburing/test/unlink.c +94 -1
  131. data/vendor/liburing/test/uring_cmd_ublk.c +1252 -0
  132. data/vendor/liburing/test/waitid.c +62 -8
  133. data/vendor/liburing/test/wq-aff.c +35 -0
  134. data/vendor/liburing/test/xfail_prep_link_timeout_out_of_scope.c +46 -0
  135. data/vendor/liburing/test/xfail_register_buffers_out_of_scope.c +51 -0
  136. metadata +17 -4
  137. data/examples/event_loop.rb +0 -69
  138. data/examples/fibers.rb +0 -105
@@ -0,0 +1,203 @@
1
+ /* SPDX-License-Identifier: MIT */
2
+ /*
3
+ * Description: read /proc/kallsyms. Mostly just here so that fops->read() can
4
+ * get exercised, with and without registered buffers
5
+ */
6
+ #include <errno.h>
7
+ #include <stdio.h>
8
+ #include <unistd.h>
9
+ #include <stdlib.h>
10
+ #include <string.h>
11
+ #include <fcntl.h>
12
+ #include <sys/types.h>
13
+ #include <poll.h>
14
+ #include <sys/eventfd.h>
15
+ #include <sys/resource.h>
16
+
17
+ #include "helpers.h"
18
+ #include "liburing.h"
19
+
20
+ #define FILE_SIZE (8 * 1024)
21
+ #define BS 8192
22
+ #define BUFFERS (FILE_SIZE / BS)
23
+
24
+ static struct iovec *vecs;
25
+ static int warned;
26
+
27
+ static int __test_io(const char *file, struct io_uring *ring, int fixed, int nonvec)
28
+ {
29
+ struct io_uring_sqe *sqe;
30
+ struct io_uring_cqe *cqe;
31
+ int open_flags;
32
+ int i, fd = -1, ret;
33
+ off_t offset;
34
+
35
+ open_flags = O_RDONLY;
36
+ if (fixed) {
37
+ ret = t_register_buffers(ring, vecs, BUFFERS);
38
+ if (ret == T_SETUP_SKIP)
39
+ return 0;
40
+ if (ret != T_SETUP_OK) {
41
+ fprintf(stderr, "buffer reg failed: %d\n", ret);
42
+ goto err;
43
+ }
44
+ }
45
+
46
+ fd = open(file, open_flags);
47
+ if (fd < 0) {
48
+ if (errno == EINVAL || errno == EPERM || errno == ENOENT)
49
+ return 0;
50
+ perror("file open");
51
+ goto err;
52
+ }
53
+
54
+ offset = 0;
55
+ for (i = 0; i < BUFFERS; i++) {
56
+ int do_fixed = fixed;
57
+
58
+ sqe = io_uring_get_sqe(ring);
59
+ if (!sqe) {
60
+ fprintf(stderr, "sqe get failed\n");
61
+ goto err;
62
+ }
63
+ if (fixed && (i & 1))
64
+ do_fixed = 0;
65
+ if (do_fixed) {
66
+ io_uring_prep_read_fixed(sqe, fd, vecs[i].iov_base,
67
+ vecs[i].iov_len, offset, i);
68
+ } else if (nonvec) {
69
+ io_uring_prep_read(sqe, fd, vecs[i].iov_base,
70
+ vecs[i].iov_len, offset);
71
+ } else {
72
+ io_uring_prep_readv(sqe, fd, &vecs[i], 1, offset);
73
+ }
74
+ sqe->user_data = i;
75
+ offset += BS;
76
+ }
77
+
78
+ ret = io_uring_submit(ring);
79
+ if (ret != BUFFERS) {
80
+ fprintf(stderr, "submit got %d, wanted %d\n", ret, BUFFERS);
81
+ goto err;
82
+ }
83
+
84
+ for (i = 0; i < BUFFERS; i++) {
85
+ ret = io_uring_wait_cqe(ring, &cqe);
86
+ if (ret) {
87
+ fprintf(stderr, "wait_cqe=%d\n", ret);
88
+ goto err;
89
+ }
90
+ if (cqe->res == -EINVAL && nonvec) {
91
+ if (!warned) {
92
+ fprintf(stdout, "Non-vectored IO not "
93
+ "supported, skipping\n");
94
+ warned = 1;
95
+ }
96
+ }
97
+ io_uring_cqe_seen(ring, cqe);
98
+ }
99
+
100
+ if (fixed) {
101
+ ret = io_uring_unregister_buffers(ring);
102
+ if (ret) {
103
+ fprintf(stderr, "buffer unreg failed: %d\n", ret);
104
+ goto err;
105
+ }
106
+ }
107
+
108
+ close(fd);
109
+ return 0;
110
+ err:
111
+ if (fd != -1)
112
+ close(fd);
113
+ return 1;
114
+ }
115
+ static int test_io(const char *file, int fixed, int nonvec)
116
+ {
117
+ struct io_uring ring;
118
+ int ret, ring_flags = 0;
119
+
120
+ ret = t_create_ring(64, &ring, ring_flags);
121
+ if (ret == T_SETUP_SKIP)
122
+ return 0;
123
+ if (ret != T_SETUP_OK) {
124
+ fprintf(stderr, "ring create failed: %d\n", ret);
125
+ return 1;
126
+ }
127
+
128
+ ret = __test_io(file, &ring, fixed, nonvec);
129
+ io_uring_queue_exit(&ring);
130
+ return ret;
131
+ }
132
+
133
+ static int has_nonvec_read(void)
134
+ {
135
+ struct io_uring_probe *p;
136
+ struct io_uring ring;
137
+ int ret;
138
+
139
+ ret = io_uring_queue_init(1, &ring, 0);
140
+ if (ret) {
141
+ fprintf(stderr, "queue init failed: %d\n", ret);
142
+ exit(ret);
143
+ }
144
+
145
+ p = t_calloc(1, sizeof(*p) + 256 * sizeof(struct io_uring_probe_op));
146
+ ret = io_uring_register_probe(&ring, p, 256);
147
+ /* if we don't have PROBE_REGISTER, we don't have OP_READ/WRITE */
148
+ if (ret == -EINVAL) {
149
+ out:
150
+ io_uring_queue_exit(&ring);
151
+ free(p);
152
+ return 0;
153
+ } else if (ret) {
154
+ fprintf(stderr, "register_probe: %d\n", ret);
155
+ goto out;
156
+ }
157
+
158
+ if (p->ops_len <= IORING_OP_READ)
159
+ goto out;
160
+ if (!(p->ops[IORING_OP_READ].flags & IO_URING_OP_SUPPORTED))
161
+ goto out;
162
+ io_uring_queue_exit(&ring);
163
+ free(p);
164
+ return 1;
165
+ }
166
+
167
+ int main(int argc, char *argv[])
168
+ {
169
+ int ret, nonvec;
170
+
171
+ if (argc > 1)
172
+ return T_EXIT_SKIP;
173
+
174
+ vecs = t_create_buffers(BUFFERS, BS);
175
+
176
+ /* if we don't have nonvec read, skip testing that */
177
+ nonvec = has_nonvec_read();
178
+
179
+ if (nonvec) {
180
+ ret = test_io("/proc/kallsyms", 0, 0);
181
+ if (ret)
182
+ goto err;
183
+ }
184
+
185
+ ret = test_io("/proc/kallsyms", 0, 1);
186
+ if (ret)
187
+ goto err;
188
+
189
+ if (nonvec) {
190
+ ret = test_io("/proc/kallsyms", 1, 0);
191
+ if (ret)
192
+ goto err;
193
+ }
194
+
195
+ ret = test_io("/proc/kallsyms", 1, 1);
196
+ if (ret)
197
+ goto err;
198
+
199
+ return 0;
200
+ err:
201
+ fprintf(stderr, "Reading kallsyms failed\n");
202
+ return 1;
203
+ }
@@ -10,6 +10,7 @@
10
10
  #include <string.h>
11
11
  #include <fcntl.h>
12
12
  #include <poll.h>
13
+ #include <sys/time.h>
13
14
 
14
15
  #include "liburing.h"
15
16
  #include "helpers.h"
@@ -537,6 +538,139 @@ err:
537
538
  return 1;
538
539
  }
539
540
 
541
+ static int test_link_timeout_update(struct io_uring *ring, int async)
542
+ {
543
+ struct __kernel_timespec ts;
544
+ struct io_uring_cqe *cqe;
545
+ struct io_uring_sqe *sqe;
546
+ struct timeval start;
547
+ unsigned long msec;
548
+ int fds[2], ret, i;
549
+ struct iovec iov;
550
+ char buffer[128];
551
+
552
+ if (pipe(fds)) {
553
+ perror("pipe");
554
+ return 1;
555
+ }
556
+
557
+ sqe = io_uring_get_sqe(ring);
558
+ if (!sqe) {
559
+ printf("get sqe failed\n");
560
+ goto err;
561
+ }
562
+ iov.iov_base = buffer;
563
+ iov.iov_len = sizeof(buffer);
564
+ io_uring_prep_readv(sqe, fds[0], &iov, 1, 0);
565
+ sqe->flags |= IOSQE_IO_LINK;
566
+ sqe->user_data = 1;
567
+
568
+ sqe = io_uring_get_sqe(ring);
569
+ if (!sqe) {
570
+ printf("get sqe failed\n");
571
+ goto err;
572
+ }
573
+ ts.tv_sec = 5;
574
+ ts.tv_nsec = 0;
575
+ io_uring_prep_link_timeout(sqe, &ts, 0);
576
+ sqe->user_data = 2;
577
+
578
+ ret = io_uring_submit(ring);
579
+ if (ret != 2) {
580
+ printf("sqe submit failed: %d\n", ret);
581
+ goto err;
582
+ }
583
+
584
+ ts.tv_sec = 0;
585
+ ts.tv_nsec = 100000000LL;
586
+ sqe = io_uring_get_sqe(ring);
587
+ io_uring_prep_timeout_update(sqe, &ts, 2, IORING_LINK_TIMEOUT_UPDATE);
588
+ if (async)
589
+ sqe->flags |= IOSQE_ASYNC;
590
+ sqe->user_data = 3;
591
+
592
+ io_uring_submit(ring);
593
+
594
+ gettimeofday(&start, NULL);
595
+ for (i = 0; i < 3; i++) {
596
+ ret = io_uring_wait_cqe(ring, &cqe);
597
+ if (ret < 0) {
598
+ printf("wait completion %d\n", ret);
599
+ goto err;
600
+ }
601
+ switch (cqe->user_data) {
602
+ case 1:
603
+ if (cqe->res != -EINTR && cqe->res != -ECANCELED) {
604
+ fprintf(stderr, "Req %" PRIu64 " got %d\n", (uint64_t) cqe->user_data,
605
+ cqe->res);
606
+ goto err;
607
+ }
608
+ break;
609
+ case 2:
610
+ /* FASTPOLL kernels can cancel successfully */
611
+ if (cqe->res != -EALREADY && cqe->res != -ETIME) {
612
+ fprintf(stderr, "Req %" PRIu64 " got %d\n", (uint64_t) cqe->user_data,
613
+ cqe->res);
614
+ goto err;
615
+ }
616
+ break;
617
+ case 3:
618
+ if (cqe->res) {
619
+ fprintf(stderr, "Req %" PRIu64 " got %d\n", (uint64_t) cqe->user_data,
620
+ cqe->res);
621
+ goto err;
622
+ }
623
+ break;
624
+ }
625
+
626
+ io_uring_cqe_seen(ring, cqe);
627
+ }
628
+
629
+ msec = mtime_since_now(&start);
630
+ if (msec < 10 || msec > 200) {
631
+ fprintf(stderr, "Timeout appears incorrect: %lu\n", msec);
632
+ goto err;
633
+ }
634
+
635
+ close(fds[0]);
636
+ close(fds[1]);
637
+ return 0;
638
+ err:
639
+ return 1;
640
+ }
641
+
642
+ static int test_link_timeout_update_invalid(struct io_uring *ring, int async)
643
+ {
644
+ struct __kernel_timespec ts;
645
+ struct io_uring_cqe *cqe;
646
+ struct io_uring_sqe *sqe;
647
+ int ret;
648
+
649
+ ts.tv_sec = 0;
650
+ ts.tv_nsec = 100000000LL;
651
+ sqe = io_uring_get_sqe(ring);
652
+ io_uring_prep_timeout_update(sqe, &ts, 2, IORING_LINK_TIMEOUT_UPDATE);
653
+ sqe->user_data = 0xcafe0000;
654
+ if (async)
655
+ sqe->flags |= IOSQE_ASYNC;
656
+
657
+ io_uring_submit(ring);
658
+
659
+ ret = io_uring_wait_cqe(ring, &cqe);
660
+ if (ret < 0) {
661
+ printf("wait completion %d\n", ret);
662
+ goto err;
663
+ }
664
+ if (cqe->res != -ENOENT) {
665
+ fprintf(stderr, "bad timeout update: %d\n", cqe->res);
666
+ goto err;
667
+ }
668
+ io_uring_cqe_seen(ring, cqe);
669
+ return 0;
670
+ err:
671
+ return 1;
672
+ }
673
+
540
674
  static int test_timeout_link_chain1(struct io_uring *ring)
541
675
  {
542
676
  struct __kernel_timespec ts;
@@ -1104,5 +1238,30 @@ int main(int argc, char *argv[])
1104
1238
  return ret;
1105
1239
  }
1106
1240
 
1241
+ ret = test_link_timeout_update(&ring, 0);
1242
+ if (ret) {
1243
+ printf("test_link_timeout_update 0 failed\n");
1244
+ return ret;
1245
+ }
1246
+
1247
+ ret = test_link_timeout_update(&ring, 1);
1248
+ if (ret) {
1249
+ printf("test_link_timeout_update 1 failed\n");
1250
+ return ret;
1251
+ }
1252
+
1253
+ ret = test_link_timeout_update_invalid(&ring, 0);
1254
+ if (ret) {
1255
+ printf("test_link_timeout_update_invalid 0 failed\n");
1256
+ return ret;
1257
+ }
1258
+
1259
+ ret = test_link_timeout_update_invalid(&ring, 1);
1260
+ if (ret) {
1261
+ printf("test_link_timeout_update_invalid 1 failed\n");
1262
+ return ret;
1263
+ }
1264
+
1265
+
1107
1266
  return T_EXIT_PASS;
1108
1267
  }
@@ -0,0 +1,224 @@
1
+ /* SPDX-License-Identifier: MIT */
2
+ /*
3
+ * Test that the final close of a file does indeed get it closed, if the
4
+ * ring is setup with DEFER_TASKRUN and the task is waiting in cqring_wait()
5
+ * during. Also see:
6
+ *
7
+ * https://github.com/axboe/liburing/issues/1235
8
+ *
9
+ * for a bug report, and the zig code on which this test program is based.
10
+ */
11
+ #include <stdio.h>
12
+ #include <stdlib.h>
13
+ #include <string.h>
14
+ #include <unistd.h>
15
+ #include <errno.h>
16
+ #include <arpa/inet.h>
17
+ #include <sys/socket.h>
18
+ #include <signal.h>
19
+ #include <pthread.h>
20
+
21
+ #include "liburing.h"
22
+ #include "helpers.h"
23
+
24
+ enum {
25
+ IS_ACCEPT = 0,
26
+ IS_SEND = 0x100,
27
+ IS_SEND2 = 0x101,
28
+ IS_SEND3 = 0x102,
29
+ IS_CLOSE = 0x200,
30
+ };
31
+
32
+ struct thread_data {
33
+ int parent_pid;
34
+ };
35
+
36
+ static void *thread_fn(void *__data)
37
+ {
38
+ struct thread_data *data = __data;
39
+ struct sockaddr_in saddr;
40
+ int sockfd, ret;
41
+ char msg[64];
42
+
43
+ memset(&saddr, 0, sizeof(saddr));
44
+ saddr.sin_family = AF_INET;
45
+ saddr.sin_port = htons(9999);
46
+ inet_pton(AF_INET, "127.0.0.1", &saddr.sin_addr);
47
+
48
+ sockfd = socket(AF_INET, SOCK_STREAM, 0);
49
+ if (sockfd < 0) {
50
+ perror("socket");
51
+ goto done;
52
+ }
53
+
54
+ ret = connect(sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
55
+ if (ret < 0) {
56
+ perror("connect");
57
+ close(sockfd);
58
+ goto done;
59
+ }
60
+
61
+ do {
62
+ memset(msg, 0, sizeof(msg));
63
+ ret = recv(sockfd, msg, sizeof(msg), 0);
64
+ } while (ret > 0);
65
+
66
+ close(sockfd);
67
+ done:
68
+ kill(data->parent_pid, SIGUSR1);
69
+ return NULL;
70
+ }
71
+
72
+ /* we got SIGUSR1, exit normally */
73
+ static void sig_usr1(int sig)
74
+ {
75
+ exit(T_EXIT_PASS);
76
+ }
77
+
78
+ /* timed out, failure */
79
+ static void sig_timeout(int sig)
80
+ {
81
+ exit(T_EXIT_FAIL);
82
+ }
83
+
84
+ int main(int argc, char *argv[])
85
+ {
86
+ struct io_uring ring;
87
+ struct io_uring_sqe *sqe;
88
+ struct io_uring_cqe *cqe;
89
+ struct sockaddr_in saddr;
90
+ char *msg1 = "message number 1\n";
91
+ char *msg2 = "message number 2\n";
92
+ char *msg3 = "message number 3\n";
93
+ int val, send_fd, ret, sockfd;
94
+ struct sigaction act[2] = { };
95
+ struct thread_data td;
96
+ pthread_t thread;
97
+
98
+ if (argc > 1)
99
+ return T_EXIT_SKIP;
100
+
101
+ memset(&saddr, 0, sizeof(saddr));
102
+ saddr.sin_family = AF_INET;
103
+ saddr.sin_addr.s_addr = htonl(INADDR_ANY);
104
+ saddr.sin_port = htons(9999);
105
+
106
+ sockfd = socket(AF_INET, SOCK_STREAM, 0);
107
+ if (sockfd < 0) {
108
+ perror("socket");
109
+ return T_EXIT_FAIL;
110
+ }
111
+
112
+ val = 1;
113
+ setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));
114
+ setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
115
+
116
+ ret = bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr));
117
+ if (ret < 0) {
118
+ perror("bind");
119
+ close(sockfd);
120
+ return T_EXIT_FAIL;
121
+ }
122
+
123
+ ret = listen(sockfd, 1);
124
+ if (ret < 0) {
125
+ perror("listen");
126
+ close(sockfd);
127
+ return T_EXIT_FAIL;
128
+ }
129
+
130
+ ret = io_uring_queue_init(8, &ring, IORING_SETUP_SINGLE_ISSUER |
131
+ IORING_SETUP_DEFER_TASKRUN);
132
+ if (ret == -EINVAL) {
133
+ close(sockfd);
134
+ return T_EXIT_SKIP;
135
+ }
136
+
137
+ sqe = io_uring_get_sqe(&ring);
138
+ io_uring_prep_multishot_accept(sqe, sockfd, NULL, NULL, 0);
139
+ sqe->user_data = IS_ACCEPT;
140
+ io_uring_submit(&ring);
141
+
142
+ /* check for no multishot accept */
143
+ ret = io_uring_peek_cqe(&ring, &cqe);
144
+ if (!ret && cqe->res == -EINVAL) {
145
+ close(sockfd);
146
+ return T_EXIT_SKIP;
147
+ }
148
+
149
+ /* expected exit */
150
+ act[0].sa_handler = sig_usr1;
151
+ sigaction(SIGUSR1, &act[0], NULL);
152
+
153
+ /* if this hits, we have failed */
154
+ act[1].sa_handler = sig_timeout;
155
+ sigaction(SIGALRM, &act[1], NULL);
156
+ alarm(5);
157
+
158
+ /* start receiver */
159
+ td.parent_pid = getpid();
160
+ pthread_create(&thread, NULL, thread_fn, &td);
161
+
162
+ do {
163
+ ret = io_uring_submit_and_wait(&ring, 1);
164
+ if (ret < 0) {
165
+ fprintf(stderr, "submit: %d\n", ret);
166
+ return T_EXIT_FAIL;
167
+ }
168
+ ret = io_uring_peek_cqe(&ring, &cqe);
169
+ if (ret) {
170
+ fprintf(stderr, "peek: %d\n", ret);
171
+ return T_EXIT_FAIL;
172
+ }
173
+
174
+ switch (cqe->user_data) {
175
+ case IS_ACCEPT:
176
+ send_fd = cqe->res;
177
+ io_uring_cqe_seen(&ring, cqe);
178
+
179
+ /*
180
+ * prep two sends, with the 2nd linked to a close
181
+ * operation. Once the close has been completed, that
182
+ * will terminate the receiving thread and that will
183
+ * in turn send this task a SIGUSR1 signal. If the
184
+ * kernel is buggy, then we never get SIGUSR1 and we
185
+ * will sit forever waiting and be timed out.
186
+ */
187
+ sqe = io_uring_get_sqe(&ring);
188
+ io_uring_prep_send(sqe, send_fd, msg1, strlen(msg1), 0);
189
+ sqe->user_data = IS_SEND;
190
+ sqe->flags = IOSQE_CQE_SKIP_SUCCESS | IOSQE_IO_LINK;
191
+
192
+ sqe = io_uring_get_sqe(&ring);
193
+ io_uring_prep_send(sqe, send_fd, msg2, strlen(msg2), 0);
194
+ sqe->user_data = IS_SEND2;
195
+ sqe->flags = IOSQE_CQE_SKIP_SUCCESS | IOSQE_IO_LINK;
196
+
197
+ sqe = io_uring_get_sqe(&ring);
198
+ io_uring_prep_send(sqe, send_fd, msg3, strlen(msg3), 0);
199
+ sqe->user_data = IS_SEND3;
200
+ sqe->flags = IOSQE_CQE_SKIP_SUCCESS | IOSQE_IO_LINK;
201
+
202
+ sqe = io_uring_get_sqe(&ring);
203
+ io_uring_prep_close(sqe, send_fd);
204
+ sqe->user_data = IS_CLOSE;
205
+ sqe->flags = IOSQE_CQE_SKIP_SUCCESS;
206
+ break;
207
+ case IS_SEND:
208
+ case IS_SEND2:
209
+ fprintf(stderr, "Should not see send response\n");
210
+ io_uring_cqe_seen(&ring, cqe);
211
+ return T_EXIT_FAIL;
212
+ case IS_CLOSE:
213
+ fprintf(stderr, "Should not see close response\n");
214
+ io_uring_cqe_seen(&ring, cqe);
215
+ return T_EXIT_FAIL;
216
+ default:
217
+ fprintf(stderr, "got unknown cqe\n");
218
+ return T_EXIT_FAIL;
219
+ }
220
+ } while (1);
221
+
222
+ /* will never get here */
223
+ return T_EXIT_FAIL;
224
+ }
@@ -20,30 +20,6 @@
20
20
  #define LOOPS 100
21
21
  #define MIN_LOOPS 10
22
22
 
23
- static unsigned long long utime_since(const struct timeval *s,
24
- const struct timeval *e)
25
- {
26
- long long sec, usec;
27
-
28
- sec = e->tv_sec - s->tv_sec;
29
- usec = (e->tv_usec - s->tv_usec);
30
- if (sec > 0 && usec < 0) {
31
- sec--;
32
- usec += 1000000;
33
- }
34
-
35
- sec *= 1000000;
36
- return sec + usec;
37
- }
38
-
39
- static unsigned long long utime_since_now(struct timeval *tv)
40
- {
41
- struct timeval end;
42
-
43
- gettimeofday(&end, NULL);
44
- return utime_since(tv, &end);
45
- }
46
-
47
23
  static int do_madvise(struct io_uring *ring, void *addr, off_t len, int advice)
48
24
  {
49
25
  struct io_uring_sqe *sqe;
@@ -100,6 +76,8 @@ static int test_madvise(struct io_uring *ring, const char *filename)
100
76
 
101
77
  fd = open(filename, O_RDONLY);
102
78
  if (fd < 0) {
79
+ if (errno == EACCES || errno == EPERM)
80
+ return T_EXIT_SKIP;
103
81
  perror("open");
104
82
  return 1;
105
83
  }
@@ -143,9 +121,12 @@ static int test_madvise(struct io_uring *ring, const char *filename)
143
121
  return 1;
144
122
 
145
123
  if (cached_read < uncached_read &&
146
- cached_read2 < uncached_read)
124
+ cached_read2 < uncached_read) {
125
+ free(buf);
147
126
  return 0;
127
+ }
148
128
 
129
+ free(buf);
149
130
  return 2;
150
131
  }
151
132
 
@@ -170,6 +151,8 @@ int main(int argc, char *argv[])
170
151
  good = bad = 0;
171
152
  for (i = 0; i < LOOPS; i++) {
172
153
  ret = test_madvise(&ring, fname);
154
+ if (ret == T_EXIT_SKIP)
155
+ goto skip;
173
156
  if (ret == 1) {
174
157
  fprintf(stderr, "test_madvise failed\n");
175
158
  goto err;
@@ -192,4 +175,8 @@ err:
192
175
  if (fname != argv[1])
193
176
  unlink(fname);
194
177
  return T_EXIT_FAIL;
178
+ skip:
179
+ if (fname != argv[1])
180
+ unlink(fname);
181
+ return T_EXIT_SKIP;
195
182
  }
@@ -22,31 +22,6 @@ struct data {
22
22
  int nr_fds;
23
23
  };
24
24
 
25
- static unsigned long long mtime_since(const struct timeval *s,
26
- const struct timeval *e)
27
- {
28
- long long sec, usec;
29
-
30
- sec = e->tv_sec - s->tv_sec;
31
- usec = (e->tv_usec - s->tv_usec);
32
- if (sec > 0 && usec < 0) {
33
- sec--;
34
- usec += 1000000;
35
- }
36
-
37
- sec *= 1000;
38
- usec /= 1000;
39
- return sec + usec;
40
- }
41
-
42
- static unsigned long long mtime_since_now(struct timeval *tv)
43
- {
44
- struct timeval end;
45
-
46
- gettimeofday(&end, NULL);
47
- return mtime_since(tv, &end);
48
- }
49
-
50
25
  static int time_pass(struct timeval *start, unsigned long min_t,
51
26
  unsigned long max_t, const char *name)
52
27
  {