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,602 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ #include <errno.h>
4
+ #include <stdio.h>
5
+ #include <stdlib.h>
6
+ #include <string.h>
7
+ #include <unistd.h>
8
+ #include <arpa/inet.h>
9
+ #include <sys/types.h>
10
+ #include <sys/socket.h>
11
+ #include <pthread.h>
12
+ #include <assert.h>
13
+
14
+ #include "liburing.h"
15
+ #include "helpers.h"
16
+
17
+ #define ENORECVMULTISHOT 9999
18
+
19
+ enum early_error_t {
20
+ ERROR_NONE = 0,
21
+ ERROR_NOT_ENOUGH_BUFFERS,
22
+ ERROR_EARLY_CLOSE_SENDER,
23
+ ERROR_EARLY_CLOSE_RECEIVER,
24
+ ERROR_EARLY_OVERFLOW,
25
+ ERROR_EARLY_LAST
26
+ };
27
+
28
+ struct args {
29
+ bool stream;
30
+ bool wait_each;
31
+ bool recvmsg;
32
+ enum early_error_t early_error;
33
+ bool defer;
34
+ };
35
+
36
+ static int check_sockaddr(struct sockaddr_in *in)
37
+ {
38
+ struct in_addr expected;
39
+
40
+ inet_pton(AF_INET, "127.0.0.1", &expected);
41
+ if (in->sin_family != AF_INET) {
42
+ fprintf(stderr, "bad family %d\n", (int)htons(in->sin_family));
43
+ return -1;
44
+ }
45
+ if (memcmp(&expected, &in->sin_addr, sizeof(in->sin_addr))) {
46
+ char buff[256];
47
+ const char *addr = inet_ntop(AF_INET, &in->sin_addr, buff, sizeof(buff));
48
+
49
+ fprintf(stderr, "unexpected address %s\n", addr ? addr : "INVALID");
50
+ return -1;
51
+ }
52
+ return 0;
53
+ }
54
+
55
+ static int test(struct args *args)
56
+ {
57
+ int const N = 8;
58
+ int const N_BUFFS = N * 64;
59
+ int const N_CQE_OVERFLOW = 4;
60
+ int const min_cqes = args->early_error ? 2 : 8;
61
+ int const NAME_LEN = sizeof(struct sockaddr_storage);
62
+ int const CONTROL_LEN = CMSG_ALIGN(sizeof(struct sockaddr_storage))
63
+ + sizeof(struct cmsghdr);
64
+ struct io_uring ring;
65
+ struct io_uring_cqe *cqe;
66
+ struct io_uring_sqe *sqe;
67
+ int fds[2], ret, i, j;
68
+ int total_sent_bytes = 0, total_recv_bytes = 0, total_dropped_bytes = 0;
69
+ int send_buff[256];
70
+ int *sent_buffs[N_BUFFS];
71
+ int *recv_buffs[N_BUFFS];
72
+ int *at;
73
+ struct io_uring_cqe recv_cqe[N_BUFFS];
74
+ int recv_cqes = 0;
75
+ bool early_error = false;
76
+ bool early_error_started = false;
77
+ struct __kernel_timespec timeout = {
78
+ .tv_sec = 1,
79
+ };
80
+ struct msghdr msg;
81
+ struct io_uring_params params = { };
82
+ int n_sqe = 32;
83
+
84
+ memset(recv_buffs, 0, sizeof(recv_buffs));
85
+
86
+ if (args->defer)
87
+ params.flags |= IORING_SETUP_SINGLE_ISSUER |
88
+ IORING_SETUP_DEFER_TASKRUN;
89
+
90
+ if (args->early_error == ERROR_EARLY_OVERFLOW) {
91
+ params.flags |= IORING_SETUP_CQSIZE;
92
+ params.cq_entries = N_CQE_OVERFLOW;
93
+ n_sqe = N_CQE_OVERFLOW;
94
+ }
95
+
96
+ ret = io_uring_queue_init_params(n_sqe, &ring, &params);
97
+ if (ret) {
98
+ fprintf(stderr, "queue init failed: %d\n", ret);
99
+ return ret;
100
+ }
101
+
102
+ ret = t_create_socket_pair(fds, args->stream);
103
+ if (ret) {
104
+ fprintf(stderr, "t_create_socket_pair failed: %d\n", ret);
105
+ return ret;
106
+ }
107
+
108
+ if (!args->stream) {
109
+ bool val = true;
110
+
111
+ /* force some cmsgs to come back to us */
112
+ ret = setsockopt(fds[0], IPPROTO_IP, IP_RECVORIGDSTADDR, &val,
113
+ sizeof(val));
114
+ if (ret) {
115
+ fprintf(stderr, "setsockopt failed %d\n", errno);
116
+ goto cleanup;
117
+ }
118
+ }
119
+
120
+ for (i = 0; i < ARRAY_SIZE(send_buff); i++)
121
+ send_buff[i] = i;
122
+
123
+ for (i = 0; i < ARRAY_SIZE(recv_buffs); i++) {
124
+ /* prepare some different sized buffers */
125
+ int buffer_size = (i % 2 == 0 && (args->stream || args->recvmsg)) ? 1 : N;
126
+
127
+ buffer_size *= sizeof(int);
128
+ if (args->recvmsg) {
129
+ buffer_size +=
130
+ sizeof(struct io_uring_recvmsg_out) +
131
+ NAME_LEN +
132
+ CONTROL_LEN;
133
+ }
134
+
135
+ recv_buffs[i] = malloc(buffer_size);
136
+
137
+ if (i > 2 && args->early_error == ERROR_NOT_ENOUGH_BUFFERS)
138
+ continue;
139
+
140
+ sqe = io_uring_get_sqe(&ring);
141
+ io_uring_prep_provide_buffers(sqe, recv_buffs[i],
142
+ buffer_size, 1, 7, i);
143
+ io_uring_sqe_set_data64(sqe, 0x999);
144
+ memset(recv_buffs[i], 0xcc, buffer_size);
145
+ if (io_uring_submit_and_wait_timeout(&ring, &cqe, 1, &timeout, NULL) < 0) {
146
+ fprintf(stderr, "provide buffers failed: %d\n", ret);
147
+ ret = -1;
148
+ goto cleanup;
149
+ }
150
+ io_uring_cqe_seen(&ring, cqe);
151
+ }
152
+
153
+ sqe = io_uring_get_sqe(&ring);
154
+ if (args->recvmsg) {
155
+ unsigned int flags = 0;
156
+
157
+ if (!args->stream)
158
+ flags |= MSG_TRUNC;
159
+
160
+ memset(&msg, 0, sizeof(msg));
161
+ msg.msg_namelen = NAME_LEN;
162
+ msg.msg_controllen = CONTROL_LEN;
163
+ io_uring_prep_recvmsg_multishot(sqe, fds[0], &msg, flags);
164
+ } else {
165
+ io_uring_prep_recv_multishot(sqe, fds[0], NULL, 0, 0);
166
+ }
167
+ sqe->flags |= IOSQE_BUFFER_SELECT;
168
+ sqe->buf_group = 7;
169
+ io_uring_sqe_set_data64(sqe, 1234);
170
+ io_uring_submit(&ring);
171
+
172
+ at = &send_buff[0];
173
+ total_sent_bytes = 0;
174
+ for (i = 0; i < N; i++) {
175
+ int to_send = sizeof(*at) * (i+1);
176
+
177
+ total_sent_bytes += to_send;
178
+ sent_buffs[i] = at;
179
+ if (send(fds[1], at, to_send, 0) != to_send) {
180
+ if (early_error_started)
181
+ break;
182
+ fprintf(stderr, "send failed %d\n", errno);
183
+ ret = -1;
184
+ goto cleanup;
185
+ }
186
+
187
+ if (i == 2) {
188
+ if (args->early_error == ERROR_EARLY_CLOSE_RECEIVER) {
189
+ /* allow previous sends to complete */
190
+ usleep(1000);
191
+ io_uring_get_events(&ring);
192
+
193
+ sqe = io_uring_get_sqe(&ring);
194
+ io_uring_prep_recv(sqe, fds[0], NULL, 0, 0);
195
+ io_uring_prep_cancel64(sqe, 1234, 0);
196
+ io_uring_sqe_set_data64(sqe, 0x888);
197
+ sqe->flags |= IOSQE_CQE_SKIP_SUCCESS;
198
+ io_uring_submit(&ring);
199
+ early_error_started = true;
200
+
201
+ /* allow the cancel to complete */
202
+ usleep(1000);
203
+ io_uring_get_events(&ring);
204
+ }
205
+ if (args->early_error == ERROR_EARLY_CLOSE_SENDER) {
206
+ early_error_started = true;
207
+ shutdown(fds[1], SHUT_RDWR);
208
+ close(fds[1]);
209
+ }
210
+ }
211
+ at += (i+1);
212
+
213
+ if (args->wait_each) {
214
+ ret = io_uring_wait_cqes(&ring, &cqe, 1, &timeout, NULL);
215
+ if (ret) {
216
+ fprintf(stderr, "wait_each failed: %d\n", ret);
217
+ ret = -1;
218
+ goto cleanup;
219
+ }
220
+ while (io_uring_peek_cqe(&ring, &cqe) == 0) {
221
+ recv_cqe[recv_cqes++] = *cqe;
222
+ if (cqe->flags & IORING_CQE_F_MORE) {
223
+ io_uring_cqe_seen(&ring, cqe);
224
+ } else {
225
+ early_error = true;
226
+ io_uring_cqe_seen(&ring, cqe);
227
+ }
228
+ }
229
+ if (early_error)
230
+ break;
231
+ }
232
+ }
233
+
234
+ close(fds[1]);
235
+
236
+ /* allow sends to finish */
237
+ usleep(1000);
238
+
239
+ if ((args->stream && !early_error) || recv_cqes < min_cqes) {
240
+ unsigned int to_wait = 1;
241
+
242
+ if (recv_cqes < min_cqes)
243
+ to_wait = min_cqes - recv_cqes;
244
+ ret = io_uring_wait_cqes(&ring, &cqe, to_wait, &timeout, NULL);
245
+ if (ret && ret != -ETIME) {
246
+ fprintf(stderr, "wait final failed: %d\n", ret);
247
+ ret = -1;
248
+ goto cleanup;
249
+ }
250
+ }
251
+
252
+ while (io_uring_peek_cqe(&ring, &cqe) == 0) {
253
+ recv_cqe[recv_cqes++] = *cqe;
254
+ io_uring_cqe_seen(&ring, cqe);
255
+ }
256
+
257
+ ret = -1;
258
+ at = &send_buff[0];
259
+ if (recv_cqes < min_cqes) {
260
+ if (recv_cqes > 0 && recv_cqe[0].res == -EINVAL) {
261
+ return -ENORECVMULTISHOT;
262
+ }
263
+ /* some kernels apparently don't check ->ioprio, skip */
264
+ ret = -ENORECVMULTISHOT;
265
+ goto cleanup;
266
+ }
267
+ for (i = 0; i < recv_cqes; i++) {
268
+ cqe = &recv_cqe[i];
269
+
270
+ bool const is_last = i == recv_cqes - 1;
271
+
272
+ /*
273
+ * Older kernels could terminate multishot early due to overflow,
274
+ * but later ones will not. So discriminate based on the MORE flag.
275
+ */
276
+ bool const early_last = args->early_error == ERROR_EARLY_OVERFLOW &&
277
+ !args->wait_each &&
278
+ i >= N_CQE_OVERFLOW &&
279
+ !(cqe->flags & IORING_CQE_F_MORE);
280
+
281
+ bool const should_be_last =
282
+ (cqe->res <= 0) ||
283
+ (args->stream && is_last) ||
284
+ early_last;
285
+ int *this_recv;
286
+ int orig_payload_size = cqe->res;
287
+
288
+
289
+ if (should_be_last) {
290
+ int used_res = cqe->res;
291
+
292
+ if (!is_last) {
293
+ fprintf(stderr, "not last cqe had error %d\n", i);
294
+ goto cleanup;
295
+ }
296
+
297
+ switch (args->early_error) {
298
+ case ERROR_NOT_ENOUGH_BUFFERS:
299
+ if (cqe->res != -ENOBUFS) {
300
+ fprintf(stderr,
301
+ "ERROR_NOT_ENOUGH_BUFFERS: res %d\n", cqe->res);
302
+ goto cleanup;
303
+ }
304
+ break;
305
+ case ERROR_EARLY_OVERFLOW:
306
+ if (cqe->res < 0) {
307
+ fprintf(stderr,
308
+ "ERROR_EARLY_OVERFLOW: res %d\n", cqe->res);
309
+ goto cleanup;
310
+ }
311
+ break;
312
+ case ERROR_EARLY_CLOSE_RECEIVER:
313
+ if (cqe->res != -ECANCELED) {
314
+ fprintf(stderr,
315
+ "ERROR_EARLY_CLOSE_RECEIVER: res %d\n", cqe->res);
316
+ goto cleanup;
317
+ }
318
+ break;
319
+ case ERROR_NONE:
320
+ case ERROR_EARLY_CLOSE_SENDER:
321
+ if (args->recvmsg && (cqe->flags & IORING_CQE_F_BUFFER)) {
322
+ void *buff = recv_buffs[cqe->flags >> 16];
323
+ struct io_uring_recvmsg_out *o =
324
+ io_uring_recvmsg_validate(buff, cqe->res, &msg);
325
+
326
+ if (!o) {
327
+ fprintf(stderr, "invalid buff\n");
328
+ goto cleanup;
329
+ }
330
+ if (o->payloadlen != 0) {
331
+ fprintf(stderr, "expected 0 payloadlen, got %u\n",
332
+ o->payloadlen);
333
+ goto cleanup;
334
+ }
335
+ used_res = 0;
336
+ } else if (cqe->res != 0) {
337
+ fprintf(stderr, "early error: res %d\n", cqe->res);
338
+ goto cleanup;
339
+ }
340
+ break;
341
+ case ERROR_EARLY_LAST:
342
+ fprintf(stderr, "bad error_early\n");
343
+ goto cleanup;
344
+ }
345
+
346
+ if (cqe->res <= 0 && cqe->flags & IORING_CQE_F_BUFFER) {
347
+ fprintf(stderr, "final BUFFER flag set\n");
348
+ goto cleanup;
349
+ }
350
+
351
+ if (cqe->flags & IORING_CQE_F_MORE) {
352
+ fprintf(stderr, "final MORE flag set\n");
353
+ goto cleanup;
354
+ }
355
+
356
+ if (used_res <= 0)
357
+ continue;
358
+ } else {
359
+ if (!(cqe->flags & IORING_CQE_F_MORE)) {
360
+ fprintf(stderr, "MORE flag not set\n");
361
+ goto cleanup;
362
+ }
363
+ }
364
+
365
+ if (!(cqe->flags & IORING_CQE_F_BUFFER)) {
366
+ fprintf(stderr, "BUFFER flag not set\n");
367
+ goto cleanup;
368
+ }
369
+
370
+ this_recv = recv_buffs[cqe->flags >> 16];
371
+
372
+ if (args->recvmsg) {
373
+ struct io_uring_recvmsg_out *o = io_uring_recvmsg_validate(
374
+ this_recv, cqe->res, &msg);
375
+
376
+ if (!o) {
377
+ fprintf(stderr, "bad recvmsg\n");
378
+ goto cleanup;
379
+ }
380
+ orig_payload_size = o->payloadlen;
381
+
382
+ if (!args->stream) {
383
+ orig_payload_size = o->payloadlen;
384
+
385
+ struct cmsghdr *cmsg;
386
+
387
+ if (o->namelen < sizeof(struct sockaddr_in)) {
388
+ fprintf(stderr, "bad addr len %d",
389
+ o->namelen);
390
+ goto cleanup;
391
+ }
392
+ if (check_sockaddr((struct sockaddr_in *)io_uring_recvmsg_name(o)))
393
+ goto cleanup;
394
+
395
+ cmsg = io_uring_recvmsg_cmsg_firsthdr(o, &msg);
396
+ if (!cmsg ||
397
+ cmsg->cmsg_level != IPPROTO_IP ||
398
+ cmsg->cmsg_type != IP_RECVORIGDSTADDR) {
399
+ fprintf(stderr, "bad cmsg");
400
+ goto cleanup;
401
+ }
402
+ if (check_sockaddr((struct sockaddr_in *)CMSG_DATA(cmsg)))
403
+ goto cleanup;
404
+ cmsg = io_uring_recvmsg_cmsg_nexthdr(o, &msg, cmsg);
405
+ if (cmsg) {
406
+ fprintf(stderr, "unexpected extra cmsg\n");
407
+ goto cleanup;
408
+ }
409
+
410
+ }
411
+
412
+ this_recv = (int *)io_uring_recvmsg_payload(o, &msg);
413
+ cqe->res = io_uring_recvmsg_payload_length(o, cqe->res, &msg);
414
+ if (o->payloadlen != cqe->res) {
415
+ if (!(o->flags & MSG_TRUNC)) {
416
+ fprintf(stderr, "expected truncated flag\n");
417
+ goto cleanup;
418
+ }
419
+ total_dropped_bytes += (o->payloadlen - cqe->res);
420
+ }
421
+ }
422
+
423
+ total_recv_bytes += cqe->res;
424
+
425
+ if (cqe->res % 4 != 0) {
426
+ /*
427
+ * doesn't seem to happen in practice, would need some
428
+ * work to remove this requirement
429
+ */
430
+ fprintf(stderr, "unexpectedly aligned buffer cqe->res=%d\n", cqe->res);
431
+ goto cleanup;
432
+ }
433
+
434
+ /*
435
+ * for tcp: check buffer arrived in order
436
+ * for udp: based on size validate data based on size
437
+ */
438
+ if (!args->stream) {
439
+ int sent_idx = orig_payload_size / sizeof(*at) - 1;
440
+
441
+ if (sent_idx < 0 || sent_idx > N) {
442
+ fprintf(stderr, "Bad sent idx: %d\n", sent_idx);
443
+ goto cleanup;
444
+ }
445
+ at = sent_buffs[sent_idx];
446
+ }
447
+ for (j = 0; j < cqe->res / 4; j++) {
448
+ int sent = *at++;
449
+ int recv = *this_recv++;
450
+
451
+ if (sent != recv) {
452
+ fprintf(stderr, "recv=%d sent=%d\n", recv, sent);
453
+ goto cleanup;
454
+ }
455
+ }
456
+ }
457
+
458
+ if (args->early_error == ERROR_NONE &&
459
+ total_recv_bytes + total_dropped_bytes < total_sent_bytes) {
460
+ fprintf(stderr,
461
+ "missing recv: recv=%d dropped=%d sent=%d\n",
462
+ total_recv_bytes, total_sent_bytes, total_dropped_bytes);
463
+ goto cleanup;
464
+ }
465
+
466
+ ret = 0;
467
+ cleanup:
468
+ for (i = 0; i < ARRAY_SIZE(recv_buffs); i++)
469
+ free(recv_buffs[i]);
470
+ close(fds[0]);
471
+ close(fds[1]);
472
+ io_uring_queue_exit(&ring);
473
+
474
+ return ret;
475
+ }
476
+
477
+ static int test_enobuf(void)
478
+ {
479
+ struct io_uring ring;
480
+ struct io_uring_sqe *sqe;
481
+ struct io_uring_cqe *cqes[16];
482
+ char buffs[256];
483
+ int ret, i, fds[2];
484
+
485
+ if (t_create_ring(8, &ring, 0) != T_SETUP_OK) {
486
+ fprintf(stderr, "ring create\n");
487
+ return -1;
488
+ }
489
+
490
+ ret = t_create_socket_pair(fds, false);
491
+ if (ret) {
492
+ fprintf(stderr, "t_create_socket_pair\n");
493
+ return ret;
494
+ }
495
+
496
+ sqe = io_uring_get_sqe(&ring);
497
+ assert(sqe);
498
+ /* deliberately only 2 provided buffers */
499
+ io_uring_prep_provide_buffers(sqe, &buffs[0], 1, 2, 0, 0);
500
+ io_uring_sqe_set_data64(sqe, 0);
501
+
502
+ sqe = io_uring_get_sqe(&ring);
503
+ assert(sqe);
504
+ io_uring_prep_recv_multishot(sqe, fds[0], NULL, 0, 0);
505
+ io_uring_sqe_set_data64(sqe, 1);
506
+ sqe->buf_group = 0;
507
+ sqe->flags |= IOSQE_BUFFER_SELECT;
508
+
509
+ ret = io_uring_submit(&ring);
510
+ if (ret != 2) {
511
+ fprintf(stderr, "bad submit %d\n", ret);
512
+ return -1;
513
+ }
514
+ for (i = 0; i < 3; i++) {
515
+ do {
516
+ ret = write(fds[1], "?", 1);
517
+ } while (ret == -1 && errno == EINTR);
518
+ }
519
+
520
+ ret = io_uring_wait_cqes(&ring, &cqes[0], 4, NULL, NULL);
521
+ if (ret) {
522
+ fprintf(stderr, "wait cqes\n");
523
+ return ret;
524
+ }
525
+
526
+ ret = io_uring_peek_batch_cqe(&ring, &cqes[0], 4);
527
+ if (ret != 4) {
528
+ fprintf(stderr, "peek batch cqes\n");
529
+ return -1;
530
+ }
531
+
532
+ /* provide buffers */
533
+ assert(cqes[0]->user_data == 0);
534
+ assert(cqes[0]->res == 0);
535
+
536
+ /* valid recv */
537
+ assert(cqes[1]->user_data == 1);
538
+ assert(cqes[2]->user_data == 1);
539
+ assert(cqes[1]->res == 1);
540
+ assert(cqes[2]->res == 1);
541
+ assert(cqes[1]->flags & (IORING_CQE_F_BUFFER | IORING_CQE_F_MORE));
542
+ assert(cqes[2]->flags & (IORING_CQE_F_BUFFER | IORING_CQE_F_MORE));
543
+
544
+ /* missing buffer */
545
+ assert(cqes[3]->user_data == 1);
546
+ assert(cqes[3]->res == -ENOBUFS);
547
+ assert(!(cqes[3]->flags & (IORING_CQE_F_BUFFER | IORING_CQE_F_MORE)));
548
+
549
+ close(fds[0]);
550
+ close(fds[1]);
551
+ io_uring_queue_exit(&ring);
552
+ return 0;
553
+ }
554
+
555
+ int main(int argc, char *argv[])
556
+ {
557
+ int ret;
558
+ int loop;
559
+ int early_error = 0;
560
+ bool has_defer;
561
+
562
+ if (argc > 1)
563
+ return T_EXIT_SKIP;
564
+
565
+ has_defer = t_probe_defer_taskrun();
566
+
567
+ for (loop = 0; loop < 16; loop++) {
568
+ struct args a = {
569
+ .stream = loop & 0x01,
570
+ .wait_each = loop & 0x2,
571
+ .recvmsg = loop & 0x04,
572
+ .defer = loop & 0x08,
573
+ };
574
+ if (a.defer && !has_defer)
575
+ continue;
576
+ for (early_error = 0; early_error < ERROR_EARLY_LAST; early_error++) {
577
+ a.early_error = (enum early_error_t)early_error;
578
+ ret = test(&a);
579
+ if (ret) {
580
+ if (ret == -ENORECVMULTISHOT) {
581
+ if (loop == 0)
582
+ return T_EXIT_SKIP;
583
+ fprintf(stderr,
584
+ "ENORECVMULTISHOT received but loop>0\n");
585
+ }
586
+ fprintf(stderr,
587
+ "test stream=%d wait_each=%d recvmsg=%d early_error=%d "
588
+ " defer=%d failed\n",
589
+ a.stream, a.wait_each, a.recvmsg, a.early_error, a.defer);
590
+ return T_EXIT_FAIL;
591
+ }
592
+ }
593
+ }
594
+
595
+ ret = test_enobuf();
596
+ if (ret) {
597
+ fprintf(stderr, "test_enobuf() failed: %d\n", ret);
598
+ return T_EXIT_FAIL;
599
+ }
600
+
601
+ return T_EXIT_PASS;
602
+ }