uringmachine 0.1

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