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,429 @@
1
+ /* SPDX-License-Identifier: MIT */
2
+ /*
3
+ * Description: generic tests for io_uring drain io
4
+ *
5
+ * The main idea is to randomly generate different type of sqe to
6
+ * challenge the drain logic. There are some restrictions for the
7
+ * generated sqes, details in io_uring maillist:
8
+ * https://lore.kernel.org/io-uring/39a49b4c-27c2-1035-b250-51daeccaab9b@linux.alibaba.com/
9
+ *
10
+ */
11
+ #include <errno.h>
12
+ #include <stdio.h>
13
+ #include <unistd.h>
14
+ #include <stdlib.h>
15
+ #include <string.h>
16
+ #include <time.h>
17
+ #include <poll.h>
18
+
19
+ #include "liburing.h"
20
+ #include "helpers.h"
21
+
22
+ enum {
23
+ multi,
24
+ single,
25
+ nop,
26
+ cancel,
27
+ op_last,
28
+ };
29
+
30
+ struct sqe_info {
31
+ __u8 op;
32
+ unsigned flags;
33
+ };
34
+
35
+ #define max_entry 50
36
+
37
+ /*
38
+ * sqe_flags: combination of sqe flags
39
+ * multi_sqes: record the user_data/index of all the multishot sqes
40
+ * cnt: how many entries there are in multi_sqes
41
+ * we can leverage multi_sqes array for cancelation: we randomly pick
42
+ * up an entry in multi_sqes when form a cancelation sqe.
43
+ * multi_cap: limitation of number of multishot sqes
44
+ */
45
+ static const unsigned sqe_flags[4] = {
46
+ 0,
47
+ IOSQE_IO_LINK,
48
+ IOSQE_IO_DRAIN,
49
+ IOSQE_IO_LINK | IOSQE_IO_DRAIN
50
+ };
51
+ static int multi_sqes[max_entry], cnt = 0;
52
+ static int multi_cap = max_entry / 5;
53
+
54
+ static int write_pipe(int pipe, char *str)
55
+ {
56
+ int ret;
57
+ do {
58
+ errno = 0;
59
+ ret = write(pipe, str, 3);
60
+ } while (ret == -1 && errno == EINTR);
61
+ return ret;
62
+ }
63
+
64
+ static void read_pipe(int pipe)
65
+ {
66
+ char str[4] = {0};
67
+ int ret;
68
+
69
+ ret = read(pipe, &str, 3);
70
+ if (ret < 0)
71
+ perror("read");
72
+ }
73
+
74
+ static int trigger_event(struct io_uring *ring, int p[])
75
+ {
76
+ int ret;
77
+ if ((ret = write_pipe(p[1], "foo")) != 3) {
78
+ fprintf(stderr, "bad write return %d\n", ret);
79
+ return 1;
80
+ }
81
+ usleep(1000);
82
+ io_uring_get_events(ring);
83
+ read_pipe(p[0]);
84
+ return 0;
85
+ }
86
+
87
+ static void io_uring_sqe_prep(int op, struct io_uring_sqe *sqe,
88
+ unsigned sqe_flags, int arg)
89
+ {
90
+ switch (op) {
91
+ case multi:
92
+ io_uring_prep_poll_add(sqe, arg, POLLIN);
93
+ sqe->len |= IORING_POLL_ADD_MULTI;
94
+ break;
95
+ case single:
96
+ io_uring_prep_poll_add(sqe, arg, POLLIN);
97
+ break;
98
+ case nop:
99
+ io_uring_prep_nop(sqe);
100
+ break;
101
+ case cancel:
102
+ io_uring_prep_poll_remove(sqe, arg);
103
+ break;
104
+ }
105
+ sqe->flags = sqe_flags;
106
+ }
107
+
108
+ static __u8 generate_flags(int sqe_op)
109
+ {
110
+ __u8 flags = 0;
111
+ /*
112
+ * drain sqe must be put after multishot sqes canceled
113
+ */
114
+ do {
115
+ flags = sqe_flags[rand() % 4];
116
+ } while ((flags & IOSQE_IO_DRAIN) && cnt);
117
+
118
+ /*
119
+ * cancel req cannot have drain or link flag
120
+ */
121
+ if (sqe_op == cancel) {
122
+ flags &= ~(IOSQE_IO_DRAIN | IOSQE_IO_LINK);
123
+ }
124
+ /*
125
+ * avoid below case:
126
+ * sqe0(multishot, link)->sqe1(nop, link)->sqe2(nop)->sqe3(cancel_sqe0)
127
+ * sqe3 may execute before sqe0 so that sqe0 isn't canceled
128
+ */
129
+ if (sqe_op == multi)
130
+ flags &= ~IOSQE_IO_LINK;
131
+
132
+ return flags;
133
+
134
+ }
135
+
136
+ /*
137
+ * function to generate opcode of a sqe
138
+ * several restrictions here:
139
+ * - cancel all the previous multishot sqes as soon as possible when
140
+ * we reach high watermark.
141
+ * - ensure there is some multishot sqe when generating a cancel sqe
142
+ * - ensure a cancel/multshot sqe is not in a linkchain
143
+ * - ensure number of multishot sqes doesn't exceed multi_cap
144
+ * - don't generate multishot sqes after high watermark
145
+ */
146
+ static int generate_opcode(int i, int pre_flags)
147
+ {
148
+ int sqe_op;
149
+ int high_watermark = max_entry - max_entry / 5;
150
+ bool retry0 = false, retry1 = false, retry2 = false;
151
+
152
+ if ((i >= high_watermark) && cnt) {
153
+ sqe_op = cancel;
154
+ } else {
155
+ do {
156
+ sqe_op = rand() % op_last;
157
+ retry0 = (sqe_op == cancel) && (!cnt || (pre_flags & IOSQE_IO_LINK));
158
+ retry1 = (sqe_op == multi) && ((multi_cap - 1 < 0) || i >= high_watermark);
159
+ retry2 = (sqe_op == multi) && (pre_flags & IOSQE_IO_LINK);
160
+ } while (retry0 || retry1 || retry2);
161
+ }
162
+
163
+ if (sqe_op == multi)
164
+ multi_cap--;
165
+ return sqe_op;
166
+ }
167
+
168
+ static inline void add_multishot_sqe(int index)
169
+ {
170
+ multi_sqes[cnt++] = index;
171
+ }
172
+
173
+ static int remove_multishot_sqe(void)
174
+ {
175
+ int ret;
176
+
177
+ int rem_index = rand() % cnt;
178
+ ret = multi_sqes[rem_index];
179
+ multi_sqes[rem_index] = multi_sqes[cnt - 1];
180
+ cnt--;
181
+
182
+ return ret;
183
+ }
184
+
185
+ static int test_generic_drain(struct io_uring *ring)
186
+ {
187
+ struct io_uring_cqe *cqe;
188
+ struct io_uring_sqe *sqe[max_entry];
189
+ struct sqe_info si[max_entry];
190
+ int cqe_data[max_entry << 1], cqe_res[max_entry << 1];
191
+ int i, j, ret, arg = 0;
192
+ int pipes[max_entry][2];
193
+ int pre_flags = 0;
194
+
195
+ for (i = 0; i < max_entry; i++) {
196
+ if (pipe(pipes[i]) != 0) {
197
+ perror("pipe");
198
+ return 1;
199
+ }
200
+ }
201
+
202
+ srand((unsigned)time(NULL));
203
+ for (i = 0; i < max_entry; i++) {
204
+ sqe[i] = io_uring_get_sqe(ring);
205
+ if (!sqe[i]) {
206
+ printf("get sqe failed\n");
207
+ goto err;
208
+ }
209
+
210
+ int sqe_op = generate_opcode(i, pre_flags);
211
+ __u8 flags = generate_flags(sqe_op);
212
+
213
+ if (sqe_op == cancel)
214
+ arg = remove_multishot_sqe();
215
+ if (sqe_op == multi || sqe_op == single)
216
+ arg = pipes[i][0];
217
+ io_uring_sqe_prep(sqe_op, sqe[i], flags, arg);
218
+ sqe[i]->user_data = i;
219
+ si[i].op = sqe_op;
220
+ si[i].flags = flags;
221
+ pre_flags = flags;
222
+ if (sqe_op == multi)
223
+ add_multishot_sqe(i);
224
+ }
225
+
226
+ ret = io_uring_submit(ring);
227
+ if (ret < 0) {
228
+ printf("sqe submit failed\n");
229
+ goto err;
230
+ } else if (ret < max_entry) {
231
+ printf("Submitted only %d\n", ret);
232
+ goto err;
233
+ }
234
+
235
+ sleep(1);
236
+ // TODO: randomize event triggering order
237
+ for (i = 0; i < max_entry; i++) {
238
+ if (si[i].op != multi && si[i].op != single)
239
+ continue;
240
+
241
+ if (trigger_event(ring, pipes[i]))
242
+ goto err;
243
+ }
244
+ sleep(1);
245
+ i = 0;
246
+ while (!io_uring_peek_cqe(ring, &cqe)) {
247
+ cqe_data[i] = cqe->user_data;
248
+ cqe_res[i++] = cqe->res;
249
+ io_uring_cqe_seen(ring, cqe);
250
+ }
251
+
252
+ /*
253
+ * compl_bits is a bit map to record completions.
254
+ * eg. sqe[0], sqe[1], sqe[2] fully completed
255
+ * then compl_bits is 000...00111b
256
+ *
257
+ */
258
+ unsigned long long compl_bits = 0;
259
+ for (j = 0; j < i; j++) {
260
+ int index = cqe_data[j];
261
+ if ((si[index].flags & IOSQE_IO_DRAIN) && index) {
262
+ if ((~compl_bits) & ((1ULL << index) - 1)) {
263
+ printf("drain failed\n");
264
+ goto err;
265
+ }
266
+ }
267
+ /*
268
+ * for multishot sqes, record them only when it is canceled
269
+ */
270
+ if ((si[index].op != multi) || (cqe_res[j] == -ECANCELED))
271
+ compl_bits |= (1ULL << index);
272
+ }
273
+
274
+ return 0;
275
+ err:
276
+ return 1;
277
+ }
278
+
279
+ static int test_simple_drain(struct io_uring *ring)
280
+ {
281
+ struct io_uring_cqe *cqe;
282
+ struct io_uring_sqe *sqe[2];
283
+ int i, ret;
284
+ int pipe1[2], pipe2[2];
285
+
286
+ if (pipe(pipe1) != 0 || pipe(pipe2) != 0) {
287
+ perror("pipe");
288
+ return 1;
289
+ }
290
+
291
+ for (i = 0; i < 2; i++) {
292
+ sqe[i] = io_uring_get_sqe(ring);
293
+ if (!sqe[i]) {
294
+ printf("get sqe failed\n");
295
+ goto err;
296
+ }
297
+ }
298
+
299
+ io_uring_prep_poll_multishot(sqe[0], pipe1[0], POLLIN);
300
+ sqe[0]->user_data = 0;
301
+
302
+ io_uring_prep_poll_add(sqe[1], pipe2[0], POLLIN);
303
+ sqe[1]->user_data = 1;
304
+
305
+ /* This test relies on multishot poll to trigger events continually.
306
+ * however with IORING_SETUP_DEFER_TASKRUN this will only happen when
307
+ * triggered with a get_events. Hence we sprinkle get_events whenever
308
+ * there might be work to process in order to get the same result
309
+ */
310
+ ret = io_uring_submit_and_get_events(ring);
311
+ if (ret < 0) {
312
+ printf("sqe submit failed\n");
313
+ goto err;
314
+ } else if (ret < 2) {
315
+ printf("Submitted only %d\n", ret);
316
+ goto err;
317
+ }
318
+
319
+ for (i = 0; i < 2; i++) {
320
+ if (trigger_event(ring, pipe1))
321
+ goto err;
322
+ }
323
+ if (trigger_event(ring, pipe2))
324
+ goto err;
325
+
326
+ for (i = 0; i < 2; i++) {
327
+ sqe[i] = io_uring_get_sqe(ring);
328
+ if (!sqe[i]) {
329
+ printf("get sqe failed\n");
330
+ goto err;
331
+ }
332
+ }
333
+
334
+ io_uring_prep_poll_remove(sqe[0], 0);
335
+ sqe[0]->user_data = 2;
336
+
337
+ io_uring_prep_nop(sqe[1]);
338
+ sqe[1]->flags |= IOSQE_IO_DRAIN;
339
+ sqe[1]->user_data = 3;
340
+
341
+ ret = io_uring_submit(ring);
342
+ if (ret < 0) {
343
+ printf("sqe submit failed\n");
344
+ goto err;
345
+ } else if (ret < 2) {
346
+ printf("Submitted only %d\n", ret);
347
+ goto err;
348
+ }
349
+
350
+ for (i = 0; i < 6; i++) {
351
+ ret = io_uring_wait_cqe(ring, &cqe);
352
+ if (ret < 0) {
353
+ printf("wait completion %d\n", ret);
354
+ goto err;
355
+ }
356
+ if ((i == 5) && (cqe->user_data != 3))
357
+ goto err;
358
+ io_uring_cqe_seen(ring, cqe);
359
+ }
360
+
361
+ close(pipe1[0]);
362
+ close(pipe1[1]);
363
+ close(pipe2[0]);
364
+ close(pipe2[1]);
365
+ return 0;
366
+ err:
367
+ return 1;
368
+ }
369
+
370
+ static int test(bool defer_taskrun)
371
+ {
372
+ struct io_uring ring;
373
+ int i, ret;
374
+ unsigned int flags = 0;
375
+
376
+ if (defer_taskrun)
377
+ flags = IORING_SETUP_SINGLE_ISSUER |
378
+ IORING_SETUP_DEFER_TASKRUN;
379
+
380
+ ret = io_uring_queue_init(1024, &ring, flags);
381
+ if (ret) {
382
+ printf("ring setup failed\n");
383
+ return T_EXIT_FAIL;
384
+ }
385
+
386
+ for (i = 0; i < 5; i++) {
387
+ ret = test_simple_drain(&ring);
388
+ if (ret) {
389
+ fprintf(stderr, "test_simple_drain failed\n");
390
+ return T_EXIT_FAIL;
391
+ }
392
+ }
393
+
394
+ for (i = 0; i < 5; i++) {
395
+ ret = test_generic_drain(&ring);
396
+ if (ret) {
397
+ fprintf(stderr, "test_generic_drain failed\n");
398
+ return T_EXIT_FAIL;
399
+ }
400
+ }
401
+
402
+ io_uring_queue_exit(&ring);
403
+
404
+ return T_EXIT_PASS;
405
+ }
406
+
407
+ int main(int argc, char *argv[])
408
+ {
409
+ int ret;
410
+
411
+ if (argc > 1)
412
+ return T_EXIT_SKIP;
413
+
414
+ ret = test(false);
415
+ if (ret != T_EXIT_PASS) {
416
+ fprintf(stderr, "%s: test(false) failed\n", argv[0]);
417
+ return ret;
418
+ }
419
+
420
+ if (t_probe_defer_taskrun()) {
421
+ ret = test(true);
422
+ if (ret != T_EXIT_PASS) {
423
+ fprintf(stderr, "%s: test(true) failed\n", argv[0]);
424
+ return ret;
425
+ }
426
+ }
427
+
428
+ return ret;
429
+ }
@@ -0,0 +1,215 @@
1
+ /* SPDX-License-Identifier: MIT */
2
+ /*
3
+ * Description: run NAPI receive test. Meant to be run from the associated
4
+ * script, napi-test.sh. That will invoke this test program
5
+ * as either a sender or receiver, with the queue flags passed
6
+ * in for testing.
7
+ *
8
+ */
9
+ #include <stdio.h>
10
+ #include <stdlib.h>
11
+ #include <stdint.h>
12
+ #include <assert.h>
13
+ #include <errno.h>
14
+ #include <fcntl.h>
15
+ #include <unistd.h>
16
+ #include <string.h>
17
+ #include <arpa/inet.h>
18
+ #include <linux/if_packet.h>
19
+ #include <linux/socket.h>
20
+ #include <sys/socket.h>
21
+ #include <sys/stat.h>
22
+
23
+ #include "liburing.h"
24
+ #include "helpers.h"
25
+
26
+ static const char receiver_address[] = "10.10.10.20";
27
+ static const int port = 9999;
28
+ #define BUF_SIZE 4096
29
+
30
+ static char buffer[BUF_SIZE];
31
+ static unsigned current_byte = 0;
32
+
33
+ static void do_setsockopt(int fd, int level, int optname, int val)
34
+ {
35
+ int ret = setsockopt(fd, level, optname, &val, sizeof(val));
36
+
37
+ assert(ret == 0);
38
+ }
39
+
40
+ static int sender(void)
41
+ {
42
+ unsigned long long written = 0;
43
+ struct sockaddr_in addr;
44
+ int i, ret, fd;
45
+
46
+ memset(&addr, 0, sizeof(addr));
47
+ addr.sin_family = AF_INET;
48
+ addr.sin_port = htons(port);
49
+ ret = inet_pton(AF_INET, receiver_address, &addr.sin_addr);
50
+ assert(ret == 1);
51
+
52
+ fd = socket(PF_INET, SOCK_STREAM, 0);
53
+ assert(fd >= 0);
54
+
55
+ /* don't race with receiver, give it 1 second to connect */
56
+ i = 0;
57
+ do {
58
+ ret = connect(fd, (void *)&addr, sizeof(addr));
59
+ if (!ret)
60
+ break;
61
+ if (ret == -1 && errno == ECONNREFUSED) {
62
+ if (i >= 10000) {
63
+ fprintf(stderr, "Gave up trying to connect\n");
64
+ return 1;
65
+ }
66
+ usleep(100);
67
+ continue;
68
+ }
69
+ i++;
70
+ } while (1);
71
+
72
+ while (written < 8 * 1024 * 1024) {
73
+ for (i = 0; i < BUF_SIZE; i++)
74
+ buffer[i] = current_byte + i;
75
+
76
+ ret = write(fd, buffer, BUF_SIZE);
77
+ if (ret <= 0) {
78
+ if (!ret || errno == ECONNRESET)
79
+ break;
80
+ fprintf(stderr, "write failed %i %i\n", ret, errno);
81
+ return 1;
82
+ }
83
+ written += ret;
84
+ current_byte += ret;
85
+ }
86
+
87
+ close(fd);
88
+ return 0;
89
+ }
90
+
91
+ static int receiver(int queue_flags)
92
+ {
93
+ struct io_uring_sqe *sqe;
94
+ struct io_uring_cqe *cqe;
95
+ struct io_uring ring;
96
+ struct io_uring_napi napi = { };
97
+ struct sockaddr_in addr;
98
+ int fd, listen_fd;
99
+ int i, ret;
100
+
101
+ ret = io_uring_queue_init(8, &ring, queue_flags);
102
+ if (ret < 0) {
103
+ fprintf(stderr, "queue_init: %s\n", strerror(-ret));
104
+ return 1;
105
+ }
106
+
107
+ napi.prefer_busy_poll = 1;
108
+ napi.busy_poll_to = 50;
109
+ io_uring_register_napi(&ring, &napi);
110
+
111
+ memset(&addr, 0, sizeof(addr));
112
+ addr.sin_family = AF_INET;
113
+ addr.sin_port = htons(port);
114
+ addr.sin_addr.s_addr = INADDR_ANY;
115
+
116
+ listen_fd = socket(AF_INET, SOCK_STREAM, 0);
117
+ assert(listen_fd >= 0);
118
+
119
+ do_setsockopt(listen_fd, SOL_SOCKET, SO_REUSEPORT, 1);
120
+ ret = bind(listen_fd, (void *)&addr, sizeof(addr));
121
+ if (ret) {
122
+ fprintf(stderr, "bind failed %i %i\n", ret, errno);
123
+ return 1;
124
+ }
125
+
126
+ ret = listen(listen_fd, 8);
127
+ assert(ret == 0);
128
+
129
+ fd = accept(listen_fd, NULL, NULL);
130
+ assert(fd >= 0);
131
+
132
+ while (1) {
133
+ sqe = io_uring_get_sqe(&ring);
134
+ io_uring_prep_recv(sqe, fd, buffer, BUF_SIZE, 0);
135
+
136
+ ret = io_uring_submit(&ring);
137
+ if (ret != 1) {
138
+ fprintf(stderr, "io_uring_submit: %i\n", ret);
139
+ return 1;
140
+ }
141
+
142
+ ret = io_uring_wait_cqe(&ring, &cqe);
143
+ if (ret < 0) {
144
+ fprintf(stderr, "io_uring_wait_cqe: %i\n", ret);
145
+ return 1;
146
+ }
147
+
148
+ ret = cqe->res;
149
+ if (ret <= 0) {
150
+ if (!ret)
151
+ break;
152
+ fprintf(stderr, "recv failed %i %i\n", ret, errno);
153
+ return 1;
154
+ }
155
+
156
+ for (i = 0; i < ret; i++) {
157
+ char expected = current_byte + i;
158
+
159
+ if (buffer[i] != expected) {
160
+ fprintf(stderr, "data mismatch: idx %i, %c vs %c\n",
161
+ i, buffer[i], expected);
162
+ return 1;
163
+ }
164
+ }
165
+
166
+ current_byte += ret;
167
+ io_uring_cqe_seen(&ring, cqe);
168
+ }
169
+
170
+ close(fd);
171
+ io_uring_queue_exit(&ring);
172
+ return 0;
173
+ }
174
+
175
+ int main(int argc, char **argv)
176
+ {
177
+ int queue_flags;
178
+ int is_rx;
179
+
180
+ if (geteuid()) {
181
+ fprintf(stdout, "NAPI test requires root\n");
182
+ return T_EXIT_SKIP;
183
+ }
184
+
185
+ if (argc == 1) {
186
+ struct stat sb;
187
+
188
+ if (!stat("napi-test.sh", &sb)) {
189
+ return system("bash napi-test.sh");
190
+ } else if (!stat("test/napi-test.sh", &sb)) {
191
+ return system("bash test/napi-test.sh");
192
+ } else {
193
+ fprintf(stderr, "Can't find napi-test.sh\n");
194
+ return T_EXIT_SKIP;
195
+ }
196
+ } else if (argc == 2) {
197
+ return T_EXIT_SKIP;
198
+ } else if (argc != 3) {
199
+ return T_EXIT_SKIP;
200
+ }
201
+
202
+ if (!strcmp(argv[1], "receive"))
203
+ is_rx = 1;
204
+ else if (!strcmp(argv[1], "send"))
205
+ is_rx = 0;
206
+ else
207
+ return T_EXIT_FAIL;
208
+
209
+ queue_flags = strtoul(argv[2], NULL, 16);
210
+
211
+ if (is_rx)
212
+ return receiver(queue_flags);
213
+
214
+ return sender();
215
+ }
@@ -0,0 +1,48 @@
1
+ #! /usr/bin/env bash
2
+
3
+ if [ ! -x "$(command -v ip)" ]; then
4
+ echo "Need ip installed"
5
+ exit 77
6
+ fi
7
+ if [ ! -x "$(command -v ethtool)" ]; then
8
+ echo "Need ethool installed"
9
+ exit 77
10
+ fi
11
+
12
+ function clean_namespaces {
13
+ ip netns del iou-nscl
14
+ ip netns del iou-nsserv
15
+ }
16
+ trap clean_namespaces EXIT
17
+
18
+ ip link add iou-ptp-cl type veth peer name iou-ptp-serv
19
+
20
+ ip netns add iou-nscl
21
+ ip link set iou-ptp-cl netns iou-nscl
22
+ ip netns exec iou-nscl ip addr add '10.10.10.10/24' dev iou-ptp-cl
23
+ ip netns exec iou-nscl ethtool -K iou-ptp-cl tcp-segmentation-offload off
24
+ ip netns exec iou-nscl ethtool -K iou-ptp-cl generic-receive-offload on
25
+ ip netns exec iou-nscl ip link set dev iou-ptp-cl up
26
+
27
+ ip netns add iou-nsserv
28
+ ip link set iou-ptp-serv netns iou-nsserv
29
+ ip netns exec iou-nsserv ip addr add '10.10.10.20/24' dev iou-ptp-serv
30
+ ip netns exec iou-nsserv ethtool -K iou-ptp-serv tcp-segmentation-offload off
31
+ ip netns exec iou-nsserv ethtool -K iou-ptp-serv generic-receive-offload on
32
+ ip netns exec iou-nsserv ip link set dev iou-ptp-serv up
33
+
34
+ # test basic init, defer_taskrun, and sqpoll
35
+ QUEUE_FLAGS="0x0 0x3000 0x2"
36
+ for flags in $QUEUE_FLAGS; do
37
+ if [ -f "napi-test.t" ]; then
38
+ NAPI_TEST="./napi-test.t"
39
+ elif [ -f "test/napi-test.t" ]; then
40
+ NAPI_TEST="test/napi-test.t"
41
+ else
42
+ echo "Can't find napi-test.t"
43
+ exit 77
44
+ fi
45
+ ip netns exec iou-nsserv $NAPI_TEST receive $flags &
46
+ ip netns exec iou-nscl $NAPI_TEST send $flags
47
+ wait
48
+ done
@@ -0,0 +1,42 @@
1
+ /* SPDX-License-Identifier: MIT */
2
+ /*
3
+ * Description: test that using SETUP_NO_MMAP with an invalid SQ ring
4
+ * address fails.
5
+ *
6
+ */
7
+ #include <stdlib.h>
8
+ #include <sys/types.h>
9
+ #include <stdio.h>
10
+ #include <unistd.h>
11
+
12
+ #include "liburing.h"
13
+ #include "helpers.h"
14
+
15
+ int main(int argc, char *argv[])
16
+ {
17
+ struct io_uring_params p = {
18
+ .sq_entries = 2,
19
+ .cq_entries = 4,
20
+ .flags = IORING_SETUP_NO_MMAP,
21
+ };
22
+ struct io_uring ring;
23
+ void *addr;
24
+ int ret;
25
+
26
+ if (argc > 1)
27
+ return T_EXIT_SKIP;
28
+
29
+ t_posix_memalign(&addr, sysconf(_SC_PAGESIZE), 8192);
30
+ p.cq_off.user_addr = (unsigned long long) (uintptr_t) addr;
31
+
32
+ ret = io_uring_queue_init_params(2, &ring, &p);
33
+ if (ret == -EINVAL) {
34
+ /* kernel doesn't support SETUP_NO_MMAP */
35
+ return T_EXIT_SKIP;
36
+ } else if (ret && (ret != -EFAULT && ret != -ENOMEM)) {
37
+ fprintf(stderr, "Got %d, wanted -EFAULT\n", ret);
38
+ return T_EXIT_FAIL;
39
+ }
40
+
41
+ return T_EXIT_PASS;
42
+ }