polyphony 0.85 → 0.86

Sign up to get free protection for your applications and to get access to all the features.
Files changed (230) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/Gemfile.lock +1 -1
  4. data/ext/polyphony/io_extensions.c +2 -3
  5. data/lib/polyphony/version.rb +1 -1
  6. data/polyphony.gemspec +1 -1
  7. data/test/test_backend.rb +1 -1
  8. data/test/test_signal.rb +3 -3
  9. data/vendor/liburing/.github/pull_request_template.md +86 -0
  10. data/vendor/liburing/.github/workflows/build.yml +85 -0
  11. data/vendor/liburing/.github/workflows/shellcheck.yml +20 -0
  12. data/vendor/liburing/.gitignore +149 -0
  13. data/vendor/liburing/COPYING +502 -0
  14. data/vendor/liburing/COPYING.GPL +339 -0
  15. data/vendor/liburing/LICENSE +7 -0
  16. data/vendor/liburing/Makefile +82 -0
  17. data/vendor/liburing/Makefile.common +5 -0
  18. data/vendor/liburing/Makefile.quiet +11 -0
  19. data/vendor/liburing/README +46 -0
  20. data/vendor/liburing/configure +486 -0
  21. data/vendor/liburing/debian/README.Debian +7 -0
  22. data/vendor/liburing/debian/changelog +27 -0
  23. data/vendor/liburing/debian/compat +1 -0
  24. data/vendor/liburing/debian/control +48 -0
  25. data/vendor/liburing/debian/copyright +49 -0
  26. data/vendor/liburing/debian/liburing-dev.install +4 -0
  27. data/vendor/liburing/debian/liburing-dev.manpages +6 -0
  28. data/vendor/liburing/debian/liburing1-udeb.install +1 -0
  29. data/vendor/liburing/debian/liburing1.install +1 -0
  30. data/vendor/liburing/debian/liburing1.symbols +32 -0
  31. data/vendor/liburing/debian/patches/series +1 -0
  32. data/vendor/liburing/debian/rules +81 -0
  33. data/vendor/liburing/debian/source/format +1 -0
  34. data/vendor/liburing/debian/source/local-options +2 -0
  35. data/vendor/liburing/debian/source/options +1 -0
  36. data/vendor/liburing/debian/watch +3 -0
  37. data/vendor/liburing/examples/Makefile +38 -0
  38. data/vendor/liburing/examples/io_uring-cp.c +282 -0
  39. data/vendor/liburing/examples/io_uring-test.c +112 -0
  40. data/vendor/liburing/examples/link-cp.c +193 -0
  41. data/vendor/liburing/examples/ucontext-cp.c +273 -0
  42. data/vendor/liburing/liburing.pc.in +12 -0
  43. data/vendor/liburing/liburing.spec +66 -0
  44. data/vendor/liburing/make-debs.sh +53 -0
  45. data/vendor/liburing/man/io_uring.7 +754 -0
  46. data/vendor/liburing/man/io_uring_cq_advance.3 +35 -0
  47. data/vendor/liburing/man/io_uring_cq_ready.3 +25 -0
  48. data/vendor/liburing/man/io_uring_cqe_get_data.3 +34 -0
  49. data/vendor/liburing/man/io_uring_cqe_seen.3 +32 -0
  50. data/vendor/liburing/man/io_uring_enter.2 +1483 -0
  51. data/vendor/liburing/man/io_uring_free_probe.3 +24 -0
  52. data/vendor/liburing/man/io_uring_get_probe.3 +29 -0
  53. data/vendor/liburing/man/io_uring_get_sqe.3 +38 -0
  54. data/vendor/liburing/man/io_uring_opcode_supported.3 +29 -0
  55. data/vendor/liburing/man/io_uring_prep_msg_ring.3 +58 -0
  56. data/vendor/liburing/man/io_uring_prep_read.3 +50 -0
  57. data/vendor/liburing/man/io_uring_prep_read_fixed.3 +54 -0
  58. data/vendor/liburing/man/io_uring_prep_readv.3 +51 -0
  59. data/vendor/liburing/man/io_uring_prep_readv2.3 +79 -0
  60. data/vendor/liburing/man/io_uring_prep_write.3 +50 -0
  61. data/vendor/liburing/man/io_uring_prep_write_fixed.3 +54 -0
  62. data/vendor/liburing/man/io_uring_prep_writev.3 +51 -0
  63. data/vendor/liburing/man/io_uring_prep_writev2.3 +78 -0
  64. data/vendor/liburing/man/io_uring_queue_exit.3 +27 -0
  65. data/vendor/liburing/man/io_uring_queue_init.3 +44 -0
  66. data/vendor/liburing/man/io_uring_register.2 +688 -0
  67. data/vendor/liburing/man/io_uring_register_buffers.3 +41 -0
  68. data/vendor/liburing/man/io_uring_register_files.3 +35 -0
  69. data/vendor/liburing/man/io_uring_setup.2 +534 -0
  70. data/vendor/liburing/man/io_uring_sq_ready.3 +25 -0
  71. data/vendor/liburing/man/io_uring_sq_space_left.3 +25 -0
  72. data/vendor/liburing/man/io_uring_sqe_set_data.3 +30 -0
  73. data/vendor/liburing/man/io_uring_sqe_set_flags.3 +60 -0
  74. data/vendor/liburing/man/io_uring_sqring_wait.3 +30 -0
  75. data/vendor/liburing/man/io_uring_submit.3 +29 -0
  76. data/vendor/liburing/man/io_uring_submit_and_wait.3 +34 -0
  77. data/vendor/liburing/man/io_uring_submit_and_wait_timeout.3 +49 -0
  78. data/vendor/liburing/man/io_uring_unregister_buffers.3 +26 -0
  79. data/vendor/liburing/man/io_uring_unregister_files.3 +26 -0
  80. data/vendor/liburing/man/io_uring_wait_cqe.3 +33 -0
  81. data/vendor/liburing/man/io_uring_wait_cqe_nr.3 +36 -0
  82. data/vendor/liburing/man/io_uring_wait_cqe_timeout.3 +39 -0
  83. data/vendor/liburing/man/io_uring_wait_cqes.3 +46 -0
  84. data/vendor/liburing/src/Makefile +89 -0
  85. data/vendor/liburing/src/arch/aarch64/syscall.h +95 -0
  86. data/vendor/liburing/src/arch/generic/lib.h +21 -0
  87. data/vendor/liburing/src/arch/generic/syscall.h +87 -0
  88. data/vendor/liburing/src/arch/syscall-defs.h +67 -0
  89. data/vendor/liburing/src/arch/x86/lib.h +32 -0
  90. data/vendor/liburing/src/arch/x86/syscall.h +160 -0
  91. data/vendor/liburing/src/include/liburing/barrier.h +81 -0
  92. data/vendor/liburing/src/include/liburing/io_uring.h +442 -0
  93. data/vendor/liburing/src/include/liburing.h +921 -0
  94. data/vendor/liburing/src/int_flags.h +8 -0
  95. data/vendor/liburing/src/lib.h +57 -0
  96. data/vendor/liburing/src/liburing.map +53 -0
  97. data/vendor/liburing/src/nolibc.c +48 -0
  98. data/vendor/liburing/src/queue.c +403 -0
  99. data/vendor/liburing/src/register.c +293 -0
  100. data/vendor/liburing/src/setup.c +332 -0
  101. data/vendor/liburing/src/syscall.c +47 -0
  102. data/vendor/liburing/src/syscall.h +103 -0
  103. data/vendor/liburing/test/232c93d07b74-test.c +306 -0
  104. data/vendor/liburing/test/35fa71a030ca-test.c +329 -0
  105. data/vendor/liburing/test/500f9fbadef8-test.c +89 -0
  106. data/vendor/liburing/test/7ad0e4b2f83c-test.c +93 -0
  107. data/vendor/liburing/test/8a9973408177-test.c +106 -0
  108. data/vendor/liburing/test/917257daa0fe-test.c +53 -0
  109. data/vendor/liburing/test/Makefile +244 -0
  110. data/vendor/liburing/test/a0908ae19763-test.c +58 -0
  111. data/vendor/liburing/test/a4c0b3decb33-test.c +180 -0
  112. data/vendor/liburing/test/accept-link.c +254 -0
  113. data/vendor/liburing/test/accept-reuse.c +164 -0
  114. data/vendor/liburing/test/accept-test.c +79 -0
  115. data/vendor/liburing/test/accept.c +477 -0
  116. data/vendor/liburing/test/across-fork.c +283 -0
  117. data/vendor/liburing/test/b19062a56726-test.c +53 -0
  118. data/vendor/liburing/test/b5837bd5311d-test.c +77 -0
  119. data/vendor/liburing/test/ce593a6c480a-test.c +136 -0
  120. data/vendor/liburing/test/close-opath.c +122 -0
  121. data/vendor/liburing/test/config +10 -0
  122. data/vendor/liburing/test/connect.c +398 -0
  123. data/vendor/liburing/test/cq-full.c +96 -0
  124. data/vendor/liburing/test/cq-overflow.c +294 -0
  125. data/vendor/liburing/test/cq-peek-batch.c +102 -0
  126. data/vendor/liburing/test/cq-ready.c +94 -0
  127. data/vendor/liburing/test/cq-size.c +64 -0
  128. data/vendor/liburing/test/d4ae271dfaae-test.c +96 -0
  129. data/vendor/liburing/test/d77a67ed5f27-test.c +65 -0
  130. data/vendor/liburing/test/defer.c +307 -0
  131. data/vendor/liburing/test/double-poll-crash.c +185 -0
  132. data/vendor/liburing/test/drop-submit.c +92 -0
  133. data/vendor/liburing/test/eeed8b54e0df-test.c +114 -0
  134. data/vendor/liburing/test/empty-eownerdead.c +45 -0
  135. data/vendor/liburing/test/eventfd-disable.c +151 -0
  136. data/vendor/liburing/test/eventfd-reg.c +76 -0
  137. data/vendor/liburing/test/eventfd-ring.c +97 -0
  138. data/vendor/liburing/test/eventfd.c +112 -0
  139. data/vendor/liburing/test/exec-target.c +6 -0
  140. data/vendor/liburing/test/exit-no-cleanup.c +117 -0
  141. data/vendor/liburing/test/fadvise.c +202 -0
  142. data/vendor/liburing/test/fallocate.c +249 -0
  143. data/vendor/liburing/test/fc2a85cb02ef-test.c +131 -0
  144. data/vendor/liburing/test/file-register.c +858 -0
  145. data/vendor/liburing/test/file-update.c +173 -0
  146. data/vendor/liburing/test/file-verify.c +629 -0
  147. data/vendor/liburing/test/files-exit-hang-poll.c +128 -0
  148. data/vendor/liburing/test/files-exit-hang-timeout.c +134 -0
  149. data/vendor/liburing/test/fixed-link.c +90 -0
  150. data/vendor/liburing/test/fpos.c +252 -0
  151. data/vendor/liburing/test/fsync.c +224 -0
  152. data/vendor/liburing/test/hardlink.c +136 -0
  153. data/vendor/liburing/test/helpers.c +135 -0
  154. data/vendor/liburing/test/helpers.h +67 -0
  155. data/vendor/liburing/test/io-cancel.c +550 -0
  156. data/vendor/liburing/test/io_uring_enter.c +296 -0
  157. data/vendor/liburing/test/io_uring_register.c +676 -0
  158. data/vendor/liburing/test/io_uring_setup.c +192 -0
  159. data/vendor/liburing/test/iopoll.c +372 -0
  160. data/vendor/liburing/test/lfs-openat-write.c +119 -0
  161. data/vendor/liburing/test/lfs-openat.c +275 -0
  162. data/vendor/liburing/test/link-timeout.c +1107 -0
  163. data/vendor/liburing/test/link.c +496 -0
  164. data/vendor/liburing/test/link_drain.c +229 -0
  165. data/vendor/liburing/test/madvise.c +195 -0
  166. data/vendor/liburing/test/mkdir.c +108 -0
  167. data/vendor/liburing/test/msg-ring.c +234 -0
  168. data/vendor/liburing/test/multicqes_drain.c +387 -0
  169. data/vendor/liburing/test/nop-all-sizes.c +99 -0
  170. data/vendor/liburing/test/nop.c +115 -0
  171. data/vendor/liburing/test/open-close.c +261 -0
  172. data/vendor/liburing/test/openat2.c +308 -0
  173. data/vendor/liburing/test/personality.c +204 -0
  174. data/vendor/liburing/test/pipe-eof.c +83 -0
  175. data/vendor/liburing/test/pipe-reuse.c +105 -0
  176. data/vendor/liburing/test/poll-cancel-ton.c +135 -0
  177. data/vendor/liburing/test/poll-cancel.c +228 -0
  178. data/vendor/liburing/test/poll-link.c +230 -0
  179. data/vendor/liburing/test/poll-many.c +208 -0
  180. data/vendor/liburing/test/poll-mshot-update.c +273 -0
  181. data/vendor/liburing/test/poll-ring.c +48 -0
  182. data/vendor/liburing/test/poll-v-poll.c +353 -0
  183. data/vendor/liburing/test/poll.c +109 -0
  184. data/vendor/liburing/test/pollfree.c +426 -0
  185. data/vendor/liburing/test/probe.c +135 -0
  186. data/vendor/liburing/test/read-write.c +876 -0
  187. data/vendor/liburing/test/register-restrictions.c +633 -0
  188. data/vendor/liburing/test/rename.c +135 -0
  189. data/vendor/liburing/test/ring-leak.c +173 -0
  190. data/vendor/liburing/test/ring-leak2.c +249 -0
  191. data/vendor/liburing/test/rsrc_tags.c +449 -0
  192. data/vendor/liburing/test/runtests-loop.sh +16 -0
  193. data/vendor/liburing/test/runtests.sh +170 -0
  194. data/vendor/liburing/test/rw_merge_test.c +97 -0
  195. data/vendor/liburing/test/self.c +91 -0
  196. data/vendor/liburing/test/send_recv.c +286 -0
  197. data/vendor/liburing/test/send_recvmsg.c +345 -0
  198. data/vendor/liburing/test/sendmsg_fs_cve.c +200 -0
  199. data/vendor/liburing/test/shared-wq.c +84 -0
  200. data/vendor/liburing/test/short-read.c +75 -0
  201. data/vendor/liburing/test/shutdown.c +165 -0
  202. data/vendor/liburing/test/sigfd-deadlock.c +74 -0
  203. data/vendor/liburing/test/skip-cqe.c +429 -0
  204. data/vendor/liburing/test/socket-rw-eagain.c +158 -0
  205. data/vendor/liburing/test/socket-rw-offset.c +157 -0
  206. data/vendor/liburing/test/socket-rw.c +145 -0
  207. data/vendor/liburing/test/splice.c +512 -0
  208. data/vendor/liburing/test/sq-full-cpp.cc +45 -0
  209. data/vendor/liburing/test/sq-full.c +45 -0
  210. data/vendor/liburing/test/sq-poll-dup.c +204 -0
  211. data/vendor/liburing/test/sq-poll-kthread.c +169 -0
  212. data/vendor/liburing/test/sq-poll-share.c +137 -0
  213. data/vendor/liburing/test/sq-space_left.c +159 -0
  214. data/vendor/liburing/test/sqpoll-cancel-hang.c +157 -0
  215. data/vendor/liburing/test/sqpoll-disable-exit.c +196 -0
  216. data/vendor/liburing/test/sqpoll-exit-hang.c +78 -0
  217. data/vendor/liburing/test/sqpoll-sleep.c +69 -0
  218. data/vendor/liburing/test/statx.c +172 -0
  219. data/vendor/liburing/test/stdout.c +232 -0
  220. data/vendor/liburing/test/submit-link-fail.c +154 -0
  221. data/vendor/liburing/test/submit-reuse.c +239 -0
  222. data/vendor/liburing/test/symlink.c +116 -0
  223. data/vendor/liburing/test/teardowns.c +58 -0
  224. data/vendor/liburing/test/thread-exit.c +143 -0
  225. data/vendor/liburing/test/timeout-new.c +252 -0
  226. data/vendor/liburing/test/timeout-overflow.c +204 -0
  227. data/vendor/liburing/test/timeout.c +1523 -0
  228. data/vendor/liburing/test/unlink.c +112 -0
  229. data/vendor/liburing/test/wakeup-hang.c +162 -0
  230. metadata +223 -2
