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,112 @@
1
+ /* SPDX-License-Identifier: MIT */
2
+ /*
3
+ * Simple app that demonstrates how to setup an io_uring interface,
4
+ * submit and complete IO against it, and then tear it down.
5
+ *
6
+ * gcc -Wall -O2 -D_GNU_SOURCE -o io_uring-test io_uring-test.c -luring
7
+ */
8
+ #include <stdio.h>
9
+ #include <fcntl.h>
10
+ #include <string.h>
11
+ #include <stdlib.h>
12
+ #include <sys/types.h>
13
+ #include <sys/stat.h>
14
+ #include <unistd.h>
15
+ #include "liburing.h"
16
+
17
+ #define QD 4
18
+
19
+ int main(int argc, char *argv[])
20
+ {
21
+ struct io_uring ring;
22
+ int i, fd, ret, pending, done;
23
+ struct io_uring_sqe *sqe;
24
+ struct io_uring_cqe *cqe;
25
+ struct iovec *iovecs;
26
+ struct stat sb;
27
+ ssize_t fsize;
28
+ off_t offset;
29
+ void *buf;
30
+
31
+ if (argc < 2) {
32
+ printf("%s: file\n", argv[0]);
33
+ return 1;
34
+ }
35
+
36
+ ret = io_uring_queue_init(QD, &ring, 0);
37
+ if (ret < 0) {
38
+ fprintf(stderr, "queue_init: %s\n", strerror(-ret));
39
+ return 1;
40
+ }
41
+
42
+ fd = open(argv[1], O_RDONLY | O_DIRECT);
43
+ if (fd < 0) {
44
+ perror("open");
45
+ return 1;
46
+ }
47
+
48
+ if (fstat(fd, &sb) < 0) {
49
+ perror("fstat");
50
+ return 1;
51
+ }
52
+
53
+ fsize = 0;
54
+ iovecs = calloc(QD, sizeof(struct iovec));
55
+ for (i = 0; i < QD; i++) {
56
+ if (posix_memalign(&buf, 4096, 4096))
57
+ return 1;
58
+ iovecs[i].iov_base = buf;
59
+ iovecs[i].iov_len = 4096;
60
+ fsize += 4096;
61
+ }
62
+
63
+ offset = 0;
64
+ i = 0;
65
+ do {
66
+ sqe = io_uring_get_sqe(&ring);
67
+ if (!sqe)
68
+ break;
69
+ io_uring_prep_readv(sqe, fd, &iovecs[i], 1, offset);
70
+ offset += iovecs[i].iov_len;
71
+ i++;
72
+ if (offset >= sb.st_size)
73
+ break;
74
+ } while (1);
75
+
76
+ ret = io_uring_submit(&ring);
77
+ if (ret < 0) {
78
+ fprintf(stderr, "io_uring_submit: %s\n", strerror(-ret));
79
+ return 1;
80
+ } else if (ret != i) {
81
+ fprintf(stderr, "io_uring_submit submitted less %d\n", ret);
82
+ return 1;
83
+ }
84
+
85
+ done = 0;
86
+ pending = ret;
87
+ fsize = 0;
88
+ for (i = 0; i < pending; i++) {
89
+ ret = io_uring_wait_cqe(&ring, &cqe);
90
+ if (ret < 0) {
91
+ fprintf(stderr, "io_uring_wait_cqe: %s\n", strerror(-ret));
92
+ return 1;
93
+ }
94
+
95
+ done++;
96
+ ret = 0;
97
+ if (cqe->res != 4096 && cqe->res + fsize != sb.st_size) {
98
+ fprintf(stderr, "ret=%d, wanted 4096\n", cqe->res);
99
+ ret = 1;
100
+ }
101
+ fsize += cqe->res;
102
+ io_uring_cqe_seen(&ring, cqe);
103
+ if (ret)
104
+ break;
105
+ }
106
+
107
+ printf("Submitted=%d, completed=%d, bytes=%lu\n", pending, done,
108
+ (unsigned long) fsize);
109
+ close(fd);
110
+ io_uring_queue_exit(&ring);
111
+ return 0;
112
+ }
@@ -0,0 +1,403 @@
1
+ /* SPDX-License-Identifier: MIT */
2
+
3
+ #include <stdio.h>
4
+ #include <unistd.h>
5
+ #include <errno.h>
6
+ #include <sys/mman.h>
7
+ #include <stdlib.h>
8
+ #include <string.h>
9
+ #include <netinet/udp.h>
10
+ #include <arpa/inet.h>
11
+
12
+ #include "liburing.h"
13
+
14
+ #define QD 64
15
+ #define BUF_SHIFT 12 /* 4k */
16
+ #define CQES (QD * 16)
17
+ #define BUFFERS CQES
18
+ #define CONTROLLEN 0
19
+
20
+ struct sendmsg_ctx {
21
+ struct msghdr msg;
22
+ struct iovec iov;
23
+ };
24
+
25
+ struct ctx {
26
+ struct io_uring ring;
27
+ struct io_uring_buf_ring *buf_ring;
28
+ unsigned char *buffer_base;
29
+ struct msghdr msg;
30
+ int buf_shift;
31
+ int af;
32
+ bool verbose;
33
+ struct sendmsg_ctx send[BUFFERS];
34
+ size_t buf_ring_size;
35
+ };
36
+
37
+ static size_t buffer_size(struct ctx *ctx)
38
+ {
39
+ return 1U << ctx->buf_shift;
40
+ }
41
+
42
+ static unsigned char *get_buffer(struct ctx *ctx, int idx)
43
+ {
44
+ return ctx->buffer_base + (idx << ctx->buf_shift);
45
+ }
46
+
47
+ static int setup_buffer_pool(struct ctx *ctx)
48
+ {
49
+ int ret, i;
50
+ void *mapped;
51
+ struct io_uring_buf_reg reg = { .ring_addr = 0,
52
+ .ring_entries = BUFFERS,
53
+ .bgid = 0 };
54
+
55
+ ctx->buf_ring_size = (sizeof(struct io_uring_buf) + buffer_size(ctx)) * BUFFERS;
56
+ mapped = mmap(NULL, ctx->buf_ring_size, PROT_READ | PROT_WRITE,
57
+ MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
58
+ if (mapped == MAP_FAILED) {
59
+ fprintf(stderr, "buf_ring mmap: %s\n", strerror(errno));
60
+ return -1;
61
+ }
62
+ ctx->buf_ring = (struct io_uring_buf_ring *)mapped;
63
+
64
+ io_uring_buf_ring_init(ctx->buf_ring);
65
+
66
+ reg = (struct io_uring_buf_reg) {
67
+ .ring_addr = (unsigned long)ctx->buf_ring,
68
+ .ring_entries = BUFFERS,
69
+ .bgid = 0
70
+ };
71
+ ctx->buffer_base = (unsigned char *)ctx->buf_ring +
72
+ sizeof(struct io_uring_buf) * BUFFERS;
73
+
74
+ ret = io_uring_register_buf_ring(&ctx->ring, &reg, 0);
75
+ if (ret) {
76
+ fprintf(stderr, "buf_ring init failed: %s\n"
77
+ "NB This requires a kernel version >= 6.0\n",
78
+ strerror(-ret));
79
+ return ret;
80
+ }
81
+
82
+ for (i = 0; i < BUFFERS; i++) {
83
+ io_uring_buf_ring_add(ctx->buf_ring, get_buffer(ctx, i), buffer_size(ctx), i,
84
+ io_uring_buf_ring_mask(BUFFERS), i);
85
+ }
86
+ io_uring_buf_ring_advance(ctx->buf_ring, BUFFERS);
87
+
88
+ return 0;
89
+ }
90
+
91
+ static int setup_context(struct ctx *ctx)
92
+ {
93
+ struct io_uring_params params;
94
+ int ret;
95
+
96
+ memset(&params, 0, sizeof(params));
97
+ params.cq_entries = QD * 8;
98
+ params.flags = IORING_SETUP_SUBMIT_ALL | IORING_SETUP_COOP_TASKRUN |
99
+ IORING_SETUP_CQSIZE;
100
+
101
+ ret = io_uring_queue_init_params(QD, &ctx->ring, &params);
102
+ if (ret < 0) {
103
+ fprintf(stderr, "queue_init failed: %s\n"
104
+ "NB: This requires a kernel version >= 6.0\n",
105
+ strerror(-ret));
106
+ return ret;
107
+ }
108
+
109
+ ret = setup_buffer_pool(ctx);
110
+ if (ret)
111
+ io_uring_queue_exit(&ctx->ring);
112
+
113
+ memset(&ctx->msg, 0, sizeof(ctx->msg));
114
+ ctx->msg.msg_namelen = sizeof(struct sockaddr_storage);
115
+ ctx->msg.msg_controllen = CONTROLLEN;
116
+ return ret;
117
+ }
118
+
119
+ static int setup_sock(int af, int port)
120
+ {
121
+ int ret;
122
+ int fd;
123
+ uint16_t nport = port <= 0 ? 0 : htons(port);
124
+
125
+ fd = socket(af, SOCK_DGRAM, 0);
126
+ if (fd < 0) {
127
+ fprintf(stderr, "sock_init: %s\n", strerror(errno));
128
+ return -1;
129
+ }
130
+
131
+ if (af == AF_INET6) {
132
+ struct sockaddr_in6 addr6 = {
133
+ .sin6_family = af,
134
+ .sin6_port = nport,
135
+ .sin6_addr = IN6ADDR_ANY_INIT
136
+ };
137
+
138
+ ret = bind(fd, (struct sockaddr *) &addr6, sizeof(addr6));
139
+ } else {
140
+ struct sockaddr_in addr = {
141
+ .sin_family = af,
142
+ .sin_port = nport,
143
+ .sin_addr = { INADDR_ANY }
144
+ };
145
+
146
+ ret = bind(fd, (struct sockaddr *) &addr, sizeof(addr));
147
+ }
148
+
149
+ if (ret) {
150
+ fprintf(stderr, "sock_bind: %s\n", strerror(errno));
151
+ close(fd);
152
+ return -1;
153
+ }
154
+
155
+ if (port <= 0) {
156
+ int port;
157
+ struct sockaddr_storage s;
158
+ socklen_t sz = sizeof(s);
159
+
160
+ if (getsockname(fd, (struct sockaddr *)&s, &sz)) {
161
+ fprintf(stderr, "getsockname failed\n");
162
+ close(fd);
163
+ return -1;
164
+ }
165
+
166
+ port = ntohs(((struct sockaddr_in *)&s)->sin_port);
167
+ fprintf(stderr, "port bound to %d\n", port);
168
+ }
169
+
170
+ return fd;
171
+ }
172
+
173
+ static void cleanup_context(struct ctx *ctx)
174
+ {
175
+ munmap(ctx->buf_ring, ctx->buf_ring_size);
176
+ io_uring_queue_exit(&ctx->ring);
177
+ }
178
+
179
+ static bool get_sqe(struct ctx *ctx, struct io_uring_sqe **sqe)
180
+ {
181
+ *sqe = io_uring_get_sqe(&ctx->ring);
182
+
183
+ if (!*sqe) {
184
+ io_uring_submit(&ctx->ring);
185
+ *sqe = io_uring_get_sqe(&ctx->ring);
186
+ }
187
+ if (!*sqe) {
188
+ fprintf(stderr, "cannot get sqe\n");
189
+ return true;
190
+ }
191
+ return false;
192
+ }
193
+
194
+ static int add_recv(struct ctx *ctx, int idx)
195
+ {
196
+ struct io_uring_sqe *sqe;
197
+
198
+ if (get_sqe(ctx, &sqe))
199
+ return -1;
200
+
201
+ io_uring_prep_recvmsg_multishot(sqe, idx, &ctx->msg, MSG_TRUNC);
202
+ sqe->flags |= IOSQE_FIXED_FILE;
203
+
204
+ sqe->flags |= IOSQE_BUFFER_SELECT;
205
+ sqe->buf_group = 0;
206
+ io_uring_sqe_set_data64(sqe, BUFFERS + 1);
207
+ return 0;
208
+ }
209
+
210
+ static void recycle_buffer(struct ctx *ctx, int idx)
211
+ {
212
+ io_uring_buf_ring_add(ctx->buf_ring, get_buffer(ctx, idx), buffer_size(ctx), idx,
213
+ io_uring_buf_ring_mask(BUFFERS), 0);
214
+ io_uring_buf_ring_advance(ctx->buf_ring, 1);
215
+ }
216
+
217
+ static int process_cqe_send(struct ctx *ctx, struct io_uring_cqe *cqe)
218
+ {
219
+ int idx = cqe->user_data;
220
+
221
+ if (cqe->res < 0)
222
+ fprintf(stderr, "bad send %s\n", strerror(-cqe->res));
223
+ recycle_buffer(ctx, idx);
224
+ return 0;
225
+ }
226
+
227
+ static int process_cqe_recv(struct ctx *ctx, struct io_uring_cqe *cqe,
228
+ int fdidx)
229
+ {
230
+ int ret, idx;
231
+ struct io_uring_recvmsg_out *o;
232
+ struct io_uring_sqe *sqe;
233
+
234
+ if (!(cqe->flags & IORING_CQE_F_MORE)) {
235
+ ret = add_recv(ctx, fdidx);
236
+ if (ret)
237
+ return ret;
238
+ }
239
+
240
+ if (cqe->res == -ENOBUFS)
241
+ return 0;
242
+
243
+ if (!(cqe->flags & IORING_CQE_F_BUFFER) || cqe->res < 0) {
244
+ fprintf(stderr, "recv cqe bad res %d\n", cqe->res);
245
+ if (cqe->res == -EFAULT || cqe->res == -EINVAL)
246
+ fprintf(stderr,
247
+ "NB: This requires a kernel version >= 6.0\n");
248
+ return -1;
249
+ }
250
+ idx = cqe->flags >> 16;
251
+
252
+ o = io_uring_recvmsg_validate(get_buffer(ctx, cqe->flags >> 16),
253
+ cqe->res, &ctx->msg);
254
+ if (!o) {
255
+ fprintf(stderr, "bad recvmsg\n");
256
+ return -1;
257
+ }
258
+ if (o->namelen > ctx->msg.msg_namelen) {
259
+ fprintf(stderr, "truncated name\n");
260
+ recycle_buffer(ctx, idx);
261
+ return 0;
262
+ }
263
+ if (o->flags & MSG_TRUNC) {
264
+ unsigned int r;
265
+
266
+ r = io_uring_recvmsg_payload_length(o, cqe->res, &ctx->msg);
267
+ fprintf(stderr, "truncated msg need %u received %u\n",
268
+ o->payloadlen, r);
269
+ recycle_buffer(ctx, idx);
270
+ return 0;
271
+ }
272
+
273
+ if (ctx->verbose) {
274
+ struct sockaddr_in *addr = io_uring_recvmsg_name(o);
275
+ struct sockaddr_in6 *addr6 = (void *)addr;
276
+ char buff[INET6_ADDRSTRLEN + 1];
277
+ const char *name;
278
+ void *paddr;
279
+
280
+ if (ctx->af == AF_INET6)
281
+ paddr = &addr6->sin6_addr;
282
+ else
283
+ paddr = &addr->sin_addr;
284
+
285
+ name = inet_ntop(ctx->af, paddr, buff, sizeof(buff));
286
+ if (!name)
287
+ name = "<INVALID>";
288
+
289
+ fprintf(stderr, "received %u bytes %d from [%s]:%d\n",
290
+ io_uring_recvmsg_payload_length(o, cqe->res, &ctx->msg),
291
+ o->namelen, name, (int)ntohs(addr->sin_port));
292
+ }
293
+
294
+ if (get_sqe(ctx, &sqe))
295
+ return -1;
296
+
297
+ ctx->send[idx].iov = (struct iovec) {
298
+ .iov_base = io_uring_recvmsg_payload(o, &ctx->msg),
299
+ .iov_len =
300
+ io_uring_recvmsg_payload_length(o, cqe->res, &ctx->msg)
301
+ };
302
+ ctx->send[idx].msg = (struct msghdr) {
303
+ .msg_namelen = o->namelen,
304
+ .msg_name = io_uring_recvmsg_name(o),
305
+ .msg_control = NULL,
306
+ .msg_controllen = 0,
307
+ .msg_iov = &ctx->send[idx].iov,
308
+ .msg_iovlen = 1
309
+ };
310
+
311
+ io_uring_prep_sendmsg(sqe, fdidx, &ctx->send[idx].msg, 0);
312
+ io_uring_sqe_set_data64(sqe, idx);
313
+ sqe->flags |= IOSQE_FIXED_FILE;
314
+
315
+ return 0;
316
+ }
317
+ static int process_cqe(struct ctx *ctx, struct io_uring_cqe *cqe, int fdidx)
318
+ {
319
+ if (cqe->user_data < BUFFERS)
320
+ return process_cqe_send(ctx, cqe);
321
+ else
322
+ return process_cqe_recv(ctx, cqe, fdidx);
323
+ }
324
+
325
+ int main(int argc, char *argv[])
326
+ {
327
+ struct ctx ctx;
328
+ int ret;
329
+ int port = -1;
330
+ int sockfd;
331
+ int opt;
332
+ struct io_uring_cqe *cqes[CQES];
333
+ unsigned int count, i;
334
+
335
+ memset(&ctx, 0, sizeof(ctx));
336
+ ctx.verbose = false;
337
+ ctx.af = AF_INET;
338
+ ctx.buf_shift = BUF_SHIFT;
339
+
340
+ while ((opt = getopt(argc, argv, "6vp:b:")) != -1) {
341
+ switch (opt) {
342
+ case '6':
343
+ ctx.af = AF_INET6;
344
+ break;
345
+ case 'p':
346
+ port = atoi(optarg);
347
+ break;
348
+ case 'b':
349
+ ctx.buf_shift = atoi(optarg);
350
+ break;
351
+ case 'v':
352
+ ctx.verbose = true;
353
+ break;
354
+ default:
355
+ fprintf(stderr, "Usage: %s [-p port] "
356
+ "[-b log2(BufferSize)] [-6] [-v]\n",
357
+ argv[0]);
358
+ exit(-1);
359
+ }
360
+ }
361
+
362
+ sockfd = setup_sock(ctx.af, port);
363
+ if (sockfd < 0)
364
+ return 1;
365
+
366
+ if (setup_context(&ctx)) {
367
+ close(sockfd);
368
+ return 1;
369
+ }
370
+
371
+ ret = io_uring_register_files(&ctx.ring, &sockfd, 1);
372
+ if (ret) {
373
+ fprintf(stderr, "register files: %s\n", strerror(-ret));
374
+ return -1;
375
+ }
376
+
377
+ ret = add_recv(&ctx, 0);
378
+ if (ret)
379
+ return 1;
380
+
381
+ while (true) {
382
+ ret = io_uring_submit_and_wait(&ctx.ring, 1);
383
+ if (ret == -EINTR)
384
+ continue;
385
+ if (ret < 0) {
386
+ fprintf(stderr, "submit and wait failed %d\n", ret);
387
+ break;
388
+ }
389
+
390
+ count = io_uring_peek_batch_cqe(&ctx.ring, &cqes[0], CQES);
391
+ for (i = 0; i < count; i++) {
392
+ ret = process_cqe(&ctx, cqes[i], 0);
393
+ if (ret)
394
+ goto cleanup;
395
+ }
396
+ io_uring_cq_advance(&ctx.ring, count);
397
+ }
398
+
399
+ cleanup:
400
+ cleanup_context(&ctx);
401
+ close(sockfd);
402
+ return ret;
403
+ }
@@ -0,0 +1,193 @@
1
+ /* SPDX-License-Identifier: MIT */
2
+ /*
3
+ * Very basic proof-of-concept for doing a copy with linked SQEs. Needs a
4
+ * bit of error handling and short read love.
5
+ */
6
+ #include <stdio.h>
7
+ #include <fcntl.h>
8
+ #include <string.h>
9
+ #include <stdlib.h>
10
+ #include <unistd.h>
11
+ #include <assert.h>
12
+ #include <errno.h>
13
+ #include <inttypes.h>
14
+ #include <sys/types.h>
15
+ #include <sys/stat.h>
16
+ #include <sys/ioctl.h>
17
+ #include "liburing.h"
18
+
19
+ #define QD 64
20
+ #define BS (32*1024)
21
+
22
+ struct io_data {
23
+ size_t offset;
24
+ int index;
25
+ struct iovec iov;
26
+ };
27
+
28
+ static int infd, outfd;
29
+ static int inflight;
30
+
31
+ static int setup_context(unsigned entries, struct io_uring *ring)
32
+ {
33
+ int ret;
34
+
35
+ ret = io_uring_queue_init(entries, ring, 0);
36
+ if (ret < 0) {
37
+ fprintf(stderr, "queue_init: %s\n", strerror(-ret));
38
+ return -1;
39
+ }
40
+
41
+ return 0;
42
+ }
43
+
44
+ static int get_file_size(int fd, off_t *size)
45
+ {
46
+ struct stat st;
47
+
48
+ if (fstat(fd, &st) < 0)
49
+ return -1;
50
+ if (S_ISREG(st.st_mode)) {
51
+ *size = st.st_size;
52
+ return 0;
53
+ } else if (S_ISBLK(st.st_mode)) {
54
+ unsigned long long bytes;
55
+
56
+ if (ioctl(fd, BLKGETSIZE64, &bytes) != 0)
57
+ return -1;
58
+
59
+ *size = bytes;
60
+ return 0;
61
+ }
62
+
63
+ return -1;
64
+ }
65
+
66
+ static void queue_rw_pair(struct io_uring *ring, off_t size, off_t offset)
67
+ {
68
+ struct io_uring_sqe *sqe;
69
+ struct io_data *data;
70
+ void *ptr;
71
+
72
+ ptr = malloc(size + sizeof(*data));
73
+ data = ptr + size;
74
+ data->index = 0;
75
+ data->offset = offset;
76
+ data->iov.iov_base = ptr;
77
+ data->iov.iov_len = size;
78
+
79
+ sqe = io_uring_get_sqe(ring);
80
+ io_uring_prep_readv(sqe, infd, &data->iov, 1, offset);
81
+ sqe->flags |= IOSQE_IO_LINK;
82
+ io_uring_sqe_set_data(sqe, data);
83
+
84
+ sqe = io_uring_get_sqe(ring);
85
+ io_uring_prep_writev(sqe, outfd, &data->iov, 1, offset);
86
+ io_uring_sqe_set_data(sqe, data);
87
+ }
88
+
89
+ static int handle_cqe(struct io_uring *ring, struct io_uring_cqe *cqe)
90
+ {
91
+ struct io_data *data = io_uring_cqe_get_data(cqe);
92
+ int ret = 0;
93
+
94
+ data->index++;
95
+
96
+ if (cqe->res < 0) {
97
+ if (cqe->res == -ECANCELED) {
98
+ queue_rw_pair(ring, data->iov.iov_len, data->offset);
99
+ inflight += 2;
100
+ } else {
101
+ printf("cqe error: %s\n", strerror(-cqe->res));
102
+ ret = 1;
103
+ }
104
+ }
105
+
106
+ if (data->index == 2) {
107
+ void *ptr = (void *) data - data->iov.iov_len;
108
+
109
+ free(ptr);
110
+ }
111
+ io_uring_cqe_seen(ring, cqe);
112
+ return ret;
113
+ }
114
+
115
+ static int copy_file(struct io_uring *ring, off_t insize)
116
+ {
117
+ struct io_uring_cqe *cqe;
118
+ off_t this_size;
119
+ off_t offset;
120
+
121
+ offset = 0;
122
+ while (insize) {
123
+ int has_inflight = inflight;
124
+ int depth;
125
+
126
+ while (insize && inflight < QD) {
127
+ this_size = BS;
128
+ if (this_size > insize)
129
+ this_size = insize;
130
+ queue_rw_pair(ring, this_size, offset);
131
+ offset += this_size;
132
+ insize -= this_size;
133
+ inflight += 2;
134
+ }
135
+
136
+ if (has_inflight != inflight)
137
+ io_uring_submit(ring);
138
+
139
+ if (insize)
140
+ depth = QD;
141
+ else
142
+ depth = 1;
143
+ while (inflight >= depth) {
144
+ int ret;
145
+
146
+ ret = io_uring_wait_cqe(ring, &cqe);
147
+ if (ret < 0) {
148
+ printf("wait cqe: %s\n", strerror(-ret));
149
+ return 1;
150
+ }
151
+ if (handle_cqe(ring, cqe))
152
+ return 1;
153
+ inflight--;
154
+ }
155
+ }
156
+
157
+ return 0;
158
+ }
159
+
160
+ int main(int argc, char *argv[])
161
+ {
162
+ struct io_uring ring;
163
+ off_t insize;
164
+ int ret;
165
+
166
+ if (argc < 3) {
167
+ printf("%s: infile outfile\n", argv[0]);
168
+ return 1;
169
+ }
170
+
171
+ infd = open(argv[1], O_RDONLY);
172
+ if (infd < 0) {
173
+ perror("open infile");
174
+ return 1;
175
+ }
176
+ outfd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644);
177
+ if (outfd < 0) {
178
+ perror("open outfile");
179
+ return 1;
180
+ }
181
+
182
+ if (setup_context(QD, &ring))
183
+ return 1;
184
+ if (get_file_size(infd, &insize))
185
+ return 1;
186
+
187
+ ret = copy_file(&ring, insize);
188
+
189
+ close(infd);
190
+ close(outfd);
191
+ io_uring_queue_exit(&ring);
192
+ return ret;
193
+ }