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,971 @@
1
+ /* SPDX-License-Identifier: MIT */
2
+ #include <stdio.h>
3
+ #include <stdlib.h>
4
+ #include <stdint.h>
5
+ #include <assert.h>
6
+ #include <errno.h>
7
+ #include <limits.h>
8
+ #include <fcntl.h>
9
+ #include <unistd.h>
10
+ #include <stdbool.h>
11
+ #include <string.h>
12
+
13
+ #include <arpa/inet.h>
14
+ #include <linux/if_packet.h>
15
+ #include <linux/ipv6.h>
16
+ #include <linux/socket.h>
17
+ #include <linux/sockios.h>
18
+ #include <net/ethernet.h>
19
+ #include <net/if.h>
20
+ #include <netinet/ip.h>
21
+ #include <netinet/in.h>
22
+ #include <netinet/ip6.h>
23
+ #include <netinet/tcp.h>
24
+ #include <netinet/udp.h>
25
+ #include <sys/socket.h>
26
+ #include <sys/time.h>
27
+ #include <sys/resource.h>
28
+ #include <sys/un.h>
29
+ #include <sys/ioctl.h>
30
+ #include <sys/socket.h>
31
+ #include <sys/stat.h>
32
+ #include <sys/time.h>
33
+ #include <sys/types.h>
34
+ #include <sys/wait.h>
35
+ #include <sys/mman.h>
36
+ #include <linux/mman.h>
37
+
38
+ #include "liburing.h"
39
+ #include "helpers.h"
40
+
41
+ #define MAX_MSG 128
42
+
43
+ #define HOST "127.0.0.1"
44
+ #define HOSTV6 "::1"
45
+
46
+ #define MAX_IOV 32
47
+ #define CORK_REQS 5
48
+ #define RX_TAG 10000
49
+ #define BUFFER_OFFSET 41
50
+
51
+ #ifndef ARRAY_SIZE
52
+ #define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
53
+ #endif
54
+
55
+ enum {
56
+ BUF_T_NORMAL,
57
+ BUF_T_SMALL,
58
+ BUF_T_NONALIGNED,
59
+ BUF_T_LARGE,
60
+ BUF_T_HUGETLB,
61
+
62
+ __BUF_NR,
63
+ };
64
+
65
+ /* 32MB, should be enough to trigger a short send */
66
+ #define LARGE_BUF_SIZE (1U << 25)
67
+
68
+ static size_t page_sz;
69
+ static char *tx_buffer, *rx_buffer;
70
+ static struct iovec buffers_iov[__BUF_NR];
71
+
72
+ static bool has_sendzc;
73
+ static bool has_sendmsg;
74
+ static bool hit_enomem;
75
+
76
+ static int probe_zc_support(void)
77
+ {
78
+ struct io_uring ring;
79
+ struct io_uring_probe *p;
80
+ int ret;
81
+
82
+ has_sendzc = has_sendmsg = false;
83
+
84
+ ret = io_uring_queue_init(1, &ring, 0);
85
+ if (ret)
86
+ return -1;
87
+
88
+ p = t_calloc(1, sizeof(*p) + 256 * sizeof(struct io_uring_probe_op));
89
+ if (!p)
90
+ return -1;
91
+
92
+ ret = io_uring_register_probe(&ring, p, 256);
93
+ if (ret)
94
+ return -1;
95
+
96
+ has_sendzc = p->ops_len > IORING_OP_SEND_ZC;
97
+ has_sendmsg = p->ops_len > IORING_OP_SENDMSG_ZC;
98
+ io_uring_queue_exit(&ring);
99
+ free(p);
100
+ return 0;
101
+ }
102
+
103
+ static bool check_cq_empty(struct io_uring *ring)
104
+ {
105
+ struct io_uring_cqe *cqe = NULL;
106
+ int ret;
107
+
108
+ ret = io_uring_peek_cqe(ring, &cqe); /* nothing should be there */
109
+ return ret == -EAGAIN;
110
+ }
111
+
112
+ static int test_basic_send(struct io_uring *ring, int sock_tx, int sock_rx)
113
+ {
114
+ struct io_uring_sqe *sqe;
115
+ struct io_uring_cqe *cqe;
116
+ int msg_flags = 0;
117
+ unsigned zc_flags = 0;
118
+ int payload_size = 100;
119
+ int ret;
120
+
121
+ sqe = io_uring_get_sqe(ring);
122
+ io_uring_prep_send_zc(sqe, sock_tx, tx_buffer, payload_size,
123
+ msg_flags, zc_flags);
124
+ sqe->user_data = 1;
125
+
126
+ ret = io_uring_submit(ring);
127
+ assert(ret == 1);
128
+
129
+ ret = io_uring_wait_cqe(ring, &cqe);
130
+ assert(!ret && cqe->user_data == 1);
131
+ if (cqe->res != payload_size) {
132
+ fprintf(stderr, "send failed %i\n", cqe->res);
133
+ return T_EXIT_FAIL;
134
+ }
135
+
136
+ assert(cqe->flags & IORING_CQE_F_MORE);
137
+ io_uring_cqe_seen(ring, cqe);
138
+
139
+ ret = io_uring_wait_cqe(ring, &cqe);
140
+ assert(!ret);
141
+ assert(cqe->user_data == 1);
142
+ assert(cqe->flags & IORING_CQE_F_NOTIF);
143
+ assert(!(cqe->flags & IORING_CQE_F_MORE));
144
+ io_uring_cqe_seen(ring, cqe);
145
+ assert(check_cq_empty(ring));
146
+
147
+ ret = recv(sock_rx, rx_buffer, payload_size, MSG_TRUNC);
148
+ assert(ret == payload_size);
149
+ return T_EXIT_PASS;
150
+ }
151
+
152
+ static int test_send_faults_check(struct io_uring *ring, int expected)
153
+ {
154
+ struct io_uring_cqe *cqe;
155
+ int ret, nr_cqes = 0;
156
+ bool more = true;
157
+
158
+ while (more) {
159
+ nr_cqes++;
160
+ ret = io_uring_wait_cqe(ring, &cqe);
161
+ assert(!ret);
162
+ assert(cqe->user_data == 1);
163
+
164
+ if (nr_cqes == 1 && (cqe->flags & IORING_CQE_F_NOTIF)) {
165
+ fprintf(stderr, "test_send_faults_check notif came first\n");
166
+ return -1;
167
+ }
168
+
169
+ if (!(cqe->flags & IORING_CQE_F_NOTIF)) {
170
+ if (cqe->res != expected) {
171
+ fprintf(stderr, "invalid cqe res %i vs expected %i, "
172
+ "user_data %i\n",
173
+ cqe->res, expected, (int)cqe->user_data);
174
+ return -1;
175
+ }
176
+ } else {
177
+ if (cqe->res != 0 || cqe->flags != IORING_CQE_F_NOTIF) {
178
+ fprintf(stderr, "invalid notif cqe %i %i\n",
179
+ cqe->res, cqe->flags);
180
+ return -1;
181
+ }
182
+ }
183
+
184
+ more = cqe->flags & IORING_CQE_F_MORE;
185
+ io_uring_cqe_seen(ring, cqe);
186
+ }
187
+
188
+ if (nr_cqes > 2) {
189
+ fprintf(stderr, "test_send_faults_check() too many CQEs %i\n",
190
+ nr_cqes);
191
+ return -1;
192
+ }
193
+ assert(check_cq_empty(ring));
194
+ return 0;
195
+ }
196
+
197
+ static int test_send_faults(int sock_tx, int sock_rx)
198
+ {
199
+ struct io_uring_sqe *sqe;
200
+ int msg_flags = 0;
201
+ unsigned zc_flags = 0;
202
+ int ret, payload_size = 100;
203
+ struct io_uring ring;
204
+
205
+ ret = io_uring_queue_init(32, &ring, 0);
206
+ if (ret) {
207
+ fprintf(stderr, "queue init failed: %d\n", ret);
208
+ return -1;
209
+ }
210
+
211
+ /* invalid buffer */
212
+ sqe = io_uring_get_sqe(&ring);
213
+ io_uring_prep_send_zc(sqe, sock_tx, (void *)1UL, payload_size,
214
+ msg_flags, zc_flags);
215
+ sqe->user_data = 1;
216
+ ret = io_uring_submit(&ring);
217
+ assert(ret == 1);
218
+
219
+ ret = test_send_faults_check(&ring, -EFAULT);
220
+ if (ret) {
221
+ fprintf(stderr, "test_send_faults with invalid buf failed\n");
222
+ return -1;
223
+ }
224
+
225
+ /* invalid address */
226
+ sqe = io_uring_get_sqe(&ring);
227
+ io_uring_prep_send_zc(sqe, sock_tx, tx_buffer, payload_size,
228
+ msg_flags, zc_flags);
229
+ io_uring_prep_send_set_addr(sqe, (const struct sockaddr *)1UL,
230
+ sizeof(struct sockaddr_in6));
231
+ sqe->user_data = 1;
232
+ ret = io_uring_submit(&ring);
233
+ assert(ret == 1);
234
+
235
+ ret = test_send_faults_check(&ring, -EFAULT);
236
+ if (ret) {
237
+ fprintf(stderr, "test_send_faults with invalid addr failed\n");
238
+ return -1;
239
+ }
240
+
241
+ /* invalid send/recv flags */
242
+ sqe = io_uring_get_sqe(&ring);
243
+ io_uring_prep_send_zc(sqe, sock_tx, tx_buffer, payload_size,
244
+ msg_flags, ~0U);
245
+ sqe->user_data = 1;
246
+ ret = io_uring_submit(&ring);
247
+ assert(ret == 1);
248
+
249
+ ret = test_send_faults_check(&ring, -EINVAL);
250
+ if (ret) {
251
+ fprintf(stderr, "test_send_faults with invalid flags failed\n");
252
+ return -1;
253
+ }
254
+
255
+ return T_EXIT_PASS;
256
+ }
257
+
258
+ static int create_socketpair_ip(struct sockaddr_storage *addr,
259
+ int *sock_client, int *sock_server,
260
+ bool ipv6, bool client_connect,
261
+ bool msg_zc, bool tcp)
262
+ {
263
+ socklen_t addr_size;
264
+ int family, sock, listen_sock = -1;
265
+ int ret;
266
+
267
+ memset(addr, 0, sizeof(*addr));
268
+ if (ipv6) {
269
+ struct sockaddr_in6 *saddr = (struct sockaddr_in6 *)addr;
270
+
271
+ family = AF_INET6;
272
+ saddr->sin6_family = family;
273
+ saddr->sin6_port = htons(0);
274
+ addr_size = sizeof(*saddr);
275
+ } else {
276
+ struct sockaddr_in *saddr = (struct sockaddr_in *)addr;
277
+
278
+ family = AF_INET;
279
+ saddr->sin_family = family;
280
+ saddr->sin_port = htons(0);
281
+ saddr->sin_addr.s_addr = htonl(INADDR_ANY);
282
+ addr_size = sizeof(*saddr);
283
+ }
284
+
285
+ /* server sock setup */
286
+ if (tcp) {
287
+ sock = listen_sock = socket(family, SOCK_STREAM, IPPROTO_TCP);
288
+ } else {
289
+ sock = *sock_server = socket(family, SOCK_DGRAM, 0);
290
+ }
291
+ if (sock < 0) {
292
+ perror("socket");
293
+ return 1;
294
+ }
295
+
296
+ ret = bind(sock, (struct sockaddr *)addr, addr_size);
297
+ if (ret < 0) {
298
+ perror("bind");
299
+ return 1;
300
+ }
301
+
302
+ ret = getsockname(sock, (struct sockaddr *)addr, &addr_size);
303
+ if (ret < 0) {
304
+ fprintf(stderr, "getsockname failed %i\n", errno);
305
+ return 1;
306
+ }
307
+
308
+ if (tcp) {
309
+ ret = listen(sock, 128);
310
+ assert(ret != -1);
311
+ }
312
+
313
+ if (ipv6) {
314
+ struct sockaddr_in6 *saddr = (struct sockaddr_in6 *)addr;
315
+
316
+ inet_pton(AF_INET6, HOSTV6, &(saddr->sin6_addr));
317
+ } else {
318
+ struct sockaddr_in *saddr = (struct sockaddr_in *)addr;
319
+
320
+ inet_pton(AF_INET, HOST, &saddr->sin_addr);
321
+ }
322
+
323
+ /* client sock setup */
324
+ if (tcp) {
325
+ *sock_client = socket(family, SOCK_STREAM, IPPROTO_TCP);
326
+ assert(client_connect);
327
+ } else {
328
+ *sock_client = socket(family, SOCK_DGRAM, 0);
329
+ }
330
+ if (*sock_client < 0) {
331
+ perror("socket");
332
+ return 1;
333
+ }
334
+ if (client_connect) {
335
+ ret = connect(*sock_client, (struct sockaddr *)addr, addr_size);
336
+ if (ret < 0) {
337
+ perror("connect");
338
+ return 1;
339
+ }
340
+ }
341
+ if (msg_zc) {
342
+ #ifdef SO_ZEROCOPY
343
+ int val = 1;
344
+
345
+ /*
346
+ * NOTE: apps must not set SO_ZEROCOPY when using io_uring zc.
347
+ * It's only here to test interactions with MSG_ZEROCOPY.
348
+ */
349
+ if (setsockopt(*sock_client, SOL_SOCKET, SO_ZEROCOPY, &val, sizeof(val))) {
350
+ perror("setsockopt zc");
351
+ return 1;
352
+ }
353
+ #else
354
+ fprintf(stderr, "no SO_ZEROCOPY\n");
355
+ return 1;
356
+ #endif
357
+ }
358
+ if (tcp) {
359
+ *sock_server = accept(listen_sock, NULL, NULL);
360
+ if (!*sock_server) {
361
+ fprintf(stderr, "can't accept\n");
362
+ return 1;
363
+ }
364
+ close(listen_sock);
365
+ }
366
+ return 0;
367
+ }
368
+
369
+ struct send_conf {
370
+ bool fixed_buf;
371
+ bool mix_register;
372
+ bool cork;
373
+ bool force_async;
374
+ bool use_sendmsg;
375
+ bool tcp;
376
+ bool zc;
377
+ bool iovec;
378
+ bool long_iovec;
379
+ bool poll_first;
380
+ int buf_index;
381
+ struct sockaddr_storage *addr;
382
+ };
383
+
384
+ static int do_test_inet_send(struct io_uring *ring, int sock_client, int sock_server,
385
+ struct send_conf *conf)
386
+ {
387
+ struct iovec iov[MAX_IOV];
388
+ struct msghdr msghdr[CORK_REQS];
389
+ const unsigned zc_flags = 0;
390
+ struct io_uring_sqe *sqe;
391
+ struct io_uring_cqe *cqe;
392
+ int nr_reqs = conf->cork ? CORK_REQS : 1;
393
+ int i, ret, nr_cqes, addr_len = 0;
394
+ size_t send_size = buffers_iov[conf->buf_index].iov_len;
395
+ size_t chunk_size = send_size / nr_reqs;
396
+ size_t chunk_size_last = send_size - chunk_size * (nr_reqs - 1);
397
+ char *buf = buffers_iov[conf->buf_index].iov_base;
398
+
399
+ assert(MAX_IOV >= CORK_REQS);
400
+
401
+ if (conf->addr) {
402
+ sa_family_t fam = ((struct sockaddr_in *)conf->addr)->sin_family;
403
+
404
+ addr_len = (fam == AF_INET) ? sizeof(struct sockaddr_in) :
405
+ sizeof(struct sockaddr_in6);
406
+ }
407
+
408
+ memset(rx_buffer, 0, send_size);
409
+
410
+ for (i = 0; i < nr_reqs; i++) {
411
+ bool real_fixed_buf = conf->fixed_buf;
412
+ size_t cur_size = chunk_size;
413
+ int msg_flags = MSG_WAITALL;
414
+
415
+ if (conf->mix_register)
416
+ real_fixed_buf = rand() & 1;
417
+
418
+ if (i != nr_reqs - 1)
419
+ msg_flags |= MSG_MORE;
420
+ else
421
+ cur_size = chunk_size_last;
422
+
423
+ sqe = io_uring_get_sqe(ring);
424
+
425
+ if (!conf->use_sendmsg) {
426
+ if (conf->zc) {
427
+ io_uring_prep_send_zc(sqe, sock_client, buf + i * chunk_size,
428
+ cur_size, msg_flags, zc_flags);
429
+ } else {
430
+ io_uring_prep_send(sqe, sock_client, buf + i * chunk_size,
431
+ cur_size, msg_flags);
432
+ }
433
+
434
+ if (real_fixed_buf) {
435
+ sqe->ioprio |= IORING_RECVSEND_FIXED_BUF;
436
+ sqe->buf_index = conf->buf_index;
437
+ }
438
+ if (conf->addr)
439
+ io_uring_prep_send_set_addr(sqe, (const struct sockaddr *)conf->addr,
440
+ addr_len);
441
+ } else {
442
+ struct iovec *io;
443
+ int iov_len;
444
+
445
+ if (conf->zc)
446
+ io_uring_prep_sendmsg_zc(sqe, sock_client, &msghdr[i], msg_flags);
447
+ else
448
+ io_uring_prep_sendmsg(sqe, sock_client, &msghdr[i], msg_flags);
449
+
450
+ if (!conf->iovec) {
451
+ io = &iov[i];
452
+ iov_len = 1;
453
+ iov[i].iov_len = cur_size;
454
+ iov[i].iov_base = buf + i * chunk_size;
455
+ } else {
456
+ char *it = buf;
457
+ int j;
458
+
459
+ assert(nr_reqs == 1);
460
+ iov_len = conf->long_iovec ? MAX_IOV : 4;
461
+ io = iov;
462
+
463
+ for (j = 0; j < iov_len; j++)
464
+ io[j].iov_len = 1;
465
+ /* first want to be easily advanced */
466
+ io[0].iov_base = it;
467
+ it += io[0].iov_len;
468
+ /* this should cause retry */
469
+ io[1].iov_len = chunk_size - iov_len + 1;
470
+ io[1].iov_base = it;
471
+ it += io[1].iov_len;
472
+ /* fill the rest */
473
+ for (j = 2; j < iov_len; j++) {
474
+ io[j].iov_base = it;
475
+ it += io[j].iov_len;
476
+ }
477
+ }
478
+
479
+ memset(&msghdr[i], 0, sizeof(msghdr[i]));
480
+ msghdr[i].msg_iov = io;
481
+ msghdr[i].msg_iovlen = iov_len;
482
+ if (conf->addr) {
483
+ msghdr[i].msg_name = conf->addr;
484
+ msghdr[i].msg_namelen = addr_len;
485
+ }
486
+ }
487
+ sqe->user_data = i;
488
+ if (conf->force_async)
489
+ sqe->flags |= IOSQE_ASYNC;
490
+ if (conf->poll_first)
491
+ sqe->ioprio |= IORING_RECVSEND_POLL_FIRST;
492
+ if (i != nr_reqs - 1)
493
+ sqe->flags |= IOSQE_IO_LINK;
494
+ }
495
+
496
+ sqe = io_uring_get_sqe(ring);
497
+ io_uring_prep_recv(sqe, sock_server, rx_buffer, send_size, MSG_WAITALL);
498
+ sqe->user_data = RX_TAG;
499
+
500
+ ret = io_uring_submit(ring);
501
+ if (ret != nr_reqs + 1) {
502
+ fprintf(stderr, "submit failed, got %i expected %i\n", ret, nr_reqs);
503
+ return 1;
504
+ }
505
+
506
+ nr_cqes = nr_reqs + 1;
507
+ for (i = 0; i < nr_cqes; i++) {
508
+ int expected = chunk_size;
509
+
510
+ ret = io_uring_wait_cqe(ring, &cqe);
511
+ if (ret) {
512
+ fprintf(stderr, "io_uring_wait_cqe failed %i\n", ret);
513
+ return 1;
514
+ }
515
+ if (cqe->user_data == RX_TAG) {
516
+ if (cqe->res != send_size) {
517
+ fprintf(stderr, "rx failed res: %i, expected %i\n",
518
+ cqe->res, (int)send_size);
519
+ return 1;
520
+ }
521
+ io_uring_cqe_seen(ring, cqe);
522
+ continue;
523
+ }
524
+ if ((cqe->flags & IORING_CQE_F_MORE) && (cqe->flags & IORING_CQE_F_NOTIF)) {
525
+ fprintf(stderr, "unexpected cflags %i res %i\n",
526
+ cqe->flags, cqe->res);
527
+ return 1;
528
+ }
529
+ if (cqe->user_data >= nr_reqs) {
530
+ fprintf(stderr, "invalid user_data %lu\n",
531
+ (unsigned long)cqe->user_data);
532
+ return 1;
533
+ }
534
+ if (!(cqe->flags & IORING_CQE_F_NOTIF)) {
535
+ if (cqe->flags & IORING_CQE_F_MORE)
536
+ nr_cqes++;
537
+ if (cqe->user_data == nr_reqs - 1)
538
+ expected = chunk_size_last;
539
+ if (cqe->res != expected) {
540
+ if (cqe->res == -ENOMEM) {
541
+ if (!hit_enomem) {
542
+ fprintf(stderr, "Hit -ENOMEM. "
543
+ "Increase ulimit -l "
544
+ "limit for a complete "
545
+ "test run. Skipping "
546
+ "parts.\n");
547
+ hit_enomem = 1;
548
+ }
549
+ return 0;
550
+ }
551
+ fprintf(stderr, "invalid cqe->res %d expected %d\n",
552
+ cqe->res, expected);
553
+ return 1;
554
+ }
555
+ }
556
+ io_uring_cqe_seen(ring, cqe);
557
+ }
558
+
559
+ for (i = 0; i < send_size; i++) {
560
+ if (buf[i] != rx_buffer[i]) {
561
+ fprintf(stderr, "botched data, first mismated byte %i, "
562
+ "%u vs %u\n", i, buf[i], rx_buffer[i]);
563
+ return 1;
564
+ }
565
+ }
566
+ return 0;
567
+ }
568
+
569
+ static int test_inet_send(struct io_uring *ring)
570
+ {
571
+ struct send_conf conf;
572
+ struct sockaddr_storage addr;
573
+ int sock_client = -1, sock_server = -1;
574
+ int ret, j, i;
575
+ int buf_index;
576
+
577
+ for (j = 0; j < 32; j++) {
578
+ bool ipv6 = j & 1;
579
+ bool client_connect = j & 2;
580
+ bool msg_zc_set = j & 4;
581
+ bool tcp = j & 8;
582
+ bool swap_sockets = j & 16;
583
+
584
+ if (tcp && !client_connect)
585
+ continue;
586
+ if (swap_sockets && !tcp)
587
+ continue;
588
+ #ifndef SO_ZEROCOPY
589
+ if (msg_zc_set)
590
+ continue;
591
+ #endif
592
+ ret = create_socketpair_ip(&addr, &sock_client, &sock_server, ipv6,
593
+ client_connect, msg_zc_set, tcp);
594
+ if (ret) {
595
+ fprintf(stderr, "sock prep failed %d\n", ret);
596
+ return 1;
597
+ }
598
+ if (swap_sockets) {
599
+ int tmp_sock = sock_client;
600
+
601
+ sock_client = sock_server;
602
+ sock_server = tmp_sock;
603
+ }
604
+
605
+ for (i = 0; i < 1024; i++) {
606
+ bool regbuf;
607
+
608
+ conf.use_sendmsg = i & 1;
609
+ conf.poll_first = i & 2;
610
+ conf.fixed_buf = i & 4;
611
+ conf.addr = (i & 8) ? &addr : NULL;
612
+ conf.cork = i & 16;
613
+ conf.mix_register = i & 32;
614
+ conf.force_async = i & 64;
615
+ conf.zc = i & 128;
616
+ conf.iovec = i & 256;
617
+ conf.long_iovec = i & 512;
618
+ conf.tcp = tcp;
619
+ regbuf = conf.mix_register || conf.fixed_buf;
620
+
621
+ if (conf.iovec && (!conf.use_sendmsg || regbuf || conf.cork))
622
+ continue;
623
+ if (!conf.zc) {
624
+ if (regbuf)
625
+ continue;
626
+ /*
627
+ * Non zerocopy send w/ addr was added together with sendmsg_zc,
628
+ * skip if we the kernel doesn't support it.
629
+ */
630
+ if (conf.addr && !has_sendmsg)
631
+ continue;
632
+ }
633
+ if (tcp && (conf.cork || conf.addr))
634
+ continue;
635
+ if (conf.mix_register && (!conf.cork || conf.fixed_buf))
636
+ continue;
637
+ if (!client_connect && conf.addr == NULL)
638
+ continue;
639
+ if (conf.use_sendmsg && (regbuf || !has_sendmsg))
640
+ continue;
641
+ if (msg_zc_set && !conf.zc)
642
+ continue;
643
+
644
+ for (buf_index = 0; buf_index < ARRAY_SIZE(buffers_iov); buf_index++) {
645
+ size_t len = buffers_iov[buf_index].iov_len;
646
+
647
+ if (!buffers_iov[buf_index].iov_base)
648
+ continue;
649
+ /* UDP IPv4 max datagram size is under 64K */
650
+ if (!tcp && len > (1U << 15))
651
+ continue;
652
+
653
+ conf.buf_index = buf_index;
654
+ ret = do_test_inet_send(ring, sock_client, sock_server, &conf);
655
+ if (ret) {
656
+ fprintf(stderr, "send failed fixed buf %i, "
657
+ "conn %i, addr %i, cork %i\n",
658
+ conf.fixed_buf, client_connect,
659
+ !!conf.addr, conf.cork);
660
+ return 1;
661
+ }
662
+ }
663
+ }
664
+
665
+ close(sock_client);
666
+ close(sock_server);
667
+ }
668
+ return 0;
669
+ }
670
+
671
+ static int test_async_addr(struct io_uring *ring)
672
+ {
673
+ struct io_uring_sqe *sqe;
674
+ struct io_uring_cqe *cqe;
675
+ struct sockaddr_storage addr;
676
+ int sock_tx = -1, sock_rx = -1;
677
+ struct __kernel_timespec ts;
678
+ int ret;
679
+
680
+ ts.tv_sec = 1;
681
+ ts.tv_nsec = 0;
682
+ ret = create_socketpair_ip(&addr, &sock_tx, &sock_rx, true, false, false, false);
683
+ if (ret) {
684
+ fprintf(stderr, "sock prep failed %d\n", ret);
685
+ return 1;
686
+ }
687
+
688
+ sqe = io_uring_get_sqe(ring);
689
+ io_uring_prep_timeout(sqe, &ts, 0, IORING_TIMEOUT_ETIME_SUCCESS);
690
+ sqe->user_data = 1;
691
+ sqe->flags |= IOSQE_IO_LINK;
692
+
693
+ sqe = io_uring_get_sqe(ring);
694
+ io_uring_prep_send_zc(sqe, sock_tx, tx_buffer, 1, 0, 0);
695
+ sqe->user_data = 2;
696
+ io_uring_prep_send_set_addr(sqe, (const struct sockaddr *)&addr,
697
+ sizeof(struct sockaddr_in6));
698
+
699
+ ret = io_uring_submit(ring);
700
+ assert(ret == 2);
701
+ memset(&addr, 0, sizeof(addr));
702
+
703
+ ret = io_uring_wait_cqe(ring, &cqe);
704
+ if (ret) {
705
+ fprintf(stderr, "io_uring_wait_cqe failed %i\n", ret);
706
+ return 1;
707
+ }
708
+ if (cqe->user_data != 1 || cqe->res != -ETIME) {
709
+ fprintf(stderr, "invalid timeout res %i %i\n",
710
+ (int)cqe->user_data, cqe->res);
711
+ return 1;
712
+ }
713
+ io_uring_cqe_seen(ring, cqe);
714
+
715
+ ret = io_uring_wait_cqe(ring, &cqe);
716
+ if (ret) {
717
+ fprintf(stderr, "io_uring_wait_cqe failed %i\n", ret);
718
+ return 1;
719
+ }
720
+ if (cqe->user_data != 2 || cqe->res != 1) {
721
+ fprintf(stderr, "invalid send %i %i\n",
722
+ (int)cqe->user_data, cqe->res);
723
+ return 1;
724
+ }
725
+ io_uring_cqe_seen(ring, cqe);
726
+ ret = recv(sock_rx, rx_buffer, 1, MSG_TRUNC);
727
+ assert(ret == 1);
728
+
729
+ ret = io_uring_wait_cqe(ring, &cqe);
730
+ if (ret) {
731
+ fprintf(stderr, "io_uring_wait_cqe failed %i\n", ret);
732
+ return 1;
733
+ }
734
+ assert(cqe->flags & IORING_CQE_F_NOTIF);
735
+ io_uring_cqe_seen(ring, cqe);
736
+
737
+ close(sock_tx);
738
+ close(sock_rx);
739
+ return 0;
740
+ }
741
+
742
+ /* see also send_recv.c:test_invalid */
743
+ static int test_invalid_zc(int fds[2])
744
+ {
745
+ struct io_uring ring;
746
+ int ret;
747
+ struct io_uring_cqe *cqe;
748
+ struct io_uring_sqe *sqe;
749
+ bool notif = false;
750
+
751
+ if (!has_sendmsg)
752
+ return 0;
753
+
754
+ ret = t_create_ring(8, &ring, 0);
755
+ if (ret)
756
+ return ret;
757
+
758
+ sqe = io_uring_get_sqe(&ring);
759
+ io_uring_prep_sendmsg(sqe, fds[0], NULL, MSG_WAITALL);
760
+ sqe->opcode = IORING_OP_SENDMSG_ZC;
761
+ sqe->flags |= IOSQE_ASYNC;
762
+
763
+ ret = io_uring_submit(&ring);
764
+ if (ret != 1) {
765
+ fprintf(stderr, "submit failed %i\n", ret);
766
+ return ret;
767
+ }
768
+ ret = io_uring_wait_cqe(&ring, &cqe);
769
+ if (ret)
770
+ return 1;
771
+ if (cqe->flags & IORING_CQE_F_MORE)
772
+ notif = true;
773
+ io_uring_cqe_seen(&ring, cqe);
774
+
775
+ if (notif) {
776
+ ret = io_uring_wait_cqe(&ring, &cqe);
777
+ if (ret)
778
+ return 1;
779
+ io_uring_cqe_seen(&ring, cqe);
780
+ }
781
+ io_uring_queue_exit(&ring);
782
+ return 0;
783
+ }
784
+
785
+ static int run_basic_tests(void)
786
+ {
787
+ struct sockaddr_storage addr;
788
+ int ret, i, sp[2];
789
+
790
+ /* create TCP IPv6 pair */
791
+ ret = create_socketpair_ip(&addr, &sp[0], &sp[1], true, true, false, true);
792
+ if (ret) {
793
+ fprintf(stderr, "sock prep failed %d\n", ret);
794
+ return -1;
795
+ }
796
+
797
+ for (i = 0; i < 2; i++) {
798
+ struct io_uring ring;
799
+ unsigned ring_flags = 0;
800
+
801
+ if (i & 1)
802
+ ring_flags |= IORING_SETUP_DEFER_TASKRUN;
803
+
804
+ ret = io_uring_queue_init(32, &ring, ring_flags);
805
+ if (ret) {
806
+ if (ret == -EINVAL)
807
+ continue;
808
+ fprintf(stderr, "queue init failed: %d\n", ret);
809
+ return -1;
810
+ }
811
+
812
+ ret = test_basic_send(&ring, sp[0], sp[1]);
813
+ if (ret) {
814
+ fprintf(stderr, "test_basic_send() failed\n");
815
+ return -1;
816
+ }
817
+
818
+ ret = test_send_faults(sp[0], sp[1]);
819
+ if (ret) {
820
+ fprintf(stderr, "test_send_faults() failed\n");
821
+ return -1;
822
+ }
823
+
824
+ ret = test_invalid_zc(sp);
825
+ if (ret) {
826
+ fprintf(stderr, "test_invalid_zc() failed\n");
827
+ return -1;
828
+ }
829
+
830
+ ret = test_async_addr(&ring);
831
+ if (ret) {
832
+ fprintf(stderr, "test_async_addr() failed\n");
833
+ return T_EXIT_FAIL;
834
+ }
835
+
836
+ io_uring_queue_exit(&ring);
837
+ }
838
+
839
+ close(sp[0]);
840
+ close(sp[1]);
841
+ return 0;
842
+ }
843
+
844
+ int main(int argc, char *argv[])
845
+ {
846
+ size_t len;
847
+ int ret, i;
848
+
849
+ if (argc > 1)
850
+ return T_EXIT_SKIP;
851
+
852
+ ret = probe_zc_support();
853
+ if (ret) {
854
+ printf("probe failed\n");
855
+ return T_EXIT_FAIL;
856
+ }
857
+ if (!has_sendzc) {
858
+ printf("no IORING_OP_SEND_ZC support, skip\n");
859
+ return T_EXIT_SKIP;
860
+ }
861
+
862
+ page_sz = sysconf(_SC_PAGESIZE);
863
+
864
+ len = LARGE_BUF_SIZE;
865
+ tx_buffer = aligned_alloc(page_sz, len);
866
+ rx_buffer = aligned_alloc(page_sz, len);
867
+ if (tx_buffer && rx_buffer) {
868
+ buffers_iov[BUF_T_LARGE].iov_base = tx_buffer;
869
+ buffers_iov[BUF_T_LARGE].iov_len = len;
870
+ } else {
871
+ if (tx_buffer)
872
+ free(tx_buffer);
873
+ if (rx_buffer)
874
+ free(rx_buffer);
875
+
876
+ printf("skip large buffer tests, can't alloc\n");
877
+
878
+ len = 2 * page_sz;
879
+ tx_buffer = aligned_alloc(page_sz, len);
880
+ rx_buffer = aligned_alloc(page_sz, len);
881
+ }
882
+ if (!tx_buffer || !rx_buffer) {
883
+ fprintf(stderr, "can't allocate buffers\n");
884
+ return T_EXIT_FAIL;
885
+ }
886
+
887
+ srand((unsigned)time(NULL));
888
+ for (i = 0; i < len; i++)
889
+ tx_buffer[i] = i;
890
+ memset(rx_buffer, 0, len);
891
+
892
+ buffers_iov[BUF_T_NORMAL].iov_base = tx_buffer + page_sz;
893
+ buffers_iov[BUF_T_NORMAL].iov_len = page_sz;
894
+ buffers_iov[BUF_T_SMALL].iov_base = tx_buffer;
895
+ buffers_iov[BUF_T_SMALL].iov_len = 137;
896
+ buffers_iov[BUF_T_NONALIGNED].iov_base = tx_buffer + BUFFER_OFFSET;
897
+ buffers_iov[BUF_T_NONALIGNED].iov_len = 2 * page_sz - BUFFER_OFFSET - 13;
898
+
899
+ if (len == LARGE_BUF_SIZE) {
900
+ void *huge_page;
901
+ int off = page_sz + 27;
902
+
903
+ len = 1U << 22;
904
+ huge_page = mmap(NULL, len, PROT_READ|PROT_WRITE,
905
+ MAP_PRIVATE | MAP_HUGETLB | MAP_HUGE_2MB | MAP_ANONYMOUS,
906
+ -1, 0);
907
+ if (huge_page != MAP_FAILED) {
908
+ buffers_iov[BUF_T_HUGETLB].iov_base = huge_page + off;
909
+ buffers_iov[BUF_T_HUGETLB].iov_len = len - off;
910
+ }
911
+ }
912
+
913
+ ret = run_basic_tests();
914
+ if (ret)
915
+ return T_EXIT_FAIL;
916
+
917
+ for (i = 0; i < 2; i++) {
918
+ struct io_uring ring;
919
+ unsigned ring_flags = 0;
920
+
921
+ if (i & 1)
922
+ ring_flags |= IORING_SETUP_SINGLE_ISSUER |
923
+ IORING_SETUP_DEFER_TASKRUN;
924
+
925
+ ret = io_uring_queue_init(32, &ring, ring_flags);
926
+ if (ret) {
927
+ if (ret == -EINVAL)
928
+ continue;
929
+ fprintf(stderr, "queue init failed: %d\n", ret);
930
+ return -1;
931
+ }
932
+
933
+ ret = t_register_buffers(&ring, buffers_iov, ARRAY_SIZE(buffers_iov));
934
+ if (ret == T_SETUP_SKIP) {
935
+ fprintf(stderr, "can't register bufs, skip\n");
936
+ goto out;
937
+ } else if (ret != T_SETUP_OK) {
938
+ fprintf(stderr, "buffer registration failed %i\n", ret);
939
+ return T_EXIT_FAIL;
940
+ }
941
+
942
+ if (buffers_iov[BUF_T_HUGETLB].iov_base) {
943
+ buffers_iov[BUF_T_HUGETLB].iov_base += 13;
944
+ buffers_iov[BUF_T_HUGETLB].iov_len -= 26;
945
+ }
946
+ if (buffers_iov[BUF_T_LARGE].iov_base) {
947
+ buffers_iov[BUF_T_LARGE].iov_base += 13;
948
+ buffers_iov[BUF_T_LARGE].iov_len -= 26;
949
+ }
950
+
951
+ ret = test_inet_send(&ring);
952
+ if (ret) {
953
+ fprintf(stderr, "test_inet_send() failed (defer_taskrun %i)\n",
954
+ ring_flags & IORING_SETUP_DEFER_TASKRUN);
955
+ return T_EXIT_FAIL;
956
+ }
957
+
958
+ if (buffers_iov[BUF_T_HUGETLB].iov_base) {
959
+ buffers_iov[BUF_T_HUGETLB].iov_base -= 13;
960
+ buffers_iov[BUF_T_HUGETLB].iov_len += 26;
961
+ }
962
+ if (buffers_iov[BUF_T_LARGE].iov_base) {
963
+ buffers_iov[BUF_T_LARGE].iov_base -= 13;
964
+ buffers_iov[BUF_T_LARGE].iov_len += 26;
965
+ }
966
+ out:
967
+ io_uring_queue_exit(&ring);
968
+ }
969
+
970
+ return T_EXIT_PASS;
971
+ }