@@ -0,0 +1,1523 @@
1
+ /* SPDX-License-Identifier: MIT */
2
+ /*
3
+ * Description: run various timeout tests
4
+ *
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/time.h>
13
+ #include <sys/wait.h>
14
+ #include <sys/types.h>
15
+ #include <sys/stat.h>
16
+
17
+ #include "liburing.h"
18
+ #include "../src/syscall.h"
19
+
20
+ #define TIMEOUT_MSEC 200
21
+ static int not_supported;
22
+ static int no_modify;
23
+
24
+ static void msec_to_ts(struct __kernel_timespec *ts, unsigned int msec)
25
+ {
26
+ ts->tv_sec = msec / 1000;
27
+ ts->tv_nsec = (msec % 1000) * 1000000;
28
+ }
29
+
30
+ static unsigned long long mtime_since(const struct timeval *s,
31
+ const struct timeval *e)
32
+ {
33
+ long long sec, usec;
34
+
35
+ sec = e->tv_sec - s->tv_sec;
36
+ usec = (e->tv_usec - s->tv_usec);
37
+ if (sec > 0 && usec < 0) {
38
+ sec--;
39
+ usec += 1000000;
40
+ }
41
+
42
+ sec *= 1000;
43
+ usec /= 1000;
44
+ return sec + usec;
45
+ }
46
+
47
+ static unsigned long long mtime_since_now(struct timeval *tv)
48
+ {
49
+ struct timeval end;
50
+
51
+ gettimeofday(&end, NULL);
52
+ return mtime_since(tv, &end);
53
+ }
54
+
55
+ /*
56
+ * Test that we return to userspace if a timeout triggers, even if we
57
+ * don't satisfy the number of events asked for.
58
+ */
59
+ static int test_single_timeout_many(struct io_uring *ring)
60
+ {
61
+ struct io_uring_cqe *cqe;
62
+ struct io_uring_sqe *sqe;
63
+ unsigned long long exp;
64
+ struct __kernel_timespec ts;
65
+ struct timeval tv;
66
+ int ret;
67
+
68
+ sqe = io_uring_get_sqe(ring);
69
+ if (!sqe) {
70
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
71
+ goto err;
72
+ }
73
+
74
+ msec_to_ts(&ts, TIMEOUT_MSEC);
75
+ io_uring_prep_timeout(sqe, &ts, 0, 0);
76
+
77
+ ret = io_uring_submit(ring);
78
+ if (ret <= 0) {
79
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
80
+ goto err;
81
+ }
82
+
83
+ gettimeofday(&tv, NULL);
84
+ ret = __sys_io_uring_enter(ring->ring_fd, 0, 4, IORING_ENTER_GETEVENTS,
85
+ NULL);
86
+ if (ret < 0) {
87
+ fprintf(stderr, "%s: io_uring_enter %d\n", __FUNCTION__, ret);
88
+ goto err;
89
+ }
90
+
91
+ ret = io_uring_wait_cqe(ring, &cqe);
92
+ if (ret < 0) {
93
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
94
+ goto err;
95
+ }
96
+ ret = cqe->res;
97
+ io_uring_cqe_seen(ring, cqe);
98
+ if (ret == -EINVAL) {
99
+ fprintf(stdout, "Timeout not supported, ignored\n");
100
+ not_supported = 1;
101
+ return 0;
102
+ } else if (ret != -ETIME) {
103
+ fprintf(stderr, "Timeout: %s\n", strerror(-ret));
104
+ goto err;
105
+ }
106
+
107
+ exp = mtime_since_now(&tv);
108
+ if (exp >= TIMEOUT_MSEC / 2 && exp <= (TIMEOUT_MSEC * 3) / 2)
109
+ return 0;
110
+ fprintf(stderr, "%s: Timeout seems wonky (got %llu)\n", __FUNCTION__, exp);
111
+ err:
112
+ return 1;
113
+ }
114
+
115
+ /*
116
+ * Test numbered trigger of timeout
117
+ */
118
+ static int test_single_timeout_nr(struct io_uring *ring, int nr)
119
+ {
120
+ struct io_uring_cqe *cqe;
121
+ struct io_uring_sqe *sqe;
122
+ struct __kernel_timespec ts;
123
+ int i, ret;
124
+
125
+ sqe = io_uring_get_sqe(ring);
126
+ if (!sqe) {
127
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
128
+ goto err;
129
+ }
130
+
131
+ msec_to_ts(&ts, TIMEOUT_MSEC);
132
+ io_uring_prep_timeout(sqe, &ts, nr, 0);
133
+
134
+ sqe = io_uring_get_sqe(ring);
135
+ io_uring_prep_nop(sqe);
136
+ io_uring_sqe_set_data(sqe, (void *) 1);
137
+ sqe = io_uring_get_sqe(ring);
138
+ io_uring_prep_nop(sqe);
139
+ io_uring_sqe_set_data(sqe, (void *) 1);
140
+
141
+ ret = io_uring_submit_and_wait(ring, 3);
142
+ if (ret <= 0) {
143
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
144
+ goto err;
145
+ }
146
+
147
+ i = 0;
148
+ while (i < 3) {
149
+ ret = io_uring_wait_cqe(ring, &cqe);
150
+ if (ret < 0) {
151
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
152
+ goto err;
153
+ }
154
+
155
+ ret = cqe->res;
156
+
157
+ /*
158
+ * NOP commands have user_data as 1. Check that we get the
159
+ * at least 'nr' NOPs first, then the successfully removed timout.
160
+ */
161
+ if (io_uring_cqe_get_data(cqe) == NULL) {
162
+ if (i < nr) {
163
+ fprintf(stderr, "%s: timeout received too early\n", __FUNCTION__);
164
+ goto err;
165
+ }
166
+ if (ret) {
167
+ fprintf(stderr, "%s: timeout triggered by passage of"
168
+ " time, not by events completed\n", __FUNCTION__);
169
+ goto err;
170
+ }
171
+ }
172
+
173
+ io_uring_cqe_seen(ring, cqe);
174
+ if (ret) {
175
+ fprintf(stderr, "res: %d\n", ret);
176
+ goto err;
177
+ }
178
+ i++;
179
+ };
180
+
181
+ return 0;
182
+ err:
183
+ return 1;
184
+ }
185
+
186
+ static int test_single_timeout_wait(struct io_uring *ring,
187
+ struct io_uring_params *p)
188
+ {
189
+ struct io_uring_cqe *cqe;
190
+ struct io_uring_sqe *sqe;
191
+ struct __kernel_timespec ts;
192
+ int i, ret;
193
+
194
+ sqe = io_uring_get_sqe(ring);
195
+ io_uring_prep_nop(sqe);
196
+ io_uring_sqe_set_data(sqe, (void *) 1);
197
+
198
+ sqe = io_uring_get_sqe(ring);
199
+ io_uring_prep_nop(sqe);
200
+ io_uring_sqe_set_data(sqe, (void *) 1);
201
+
202
+ /* no implied submit for newer kernels */
203
+ if (p->features & IORING_FEAT_EXT_ARG) {
204
+ ret = io_uring_submit(ring);
205
+ if (ret != 2) {
206
+ fprintf(stderr, "%s: submit %d\n", __FUNCTION__, ret);
207
+ return 1;
208
+ }
209
+ }
210
+
211
+ msec_to_ts(&ts, 1000);
212
+
213
+ i = 0;
214
+ do {
215
+ ret = io_uring_wait_cqes(ring, &cqe, 2, &ts, NULL);
216
+ if (ret == -ETIME)
217
+ break;
218
+ if (ret < 0) {
219
+ fprintf(stderr, "%s: wait timeout failed: %d\n", __FUNCTION__, ret);
220
+ goto err;
221
+ }
222
+
223
+ ret = cqe->res;
224
+ io_uring_cqe_seen(ring, cqe);
225
+ if (ret < 0) {
226
+ fprintf(stderr, "res: %d\n", ret);
227
+ goto err;
228
+ }
229
+ i++;
230
+ } while (1);
231
+
232
+ if (i != 2) {
233
+ fprintf(stderr, "got %d completions\n", i);
234
+ goto err;
235
+ }
236
+ return 0;
237
+ err:
238
+ return 1;
239
+ }
240
+
241
+ /*
242
+ * Test single timeout waking us up
243
+ */
244
+ static int test_single_timeout(struct io_uring *ring)
245
+ {
246
+ struct io_uring_cqe *cqe;
247
+ struct io_uring_sqe *sqe;
248
+ unsigned long long exp;
249
+ struct __kernel_timespec ts;
250
+ struct timeval tv;
251
+ int ret;
252
+
253
+ sqe = io_uring_get_sqe(ring);
254
+ if (!sqe) {
255
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
256
+ goto err;
257
+ }
258
+
259
+ msec_to_ts(&ts, TIMEOUT_MSEC);
260
+ io_uring_prep_timeout(sqe, &ts, 0, 0);
261
+
262
+ ret = io_uring_submit(ring);
263
+ if (ret <= 0) {
264
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
265
+ goto err;
266
+ }
267
+
268
+ gettimeofday(&tv, NULL);
269
+ ret = io_uring_wait_cqe(ring, &cqe);
270
+ if (ret < 0) {
271
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
272
+ goto err;
273
+ }
274
+ ret = cqe->res;
275
+ io_uring_cqe_seen(ring, cqe);
276
+ if (ret == -EINVAL) {
277
+ fprintf(stdout, "%s: Timeout not supported, ignored\n", __FUNCTION__);
278
+ not_supported = 1;
279
+ return 0;
280
+ } else if (ret != -ETIME) {
281
+ fprintf(stderr, "%s: Timeout: %s\n", __FUNCTION__, strerror(-ret));
282
+ goto err;
283
+ }
284
+
285
+ exp = mtime_since_now(&tv);
286
+ if (exp >= TIMEOUT_MSEC / 2 && exp <= (TIMEOUT_MSEC * 3) / 2)
287
+ return 0;
288
+ fprintf(stderr, "%s: Timeout seems wonky (got %llu)\n", __FUNCTION__, exp);
289
+ err:
290
+ return 1;
291
+ }
292
+
293
+ static int test_single_timeout_remove_notfound(struct io_uring *ring)
294
+ {
295
+ struct io_uring_cqe *cqe;
296
+ struct io_uring_sqe *sqe;
297
+ struct __kernel_timespec ts;
298
+ int ret, i;
299
+
300
+ if (no_modify)
301
+ return 0;
302
+
303
+ sqe = io_uring_get_sqe(ring);
304
+ if (!sqe) {
305
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
306
+ goto err;
307
+ }
308
+
309
+ msec_to_ts(&ts, TIMEOUT_MSEC);
310
+ io_uring_prep_timeout(sqe, &ts, 2, 0);
311
+ sqe->user_data = 1;
312
+
313
+ ret = io_uring_submit(ring);
314
+ if (ret <= 0) {
315
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
316
+ goto err;
317
+ }
318
+
319
+ sqe = io_uring_get_sqe(ring);
320
+ if (!sqe) {
321
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
322
+ goto err;
323
+ }
324
+
325
+ io_uring_prep_timeout_remove(sqe, 2, 0);
326
+ sqe->user_data = 2;
327
+
328
+ ret = io_uring_submit(ring);
329
+ if (ret <= 0) {
330
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
331
+ goto err;
332
+ }
333
+
334
+ /*
335
+ * We should get two completions. One is our modify request, which should
336
+ * complete with -ENOENT. The other is the timeout that will trigger after
337
+ * TIMEOUT_MSEC.
338
+ */
339
+ for (i = 0; i < 2; i++) {
340
+ ret = io_uring_wait_cqe(ring, &cqe);
341
+ if (ret < 0) {
342
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
343
+ goto err;
344
+ }
345
+ if (cqe->user_data == 2) {
346
+ if (cqe->res != -ENOENT) {
347
+ fprintf(stderr, "%s: modify ret %d, wanted ENOENT\n", __FUNCTION__, cqe->res);
348
+ break;
349
+ }
350
+ } else if (cqe->user_data == 1) {
351
+ if (cqe->res != -ETIME) {
352
+ fprintf(stderr, "%s: timeout ret %d, wanted -ETIME\n", __FUNCTION__, cqe->res);
353
+ break;
354
+ }
355
+ }
356
+ io_uring_cqe_seen(ring, cqe);
357
+ }
358
+ return 0;
359
+ err:
360
+ return 1;
361
+ }
362
+
363
+ static int test_single_timeout_remove(struct io_uring *ring)
364
+ {
365
+ struct io_uring_cqe *cqe;
366
+ struct io_uring_sqe *sqe;
367
+ struct __kernel_timespec ts;
368
+ int ret, i;
369
+
370
+ sqe = io_uring_get_sqe(ring);
371
+ if (!sqe) {
372
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
373
+ goto err;
374
+ }
375
+
376
+ msec_to_ts(&ts, TIMEOUT_MSEC);
377
+ io_uring_prep_timeout(sqe, &ts, 0, 0);
378
+ sqe->user_data = 1;
379
+
380
+ ret = io_uring_submit(ring);
381
+ if (ret <= 0) {
382
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
383
+ goto err;
384
+ }
385
+
386
+ sqe = io_uring_get_sqe(ring);
387
+ if (!sqe) {
388
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
389
+ goto err;
390
+ }
391
+
392
+ io_uring_prep_timeout_remove(sqe, 1, 0);
393
+ sqe->user_data = 2;
394
+
395
+ ret = io_uring_submit(ring);
396
+ if (ret <= 0) {
397
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
398
+ goto err;
399
+ }
400
+
401
+ /*
402
+ * We should have two completions ready. One is for the original timeout
403
+ * request, user_data == 1, that should have a ret of -ECANCELED. The other
404
+ * is for our modify request, user_data == 2, that should have a ret of 0.
405
+ */
406
+ for (i = 0; i < 2; i++) {
407
+ ret = io_uring_wait_cqe(ring, &cqe);
408
+ if (ret < 0) {
409
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
410
+ goto err;
411
+ }
412
+ if (no_modify)
413
+ goto seen;
414
+ if (cqe->res == -EINVAL && cqe->user_data == 2) {
415
+ fprintf(stdout, "Timeout modify not supported, ignoring\n");
416
+ no_modify = 1;
417
+ goto seen;
418
+ }
419
+ if (cqe->user_data == 1) {
420
+ if (cqe->res != -ECANCELED) {
421
+ fprintf(stderr, "%s: timeout ret %d, wanted canceled\n", __FUNCTION__, cqe->res);
422
+ break;
423
+ }
424
+ } else if (cqe->user_data == 2) {
425
+ if (cqe->res) {
426
+ fprintf(stderr, "%s: modify ret %d, wanted 0\n", __FUNCTION__, cqe->res);
427
+ break;
428
+ }
429
+ }
430
+ seen:
431
+ io_uring_cqe_seen(ring, cqe);
432
+ }
433
+ return 0;
434
+ err:
435
+ return 1;
436
+ }
437
+
438
+ /*
439
+ * Test single absolute timeout waking us up
440
+ */
441
+ static int test_single_timeout_abs(struct io_uring *ring)
442
+ {
443
+ struct io_uring_cqe *cqe;
444
+ struct io_uring_sqe *sqe;
445
+ unsigned long long exp;
446
+ struct __kernel_timespec ts;
447
+ struct timespec abs_ts;
448
+ struct timeval tv;
449
+ int ret;
450
+
451
+ sqe = io_uring_get_sqe(ring);
452
+ if (!sqe) {
453
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
454
+ goto err;
455
+ }
456
+
457
+ clock_gettime(CLOCK_MONOTONIC, &abs_ts);
458
+ ts.tv_sec = abs_ts.tv_sec + 1;
459
+ ts.tv_nsec = abs_ts.tv_nsec;
460
+ io_uring_prep_timeout(sqe, &ts, 0, IORING_TIMEOUT_ABS);
461
+
462
+ ret = io_uring_submit(ring);
463
+ if (ret <= 0) {
464
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
465
+ goto err;
466
+ }
467
+
468
+ gettimeofday(&tv, NULL);
469
+ ret = io_uring_wait_cqe(ring, &cqe);
470
+ if (ret < 0) {
471
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
472
+ goto err;
473
+ }
474
+ ret = cqe->res;
475
+ io_uring_cqe_seen(ring, cqe);
476
+ if (ret == -EINVAL) {
477
+ fprintf(stdout, "Absolute timeouts not supported, ignored\n");
478
+ return 0;
479
+ } else if (ret != -ETIME) {
480
+ fprintf(stderr, "Timeout: %s\n", strerror(-ret));
481
+ goto err;
482
+ }
483
+
484
+ exp = mtime_since_now(&tv);
485
+ if (exp >= 1000 / 2 && exp <= (1000 * 3) / 2)
486
+ return 0;
487
+ fprintf(stderr, "%s: Timeout seems wonky (got %llu)\n", __FUNCTION__, exp);
488
+ err:
489
+ return 1;
490
+ }
491
+
492
+ /*
493
+ * Test that timeout is canceled on exit
494
+ */
495
+ static int test_single_timeout_exit(struct io_uring *ring)
496
+ {
497
+ struct io_uring_sqe *sqe;
498
+ struct __kernel_timespec ts;
499
+ int ret;
500
+
501
+ sqe = io_uring_get_sqe(ring);
502
+ if (!sqe) {
503
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
504
+ goto err;
505
+ }
506
+
507
+ msec_to_ts(&ts, 30000);
508
+ io_uring_prep_timeout(sqe, &ts, 0, 0);
509
+
510
+ ret = io_uring_submit(ring);
511
+ if (ret <= 0) {
512
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
513
+ goto err;
514
+ }
515
+
516
+ io_uring_queue_exit(ring);
517
+ return 0;
518
+ err:
519
+ io_uring_queue_exit(ring);
520
+ return 1;
521
+ }
522
+
523
+ /*
524
+ * Test multi timeouts waking us up
525
+ */
526
+ static int test_multi_timeout(struct io_uring *ring)
527
+ {
528
+ struct io_uring_sqe *sqe;
529
+ struct io_uring_cqe *cqe;
530
+ struct __kernel_timespec ts[2];
531
+ unsigned int timeout[2];
532
+ unsigned long long exp;
533
+ struct timeval tv;
534
+ int ret, i;
535
+
536
+ /* req_1: timeout req, count = 1, time = (TIMEOUT_MSEC * 2) */
537
+ timeout[0] = TIMEOUT_MSEC * 2;
538
+ msec_to_ts(&ts[0], timeout[0]);
539
+ sqe = io_uring_get_sqe(ring);
540
+ if (!sqe) {
541
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
542
+ goto err;
543
+ }
544
+ io_uring_prep_timeout(sqe, &ts[0], 1, 0);
545
+ sqe->user_data = 1;
546
+
547
+ /* req_2: timeout req, count = 1, time = TIMEOUT_MSEC */
548
+ timeout[1] = TIMEOUT_MSEC;
549
+ msec_to_ts(&ts[1], timeout[1]);
550
+ sqe = io_uring_get_sqe(ring);
551
+ if (!sqe) {
552
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
553
+ goto err;
554
+ }
555
+ io_uring_prep_timeout(sqe, &ts[1], 1, 0);
556
+ sqe->user_data = 2;
557
+
558
+ ret = io_uring_submit(ring);
559
+ if (ret <= 0) {
560
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
561
+ goto err;
562
+ }
563
+
564
+ gettimeofday(&tv, NULL);
565
+ for (i = 0; i < 2; i++) {
566
+ unsigned int time = 0;
567
+ __u64 user_data = 0;
568
+
569
+ ret = io_uring_wait_cqe(ring, &cqe);
570
+ if (ret < 0) {
571
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
572
+ goto err;
573
+ }
574
+
575
+ /*
576
+ * Both of these two reqs should timeout, but req_2 should
577
+ * return before req_1.
578
+ */
579
+ switch (i) {
580
+ case 0:
581
+ user_data = 2;
582
+ time = timeout[1];
583
+ break;
584
+ case 1:
585
+ user_data = 1;
586
+ time = timeout[0];
587
+ break;
588
+ }
589
+
590
+ if (cqe->user_data != user_data) {
591
+ fprintf(stderr, "%s: unexpected timeout req %d sequece\n",
592
+ __FUNCTION__, i+1);
593
+ goto err;
594
+ }
595
+ if (cqe->res != -ETIME) {
596
+ fprintf(stderr, "%s: Req %d timeout: %s\n",
597
+ __FUNCTION__, i+1, strerror(cqe->res));
598
+ goto err;
599
+ }
600
+ exp = mtime_since_now(&tv);
601
+ if (exp < time / 2 || exp > (time * 3) / 2) {
602
+ fprintf(stderr, "%s: Req %d timeout seems wonky (got %llu)\n",
603
+ __FUNCTION__, i+1, exp);
604
+ goto err;
605
+ }
606
+ io_uring_cqe_seen(ring, cqe);
607
+ }
608
+
609
+ return 0;
610
+ err:
611
+ return 1;
612
+ }
613
+
614
+ /*
615
+ * Test multi timeout req with different count
616
+ */
617
+ static int test_multi_timeout_nr(struct io_uring *ring)
618
+ {
619
+ struct io_uring_sqe *sqe;
620
+ struct io_uring_cqe *cqe;
621
+ struct __kernel_timespec ts;
622
+ int ret, i;
623
+
624
+ msec_to_ts(&ts, TIMEOUT_MSEC);
625
+
626
+ /* req_1: timeout req, count = 2 */
627
+ sqe = io_uring_get_sqe(ring);
628
+ if (!sqe) {
629
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
630
+ goto err;
631
+ }
632
+ io_uring_prep_timeout(sqe, &ts, 2, 0);
633
+ sqe->user_data = 1;
634
+
635
+ /* req_2: timeout req, count = 1 */
636
+ sqe = io_uring_get_sqe(ring);
637
+ if (!sqe) {
638
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
639
+ goto err;
640
+ }
641
+ io_uring_prep_timeout(sqe, &ts, 1, 0);
642
+ sqe->user_data = 2;
643
+
644
+ /* req_3: nop req */
645
+ sqe = io_uring_get_sqe(ring);
646
+ if (!sqe) {
647
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
648
+ goto err;
649
+ }
650
+ io_uring_prep_nop(sqe);
651
+ io_uring_sqe_set_data(sqe, (void *) 1);
652
+
653
+ ret = io_uring_submit(ring);
654
+ if (ret <= 0) {
655
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
656
+ goto err;
657
+ }
658
+
659
+ /*
660
+ * req_2 (count=1) should return without error and req_1 (count=2)
661
+ * should timeout.
662
+ */
663
+ for (i = 0; i < 3; i++) {
664
+ ret = io_uring_wait_cqe(ring, &cqe);
665
+ if (ret < 0) {
666
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
667
+ goto err;
668
+ }
669
+
670
+ switch (i) {
671
+ case 0:
672
+ /* Should be nop req */
673
+ if (io_uring_cqe_get_data(cqe) != (void *) 1) {
674
+ fprintf(stderr, "%s: nop not seen as 1 or 2\n", __FUNCTION__);
675
+ goto err;
676
+ }
677
+ break;
678
+ case 1:
679
+ /* Should be timeout req_2 */
680
+ if (cqe->user_data != 2) {
681
+ fprintf(stderr, "%s: unexpected timeout req %d sequece\n",
682
+ __FUNCTION__, i+1);
683
+ goto err;
684
+ }
685
+ if (cqe->res < 0) {
686
+ fprintf(stderr, "%s: Req %d res %d\n",
687
+ __FUNCTION__, i+1, cqe->res);
688
+ goto err;
689
+ }
690
+ break;
691
+ case 2:
692
+ /* Should be timeout req_1 */
693
+ if (cqe->user_data != 1) {
694
+ fprintf(stderr, "%s: unexpected timeout req %d sequece\n",
695
+ __FUNCTION__, i+1);
696
+ goto err;
697
+ }
698
+ if (cqe->res != -ETIME) {
699
+ fprintf(stderr, "%s: Req %d timeout: %s\n",
700
+ __FUNCTION__, i+1, strerror(cqe->res));
701
+ goto err;
702
+ }
703
+ break;
704
+ }
705
+ io_uring_cqe_seen(ring, cqe);
706
+ }
707
+
708
+ return 0;
709
+ err:
710
+ return 1;
711
+ }
712
+
713
+ /*
714
+ * Test timeout <link> timeout <drain> timeout
715
+ */
716
+ static int test_timeout_flags1(struct io_uring *ring)
717
+ {
718
+ struct io_uring_sqe *sqe;
719
+ struct io_uring_cqe *cqe;
720
+ struct __kernel_timespec ts;
721
+ int ret, i;
722
+
723
+ msec_to_ts(&ts, TIMEOUT_MSEC);
724
+
725
+ sqe = io_uring_get_sqe(ring);
726
+ if (!sqe) {
727
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
728
+ goto err;
729
+ }
730
+ io_uring_prep_timeout(sqe, &ts, 0, 0);
731
+ sqe->user_data = 1;
732
+ sqe->flags |= IOSQE_IO_LINK;
733
+
734
+ sqe = io_uring_get_sqe(ring);
735
+ if (!sqe) {
736
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
737
+ goto err;
738
+ }
739
+ io_uring_prep_timeout(sqe, &ts, 0, 0);
740
+ sqe->user_data = 2;
741
+ sqe->flags |= IOSQE_IO_DRAIN;
742
+
743
+ sqe = io_uring_get_sqe(ring);
744
+ if (!sqe) {
745
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
746
+ goto err;
747
+ }
748
+ io_uring_prep_timeout(sqe, &ts, 0, 0);
749
+ sqe->user_data = 3;
750
+
751
+ ret = io_uring_submit(ring);
752
+ if (ret <= 0) {
753
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
754
+ goto err;
755
+ }
756
+
757
+ for (i = 0; i < 3; i++) {
758
+ ret = io_uring_wait_cqe(ring, &cqe);
759
+ if (ret < 0) {
760
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
761
+ goto err;
762
+ }
763
+
764
+ if (cqe->res == -EINVAL) {
765
+ if (!i)
766
+ fprintf(stdout, "%s: timeout flags not supported\n",
767
+ __FUNCTION__);
768
+ io_uring_cqe_seen(ring, cqe);
769
+ continue;
770
+ }
771
+
772
+ switch (cqe->user_data) {
773
+ case 1:
774
+ if (cqe->res != -ETIME) {
775
+ fprintf(stderr, "%s: got %d, wanted %d\n",
776
+ __FUNCTION__, cqe->res, -ETIME);
777
+ goto err;
778
+ }
779
+ break;
780
+ case 2:
781
+ if (cqe->res != -ECANCELED) {
782
+ fprintf(stderr, "%s: got %d, wanted %d\n",
783
+ __FUNCTION__, cqe->res,
784
+ -ECANCELED);
785
+ goto err;
786
+ }
787
+ break;
788
+ case 3:
789
+ if (cqe->res != -ETIME) {
790
+ fprintf(stderr, "%s: got %d, wanted %d\n",
791
+ __FUNCTION__, cqe->res, -ETIME);
792
+ goto err;
793
+ }
794
+ break;
795
+ }
796
+ io_uring_cqe_seen(ring, cqe);
797
+ }
798
+
799
+ return 0;
800
+ err:
801
+ return 1;
802
+ }
803
+
804
+ /*
805
+ * Test timeout <link> timeout <link> timeout
806
+ */
807
+ static int test_timeout_flags2(struct io_uring *ring)
808
+ {
809
+ struct io_uring_sqe *sqe;
810
+ struct io_uring_cqe *cqe;
811
+ struct __kernel_timespec ts;
812
+ int ret, i;
813
+
814
+ msec_to_ts(&ts, TIMEOUT_MSEC);
815
+
816
+ sqe = io_uring_get_sqe(ring);
817
+ if (!sqe) {
818
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
819
+ goto err;
820
+ }
821
+ io_uring_prep_timeout(sqe, &ts, 0, 0);
822
+ sqe->user_data = 1;
823
+ sqe->flags |= IOSQE_IO_LINK;
824
+
825
+ sqe = io_uring_get_sqe(ring);
826
+ if (!sqe) {
827
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
828
+ goto err;
829
+ }
830
+ io_uring_prep_timeout(sqe, &ts, 0, 0);
831
+ sqe->user_data = 2;
832
+ sqe->flags |= IOSQE_IO_LINK;
833
+
834
+ sqe = io_uring_get_sqe(ring);
835
+ if (!sqe) {
836
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
837
+ goto err;
838
+ }
839
+ io_uring_prep_timeout(sqe, &ts, 0, 0);
840
+ sqe->user_data = 3;
841
+
842
+ ret = io_uring_submit(ring);
843
+ if (ret <= 0) {
844
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
845
+ goto err;
846
+ }
847
+
848
+ for (i = 0; i < 3; i++) {
849
+ ret = io_uring_wait_cqe(ring, &cqe);
850
+ if (ret < 0) {
851
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
852
+ goto err;
853
+ }
854
+
855
+ if (cqe->res == -EINVAL) {
856
+ if (!i)
857
+ fprintf(stdout, "%s: timeout flags not supported\n",
858
+ __FUNCTION__);
859
+ io_uring_cqe_seen(ring, cqe);
860
+ continue;
861
+ }
862
+
863
+ switch (cqe->user_data) {
864
+ case 1:
865
+ if (cqe->res != -ETIME) {
866
+ fprintf(stderr, "%s: got %d, wanted %d\n",
867
+ __FUNCTION__, cqe->res, -ETIME);
868
+ goto err;
869
+ }
870
+ break;
871
+ case 2:
872
+ case 3:
873
+ if (cqe->res != -ECANCELED) {
874
+ fprintf(stderr, "%s: got %d, wanted %d\n",
875
+ __FUNCTION__, cqe->res,
876
+ -ECANCELED);
877
+ goto err;
878
+ }
879
+ break;
880
+ }
881
+ io_uring_cqe_seen(ring, cqe);
882
+ }
883
+
884
+ return 0;
885
+ err:
886
+ return 1;
887
+ }
888
+
889
+ /*
890
+ * Test timeout <drain> timeout <link> timeout
891
+ */
892
+ static int test_timeout_flags3(struct io_uring *ring)
893
+ {
894
+ struct io_uring_sqe *sqe;
895
+ struct io_uring_cqe *cqe;
896
+ struct __kernel_timespec ts;
897
+ int ret, i;
898
+
899
+ msec_to_ts(&ts, TIMEOUT_MSEC);
900
+
901
+ sqe = io_uring_get_sqe(ring);
902
+ if (!sqe) {
903
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
904
+ goto err;
905
+ }
906
+ io_uring_prep_timeout(sqe, &ts, 0, 0);
907
+ sqe->user_data = 1;
908
+ sqe->flags |= IOSQE_IO_DRAIN;
909
+
910
+ sqe = io_uring_get_sqe(ring);
911
+ if (!sqe) {
912
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
913
+ goto err;
914
+ }
915
+ io_uring_prep_timeout(sqe, &ts, 0, 0);
916
+ sqe->user_data = 2;
917
+ sqe->flags |= IOSQE_IO_LINK;
918
+
919
+ sqe = io_uring_get_sqe(ring);
920
+ if (!sqe) {
921
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
922
+ goto err;
923
+ }
924
+ io_uring_prep_timeout(sqe, &ts, 0, 0);
925
+ sqe->user_data = 3;
926
+
927
+ ret = io_uring_submit(ring);
928
+ if (ret <= 0) {
929
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
930
+ goto err;
931
+ }
932
+
933
+ for (i = 0; i < 3; i++) {
934
+ ret = io_uring_wait_cqe(ring, &cqe);
935
+ if (ret < 0) {
936
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
937
+ goto err;
938
+ }
939
+
940
+ if (cqe->res == -EINVAL) {
941
+ if (!i)
942
+ fprintf(stdout, "%s: timeout flags not supported\n",
943
+ __FUNCTION__);
944
+ io_uring_cqe_seen(ring, cqe);
945
+ continue;
946
+ }
947
+
948
+ switch (cqe->user_data) {
949
+ case 1:
950
+ case 2:
951
+ if (cqe->res != -ETIME) {
952
+ fprintf(stderr, "%s: got %d, wanted %d\n",
953
+ __FUNCTION__, cqe->res, -ETIME);
954
+ goto err;
955
+ }
956
+ break;
957
+ case 3:
958
+ if (cqe->res != -ECANCELED) {
959
+ fprintf(stderr, "%s: got %d, wanted %d\n",
960
+ __FUNCTION__, cqe->res,
961
+ -ECANCELED);
962
+ goto err;
963
+ }
964
+ break;
965
+ }
966
+ io_uring_cqe_seen(ring, cqe);
967
+ }
968
+
969
+ return 0;
970
+ err:
971
+ return 1;
972
+ }
973
+
974
+ static int test_update_timeout(struct io_uring *ring, unsigned long ms,
975
+ bool abs, bool async, bool linked)
976
+ {
977
+ struct io_uring_sqe *sqe;
978
+ struct io_uring_cqe *cqe;
979
+ struct __kernel_timespec ts, ts_upd;
980
+ unsigned long long exp_ms, base_ms = 10000;
981
+ struct timeval tv;
982
+ int ret, i, nr = 2;
983
+ __u32 mode = abs ? IORING_TIMEOUT_ABS : 0;
984
+
985
+ msec_to_ts(&ts_upd, ms);
986
+ gettimeofday(&tv, NULL);
987
+
988
+ sqe = io_uring_get_sqe(ring);
989
+ if (!sqe) {
990
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
991
+ goto err;
992
+ }
993
+ msec_to_ts(&ts, base_ms);
994
+ io_uring_prep_timeout(sqe, &ts, 0, 0);
995
+ sqe->user_data = 1;
996
+
997
+ if (linked) {
998
+ sqe = io_uring_get_sqe(ring);
999
+ if (!sqe) {
1000
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
1001
+ goto err;
1002
+ }
1003
+ io_uring_prep_nop(sqe);
1004
+ sqe->user_data = 3;
1005
+ sqe->flags = IOSQE_IO_LINK;
1006
+ if (async)
1007
+ sqe->flags |= IOSQE_ASYNC;
1008
+ nr++;
1009
+ }
1010
+
1011
+ sqe = io_uring_get_sqe(ring);
1012
+ if (!sqe) {
1013
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
1014
+ goto err;
1015
+ }
1016
+ io_uring_prep_timeout_update(sqe, &ts_upd, 1, mode);
1017
+ sqe->user_data = 2;
1018
+ if (async)
1019
+ sqe->flags |= IOSQE_ASYNC;
1020
+
1021
+ ret = io_uring_submit(ring);
1022
+ if (ret != nr) {
1023
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
1024
+ goto err;
1025
+ }
1026
+
1027
+ for (i = 0; i < nr; i++) {
1028
+ ret = io_uring_wait_cqe(ring, &cqe);
1029
+ if (ret < 0) {
1030
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
1031
+ goto err;
1032
+ }
1033
+
1034
+ switch (cqe->user_data) {
1035
+ case 1:
1036
+ if (cqe->res != -ETIME) {
1037
+ fprintf(stderr, "%s: got %d, wanted %d\n",
1038
+ __FUNCTION__, cqe->res, -ETIME);
1039
+ goto err;
1040
+ }
1041
+ break;
1042
+ case 2:
1043
+ if (cqe->res != 0) {
1044
+ fprintf(stderr, "%s: got %d, wanted %d\n",
1045
+ __FUNCTION__, cqe->res,
1046
+ 0);
1047
+ goto err;
1048
+ }
1049
+ break;
1050
+ case 3:
1051
+ if (cqe->res != 0) {
1052
+ fprintf(stderr, "nop failed\n");
1053
+ goto err;
1054
+ }
1055
+ break;
1056
+ default:
1057
+ goto err;
1058
+ }
1059
+ io_uring_cqe_seen(ring, cqe);
1060
+ }
1061
+
1062
+ exp_ms = mtime_since_now(&tv);
1063
+ if (exp_ms >= base_ms / 2) {
1064
+ fprintf(stderr, "too long, timeout wasn't updated\n");
1065
+ goto err;
1066
+ }
1067
+ if (ms >= 1000 && !abs && exp_ms < ms / 2) {
1068
+ fprintf(stderr, "fired too early, potentially updated to 0 ms"
1069
+ "instead of %lu\n", ms);
1070
+ goto err;
1071
+ }
1072
+ return 0;
1073
+ err:
1074
+ return 1;
1075
+ }
1076
+
1077
+ static int test_update_nonexistent_timeout(struct io_uring *ring)
1078
+ {
1079
+ struct io_uring_sqe *sqe;
1080
+ struct io_uring_cqe *cqe;
1081
+ struct __kernel_timespec ts;
1082
+ int ret;
1083
+
1084
+ sqe = io_uring_get_sqe(ring);
1085
+ if (!sqe) {
1086
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
1087
+ goto err;
1088
+ }
1089
+ msec_to_ts(&ts, 0);
1090
+ io_uring_prep_timeout_update(sqe, &ts, 42, 0);
1091
+
1092
+ ret = io_uring_submit(ring);
1093
+ if (ret != 1) {
1094
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
1095
+ goto err;
1096
+ }
1097
+
1098
+ ret = io_uring_wait_cqe(ring, &cqe);
1099
+ if (ret < 0) {
1100
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
1101
+ goto err;
1102
+ }
1103
+
1104
+ ret = cqe->res;
1105
+ if (ret == -ENOENT)
1106
+ ret = 0;
1107
+ io_uring_cqe_seen(ring, cqe);
1108
+ return ret;
1109
+ err:
1110
+ return 1;
1111
+ }
1112
+
1113
+ static int test_update_invalid_flags(struct io_uring *ring)
1114
+ {
1115
+ struct io_uring_sqe *sqe;
1116
+ struct io_uring_cqe *cqe;
1117
+ struct __kernel_timespec ts;
1118
+ int ret;
1119
+
1120
+ sqe = io_uring_get_sqe(ring);
1121
+ if (!sqe) {
1122
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
1123
+ goto err;
1124
+ }
1125
+ io_uring_prep_timeout_remove(sqe, 0, IORING_TIMEOUT_ABS);
1126
+
1127
+ ret = io_uring_submit(ring);
1128
+ if (ret != 1) {
1129
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
1130
+ goto err;
1131
+ }
1132
+
1133
+ ret = io_uring_wait_cqe(ring, &cqe);
1134
+ if (ret < 0) {
1135
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
1136
+ goto err;
1137
+ }
1138
+ if (cqe->res != -EINVAL) {
1139
+ fprintf(stderr, "%s: got %d, wanted %d\n",
1140
+ __FUNCTION__, cqe->res, -EINVAL);
1141
+ goto err;
1142
+ }
1143
+ io_uring_cqe_seen(ring, cqe);
1144
+
1145
+
1146
+ sqe = io_uring_get_sqe(ring);
1147
+ if (!sqe) {
1148
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
1149
+ goto err;
1150
+ }
1151
+ msec_to_ts(&ts, 0);
1152
+ io_uring_prep_timeout_update(sqe, &ts, 0, -1);
1153
+
1154
+ ret = io_uring_submit(ring);
1155
+ if (ret != 1) {
1156
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
1157
+ goto err;
1158
+ }
1159
+
1160
+ ret = io_uring_wait_cqe(ring, &cqe);
1161
+ if (ret < 0) {
1162
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
1163
+ goto err;
1164
+ }
1165
+ if (cqe->res != -EINVAL) {
1166
+ fprintf(stderr, "%s: got %d, wanted %d\n",
1167
+ __FUNCTION__, cqe->res, -EINVAL);
1168
+ goto err;
1169
+ }
1170
+ io_uring_cqe_seen(ring, cqe);
1171
+
1172
+ return 0;
1173
+ err:
1174
+ return 1;
1175
+ }
1176
+
1177
+ static int fill_exec_target(char *dst, char *path)
1178
+ {
1179
+ struct stat sb;
1180
+
1181
+ /*
1182
+ * Should either be ./exec-target or test/exec-target
1183
+ */
1184
+ sprintf(dst, "%s", path);
1185
+ return stat(dst, &sb);
1186
+ }
1187
+
1188
+ static int test_timeout_link_cancel(void)
1189
+ {
1190
+ struct io_uring ring;
1191
+ struct io_uring_cqe *cqe;
1192
+ char prog_path[PATH_MAX];
1193
+ pid_t p;
1194
+ int ret, i, wstatus;
1195
+
1196
+ if (fill_exec_target(prog_path, "./exec-target") &&
1197
+ fill_exec_target(prog_path, "test/exec-target")) {
1198
+ fprintf(stdout, "Can't find exec-target, skipping\n");
1199
+ return 0;
1200
+ }
1201
+
1202
+ ret = io_uring_queue_init(8, &ring, 0);
1203
+ if (ret) {
1204
+ fprintf(stderr, "ring create failed: %d\n", ret);
1205
+ return 1;
1206
+ }
1207
+
1208
+ p = fork();
1209
+ if (p == -1) {
1210
+ fprintf(stderr, "fork() failed\n");
1211
+ return 1;
1212
+ }
1213
+
1214
+ if (p == 0) {
1215
+ struct io_uring_sqe *sqe;
1216
+ struct __kernel_timespec ts;
1217
+
1218
+ msec_to_ts(&ts, 10000);
1219
+ sqe = io_uring_get_sqe(&ring);
1220
+ io_uring_prep_timeout(sqe, &ts, 0, 0);
1221
+ sqe->flags |= IOSQE_IO_LINK;
1222
+ sqe->user_data = 0;
1223
+
1224
+ sqe = io_uring_get_sqe(&ring);
1225
+ io_uring_prep_nop(sqe);
1226
+ sqe->user_data = 1;
1227
+
1228
+ ret = io_uring_submit(&ring);
1229
+ if (ret != 2) {
1230
+ fprintf(stderr, "%s: got %d, wanted 1\n", __FUNCTION__, ret);
1231
+ exit(1);
1232
+ }
1233
+
1234
+ /* trigger full cancellation */
1235
+ ret = execl(prog_path, prog_path, NULL);
1236
+ if (ret) {
1237
+ fprintf(stderr, "exec failed %i\n", errno);
1238
+ exit(1);
1239
+ }
1240
+ exit(0);
1241
+ }
1242
+
1243
+ if (waitpid(p, &wstatus, 0) == (pid_t)-1) {
1244
+ perror("waitpid()");
1245
+ return 1;
1246
+ }
1247
+ if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus)) {
1248
+ fprintf(stderr, "child failed %i\n", WEXITSTATUS(wstatus));
1249
+ return 1;
1250
+ }
1251
+
1252
+ for (i = 0; i < 2; ++i) {
1253
+ ret = io_uring_wait_cqe(&ring, &cqe);
1254
+ if (ret) {
1255
+ fprintf(stderr, "wait_cqe=%d\n", ret);
1256
+ return 1;
1257
+ }
1258
+ if (cqe->res != -ECANCELED) {
1259
+ fprintf(stderr, "invalid result, user_data: %i res: %i\n",
1260
+ (int)cqe->user_data, cqe->res);
1261
+ return 1;
1262
+ }
1263
+ io_uring_cqe_seen(&ring, cqe);
1264
+ }
1265
+
1266
+ io_uring_queue_exit(&ring);
1267
+ return 0;
1268
+ }
1269
+
1270
+
1271
+ static int test_not_failing_links(void)
1272
+ {
1273
+ struct io_uring ring;
1274
+ struct io_uring_sqe *sqe;
1275
+ struct io_uring_cqe *cqe;
1276
+ struct __kernel_timespec ts;
1277
+ int ret;
1278
+
1279
+ ret = io_uring_queue_init(8, &ring, 0);
1280
+ if (ret) {
1281
+ fprintf(stderr, "ring create failed: %d\n", ret);
1282
+ return 1;
1283
+ }
1284
+
1285
+ msec_to_ts(&ts, 1);
1286
+ sqe = io_uring_get_sqe(&ring);
1287
+ io_uring_prep_timeout(sqe, &ts, 0, IORING_TIMEOUT_ETIME_SUCCESS);
1288
+ sqe->user_data = 1;
1289
+ sqe->flags |= IOSQE_IO_LINK;
1290
+
1291
+ sqe = io_uring_get_sqe(&ring);
1292
+ io_uring_prep_nop(sqe);
1293
+ sqe->user_data = 2;
1294
+
1295
+ ret = io_uring_submit(&ring);
1296
+ if (ret != 2) {
1297
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
1298
+ return 1;
1299
+ }
1300
+
1301
+ ret = io_uring_wait_cqe(&ring, &cqe);
1302
+ if (ret < 0) {
1303
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
1304
+ return 1;
1305
+ } else if (cqe->user_data == 1 && cqe->res == -EINVAL) {
1306
+ fprintf(stderr, "ETIME_SUCCESS is not supported, skip\n");
1307
+ goto done;
1308
+ } else if (cqe->res != -ETIME || cqe->user_data != 1) {
1309
+ fprintf(stderr, "timeout failed %i %i\n", cqe->res,
1310
+ (int)cqe->user_data);
1311
+ return 1;
1312
+ }
1313
+ io_uring_cqe_seen(&ring, cqe);
1314
+
1315
+ ret = io_uring_wait_cqe(&ring, &cqe);
1316
+ if (ret < 0) {
1317
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
1318
+ return 1;
1319
+ } else if (cqe->res || cqe->user_data != 2) {
1320
+ fprintf(stderr, "nop failed %i %i\n", cqe->res,
1321
+ (int)cqe->user_data);
1322
+ return 1;
1323
+ }
1324
+ done:
1325
+ io_uring_cqe_seen(&ring, cqe);
1326
+ io_uring_queue_exit(&ring);
1327
+ return 0;
1328
+ }
1329
+
1330
+
1331
+ int main(int argc, char *argv[])
1332
+ {
1333
+ struct io_uring ring, sqpoll_ring;
1334
+ bool has_timeout_update, sqpoll;
1335
+ struct io_uring_params p = { };
1336
+ int ret;
1337
+
1338
+ if (argc > 1)
1339
+ return 0;
1340
+
1341
+ ret = io_uring_queue_init_params(8, &ring, &p);
1342
+ if (ret) {
1343
+ fprintf(stderr, "ring setup failed\n");
1344
+ return 1;
1345
+ }
1346
+
1347
+ ret = io_uring_queue_init(8, &sqpoll_ring, IORING_SETUP_SQPOLL);
1348
+ sqpoll = !ret;
1349
+
1350
+ ret = test_single_timeout(&ring);
1351
+ if (ret) {
1352
+ fprintf(stderr, "test_single_timeout failed\n");
1353
+ return ret;
1354
+ }
1355
+ if (not_supported)
1356
+ return 0;
1357
+
1358
+ ret = test_multi_timeout(&ring);
1359
+ if (ret) {
1360
+ fprintf(stderr, "test_multi_timeout failed\n");
1361
+ return ret;
1362
+ }
1363
+
1364
+ ret = test_single_timeout_abs(&ring);
1365
+ if (ret) {
1366
+ fprintf(stderr, "test_single_timeout_abs failed\n");
1367
+ return ret;
1368
+ }
1369
+
1370
+ ret = test_single_timeout_remove(&ring);
1371
+ if (ret) {
1372
+ fprintf(stderr, "test_single_timeout_remove failed\n");
1373
+ return ret;
1374
+ }
1375
+
1376
+ ret = test_single_timeout_remove_notfound(&ring);
1377
+ if (ret) {
1378
+ fprintf(stderr, "test_single_timeout_remove_notfound failed\n");
1379
+ return ret;
1380
+ }
1381
+
1382
+ ret = test_single_timeout_many(&ring);
1383
+ if (ret) {
1384
+ fprintf(stderr, "test_single_timeout_many failed\n");
1385
+ return ret;
1386
+ }
1387
+
1388
+ ret = test_single_timeout_nr(&ring, 1);
1389
+ if (ret) {
1390
+ fprintf(stderr, "test_single_timeout_nr(1) failed\n");
1391
+ return ret;
1392
+ }
1393
+ ret = test_single_timeout_nr(&ring, 2);
1394
+ if (ret) {
1395
+ fprintf(stderr, "test_single_timeout_nr(2) failed\n");
1396
+ return ret;
1397
+ }
1398
+
1399
+ ret = test_multi_timeout_nr(&ring);
1400
+ if (ret) {
1401
+ fprintf(stderr, "test_multi_timeout_nr failed\n");
1402
+ return ret;
1403
+ }
1404
+
1405
+ ret = test_timeout_flags1(&ring);
1406
+ if (ret) {
1407
+ fprintf(stderr, "test_timeout_flags1 failed\n");
1408
+ return ret;
1409
+ }
1410
+
1411
+ ret = test_timeout_flags2(&ring);
1412
+ if (ret) {
1413
+ fprintf(stderr, "test_timeout_flags2 failed\n");
1414
+ return ret;
1415
+ }
1416
+
1417
+ ret = test_timeout_flags3(&ring);
1418
+ if (ret) {
1419
+ fprintf(stderr, "test_timeout_flags3 failed\n");
1420
+ return ret;
1421
+ }
1422
+
1423
+ ret = test_single_timeout_wait(&ring, &p);
1424
+ if (ret) {
1425
+ fprintf(stderr, "test_single_timeout_wait failed\n");
1426
+ return ret;
1427
+ }
1428
+
1429
+ /* io_uring_wait_cqes() may have left a timeout, reinit ring */
1430
+ io_uring_queue_exit(&ring);
1431
+ ret = io_uring_queue_init(8, &ring, 0);
1432
+ if (ret) {
1433
+ fprintf(stderr, "ring setup failed\n");
1434
+ return 1;
1435
+ }
1436
+
1437
+ ret = test_update_nonexistent_timeout(&ring);
1438
+ has_timeout_update = (ret != -EINVAL);
1439
+ if (has_timeout_update) {
1440
+ if (ret) {
1441
+ fprintf(stderr, "test_update_nonexistent_timeout failed\n");
1442
+ return ret;
1443
+ }
1444
+
1445
+ ret = test_update_invalid_flags(&ring);
1446
+ if (ret) {
1447
+ fprintf(stderr, "test_update_invalid_flags failed\n");
1448
+ return ret;
1449
+ }
1450
+
1451
+ ret = test_update_timeout(&ring, 0, false, false, false);
1452
+ if (ret) {
1453
+ fprintf(stderr, "test_update_timeout failed\n");
1454
+ return ret;
1455
+ }
1456
+
1457
+ ret = test_update_timeout(&ring, 1, false, false, false);
1458
+ if (ret) {
1459
+ fprintf(stderr, "test_update_timeout 1ms failed\n");
1460
+ return ret;
1461
+ }
1462
+
1463
+ ret = test_update_timeout(&ring, 1000, false, false, false);
1464
+ if (ret) {
1465
+ fprintf(stderr, "test_update_timeout 1s failed\n");
1466
+ return ret;
1467
+ }
1468
+
1469
+ ret = test_update_timeout(&ring, 0, true, true, false);
1470
+ if (ret) {
1471
+ fprintf(stderr, "test_update_timeout abs failed\n");
1472
+ return ret;
1473
+ }
1474
+
1475
+
1476
+ ret = test_update_timeout(&ring, 0, false, true, false);
1477
+ if (ret) {
1478
+ fprintf(stderr, "test_update_timeout async failed\n");
1479
+ return ret;
1480
+ }
1481
+
1482
+ ret = test_update_timeout(&ring, 0, false, false, true);
1483
+ if (ret) {
1484
+ fprintf(stderr, "test_update_timeout linked failed\n");
1485
+ return ret;
1486
+ }
1487
+
1488
+ if (sqpoll) {
1489
+ ret = test_update_timeout(&sqpoll_ring, 0, false, false,
1490
+ false);
1491
+ if (ret) {
1492
+ fprintf(stderr, "test_update_timeout sqpoll"
1493
+ "failed\n");
1494
+ return ret;
1495
+ }
1496
+ }
1497
+ }
1498
+
1499
+ /*
1500
+ * this test must go last, it kills the ring
1501
+ */
1502
+ ret = test_single_timeout_exit(&ring);
1503
+ if (ret) {
1504
+ fprintf(stderr, "test_single_timeout_exit failed\n");
1505
+ return ret;
1506
+ }
1507
+
1508
+ ret = test_timeout_link_cancel();
1509
+ if (ret) {
1510
+ fprintf(stderr, "test_timeout_link_cancel failed\n");
1511
+ return ret;
1512
+ }
1513
+
1514
+ ret = test_not_failing_links();
1515
+ if (ret) {
1516
+ fprintf(stderr, "test_not_failing_links failed\n");
1517
+ return ret;
1518
+ }
1519
+
1520
+ if (sqpoll)
1521
+ io_uring_queue_exit(&sqpoll_ring);
1522
+ return 0;
1523
+ }