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,691 @@
1
+ /* SPDX-License-Identifier: MIT */
2
+ /*
3
+ * Simple test case showing using send and recv bundles
4
+ */
5
+ #include <errno.h>
6
+ #include <stdio.h>
7
+ #include <stdlib.h>
8
+ #include <string.h>
9
+ #include <unistd.h>
10
+ #include <arpa/inet.h>
11
+ #include <sys/types.h>
12
+ #include <sys/socket.h>
13
+ #include <pthread.h>
14
+
15
+ #define MSG_SIZE 128
16
+ #define NR_MIN_MSGS 4
17
+ #define NR_MAX_MSGS 32
18
+ #define SEQ_SIZE (MSG_SIZE / sizeof(unsigned long))
19
+
20
+ static int nr_msgs;
21
+ static int use_tcp;
22
+
23
+ #define RECV_BIDS 8192
24
+ #define RECV_BID_MASK (RECV_BIDS - 1)
25
+
26
+ #include "liburing.h"
27
+ #include "helpers.h"
28
+
29
+ #define PORT 10202
30
+ #define HOST "127.0.0.1"
31
+
32
+ static int use_port = PORT;
33
+
34
+ #define SEND_BGID 7
35
+ #define RECV_BGID 8
36
+
37
+ static int no_send_mshot;
38
+
39
+ struct recv_data {
40
+ pthread_barrier_t connect;
41
+ pthread_barrier_t startup;
42
+ pthread_barrier_t barrier;
43
+ pthread_barrier_t finish;
44
+ unsigned long seq;
45
+ int recv_bytes;
46
+ int accept_fd;
47
+ int abort;
48
+ unsigned int max_sends;
49
+ int to_eagain;
50
+ void *recv_buf;
51
+
52
+ int send_bundle;
53
+ int recv_bundle;
54
+ };
55
+
56
+ static int arm_recv(struct io_uring *ring, struct recv_data *rd)
57
+ {
58
+ struct io_uring_sqe *sqe;
59
+ int ret;
60
+
61
+ sqe = io_uring_get_sqe(ring);
62
+ io_uring_prep_recv_multishot(sqe, rd->accept_fd, NULL, 0, 0);
63
+ if (rd->recv_bundle && use_tcp)
64
+ sqe->ioprio |= IORING_RECVSEND_BUNDLE;
65
+ sqe->buf_group = RECV_BGID;
66
+ sqe->flags |= IOSQE_BUFFER_SELECT;
67
+ sqe->user_data = 2;
68
+
69
+ ret = io_uring_submit(ring);
70
+ if (ret != 1) {
71
+ fprintf(stderr, "submit failed: %d\n", ret);
72
+ return 1;
73
+ }
74
+
75
+ return 0;
76
+ }
77
+
78
+ static int recv_prep(struct io_uring *ring, struct recv_data *rd, int *sock)
79
+ {
80
+ struct sockaddr_in saddr;
81
+ int sockfd, ret, val, use_fd;
82
+ socklen_t socklen;
83
+
84
+ memset(&saddr, 0, sizeof(saddr));
85
+ saddr.sin_family = AF_INET;
86
+ saddr.sin_addr.s_addr = htonl(INADDR_ANY);
87
+ saddr.sin_port = htons(use_port);
88
+
89
+ if (use_tcp)
90
+ sockfd = socket(AF_INET, SOCK_STREAM, 0);
91
+ else
92
+ sockfd = socket(AF_INET, SOCK_DGRAM, 0);
93
+ if (sockfd < 0) {
94
+ perror("socket");
95
+ return 1;
96
+ }
97
+
98
+ val = 1;
99
+ setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
100
+
101
+ ret = bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr));
102
+ if (ret < 0) {
103
+ perror("bind");
104
+ goto err;
105
+ }
106
+
107
+ if (use_tcp) {
108
+ ret = listen(sockfd, 1);
109
+ if (ret < 0) {
110
+ perror("listen");
111
+ goto err;
112
+ }
113
+
114
+ pthread_barrier_wait(&rd->connect);
115
+
116
+ socklen = sizeof(saddr);
117
+ use_fd = accept(sockfd, (struct sockaddr *)&saddr, &socklen);
118
+ if (use_fd < 0) {
119
+ perror("accept");
120
+ goto err;
121
+ }
122
+ } else {
123
+ use_fd = sockfd;
124
+ pthread_barrier_wait(&rd->connect);
125
+ }
126
+
127
+ rd->accept_fd = use_fd;
128
+ pthread_barrier_wait(&rd->startup);
129
+ pthread_barrier_wait(&rd->barrier);
130
+
131
+ if (arm_recv(ring, rd))
132
+ goto err;
133
+
134
+ *sock = sockfd;
135
+ return 0;
136
+ err:
137
+ close(sockfd);
138
+ return 1;
139
+ }
140
+
141
+ static int verify_seq(struct recv_data *rd, void *verify_ptr, int verify_sz,
142
+ int start_bid)
143
+ {
144
+ unsigned long *seqp;
145
+ int seq_size = verify_sz / sizeof(unsigned long);
146
+ int i;
147
+
148
+ seqp = verify_ptr;
149
+ for (i = 0; i < seq_size; i++) {
150
+ if (rd->seq != *seqp) {
151
+ fprintf(stderr, "bid=%d, got seq %lu, wanted %lu, offset %d\n", start_bid, *seqp, rd->seq, i);
152
+ return 0;
153
+ }
154
+ seqp++;
155
+ rd->seq++;
156
+ }
157
+
158
+ return 1;
159
+ }
160
+
161
+ static int recv_get_cqe(struct io_uring *ring, struct recv_data *rd,
162
+ struct io_uring_cqe **cqe)
163
+ {
164
+ struct __kernel_timespec ts = { .tv_sec = 0, .tv_nsec = 100000000LL };
165
+ int ret;
166
+
167
+ do {
168
+ ret = io_uring_wait_cqe_timeout(ring, cqe, &ts);
169
+ if (!ret)
170
+ return 0;
171
+ if (ret == -ETIME) {
172
+ if (rd->abort)
173
+ break;
174
+ continue;
175
+ }
176
+ fprintf(stderr, "wait recv: %d\n", ret);
177
+ break;
178
+ } while (1);
179
+
180
+ return 1;
181
+ }
182
+
183
+ static int do_recv(struct io_uring *ring, struct recv_data *rd)
184
+ {
185
+ struct io_uring_cqe *cqe;
186
+ int bid, next_bid = 0;
187
+ void *verify_ptr;
188
+ int verify_sz = 0;
189
+ int verify_bid = 0;
190
+
191
+ verify_ptr = malloc(rd->recv_bytes);
192
+
193
+ do {
194
+ if (recv_get_cqe(ring, rd, &cqe))
195
+ break;
196
+ if (cqe->res == -EINVAL) {
197
+ fprintf(stdout, "recv not supported, skipping\n");
198
+ return 0;
199
+ }
200
+ if (cqe->res < 0) {
201
+ fprintf(stderr, "failed recv cqe: %d\n", cqe->res);
202
+ goto err;
203
+ }
204
+ if (!(cqe->flags & IORING_CQE_F_BUFFER)) {
205
+ fprintf(stderr, "no buffer set in recv\n");
206
+ goto err;
207
+ }
208
+ bid = cqe->flags >> IORING_CQE_BUFFER_SHIFT;
209
+ if (bid != next_bid) {
210
+ fprintf(stderr, "got bid %d, wanted %d\n", bid, next_bid);
211
+ goto err;
212
+ }
213
+ if (!rd->recv_bundle && cqe->res > MSG_SIZE) {
214
+ fprintf(stderr, "recv got wrong length: %d\n", cqe->res);
215
+ goto err;
216
+ }
217
+ if (!(verify_sz % MSG_SIZE)) {
218
+ if (!verify_seq(rd, verify_ptr, verify_sz, verify_bid))
219
+ goto err;
220
+ verify_bid += verify_sz / MSG_SIZE;
221
+ verify_bid &= RECV_BID_MASK;
222
+ verify_sz = 0;
223
+ } else {
224
+ memcpy(verify_ptr + verify_sz, rd->recv_buf + (bid * MSG_SIZE), cqe->res);
225
+ verify_sz += cqe->res;
226
+ }
227
+ next_bid = bid + ((cqe->res + MSG_SIZE - 1) / MSG_SIZE);
228
+ next_bid &= RECV_BID_MASK;
229
+ rd->recv_bytes -= cqe->res;
230
+ io_uring_cqe_seen(ring, cqe);
231
+ if (!(cqe->flags & IORING_CQE_F_MORE) && rd->recv_bytes) {
232
+ if (arm_recv(ring, rd))
233
+ goto err;
234
+ }
235
+ } while (rd->recv_bytes);
236
+
237
+ if (verify_sz && !(verify_sz % MSG_SIZE) &&
238
+ !verify_seq(rd, verify_ptr, verify_sz, verify_bid))
239
+ goto err;
240
+
241
+ pthread_barrier_wait(&rd->finish);
242
+ return 0;
243
+ err:
244
+ pthread_barrier_wait(&rd->finish);
245
+ return 1;
246
+ }
247
+
248
+ static void *recv_fn(void *data)
249
+ {
250
+ struct recv_data *rd = data;
251
+ struct io_uring_params p = { };
252
+ struct io_uring ring;
253
+ struct io_uring_buf_ring *br;
254
+ void *buf, *ptr;
255
+ int ret, sock, i;
256
+
257
+ p.cq_entries = 4096;
258
+ p.flags = IORING_SETUP_CQSIZE;
259
+ ret = t_create_ring_params(16, &ring, &p);
260
+ if (ret == T_SETUP_SKIP) {
261
+ ret = 0;
262
+ goto err;
263
+ } else if (ret < 0) {
264
+ goto err;
265
+ }
266
+
267
+ if (posix_memalign(&buf, 4096, MSG_SIZE * RECV_BIDS))
268
+ goto err;
269
+
270
+ br = io_uring_setup_buf_ring(&ring, RECV_BIDS, RECV_BGID, 0, &ret);
271
+ if (!br) {
272
+ fprintf(stderr, "failed setting up recv ring %d\n", ret);
273
+ goto err;
274
+ }
275
+
276
+ ptr = buf;
277
+ for (i = 0; i < RECV_BIDS; i++) {
278
+ io_uring_buf_ring_add(br, ptr, MSG_SIZE, i, RECV_BID_MASK, i);
279
+ ptr += MSG_SIZE;
280
+ }
281
+ io_uring_buf_ring_advance(br, RECV_BIDS);
282
+ rd->recv_buf = buf;
283
+
284
+ ret = recv_prep(&ring, rd, &sock);
285
+ if (ret) {
286
+ fprintf(stderr, "recv_prep failed: %d\n", ret);
287
+ goto err;
288
+ }
289
+
290
+ ret = do_recv(&ring, rd);
291
+
292
+ close(sock);
293
+ close(rd->accept_fd);
294
+ io_uring_queue_exit(&ring);
295
+ err:
296
+ return (void *)(intptr_t)ret;
297
+ }
298
+
299
+ static int __do_send_bundle(struct recv_data *rd, struct io_uring *ring, int sockfd)
300
+ {
301
+ struct io_uring_cqe *cqe;
302
+ struct io_uring_sqe *sqe;
303
+ int bytes_needed = MSG_SIZE * nr_msgs;
304
+ int i, ret;
305
+
306
+ sqe = io_uring_get_sqe(ring);
307
+ io_uring_prep_send_bundle(sqe, sockfd, 0, 0);
308
+ sqe->flags |= IOSQE_BUFFER_SELECT;
309
+ sqe->buf_group = SEND_BGID;
310
+ sqe->user_data = 1;
311
+
312
+ ret = io_uring_submit(ring);
313
+ if (ret != 1)
314
+ return 1;
315
+
316
+ pthread_barrier_wait(&rd->barrier);
317
+
318
+ for (i = 0; i < nr_msgs; i++) {
319
+ ret = io_uring_wait_cqe(ring, &cqe);
320
+ if (ret) {
321
+ fprintf(stderr, "wait send: %d\n", ret);
322
+ return 1;
323
+ }
324
+ if (!i && cqe->res == -EINVAL) {
325
+ rd->abort = 1;
326
+ no_send_mshot = 1;
327
+ break;
328
+ }
329
+ if (cqe->res < 0) {
330
+ fprintf(stderr, "bad send cqe res: %d\n", cqe->res);
331
+ return 1;
332
+ }
333
+ bytes_needed -= cqe->res;
334
+ if (!bytes_needed) {
335
+ io_uring_cqe_seen(ring, cqe);
336
+ break;
337
+ }
338
+ if (!(cqe->flags & IORING_CQE_F_MORE)) {
339
+ fprintf(stderr, "expected more, but MORE not set\n");
340
+ return 1;
341
+ }
342
+ io_uring_cqe_seen(ring, cqe);
343
+ }
344
+
345
+ return 0;
346
+ }
347
+
348
+ static int __do_send(struct recv_data *rd, struct io_uring *ring, int sockfd)
349
+ {
350
+ struct io_uring_cqe *cqe;
351
+ struct io_uring_sqe *sqe;
352
+ int bytes_needed = MSG_SIZE * nr_msgs;
353
+ int i, ret;
354
+
355
+ for (i = 0; i < nr_msgs; i++) {
356
+ sqe = io_uring_get_sqe(ring);
357
+ io_uring_prep_send(sqe, sockfd, NULL, 0, 0);
358
+ sqe->user_data = 10 + i;
359
+ sqe->flags |= IOSQE_BUFFER_SELECT;
360
+ sqe->buf_group = SEND_BGID;
361
+
362
+ ret = io_uring_submit(ring);
363
+ if (ret != 1)
364
+ return 1;
365
+
366
+ if (!i)
367
+ pthread_barrier_wait(&rd->barrier);
368
+ ret = io_uring_wait_cqe(ring, &cqe);
369
+ if (ret) {
370
+ fprintf(stderr, "send wait cqe %d\n", ret);
371
+ return 1;
372
+ }
373
+
374
+ if (!i && cqe->res == -EINVAL) {
375
+ rd->abort = 1;
376
+ no_send_mshot = 1;
377
+ break;
378
+ }
379
+ if (cqe->res != MSG_SIZE) {
380
+ fprintf(stderr, "send failed cqe: %d\n", cqe->res);
381
+ return 1;
382
+ }
383
+ if (cqe->res < 0) {
384
+ fprintf(stderr, "bad send cqe res: %d\n", cqe->res);
385
+ return 1;
386
+ }
387
+ bytes_needed -= cqe->res;
388
+ io_uring_cqe_seen(ring, cqe);
389
+ if (!bytes_needed)
390
+ break;
391
+ }
392
+
393
+ return 0;
394
+ }
395
+
396
+ static int do_send(struct recv_data *rd)
397
+ {
398
+ struct sockaddr_in saddr;
399
+ struct io_uring ring;
400
+ unsigned long seq_buf[SEQ_SIZE], send_seq;
401
+ struct io_uring_params p = { };
402
+ struct io_uring_buf_ring *br;
403
+ int sockfd, ret, len, i;
404
+ socklen_t optlen;
405
+ void *buf, *ptr;
406
+
407
+ ret = io_uring_queue_init_params(16, &ring, &p);
408
+ if (ret) {
409
+ fprintf(stderr, "queue init failed: %d\n", ret);
410
+ return 1;
411
+ }
412
+ if (!(p.features & IORING_FEAT_RECVSEND_BUNDLE)) {
413
+ no_send_mshot = 1;
414
+ return 0;
415
+ }
416
+
417
+ if (posix_memalign(&buf, 4096, MSG_SIZE * nr_msgs))
418
+ return 1;
419
+
420
+ br = io_uring_setup_buf_ring(&ring, nr_msgs, SEND_BGID, 0, &ret);
421
+ if (!br) {
422
+ if (ret == -EINVAL) {
423
+ fprintf(stderr, "einval on br setup\n");
424
+ return 0;
425
+ }
426
+ fprintf(stderr, "failed setting up send ring %d\n", ret);
427
+ return 1;
428
+ }
429
+
430
+ ptr = buf;
431
+ for (i = 0; i < nr_msgs; i++) {
432
+ io_uring_buf_ring_add(br, ptr, MSG_SIZE, i, nr_msgs - 1, i);
433
+ ptr += MSG_SIZE;
434
+ }
435
+ io_uring_buf_ring_advance(br, nr_msgs);
436
+
437
+ memset(&saddr, 0, sizeof(saddr));
438
+ saddr.sin_family = AF_INET;
439
+ saddr.sin_port = htons(use_port);
440
+ inet_pton(AF_INET, HOST, &saddr.sin_addr);
441
+
442
+ if (use_tcp)
443
+ sockfd = socket(AF_INET, SOCK_STREAM, 0);
444
+ else
445
+ sockfd = socket(AF_INET, SOCK_DGRAM, 0);
446
+ if (sockfd < 0) {
447
+ perror("socket");
448
+ goto err2;
449
+ }
450
+
451
+ pthread_barrier_wait(&rd->connect);
452
+
453
+ ret = connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr));
454
+ if (ret < 0) {
455
+ perror("connect");
456
+ goto err;
457
+ }
458
+
459
+ pthread_barrier_wait(&rd->startup);
460
+
461
+ optlen = sizeof(len);
462
+ len = 1024 * MSG_SIZE;
463
+ setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &len, optlen);
464
+
465
+ /* almost fill queue, leave room for one message */
466
+ send_seq = 0;
467
+ rd->to_eagain = 0;
468
+ while (rd->max_sends && rd->max_sends--) {
469
+ for (i = 0; i < SEQ_SIZE; i++)
470
+ seq_buf[i] = send_seq++;
471
+
472
+ ret = send(sockfd, seq_buf, sizeof(seq_buf), MSG_DONTWAIT);
473
+ if (ret < 0) {
474
+ if (errno == EAGAIN) {
475
+ send_seq -= SEQ_SIZE;
476
+ break;
477
+ }
478
+ perror("send");
479
+ return 1;
480
+ } else if (ret != sizeof(seq_buf)) {
481
+ fprintf(stderr, "short %d send\n", ret);
482
+ return 1;
483
+ }
484
+
485
+ rd->to_eagain++;
486
+ rd->recv_bytes += sizeof(seq_buf);
487
+ }
488
+
489
+ ptr = buf;
490
+ for (i = 0; i < nr_msgs; i++) {
491
+ unsigned long *pseq = ptr;
492
+ int j;
493
+
494
+ for (j = 0; j < SEQ_SIZE; j++)
495
+ pseq[j] = send_seq++;
496
+ ptr += MSG_SIZE;
497
+ }
498
+
499
+ /* prepare more messages, sending with bundle */
500
+ rd->recv_bytes += (nr_msgs * MSG_SIZE);
501
+ if (rd->send_bundle && use_tcp)
502
+ ret = __do_send_bundle(rd, &ring, sockfd);
503
+ else
504
+ ret = __do_send(rd, &ring, sockfd);
505
+ if (ret)
506
+ goto err;
507
+
508
+ pthread_barrier_wait(&rd->finish);
509
+
510
+ close(sockfd);
511
+ io_uring_queue_exit(&ring);
512
+ return 0;
513
+
514
+ err:
515
+ close(sockfd);
516
+ err2:
517
+ io_uring_queue_exit(&ring);
518
+ pthread_barrier_wait(&rd->finish);
519
+ return 1;
520
+ }
521
+
522
+ static int test(int backlog, unsigned int max_sends, int *to_eagain,
523
+ int send_bundle, int recv_bundle)
524
+ {
525
+ pthread_t recv_thread;
526
+ struct recv_data rd;
527
+ int ret;
528
+ void *retval;
529
+
530
+ /* backlog not reliable on UDP, skip it */
531
+ if ((backlog || max_sends) && !use_tcp)
532
+ return T_EXIT_PASS;
533
+
534
+ memset(&rd, 0, sizeof(rd));
535
+ pthread_barrier_init(&rd.connect, NULL, 2);
536
+ pthread_barrier_init(&rd.startup, NULL, 2);
537
+ pthread_barrier_init(&rd.barrier, NULL, 2);
538
+ pthread_barrier_init(&rd.finish, NULL, 2);
539
+ rd.max_sends = max_sends;
540
+ if (to_eagain)
541
+ *to_eagain = 0;
542
+
543
+ rd.send_bundle = send_bundle;
544
+ rd.recv_bundle = recv_bundle;
545
+
546
+ ret = pthread_create(&recv_thread, NULL, recv_fn, &rd);
547
+ if (ret) {
548
+ fprintf(stderr, "Thread create failed: %d\n", ret);
549
+ return 1;
550
+ }
551
+
552
+ ret = do_send(&rd);
553
+ if (no_send_mshot)
554
+ return 0;
555
+
556
+ if (ret)
557
+ return ret;
558
+
559
+ pthread_join(recv_thread, &retval);
560
+ if (to_eagain)
561
+ *to_eagain = rd.to_eagain;
562
+ return (intptr_t)retval;
563
+ }
564
+
565
+ static int run_tests(int is_udp)
566
+ {
567
+ int ret, eagain_hit;
568
+
569
+ nr_msgs = NR_MIN_MSGS;
570
+
571
+ /* test basic send bundle first */
572
+ ret = test(0, 0, NULL, 0, 0);
573
+ if (ret) {
574
+ fprintf(stderr, "test a failed\n");
575
+ return T_EXIT_FAIL;
576
+ }
577
+ if (no_send_mshot)
578
+ return T_EXIT_SKIP;
579
+
580
+ /* test recv bundle */
581
+ ret = test(0, 0, NULL, 0, 1);
582
+ if (ret) {
583
+ fprintf(stderr, "test b failed\n");
584
+ return T_EXIT_FAIL;
585
+ }
586
+
587
+ /* test bundling recv and send */
588
+ ret = test(0, 0, NULL, 1, 1);
589
+ if (ret) {
590
+ fprintf(stderr, "test c failed\n");
591
+ return T_EXIT_FAIL;
592
+ }
593
+
594
+ /* test bundling with full socket */
595
+ ret = test(1, 1000000, &eagain_hit, 1, 1);
596
+ if (ret) {
597
+ fprintf(stderr, "test d failed\n");
598
+ return T_EXIT_FAIL;
599
+ }
600
+
601
+ /* test bundling with almost full socket */
602
+ ret = test(1, eagain_hit - (nr_msgs / 2), NULL, 1, 1);
603
+ if (ret) {
604
+ fprintf(stderr, "test e failed\n");
605
+ return T_EXIT_FAIL;
606
+ }
607
+
608
+ /* test recv bundle with almost full socket */
609
+ ret = test(1, eagain_hit - (nr_msgs / 2), NULL, 0, 1);
610
+ if (ret) {
611
+ fprintf(stderr, "test f failed\n");
612
+ return T_EXIT_FAIL;
613
+ }
614
+
615
+ if (is_udp)
616
+ return T_EXIT_PASS;
617
+
618
+ /* test send bundle with almost full socket */
619
+ ret = test(1, eagain_hit - (nr_msgs / 2), &eagain_hit, 1, 0);
620
+ if (ret) {
621
+ fprintf(stderr, "test g failed\n");
622
+ return T_EXIT_FAIL;
623
+ }
624
+
625
+ /* now repeat the last three tests, but with > FAST_UIOV segments */
626
+ nr_msgs = NR_MAX_MSGS;
627
+
628
+ /* test bundling with almost full socket */
629
+ ret = test(1, eagain_hit - (nr_msgs / 2), NULL, 1, 1);
630
+ if (ret) {
631
+ fprintf(stderr, "test h failed\n");
632
+ return T_EXIT_FAIL;
633
+ }
634
+
635
+ /* test recv bundle with almost full socket */
636
+ ret = test(1, eagain_hit - (nr_msgs / 2), NULL, 0, 1);
637
+ if (ret) {
638
+ fprintf(stderr, "test i failed\n");
639
+ return T_EXIT_FAIL;
640
+ }
641
+
642
+ /* test send bundle with almost full socket */
643
+ ret = test(1, eagain_hit - (nr_msgs / 2), &eagain_hit, 1, 0);
644
+ if (ret) {
645
+ fprintf(stderr, "test j failed\n");
646
+ return T_EXIT_FAIL;
647
+ }
648
+
649
+ return T_EXIT_PASS;
650
+ }
651
+
652
+ static int test_tcp(void)
653
+ {
654
+ int ret;
655
+
656
+ use_tcp = 1;
657
+ ret = run_tests(false);
658
+ if (ret == T_EXIT_FAIL)
659
+ fprintf(stderr, "TCP test case failed\n");
660
+ return ret;
661
+ }
662
+
663
+ static int test_udp(void)
664
+ {
665
+ int ret;
666
+
667
+ use_tcp = 0;
668
+ use_port++;
669
+ ret = run_tests(true);
670
+ if (ret == T_EXIT_FAIL)
671
+ fprintf(stderr, "UDP test case failed\n");
672
+ return ret;
673
+ }
674
+
675
+ int main(int argc, char *argv[])
676
+ {
677
+ int ret;
678
+
679
+ if (argc > 1)
680
+ return T_EXIT_SKIP;
681
+
682
+ ret = test_tcp();
683
+ if (ret != T_EXIT_PASS)
684
+ return ret;
685
+
686
+ ret = test_udp();
687
+ if (ret != T_EXIT_PASS)
688
+ return ret;
689
+
690
+ return T_EXIT_PASS;
691
+ }