iou 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 (297) hide show
  1. checksums.yaml +7 -0
  2. data/.github/dependabot.yml +12 -0
  3. data/.gitignore +59 -0
  4. data/.gitmodules +3 -0
  5. data/Gemfile +3 -0
  6. data/LICENSE +21 -0
  7. data/README.md +106 -0
  8. data/Rakefile +39 -0
  9. data/TODO.md +4 -0
  10. data/examples/echo_server.rb +52 -0
  11. data/examples/event_loop.rb +69 -0
  12. data/examples/http_server.rb +56 -0
  13. data/examples/http_server_multishot.rb +59 -0
  14. data/ext/iou/extconf.rb +71 -0
  15. data/ext/iou/iou.c +729 -0
  16. data/ext/iou/iou.h +66 -0
  17. data/ext/iou/iou_ext.c +9 -0
  18. data/ext/iou/op_spec_data.c +61 -0
  19. data/iou.gemspec +27 -0
  20. data/lib/iou/version.rb +5 -0
  21. data/lib/iou.rb +3 -0
  22. data/test/helper.rb +59 -0
  23. data/test/test_iou.rb +794 -0
  24. data/vendor/liburing/.github/actions/codespell/stopwords +7 -0
  25. data/vendor/liburing/.github/pull_request_template.md +86 -0
  26. data/vendor/liburing/.github/workflows/build.yml +137 -0
  27. data/vendor/liburing/.github/workflows/codespell.yml +25 -0
  28. data/vendor/liburing/.github/workflows/shellcheck.yml +20 -0
  29. data/vendor/liburing/.gitignore +41 -0
  30. data/vendor/liburing/CHANGELOG +111 -0
  31. data/vendor/liburing/CITATION.cff +11 -0
  32. data/vendor/liburing/COPYING +502 -0
  33. data/vendor/liburing/COPYING.GPL +339 -0
  34. data/vendor/liburing/LICENSE +20 -0
  35. data/vendor/liburing/Makefile +96 -0
  36. data/vendor/liburing/Makefile.common +7 -0
  37. data/vendor/liburing/Makefile.quiet +11 -0
  38. data/vendor/liburing/README +106 -0
  39. data/vendor/liburing/SECURITY.md +6 -0
  40. data/vendor/liburing/configure +624 -0
  41. data/vendor/liburing/debian/README.Debian +7 -0
  42. data/vendor/liburing/debian/changelog +38 -0
  43. data/vendor/liburing/debian/control +39 -0
  44. data/vendor/liburing/debian/copyright +49 -0
  45. data/vendor/liburing/debian/liburing-dev.install +4 -0
  46. data/vendor/liburing/debian/liburing-dev.manpages +5 -0
  47. data/vendor/liburing/debian/liburing2.install +1 -0
  48. data/vendor/liburing/debian/liburing2.symbols +56 -0
  49. data/vendor/liburing/debian/patches/series +1 -0
  50. data/vendor/liburing/debian/rules +29 -0
  51. data/vendor/liburing/debian/source/format +1 -0
  52. data/vendor/liburing/debian/source/local-options +2 -0
  53. data/vendor/liburing/debian/source/options +1 -0
  54. data/vendor/liburing/debian/watch +3 -0
  55. data/vendor/liburing/examples/Makefile +53 -0
  56. data/vendor/liburing/examples/helpers.c +62 -0
  57. data/vendor/liburing/examples/helpers.h +7 -0
  58. data/vendor/liburing/examples/io_uring-close-test.c +123 -0
  59. data/vendor/liburing/examples/io_uring-cp.c +282 -0
  60. data/vendor/liburing/examples/io_uring-test.c +112 -0
  61. data/vendor/liburing/examples/io_uring-udp.c +403 -0
  62. data/vendor/liburing/examples/link-cp.c +193 -0
  63. data/vendor/liburing/examples/napi-busy-poll-client.c +509 -0
  64. data/vendor/liburing/examples/napi-busy-poll-server.c +450 -0
  65. data/vendor/liburing/examples/poll-bench.c +101 -0
  66. data/vendor/liburing/examples/proxy.c +2461 -0
  67. data/vendor/liburing/examples/proxy.h +102 -0
  68. data/vendor/liburing/examples/rsrc-update-bench.c +100 -0
  69. data/vendor/liburing/examples/send-zerocopy.c +658 -0
  70. data/vendor/liburing/examples/ucontext-cp.c +258 -0
  71. data/vendor/liburing/liburing-ffi.pc.in +12 -0
  72. data/vendor/liburing/liburing.pc.in +12 -0
  73. data/vendor/liburing/liburing.spec +66 -0
  74. data/vendor/liburing/make-debs.sh +55 -0
  75. data/vendor/liburing/src/Makefile +129 -0
  76. data/vendor/liburing/src/arch/aarch64/lib.h +47 -0
  77. data/vendor/liburing/src/arch/aarch64/syscall.h +91 -0
  78. data/vendor/liburing/src/arch/generic/lib.h +17 -0
  79. data/vendor/liburing/src/arch/generic/syscall.h +100 -0
  80. data/vendor/liburing/src/arch/riscv64/lib.h +48 -0
  81. data/vendor/liburing/src/arch/riscv64/syscall.h +100 -0
  82. data/vendor/liburing/src/arch/syscall-defs.h +94 -0
  83. data/vendor/liburing/src/arch/x86/lib.h +11 -0
  84. data/vendor/liburing/src/arch/x86/syscall.h +296 -0
  85. data/vendor/liburing/src/ffi.c +15 -0
  86. data/vendor/liburing/src/include/liburing/barrier.h +81 -0
  87. data/vendor/liburing/src/include/liburing/io_uring.h +818 -0
  88. data/vendor/liburing/src/include/liburing.h +1602 -0
  89. data/vendor/liburing/src/int_flags.h +11 -0
  90. data/vendor/liburing/src/lib.h +52 -0
  91. data/vendor/liburing/src/liburing-ffi.map +211 -0
  92. data/vendor/liburing/src/liburing.map +104 -0
  93. data/vendor/liburing/src/nolibc.c +55 -0
  94. data/vendor/liburing/src/queue.c +468 -0
  95. data/vendor/liburing/src/register.c +374 -0
  96. data/vendor/liburing/src/setup.c +689 -0
  97. data/vendor/liburing/src/setup.h +9 -0
  98. data/vendor/liburing/src/syscall.c +29 -0
  99. data/vendor/liburing/src/syscall.h +53 -0
  100. data/vendor/liburing/src/version.c +21 -0
  101. data/vendor/liburing/test/232c93d07b74.c +305 -0
  102. data/vendor/liburing/test/35fa71a030ca.c +329 -0
  103. data/vendor/liburing/test/500f9fbadef8.c +91 -0
  104. data/vendor/liburing/test/7ad0e4b2f83c.c +94 -0
  105. data/vendor/liburing/test/8a9973408177.c +107 -0
  106. data/vendor/liburing/test/917257daa0fe.c +54 -0
  107. data/vendor/liburing/test/Makefile +297 -0
  108. data/vendor/liburing/test/a0908ae19763.c +59 -0
  109. data/vendor/liburing/test/a4c0b3decb33.c +181 -0
  110. data/vendor/liburing/test/accept-link.c +255 -0
  111. data/vendor/liburing/test/accept-non-empty.c +256 -0
  112. data/vendor/liburing/test/accept-reuse.c +163 -0
  113. data/vendor/liburing/test/accept-test.c +83 -0
  114. data/vendor/liburing/test/accept.c +919 -0
  115. data/vendor/liburing/test/across-fork.c +284 -0
  116. data/vendor/liburing/test/b19062a56726.c +54 -0
  117. data/vendor/liburing/test/b5837bd5311d.c +78 -0
  118. data/vendor/liburing/test/bind-listen.c +408 -0
  119. data/vendor/liburing/test/buf-ring-nommap.c +123 -0
  120. data/vendor/liburing/test/buf-ring-put.c +83 -0
  121. data/vendor/liburing/test/buf-ring.c +473 -0
  122. data/vendor/liburing/test/ce593a6c480a.c +139 -0
  123. data/vendor/liburing/test/close-opath.c +123 -0
  124. data/vendor/liburing/test/config +14 -0
  125. data/vendor/liburing/test/connect-rep.c +204 -0
  126. data/vendor/liburing/test/connect.c +442 -0
  127. data/vendor/liburing/test/coredump.c +60 -0
  128. data/vendor/liburing/test/cq-full.c +97 -0
  129. data/vendor/liburing/test/cq-overflow.c +530 -0
  130. data/vendor/liburing/test/cq-peek-batch.c +103 -0
  131. data/vendor/liburing/test/cq-ready.c +95 -0
  132. data/vendor/liburing/test/cq-size.c +65 -0
  133. data/vendor/liburing/test/d4ae271dfaae.c +96 -0
  134. data/vendor/liburing/test/d77a67ed5f27.c +65 -0
  135. data/vendor/liburing/test/defer-taskrun.c +391 -0
  136. data/vendor/liburing/test/defer-tw-timeout.c +173 -0
  137. data/vendor/liburing/test/defer.c +319 -0
  138. data/vendor/liburing/test/double-poll-crash.c +195 -0
  139. data/vendor/liburing/test/drop-submit.c +94 -0
  140. data/vendor/liburing/test/eeed8b54e0df.c +120 -0
  141. data/vendor/liburing/test/empty-eownerdead.c +45 -0
  142. data/vendor/liburing/test/eploop.c +74 -0
  143. data/vendor/liburing/test/eventfd-disable.c +179 -0
  144. data/vendor/liburing/test/eventfd-reg.c +77 -0
  145. data/vendor/liburing/test/eventfd-ring.c +98 -0
  146. data/vendor/liburing/test/eventfd.c +113 -0
  147. data/vendor/liburing/test/evloop.c +73 -0
  148. data/vendor/liburing/test/exec-target.c +6 -0
  149. data/vendor/liburing/test/exit-no-cleanup.c +117 -0
  150. data/vendor/liburing/test/fadvise.c +202 -0
  151. data/vendor/liburing/test/fallocate.c +265 -0
  152. data/vendor/liburing/test/fc2a85cb02ef.c +132 -0
  153. data/vendor/liburing/test/fd-install.c +500 -0
  154. data/vendor/liburing/test/fd-pass.c +237 -0
  155. data/vendor/liburing/test/fdinfo.c +419 -0
  156. data/vendor/liburing/test/file-register.c +1189 -0
  157. data/vendor/liburing/test/file-update.c +231 -0
  158. data/vendor/liburing/test/file-verify.c +654 -0
  159. data/vendor/liburing/test/files-exit-hang-poll.c +114 -0
  160. data/vendor/liburing/test/files-exit-hang-timeout.c +137 -0
  161. data/vendor/liburing/test/fixed-buf-iter.c +115 -0
  162. data/vendor/liburing/test/fixed-buf-merge.c +101 -0
  163. data/vendor/liburing/test/fixed-hugepage.c +411 -0
  164. data/vendor/liburing/test/fixed-link.c +90 -0
  165. data/vendor/liburing/test/fixed-reuse.c +160 -0
  166. data/vendor/liburing/test/fpos.c +255 -0
  167. data/vendor/liburing/test/fsnotify.c +118 -0
  168. data/vendor/liburing/test/fsync.c +224 -0
  169. data/vendor/liburing/test/futex.c +571 -0
  170. data/vendor/liburing/test/hardlink.c +170 -0
  171. data/vendor/liburing/test/helpers.c +318 -0
  172. data/vendor/liburing/test/helpers.h +108 -0
  173. data/vendor/liburing/test/ignore-single-mmap.c +48 -0
  174. data/vendor/liburing/test/init-mem.c +164 -0
  175. data/vendor/liburing/test/io-cancel.c +561 -0
  176. data/vendor/liburing/test/io_uring_enter.c +264 -0
  177. data/vendor/liburing/test/io_uring_passthrough.c +482 -0
  178. data/vendor/liburing/test/io_uring_register.c +503 -0
  179. data/vendor/liburing/test/io_uring_setup.c +110 -0
  180. data/vendor/liburing/test/iopoll-leak.c +85 -0
  181. data/vendor/liburing/test/iopoll-overflow.c +118 -0
  182. data/vendor/liburing/test/iopoll.c +465 -0
  183. data/vendor/liburing/test/lfs-openat-write.c +119 -0
  184. data/vendor/liburing/test/lfs-openat.c +273 -0
  185. data/vendor/liburing/test/link-timeout.c +1108 -0
  186. data/vendor/liburing/test/link.c +497 -0
  187. data/vendor/liburing/test/link_drain.c +255 -0
  188. data/vendor/liburing/test/madvise.c +195 -0
  189. data/vendor/liburing/test/min-timeout-wait.c +354 -0
  190. data/vendor/liburing/test/min-timeout.c +233 -0
  191. data/vendor/liburing/test/mkdir.c +112 -0
  192. data/vendor/liburing/test/msg-ring-fd.c +331 -0
  193. data/vendor/liburing/test/msg-ring-flags.c +212 -0
  194. data/vendor/liburing/test/msg-ring-overflow.c +159 -0
  195. data/vendor/liburing/test/msg-ring.c +467 -0
  196. data/vendor/liburing/test/multicqes_drain.c +429 -0
  197. data/vendor/liburing/test/napi-test.c +215 -0
  198. data/vendor/liburing/test/napi-test.sh +48 -0
  199. data/vendor/liburing/test/no-mmap-inval.c +42 -0
  200. data/vendor/liburing/test/nolibc.c +62 -0
  201. data/vendor/liburing/test/nop-all-sizes.c +99 -0
  202. data/vendor/liburing/test/nop.c +177 -0
  203. data/vendor/liburing/test/nvme.h +169 -0
  204. data/vendor/liburing/test/ooo-file-unreg.c +82 -0
  205. data/vendor/liburing/test/open-close.c +261 -0
  206. data/vendor/liburing/test/open-direct-link.c +188 -0
  207. data/vendor/liburing/test/open-direct-pick.c +180 -0
  208. data/vendor/liburing/test/openat2.c +312 -0
  209. data/vendor/liburing/test/personality.c +204 -0
  210. data/vendor/liburing/test/pipe-bug.c +95 -0
  211. data/vendor/liburing/test/pipe-eof.c +83 -0
  212. data/vendor/liburing/test/pipe-reuse.c +105 -0
  213. data/vendor/liburing/test/poll-cancel-all.c +496 -0
  214. data/vendor/liburing/test/poll-cancel-ton.c +135 -0
  215. data/vendor/liburing/test/poll-cancel.c +228 -0
  216. data/vendor/liburing/test/poll-link.c +221 -0
  217. data/vendor/liburing/test/poll-many.c +230 -0
  218. data/vendor/liburing/test/poll-mshot-overflow.c +265 -0
  219. data/vendor/liburing/test/poll-mshot-update.c +323 -0
  220. data/vendor/liburing/test/poll-race-mshot.c +276 -0
  221. data/vendor/liburing/test/poll-race.c +105 -0
  222. data/vendor/liburing/test/poll-ring.c +48 -0
  223. data/vendor/liburing/test/poll-v-poll.c +353 -0
  224. data/vendor/liburing/test/poll.c +327 -0
  225. data/vendor/liburing/test/probe.c +135 -0
  226. data/vendor/liburing/test/read-before-exit.c +129 -0
  227. data/vendor/liburing/test/read-mshot-empty.c +153 -0
  228. data/vendor/liburing/test/read-mshot.c +404 -0
  229. data/vendor/liburing/test/read-write.c +1013 -0
  230. data/vendor/liburing/test/recv-msgall-stream.c +398 -0
  231. data/vendor/liburing/test/recv-msgall.c +263 -0
  232. data/vendor/liburing/test/recv-multishot.c +602 -0
  233. data/vendor/liburing/test/recvsend_bundle.c +691 -0
  234. data/vendor/liburing/test/reg-fd-only.c +131 -0
  235. data/vendor/liburing/test/reg-hint.c +56 -0
  236. data/vendor/liburing/test/reg-reg-ring.c +90 -0
  237. data/vendor/liburing/test/regbuf-merge.c +91 -0
  238. data/vendor/liburing/test/register-restrictions.c +633 -0
  239. data/vendor/liburing/test/rename.c +132 -0
  240. data/vendor/liburing/test/ring-leak.c +283 -0
  241. data/vendor/liburing/test/ring-leak2.c +249 -0
  242. data/vendor/liburing/test/ringbuf-read.c +196 -0
  243. data/vendor/liburing/test/ringbuf-status.c +242 -0
  244. data/vendor/liburing/test/rsrc_tags.c +461 -0
  245. data/vendor/liburing/test/runtests-loop.sh +16 -0
  246. data/vendor/liburing/test/runtests-quiet.sh +11 -0
  247. data/vendor/liburing/test/runtests.sh +168 -0
  248. data/vendor/liburing/test/rw_merge_test.c +98 -0
  249. data/vendor/liburing/test/self.c +91 -0
  250. data/vendor/liburing/test/send-zerocopy.c +971 -0
  251. data/vendor/liburing/test/send_recv.c +412 -0
  252. data/vendor/liburing/test/send_recvmsg.c +444 -0
  253. data/vendor/liburing/test/shared-wq.c +84 -0
  254. data/vendor/liburing/test/short-read.c +75 -0
  255. data/vendor/liburing/test/shutdown.c +165 -0
  256. data/vendor/liburing/test/sigfd-deadlock.c +88 -0
  257. data/vendor/liburing/test/single-issuer.c +169 -0
  258. data/vendor/liburing/test/skip-cqe.c +428 -0
  259. data/vendor/liburing/test/socket-getsetsock-cmd.c +346 -0
  260. data/vendor/liburing/test/socket-io-cmd.c +237 -0
  261. data/vendor/liburing/test/socket-rw-eagain.c +149 -0
  262. data/vendor/liburing/test/socket-rw-offset.c +149 -0
  263. data/vendor/liburing/test/socket-rw.c +137 -0
  264. data/vendor/liburing/test/socket.c +408 -0
  265. data/vendor/liburing/test/splice.c +512 -0
  266. data/vendor/liburing/test/sq-full-cpp.cc +45 -0
  267. data/vendor/liburing/test/sq-full.c +45 -0
  268. data/vendor/liburing/test/sq-poll-dup.c +211 -0
  269. data/vendor/liburing/test/sq-poll-kthread.c +169 -0
  270. data/vendor/liburing/test/sq-poll-share.c +138 -0
  271. data/vendor/liburing/test/sq-space_left.c +159 -0
  272. data/vendor/liburing/test/sqpoll-disable-exit.c +196 -0
  273. data/vendor/liburing/test/sqpoll-exec.c +132 -0
  274. data/vendor/liburing/test/sqpoll-exit-hang.c +78 -0
  275. data/vendor/liburing/test/sqpoll-sleep.c +69 -0
  276. data/vendor/liburing/test/statx.c +172 -0
  277. data/vendor/liburing/test/stdout.c +232 -0
  278. data/vendor/liburing/test/submit-and-wait.c +108 -0
  279. data/vendor/liburing/test/submit-link-fail.c +156 -0
  280. data/vendor/liburing/test/submit-reuse.c +237 -0
  281. data/vendor/liburing/test/symlink.c +117 -0
  282. data/vendor/liburing/test/sync-cancel.c +235 -0
  283. data/vendor/liburing/test/teardowns.c +58 -0
  284. data/vendor/liburing/test/test.h +36 -0
  285. data/vendor/liburing/test/thread-exit.c +143 -0
  286. data/vendor/liburing/test/timeout-new.c +256 -0
  287. data/vendor/liburing/test/timeout.c +1798 -0
  288. data/vendor/liburing/test/truncate.c +186 -0
  289. data/vendor/liburing/test/tty-write-dpoll.c +60 -0
  290. data/vendor/liburing/test/unlink.c +112 -0
  291. data/vendor/liburing/test/version.c +25 -0
  292. data/vendor/liburing/test/wait-timeout.c +287 -0
  293. data/vendor/liburing/test/waitid.c +373 -0
  294. data/vendor/liburing/test/wakeup-hang.c +162 -0
  295. data/vendor/liburing/test/wq-aff.c +146 -0
  296. data/vendor/liburing/test/xattr.c +442 -0
  297. metadata +402 -0
data/ext/iou/iou.c ADDED
@@ -0,0 +1,729 @@
1
+ #include "iou.h"
2
+ #include "ruby/thread.h"
3
+ #include <sys/mman.h>
4
+
5
+ VALUE mIOU;
6
+ VALUE cRing;
7
+ VALUE cArgumentError;
8
+
9
+ VALUE SYM_accept;
10
+ VALUE SYM_block;
11
+ VALUE SYM_buffer;
12
+ VALUE SYM_buffer_group;
13
+ VALUE SYM_buffer_offset;
14
+ VALUE SYM_close;
15
+ VALUE SYM_count;
16
+ VALUE SYM_emit;
17
+ VALUE SYM_fd;
18
+ VALUE SYM_id;
19
+ VALUE SYM_interval;
20
+ VALUE SYM_len;
21
+ VALUE SYM_multishot;
22
+ VALUE SYM_op;
23
+ VALUE SYM_read;
24
+ VALUE SYM_result;
25
+ VALUE SYM_signal;
26
+ VALUE SYM_size;
27
+ VALUE SYM_spec_data;
28
+ VALUE SYM_stop;
29
+ VALUE SYM_timeout;
30
+ VALUE SYM_utf8;
31
+ VALUE SYM_write;
32
+
33
+ static void IOU_mark(void *ptr) {
34
+ IOU_t *iou = ptr;
35
+ rb_gc_mark_movable(iou->pending_ops);
36
+ }
37
+
38
+ static void IOU_compact(void *ptr) {
39
+ IOU_t *iou = ptr;
40
+ iou->pending_ops = rb_gc_location(iou->pending_ops);
41
+ }
42
+
43
+ void cleanup_iou(IOU_t *iou) {
44
+ if (!iou->ring_initialized) return;
45
+
46
+ for (unsigned i = 0; i < iou->br_counter; i++) {
47
+ struct buf_ring_descriptor *desc = iou->brs + i;
48
+ io_uring_free_buf_ring(&iou->ring, desc->br, desc->buf_count, i);
49
+ free(desc->buf_base);
50
+ }
51
+ iou->br_counter = 0;
52
+ io_uring_queue_exit(&iou->ring);
53
+ iou->ring_initialized = 0;
54
+ }
55
+
56
+ static void IOU_free(void *ptr) {
57
+ cleanup_iou((IOU_t *)ptr);
58
+ }
59
+
60
+ static size_t IOU_size(const void *ptr) {
61
+ return sizeof(IOU_t);
62
+ }
63
+
64
+ static const rb_data_type_t IOU_type = {
65
+ "IOURing",
66
+ {IOU_mark, IOU_free, IOU_size, IOU_compact},
67
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
68
+ };
69
+
70
+ static VALUE IOU_allocate(VALUE klass) {
71
+ IOU_t *iou = ALLOC(IOU_t);
72
+
73
+ return TypedData_Wrap_Struct(klass, &IOU_type, iou);
74
+ }
75
+
76
+ VALUE IOU_initialize(VALUE self) {
77
+ IOU_t *iou = RTYPEDDATA_DATA(self);
78
+
79
+ iou->ring_initialized = 0;
80
+ iou->op_counter = 0;
81
+ iou->unsubmitted_sqes = 0;
82
+ iou->br_counter = 0;
83
+
84
+ iou->pending_ops = rb_hash_new();
85
+
86
+ unsigned prepared_limit = 1024;
87
+ int flags = 0;
88
+ #ifdef HAVE_IORING_SETUP_SUBMIT_ALL
89
+ flags |= IORING_SETUP_SUBMIT_ALL;
90
+ #endif
91
+ #ifdef HAVE_IORING_SETUP_COOP_TASKRUN
92
+ flags |= IORING_SETUP_COOP_TASKRUN;
93
+ #endif
94
+
95
+ while (1) {
96
+ int ret = io_uring_queue_init(prepared_limit, &iou->ring, flags);
97
+ if (likely(!ret)) break;
98
+
99
+ // if ENOMEM is returned, try with half as much entries
100
+ if (unlikely(ret == -ENOMEM && prepared_limit > 64))
101
+ prepared_limit = prepared_limit / 2;
102
+ else
103
+ rb_syserr_fail(-ret, strerror(-ret));
104
+ }
105
+ iou->ring_initialized = 1;
106
+
107
+ return self;
108
+ }
109
+
110
+ VALUE IOU_close(VALUE self) {
111
+ IOU_t *iou = RTYPEDDATA_DATA(self);
112
+ cleanup_iou(iou);
113
+ return self;
114
+ }
115
+
116
+ VALUE IOU_closed_p(VALUE self) {
117
+ IOU_t *iou = RTYPEDDATA_DATA(self);
118
+ return iou->ring_initialized ? Qfalse : Qtrue;
119
+ }
120
+
121
+ VALUE IOU_pending_ops(VALUE self) {
122
+ IOU_t *iou = RTYPEDDATA_DATA(self);
123
+ return iou->pending_ops;
124
+ }
125
+
126
+ inline IOU_t *get_iou(VALUE self) {
127
+ IOU_t *iou = RTYPEDDATA_DATA(self);
128
+ if (!iou->ring_initialized)
129
+ rb_raise(rb_eRuntimeError, "IOU ring was not initialized");
130
+ return iou;
131
+ }
132
+
133
+ static inline struct io_uring_sqe *get_sqe(IOU_t *iou) {
134
+ struct io_uring_sqe *sqe;
135
+ sqe = io_uring_get_sqe(&iou->ring);
136
+ if (likely(sqe)) goto done;
137
+
138
+ rb_raise(rb_eRuntimeError, "Failed to get SQE");
139
+
140
+ // TODO: retry getting SQE?
141
+
142
+ // if (likely(backend->pending_sqes))
143
+ // io_uring_backend_immediate_submit(backend);
144
+ // else {
145
+ // VALUE resume_value = backend_snooze(&backend->base);
146
+ // RAISE_IF_EXCEPTION(resume_value);
147
+ // }
148
+ done:
149
+ return sqe;
150
+ }
151
+
152
+ static inline void get_required_kwargs(VALUE spec, VALUE *values, int argc, ...) {
153
+ if (TYPE(spec) != T_HASH)
154
+ rb_raise(cArgumentError, "Expected keyword arguments");
155
+
156
+ va_list ptr;
157
+ va_start(ptr, argc);
158
+ for (int i = 0; i < argc; i++) {
159
+ VALUE k = va_arg(ptr, VALUE);
160
+ VALUE v = rb_hash_aref(spec, k);
161
+ if (NIL_P(v))
162
+ rb_raise(cArgumentError, "Missing %"PRIsVALUE" value", k);
163
+ values[i] = v;
164
+ }
165
+ va_end(ptr);
166
+ }
167
+
168
+ VALUE IOU_setup_buffer_ring(VALUE self, VALUE opts) {
169
+ IOU_t *iou = get_iou(self);
170
+
171
+ if (iou->br_counter == BUFFER_RING_MAX_COUNT)
172
+ rb_raise(rb_eRuntimeError, "Cannot setup more than BUFFER_RING_MAX_COUNT buffer rings");
173
+
174
+ VALUE values[2];
175
+ get_required_kwargs(opts, values, 2, SYM_count, SYM_size);
176
+ VALUE count = values[0];
177
+ VALUE size = values[1];
178
+
179
+ struct buf_ring_descriptor *desc = iou->brs + iou->br_counter;
180
+ desc->buf_count = NUM2UINT(count);
181
+ desc->buf_size = NUM2UINT(size);
182
+
183
+ desc->br_size = sizeof(struct io_uring_buf) * desc->buf_count;
184
+ void *mapped = mmap(
185
+ NULL, desc->br_size, PROT_READ | PROT_WRITE,
186
+ MAP_ANONYMOUS | MAP_PRIVATE, 0, 0
187
+ );
188
+ if (mapped == MAP_FAILED)
189
+ rb_raise(rb_eRuntimeError, "Failed to allocate buffer ring");
190
+
191
+ desc->br = (struct io_uring_buf_ring *)mapped;
192
+ io_uring_buf_ring_init(desc->br);
193
+
194
+ unsigned bg_id = iou->br_counter;
195
+ struct io_uring_buf_reg reg = {
196
+ .ring_addr = (unsigned long)desc->br,
197
+ .ring_entries = desc->buf_count,
198
+ .bgid = bg_id
199
+ };
200
+ int ret = io_uring_register_buf_ring(&iou->ring, &reg, 0);
201
+ if (ret) {
202
+ munmap(desc->br, desc->br_size);
203
+ rb_syserr_fail(-ret, strerror(-ret));
204
+ }
205
+
206
+ desc->buf_base = malloc(desc->buf_count * desc->buf_size);
207
+ if (!desc->buf_base) {
208
+ io_uring_free_buf_ring(&iou->ring, desc->br, desc->buf_count, bg_id);
209
+ rb_raise(rb_eRuntimeError, "Failed to allocate buffers");
210
+ }
211
+
212
+ int mask = io_uring_buf_ring_mask(desc->buf_count);
213
+ for (unsigned i = 0; i < desc->buf_count; i++) {
214
+ io_uring_buf_ring_add(
215
+ desc->br, desc->buf_base + i * desc->buf_size, desc->buf_size,
216
+ i, mask, i);
217
+ }
218
+ io_uring_buf_ring_advance(desc->br, desc->buf_count);
219
+ iou->br_counter++;
220
+ return UINT2NUM(bg_id);
221
+ }
222
+
223
+ inline void store_spec(IOU_t *iou, VALUE spec, VALUE id, VALUE op) {
224
+ rb_hash_aset(spec, SYM_id, id);
225
+ rb_hash_aset(spec, SYM_op, op);
226
+ if (rb_block_given_p())
227
+ rb_hash_aset(spec, SYM_block, rb_block_proc());
228
+ rb_hash_aset(iou->pending_ops, id, spec);
229
+ }
230
+
231
+ VALUE IOU_emit(VALUE self, VALUE obj) {
232
+ IOU_t *iou = get_iou(self);
233
+ unsigned id_i = ++iou->op_counter;
234
+ VALUE id = UINT2NUM(id_i);
235
+
236
+ struct io_uring_sqe *sqe = get_sqe(iou);
237
+ sqe->user_data = id_i;
238
+ store_spec(iou, obj, id, SYM_emit);
239
+
240
+ io_uring_prep_nop(sqe);
241
+
242
+ // immediately submit
243
+ io_uring_submit(&iou->ring);
244
+ iou->unsubmitted_sqes = 0;
245
+
246
+ return id;
247
+ }
248
+
249
+ VALUE IOU_prep_accept(VALUE self, VALUE spec) {
250
+ IOU_t *iou = get_iou(self);
251
+ unsigned id_i = ++iou->op_counter;
252
+ VALUE id = UINT2NUM(id_i);
253
+
254
+ VALUE values[1];
255
+ get_required_kwargs(spec, values, 1, SYM_fd);
256
+ VALUE fd = values[0];
257
+ VALUE multishot = rb_hash_aref(spec, SYM_multishot);
258
+
259
+ VALUE spec_data = rb_funcall(cOpSpecData, rb_intern("new"), 0);
260
+ struct io_uring_sqe *sqe = get_sqe(iou);
261
+ sqe->user_data = id_i;
262
+ rb_hash_aset(spec, SYM_spec_data, spec_data);
263
+ store_spec(iou, spec, id, SYM_accept);
264
+
265
+ struct sa_data *sa = OpSpecData_sa_get(spec_data);
266
+ if (RTEST(multishot))
267
+ io_uring_prep_multishot_accept(sqe, NUM2INT(fd), &sa->addr, &sa->len, 0);
268
+ else
269
+ io_uring_prep_accept(sqe, NUM2INT(fd), &sa->addr, &sa->len, 0);
270
+ iou->unsubmitted_sqes++;
271
+ return id;
272
+ }
273
+
274
+ VALUE prep_cancel_id(IOU_t *iou, unsigned op_id_i) {
275
+ unsigned id_i = ++iou->op_counter;
276
+ VALUE id = UINT2NUM(id_i);
277
+
278
+ struct io_uring_sqe *sqe = get_sqe(iou);
279
+ io_uring_prep_cancel64(sqe, op_id_i, 0);
280
+ sqe->user_data = id_i;
281
+ iou->unsubmitted_sqes++;
282
+
283
+ return id;
284
+ }
285
+
286
+ VALUE IOU_prep_cancel(VALUE self, VALUE spec) {
287
+ IOU_t *iou = get_iou(self);
288
+
289
+ if (TYPE(spec) == T_FIXNUM)
290
+ return prep_cancel_id(iou, NUM2UINT(spec));
291
+
292
+ if (TYPE(spec) != T_HASH)
293
+ rb_raise(cArgumentError, "Expected operation id or keyword arguments");
294
+
295
+ VALUE id = rb_hash_aref(spec, SYM_id);
296
+ if (!NIL_P(id))
297
+ return prep_cancel_id(iou, NUM2UINT(id));
298
+
299
+ rb_raise(cArgumentError, "Missing operation id");
300
+ }
301
+
302
+ VALUE IOU_prep_close(VALUE self, VALUE spec) {
303
+ IOU_t *iou = get_iou(self);
304
+ unsigned id_i = ++iou->op_counter;
305
+ VALUE id = UINT2NUM(id_i);
306
+
307
+ VALUE values[1];
308
+ get_required_kwargs(spec, values, 1, SYM_fd);
309
+ VALUE fd = values[0];
310
+
311
+ struct io_uring_sqe *sqe = get_sqe(iou);
312
+ sqe->user_data = id_i;
313
+ store_spec(iou, spec, id, SYM_close);
314
+
315
+ io_uring_prep_close(sqe, NUM2INT(fd));
316
+ iou->unsubmitted_sqes++;
317
+ return id;
318
+ }
319
+
320
+ VALUE IOU_prep_nop(VALUE self) {
321
+ IOU_t *iou = get_iou(self);
322
+ unsigned id_i = ++iou->op_counter;
323
+ VALUE id = UINT2NUM(id_i);
324
+
325
+ struct io_uring_sqe *sqe = get_sqe(iou);
326
+ io_uring_prep_nop(sqe);
327
+ sqe->user_data = id_i;
328
+ iou->unsubmitted_sqes++;
329
+
330
+ return id;
331
+ }
332
+
333
+ static inline void * prepare_read_buffer(VALUE buffer, unsigned len, int ofs) {
334
+ unsigned current_len = RSTRING_LEN(buffer);
335
+ if (ofs < 0) ofs = current_len + ofs + 1;
336
+ unsigned new_len = len + (unsigned)ofs;
337
+
338
+ if (current_len < new_len)
339
+ rb_str_modify_expand(buffer, new_len);
340
+ else
341
+ rb_str_modify(buffer);
342
+ return RSTRING_PTR(buffer) + ofs;
343
+ }
344
+
345
+ static inline void adjust_read_buffer_len(VALUE buffer, int result, int ofs) {
346
+ rb_str_modify(buffer);
347
+ unsigned len = result > 0 ? (unsigned)result : 0;
348
+ unsigned current_len = RSTRING_LEN(buffer);
349
+ if (ofs < 0) ofs = current_len + ofs + 1;
350
+ rb_str_set_len(buffer, len + (unsigned)ofs);
351
+ }
352
+
353
+ VALUE prep_read_multishot(IOU_t *iou, VALUE spec) {
354
+ unsigned id_i = ++iou->op_counter;
355
+ VALUE id = UINT2NUM(id_i);
356
+
357
+ VALUE values[2];
358
+ get_required_kwargs(spec, values, 2, SYM_fd, SYM_buffer_group);
359
+ int fd = NUM2INT(values[0]);
360
+ unsigned bg_id = NUM2UINT(values[1]);
361
+
362
+ struct io_uring_sqe *sqe = get_sqe(iou);
363
+ sqe->user_data = id_i;
364
+ store_spec(iou, spec, id, SYM_read);
365
+
366
+ io_uring_prep_read_multishot(sqe, fd, 0, -1, bg_id);
367
+ iou->unsubmitted_sqes++;
368
+ return id;
369
+ }
370
+
371
+ VALUE IOU_prep_read(VALUE self, VALUE spec) {
372
+ IOU_t *iou = get_iou(self);
373
+
374
+ if (RTEST(rb_hash_aref(spec, SYM_multishot)))
375
+ return prep_read_multishot(iou, spec);
376
+
377
+ unsigned id_i = ++iou->op_counter;
378
+ VALUE id = UINT2NUM(id_i);
379
+
380
+ VALUE values[3];
381
+ get_required_kwargs(spec, values, 3, SYM_fd, SYM_buffer, SYM_len);
382
+
383
+ VALUE fd = values[0];
384
+ VALUE buffer = values[1];
385
+ VALUE len = values[2];
386
+ unsigned len_i = NUM2UINT(len);
387
+
388
+ VALUE buffer_offset = rb_hash_aref(spec, SYM_buffer_offset);
389
+ int buffer_offset_i = NIL_P(buffer_offset) ? 0 : NUM2INT(buffer_offset);
390
+
391
+ struct io_uring_sqe *sqe = get_sqe(iou);
392
+ sqe->user_data = id_i;
393
+ store_spec(iou, spec, id, SYM_read);
394
+
395
+ void *ptr = prepare_read_buffer(buffer, len_i, buffer_offset_i);
396
+ io_uring_prep_read(sqe, NUM2INT(fd), ptr, len_i, -1);
397
+ iou->unsubmitted_sqes++;
398
+ return id;
399
+ }
400
+
401
+ VALUE IOU_prep_timeout(VALUE self, VALUE spec) {
402
+ IOU_t *iou = get_iou(self);
403
+ unsigned id_i = ++iou->op_counter;
404
+ VALUE id = UINT2NUM(id_i);
405
+
406
+ VALUE values[1];
407
+ get_required_kwargs(spec, values, 1, SYM_interval);
408
+ VALUE interval = values[0];
409
+ VALUE multishot = rb_hash_aref(spec, SYM_multishot);
410
+ unsigned flags = RTEST(multishot) ? IORING_TIMEOUT_MULTISHOT : 0;
411
+
412
+ VALUE spec_data = rb_funcall(cOpSpecData, rb_intern("new"), 0);
413
+ OpSpecData_ts_set(spec_data, interval);
414
+
415
+ struct io_uring_sqe *sqe = get_sqe(iou);
416
+ sqe->user_data = id_i;
417
+ rb_hash_aset(spec, SYM_spec_data, spec_data);
418
+ store_spec(iou, spec, id, SYM_timeout);
419
+
420
+ io_uring_prep_timeout(sqe, OpSpecData_ts_get(spec_data), 0, flags);
421
+ iou->unsubmitted_sqes++;
422
+ return id;
423
+ }
424
+
425
+ VALUE IOU_prep_write(VALUE self, VALUE spec) {
426
+ IOU_t *iou = get_iou(self);
427
+ unsigned id_i = ++iou->op_counter;
428
+ VALUE id = UINT2NUM(id_i);
429
+
430
+ VALUE values[2];
431
+ get_required_kwargs(spec, values, 2, SYM_fd, SYM_buffer);
432
+ VALUE fd = values[0];
433
+ VALUE buffer = values[1];
434
+ VALUE len = rb_hash_aref(spec, SYM_len);
435
+ unsigned nbytes = NIL_P(len) ? RSTRING_LEN(buffer) : NUM2UINT(len);
436
+
437
+ struct io_uring_sqe *sqe = get_sqe(iou);
438
+ sqe->user_data = id_i;
439
+ store_spec(iou, spec, id, SYM_write);
440
+
441
+ io_uring_prep_write(sqe, NUM2INT(fd), RSTRING_PTR(buffer), nbytes, -1);
442
+ iou->unsubmitted_sqes++;
443
+ return id;
444
+ }
445
+
446
+ VALUE IOU_submit(VALUE self) {
447
+ IOU_t *iou = get_iou(self);
448
+ if (!iou->unsubmitted_sqes) goto done;
449
+
450
+ iou->unsubmitted_sqes = 0;
451
+ int ret = io_uring_submit(&iou->ring);
452
+ if (ret < 0)
453
+ rb_syserr_fail(-ret, strerror(-ret));
454
+
455
+ done:
456
+ return self;
457
+ }
458
+
459
+ inline VALUE make_empty_op_with_result(VALUE id, VALUE result) {
460
+ VALUE hash = rb_hash_new();
461
+ rb_hash_aset(hash, SYM_id, id);
462
+ rb_hash_aset(hash, SYM_result, result);
463
+ RB_GC_GUARD(hash);
464
+ return hash;
465
+ }
466
+
467
+ typedef struct {
468
+ IOU_t *iou;
469
+ struct io_uring_cqe *cqe;
470
+ int ret;
471
+ } wait_for_completion_ctx_t;
472
+
473
+ void *wait_for_completion_without_gvl(void *ptr) {
474
+ wait_for_completion_ctx_t *ctx = (wait_for_completion_ctx_t *)ptr;
475
+ ctx->ret = io_uring_wait_cqe(&ctx->iou->ring, &ctx->cqe);
476
+ return NULL;
477
+ }
478
+
479
+ static inline void update_read_buffer_from_buffer_ring(IOU_t *iou, VALUE spec, struct io_uring_cqe *cqe) {
480
+ VALUE buf = Qnil;
481
+ if (cqe->res == 0) {
482
+ buf = rb_str_new_literal("");
483
+ goto done;
484
+ }
485
+
486
+ unsigned bg_id = NUM2UINT(rb_hash_aref(spec, SYM_buffer_group));
487
+ unsigned buf_idx = cqe->flags >> IORING_CQE_BUFFER_SHIFT;
488
+
489
+ struct buf_ring_descriptor *desc = iou->brs + bg_id;
490
+ char *src = desc->buf_base + desc->buf_size * buf_idx;
491
+ buf = rb_str_new(src, cqe->res);
492
+
493
+ // release buffer back to io_uring
494
+ io_uring_buf_ring_add(
495
+ desc->br, src, desc->buf_size, buf_idx,
496
+ io_uring_buf_ring_mask(desc->buf_count), 0
497
+ );
498
+ io_uring_buf_ring_advance(desc->br, 1);
499
+ done:
500
+ rb_hash_aset(spec, SYM_buffer, buf);
501
+ RB_GC_GUARD(buf);
502
+ return;
503
+ }
504
+
505
+ static inline void update_read_buffer(IOU_t *iou, VALUE spec, struct io_uring_cqe *cqe) {
506
+ if (cqe->res < 0) return;
507
+
508
+ if (cqe->flags & IORING_CQE_F_BUFFER) {
509
+ update_read_buffer_from_buffer_ring(iou, spec, cqe);
510
+ return;
511
+ }
512
+
513
+ if (cqe->res == 0) return;
514
+
515
+ VALUE buffer = rb_hash_aref(spec, SYM_buffer);
516
+ VALUE buffer_offset = rb_hash_aref(spec, SYM_buffer_offset);
517
+ int buffer_offset_i = NIL_P(buffer_offset) ? 0 : NUM2INT(buffer_offset);
518
+ adjust_read_buffer_len(buffer, cqe->res, buffer_offset_i);
519
+ }
520
+
521
+ inline int is_stop_signal(VALUE op, VALUE spec) {
522
+ return (op == SYM_emit) && (rb_hash_aref(spec, SYM_signal) == SYM_stop);
523
+ }
524
+
525
+ static inline VALUE get_cqe_op_spec(IOU_t *iou, struct io_uring_cqe *cqe, int *stop_flag) {
526
+ VALUE id = UINT2NUM(cqe->user_data);
527
+ VALUE spec = rb_hash_aref(iou->pending_ops, id);
528
+ VALUE result = INT2NUM(cqe->res);
529
+ if (NIL_P(spec))
530
+ return make_empty_op_with_result(id, result);
531
+
532
+ // post completion work
533
+ VALUE op = rb_hash_aref(spec, SYM_op);
534
+ if (op == SYM_read)
535
+ update_read_buffer(iou, spec, cqe);
536
+ else if (stop_flag && is_stop_signal(op, spec))
537
+ *stop_flag = 1;
538
+
539
+ // for multishot ops, the IORING_CQE_F_MORE flag indicates more completions
540
+ // will be coming, so we need to keep the spec. Otherwise, we remove it.
541
+ if (!(cqe->flags & IORING_CQE_F_MORE))
542
+ rb_hash_delete(iou->pending_ops, id);
543
+
544
+ rb_hash_aset(spec, SYM_result, result);
545
+ RB_GC_GUARD(spec);
546
+ return spec;
547
+ }
548
+
549
+ VALUE IOU_wait_for_completion(VALUE self) {
550
+ IOU_t *iou = get_iou(self);
551
+
552
+ wait_for_completion_ctx_t ctx = {
553
+ .iou = iou
554
+ };
555
+
556
+ rb_thread_call_without_gvl(wait_for_completion_without_gvl, (void *)&ctx, RUBY_UBF_IO, 0);
557
+
558
+ if (unlikely(ctx.ret < 0)) {
559
+ rb_syserr_fail(-ctx.ret, strerror(-ctx.ret));
560
+ }
561
+ io_uring_cqe_seen(&iou->ring, ctx.cqe);
562
+ return get_cqe_op_spec(iou, ctx.cqe, 0);
563
+ }
564
+
565
+ static inline void process_cqe(IOU_t *iou, struct io_uring_cqe *cqe, int *stop_flag) {
566
+ if (stop_flag) *stop_flag = 0;
567
+ VALUE spec = get_cqe_op_spec(iou, cqe, stop_flag);
568
+ if (stop_flag && *stop_flag) return;
569
+
570
+ if (rb_block_given_p())
571
+ rb_yield(spec);
572
+ else {
573
+ VALUE block = rb_hash_aref(spec, SYM_block);
574
+ if (RTEST(block))
575
+ rb_proc_call_with_block_kw(block, 1, &spec, Qnil, Qnil);
576
+ }
577
+
578
+ RB_GC_GUARD(spec);
579
+ }
580
+
581
+ // copied from liburing/queue.c
582
+ static inline bool cq_ring_needs_flush(struct io_uring *ring) {
583
+ return IO_URING_READ_ONCE(*ring->sq.kflags) & IORING_SQ_CQ_OVERFLOW;
584
+ }
585
+
586
+ // adapted from io_uring_peek_batch_cqe in liburing/queue.c
587
+ // this peeks at cqes and handles each available cqe
588
+ static inline int process_ready_cqes(IOU_t *iou, int *stop_flag) {
589
+ unsigned total_count = 0;
590
+
591
+ iterate:
592
+ bool overflow_checked = false;
593
+ struct io_uring_cqe *cqe;
594
+ unsigned head;
595
+ unsigned count = 0;
596
+ io_uring_for_each_cqe(&iou->ring, head, cqe) {
597
+ ++count;
598
+ if (stop_flag) *stop_flag = 0;
599
+ process_cqe(iou, cqe, stop_flag);
600
+ if (stop_flag && *stop_flag)
601
+ break;
602
+ }
603
+ io_uring_cq_advance(&iou->ring, count);
604
+ total_count += count;
605
+
606
+ if (overflow_checked) goto done;
607
+ if (stop_flag && *stop_flag) goto done;
608
+
609
+ if (cq_ring_needs_flush(&iou->ring)) {
610
+ io_uring_enter(iou->ring.ring_fd, 0, 0, IORING_ENTER_GETEVENTS, NULL);
611
+ overflow_checked = true;
612
+ goto iterate;
613
+ }
614
+
615
+ done:
616
+ return total_count;
617
+ }
618
+
619
+ VALUE IOU_process_completions(int argc, VALUE *argv, VALUE self) {
620
+ IOU_t *iou = get_iou(self);
621
+ VALUE wait;
622
+
623
+ rb_scan_args(argc, argv, "01", &wait);
624
+ int wait_i = RTEST(wait);
625
+ unsigned count = 0;
626
+
627
+ // automatically submit any unsubmitted SQEs
628
+ if (iou->unsubmitted_sqes) {
629
+ io_uring_submit(&iou->ring);
630
+ iou->unsubmitted_sqes = 0;
631
+ }
632
+
633
+ if (wait_i) {
634
+ wait_for_completion_ctx_t ctx = { .iou = iou };
635
+
636
+ rb_thread_call_without_gvl(wait_for_completion_without_gvl, (void *)&ctx, RUBY_UBF_IO, 0);
637
+ if (unlikely(ctx.ret < 0)) {
638
+ rb_syserr_fail(-ctx.ret, strerror(-ctx.ret));
639
+ }
640
+ ++count;
641
+ io_uring_cqe_seen(&iou->ring, ctx.cqe);
642
+ process_cqe(iou, ctx.cqe, 0);
643
+ }
644
+
645
+ count += process_ready_cqes(iou, 0);
646
+ return UINT2NUM(count);
647
+ }
648
+
649
+ VALUE IOU_process_completions_loop(VALUE self) {
650
+ IOU_t *iou = get_iou(self);
651
+ int stop_flag = 0;
652
+ wait_for_completion_ctx_t ctx = { .iou = iou };
653
+
654
+ while (1) {
655
+ // automatically submit any unsubmitted SQEs
656
+ if (iou->unsubmitted_sqes) {
657
+ io_uring_submit(&iou->ring);
658
+ iou->unsubmitted_sqes = 0;
659
+ }
660
+
661
+ rb_thread_call_without_gvl(wait_for_completion_without_gvl, (void *)&ctx, RUBY_UBF_IO, 0);
662
+ if (unlikely(ctx.ret < 0)) {
663
+ rb_syserr_fail(-ctx.ret, strerror(-ctx.ret));
664
+ }
665
+ io_uring_cqe_seen(&iou->ring, ctx.cqe);
666
+ process_cqe(iou, ctx.cqe, &stop_flag);
667
+ if (stop_flag) goto done;
668
+
669
+ process_ready_cqes(iou, &stop_flag);
670
+ if (stop_flag) goto done;
671
+ }
672
+ done:
673
+ return self;
674
+ }
675
+
676
+ #define MAKE_SYM(sym) ID2SYM(rb_intern(sym))
677
+
678
+ void Init_IOU(void) {
679
+ mIOU = rb_define_module("IOU");
680
+ cRing = rb_define_class_under(mIOU, "Ring", rb_cObject);
681
+ rb_define_alloc_func(cRing, IOU_allocate);
682
+
683
+ rb_define_method(cRing, "initialize", IOU_initialize, 0);
684
+ rb_define_method(cRing, "close", IOU_close, 0);
685
+ rb_define_method(cRing, "closed?", IOU_closed_p, 0);
686
+ rb_define_method(cRing, "pending_ops", IOU_pending_ops, 0);
687
+ rb_define_method(cRing, "setup_buffer_ring", IOU_setup_buffer_ring, 1);
688
+
689
+ rb_define_method(cRing, "emit", IOU_emit, 1);
690
+
691
+ rb_define_method(cRing, "prep_accept", IOU_prep_accept, 1);
692
+ rb_define_method(cRing, "prep_cancel", IOU_prep_cancel, 1);
693
+ rb_define_method(cRing, "prep_close", IOU_prep_close, 1);
694
+ rb_define_method(cRing, "prep_nop", IOU_prep_nop, 0);
695
+ rb_define_method(cRing, "prep_read", IOU_prep_read, 1);
696
+ rb_define_method(cRing, "prep_timeout", IOU_prep_timeout, 1);
697
+ rb_define_method(cRing, "prep_write", IOU_prep_write, 1);
698
+
699
+ rb_define_method(cRing, "submit", IOU_submit, 0);
700
+ rb_define_method(cRing, "wait_for_completion", IOU_wait_for_completion, 0);
701
+ rb_define_method(cRing, "process_completions", IOU_process_completions, -1);
702
+ rb_define_method(cRing, "process_completions_loop", IOU_process_completions_loop, 0);
703
+
704
+ cArgumentError = rb_const_get(rb_cObject, rb_intern("ArgumentError"));
705
+
706
+ SYM_accept = MAKE_SYM("accept");
707
+ SYM_block = MAKE_SYM("block");
708
+ SYM_buffer = MAKE_SYM("buffer");
709
+ SYM_buffer_group = MAKE_SYM("buffer_group");
710
+ SYM_buffer_offset = MAKE_SYM("buffer_offset");
711
+ SYM_close = MAKE_SYM("close");
712
+ SYM_count = MAKE_SYM("count");
713
+ SYM_emit = MAKE_SYM("emit");
714
+ SYM_fd = MAKE_SYM("fd");
715
+ SYM_id = MAKE_SYM("id");
716
+ SYM_interval = MAKE_SYM("interval");
717
+ SYM_len = MAKE_SYM("len");
718
+ SYM_multishot = MAKE_SYM("multishot");
719
+ SYM_op = MAKE_SYM("op");
720
+ SYM_read = MAKE_SYM("read");
721
+ SYM_result = MAKE_SYM("result");
722
+ SYM_signal = MAKE_SYM("signal");
723
+ SYM_size = MAKE_SYM("size");
724
+ SYM_spec_data = MAKE_SYM("spec_data");
725
+ SYM_stop = MAKE_SYM("stop");
726
+ SYM_timeout = MAKE_SYM("timeout");
727
+ SYM_utf8 = MAKE_SYM("utf8");
728
+ SYM_write = MAKE_SYM("write");
729
+ }