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.
- checksums.yaml +7 -0
- data/.github/dependabot.yml +12 -0
- data/.gitignore +59 -0
- data/.gitmodules +3 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +106 -0
- data/Rakefile +39 -0
- data/TODO.md +4 -0
- data/examples/echo_server.rb +52 -0
- data/examples/event_loop.rb +69 -0
- data/examples/http_server.rb +56 -0
- data/examples/http_server_multishot.rb +59 -0
- data/ext/iou/extconf.rb +71 -0
- data/ext/iou/iou.c +729 -0
- data/ext/iou/iou.h +66 -0
- data/ext/iou/iou_ext.c +9 -0
- data/ext/iou/op_spec_data.c +61 -0
- data/iou.gemspec +27 -0
- data/lib/iou/version.rb +5 -0
- data/lib/iou.rb +3 -0
- data/test/helper.rb +59 -0
- data/test/test_iou.rb +794 -0
- data/vendor/liburing/.github/actions/codespell/stopwords +7 -0
- data/vendor/liburing/.github/pull_request_template.md +86 -0
- data/vendor/liburing/.github/workflows/build.yml +137 -0
- data/vendor/liburing/.github/workflows/codespell.yml +25 -0
- data/vendor/liburing/.github/workflows/shellcheck.yml +20 -0
- data/vendor/liburing/.gitignore +41 -0
- data/vendor/liburing/CHANGELOG +111 -0
- data/vendor/liburing/CITATION.cff +11 -0
- data/vendor/liburing/COPYING +502 -0
- data/vendor/liburing/COPYING.GPL +339 -0
- data/vendor/liburing/LICENSE +20 -0
- data/vendor/liburing/Makefile +96 -0
- data/vendor/liburing/Makefile.common +7 -0
- data/vendor/liburing/Makefile.quiet +11 -0
- data/vendor/liburing/README +106 -0
- data/vendor/liburing/SECURITY.md +6 -0
- data/vendor/liburing/configure +624 -0
- data/vendor/liburing/debian/README.Debian +7 -0
- data/vendor/liburing/debian/changelog +38 -0
- data/vendor/liburing/debian/control +39 -0
- data/vendor/liburing/debian/copyright +49 -0
- data/vendor/liburing/debian/liburing-dev.install +4 -0
- data/vendor/liburing/debian/liburing-dev.manpages +5 -0
- data/vendor/liburing/debian/liburing2.install +1 -0
- data/vendor/liburing/debian/liburing2.symbols +56 -0
- data/vendor/liburing/debian/patches/series +1 -0
- data/vendor/liburing/debian/rules +29 -0
- data/vendor/liburing/debian/source/format +1 -0
- data/vendor/liburing/debian/source/local-options +2 -0
- data/vendor/liburing/debian/source/options +1 -0
- data/vendor/liburing/debian/watch +3 -0
- data/vendor/liburing/examples/Makefile +53 -0
- data/vendor/liburing/examples/helpers.c +62 -0
- data/vendor/liburing/examples/helpers.h +7 -0
- data/vendor/liburing/examples/io_uring-close-test.c +123 -0
- data/vendor/liburing/examples/io_uring-cp.c +282 -0
- data/vendor/liburing/examples/io_uring-test.c +112 -0
- data/vendor/liburing/examples/io_uring-udp.c +403 -0
- data/vendor/liburing/examples/link-cp.c +193 -0
- data/vendor/liburing/examples/napi-busy-poll-client.c +509 -0
- data/vendor/liburing/examples/napi-busy-poll-server.c +450 -0
- data/vendor/liburing/examples/poll-bench.c +101 -0
- data/vendor/liburing/examples/proxy.c +2461 -0
- data/vendor/liburing/examples/proxy.h +102 -0
- data/vendor/liburing/examples/rsrc-update-bench.c +100 -0
- data/vendor/liburing/examples/send-zerocopy.c +658 -0
- data/vendor/liburing/examples/ucontext-cp.c +258 -0
- data/vendor/liburing/liburing-ffi.pc.in +12 -0
- data/vendor/liburing/liburing.pc.in +12 -0
- data/vendor/liburing/liburing.spec +66 -0
- data/vendor/liburing/make-debs.sh +55 -0
- data/vendor/liburing/src/Makefile +129 -0
- data/vendor/liburing/src/arch/aarch64/lib.h +47 -0
- data/vendor/liburing/src/arch/aarch64/syscall.h +91 -0
- data/vendor/liburing/src/arch/generic/lib.h +17 -0
- data/vendor/liburing/src/arch/generic/syscall.h +100 -0
- data/vendor/liburing/src/arch/riscv64/lib.h +48 -0
- data/vendor/liburing/src/arch/riscv64/syscall.h +100 -0
- data/vendor/liburing/src/arch/syscall-defs.h +94 -0
- data/vendor/liburing/src/arch/x86/lib.h +11 -0
- data/vendor/liburing/src/arch/x86/syscall.h +296 -0
- data/vendor/liburing/src/ffi.c +15 -0
- data/vendor/liburing/src/include/liburing/barrier.h +81 -0
- data/vendor/liburing/src/include/liburing/io_uring.h +818 -0
- data/vendor/liburing/src/include/liburing.h +1602 -0
- data/vendor/liburing/src/int_flags.h +11 -0
- data/vendor/liburing/src/lib.h +52 -0
- data/vendor/liburing/src/liburing-ffi.map +211 -0
- data/vendor/liburing/src/liburing.map +104 -0
- data/vendor/liburing/src/nolibc.c +55 -0
- data/vendor/liburing/src/queue.c +468 -0
- data/vendor/liburing/src/register.c +374 -0
- data/vendor/liburing/src/setup.c +689 -0
- data/vendor/liburing/src/setup.h +9 -0
- data/vendor/liburing/src/syscall.c +29 -0
- data/vendor/liburing/src/syscall.h +53 -0
- data/vendor/liburing/src/version.c +21 -0
- data/vendor/liburing/test/232c93d07b74.c +305 -0
- data/vendor/liburing/test/35fa71a030ca.c +329 -0
- data/vendor/liburing/test/500f9fbadef8.c +91 -0
- data/vendor/liburing/test/7ad0e4b2f83c.c +94 -0
- data/vendor/liburing/test/8a9973408177.c +107 -0
- data/vendor/liburing/test/917257daa0fe.c +54 -0
- data/vendor/liburing/test/Makefile +297 -0
- data/vendor/liburing/test/a0908ae19763.c +59 -0
- data/vendor/liburing/test/a4c0b3decb33.c +181 -0
- data/vendor/liburing/test/accept-link.c +255 -0
- data/vendor/liburing/test/accept-non-empty.c +256 -0
- data/vendor/liburing/test/accept-reuse.c +163 -0
- data/vendor/liburing/test/accept-test.c +83 -0
- data/vendor/liburing/test/accept.c +919 -0
- data/vendor/liburing/test/across-fork.c +284 -0
- data/vendor/liburing/test/b19062a56726.c +54 -0
- data/vendor/liburing/test/b5837bd5311d.c +78 -0
- data/vendor/liburing/test/bind-listen.c +408 -0
- data/vendor/liburing/test/buf-ring-nommap.c +123 -0
- data/vendor/liburing/test/buf-ring-put.c +83 -0
- data/vendor/liburing/test/buf-ring.c +473 -0
- data/vendor/liburing/test/ce593a6c480a.c +139 -0
- data/vendor/liburing/test/close-opath.c +123 -0
- data/vendor/liburing/test/config +14 -0
- data/vendor/liburing/test/connect-rep.c +204 -0
- data/vendor/liburing/test/connect.c +442 -0
- data/vendor/liburing/test/coredump.c +60 -0
- data/vendor/liburing/test/cq-full.c +97 -0
- data/vendor/liburing/test/cq-overflow.c +530 -0
- data/vendor/liburing/test/cq-peek-batch.c +103 -0
- data/vendor/liburing/test/cq-ready.c +95 -0
- data/vendor/liburing/test/cq-size.c +65 -0
- data/vendor/liburing/test/d4ae271dfaae.c +96 -0
- data/vendor/liburing/test/d77a67ed5f27.c +65 -0
- data/vendor/liburing/test/defer-taskrun.c +391 -0
- data/vendor/liburing/test/defer-tw-timeout.c +173 -0
- data/vendor/liburing/test/defer.c +319 -0
- data/vendor/liburing/test/double-poll-crash.c +195 -0
- data/vendor/liburing/test/drop-submit.c +94 -0
- data/vendor/liburing/test/eeed8b54e0df.c +120 -0
- data/vendor/liburing/test/empty-eownerdead.c +45 -0
- data/vendor/liburing/test/eploop.c +74 -0
- data/vendor/liburing/test/eventfd-disable.c +179 -0
- data/vendor/liburing/test/eventfd-reg.c +77 -0
- data/vendor/liburing/test/eventfd-ring.c +98 -0
- data/vendor/liburing/test/eventfd.c +113 -0
- data/vendor/liburing/test/evloop.c +73 -0
- data/vendor/liburing/test/exec-target.c +6 -0
- data/vendor/liburing/test/exit-no-cleanup.c +117 -0
- data/vendor/liburing/test/fadvise.c +202 -0
- data/vendor/liburing/test/fallocate.c +265 -0
- data/vendor/liburing/test/fc2a85cb02ef.c +132 -0
- data/vendor/liburing/test/fd-install.c +500 -0
- data/vendor/liburing/test/fd-pass.c +237 -0
- data/vendor/liburing/test/fdinfo.c +419 -0
- data/vendor/liburing/test/file-register.c +1189 -0
- data/vendor/liburing/test/file-update.c +231 -0
- data/vendor/liburing/test/file-verify.c +654 -0
- data/vendor/liburing/test/files-exit-hang-poll.c +114 -0
- data/vendor/liburing/test/files-exit-hang-timeout.c +137 -0
- data/vendor/liburing/test/fixed-buf-iter.c +115 -0
- data/vendor/liburing/test/fixed-buf-merge.c +101 -0
- data/vendor/liburing/test/fixed-hugepage.c +411 -0
- data/vendor/liburing/test/fixed-link.c +90 -0
- data/vendor/liburing/test/fixed-reuse.c +160 -0
- data/vendor/liburing/test/fpos.c +255 -0
- data/vendor/liburing/test/fsnotify.c +118 -0
- data/vendor/liburing/test/fsync.c +224 -0
- data/vendor/liburing/test/futex.c +571 -0
- data/vendor/liburing/test/hardlink.c +170 -0
- data/vendor/liburing/test/helpers.c +318 -0
- data/vendor/liburing/test/helpers.h +108 -0
- data/vendor/liburing/test/ignore-single-mmap.c +48 -0
- data/vendor/liburing/test/init-mem.c +164 -0
- data/vendor/liburing/test/io-cancel.c +561 -0
- data/vendor/liburing/test/io_uring_enter.c +264 -0
- data/vendor/liburing/test/io_uring_passthrough.c +482 -0
- data/vendor/liburing/test/io_uring_register.c +503 -0
- data/vendor/liburing/test/io_uring_setup.c +110 -0
- data/vendor/liburing/test/iopoll-leak.c +85 -0
- data/vendor/liburing/test/iopoll-overflow.c +118 -0
- data/vendor/liburing/test/iopoll.c +465 -0
- data/vendor/liburing/test/lfs-openat-write.c +119 -0
- data/vendor/liburing/test/lfs-openat.c +273 -0
- data/vendor/liburing/test/link-timeout.c +1108 -0
- data/vendor/liburing/test/link.c +497 -0
- data/vendor/liburing/test/link_drain.c +255 -0
- data/vendor/liburing/test/madvise.c +195 -0
- data/vendor/liburing/test/min-timeout-wait.c +354 -0
- data/vendor/liburing/test/min-timeout.c +233 -0
- data/vendor/liburing/test/mkdir.c +112 -0
- data/vendor/liburing/test/msg-ring-fd.c +331 -0
- data/vendor/liburing/test/msg-ring-flags.c +212 -0
- data/vendor/liburing/test/msg-ring-overflow.c +159 -0
- data/vendor/liburing/test/msg-ring.c +467 -0
- data/vendor/liburing/test/multicqes_drain.c +429 -0
- data/vendor/liburing/test/napi-test.c +215 -0
- data/vendor/liburing/test/napi-test.sh +48 -0
- data/vendor/liburing/test/no-mmap-inval.c +42 -0
- data/vendor/liburing/test/nolibc.c +62 -0
- data/vendor/liburing/test/nop-all-sizes.c +99 -0
- data/vendor/liburing/test/nop.c +177 -0
- data/vendor/liburing/test/nvme.h +169 -0
- data/vendor/liburing/test/ooo-file-unreg.c +82 -0
- data/vendor/liburing/test/open-close.c +261 -0
- data/vendor/liburing/test/open-direct-link.c +188 -0
- data/vendor/liburing/test/open-direct-pick.c +180 -0
- data/vendor/liburing/test/openat2.c +312 -0
- data/vendor/liburing/test/personality.c +204 -0
- data/vendor/liburing/test/pipe-bug.c +95 -0
- data/vendor/liburing/test/pipe-eof.c +83 -0
- data/vendor/liburing/test/pipe-reuse.c +105 -0
- data/vendor/liburing/test/poll-cancel-all.c +496 -0
- data/vendor/liburing/test/poll-cancel-ton.c +135 -0
- data/vendor/liburing/test/poll-cancel.c +228 -0
- data/vendor/liburing/test/poll-link.c +221 -0
- data/vendor/liburing/test/poll-many.c +230 -0
- data/vendor/liburing/test/poll-mshot-overflow.c +265 -0
- data/vendor/liburing/test/poll-mshot-update.c +323 -0
- data/vendor/liburing/test/poll-race-mshot.c +276 -0
- data/vendor/liburing/test/poll-race.c +105 -0
- data/vendor/liburing/test/poll-ring.c +48 -0
- data/vendor/liburing/test/poll-v-poll.c +353 -0
- data/vendor/liburing/test/poll.c +327 -0
- data/vendor/liburing/test/probe.c +135 -0
- data/vendor/liburing/test/read-before-exit.c +129 -0
- data/vendor/liburing/test/read-mshot-empty.c +153 -0
- data/vendor/liburing/test/read-mshot.c +404 -0
- data/vendor/liburing/test/read-write.c +1013 -0
- data/vendor/liburing/test/recv-msgall-stream.c +398 -0
- data/vendor/liburing/test/recv-msgall.c +263 -0
- data/vendor/liburing/test/recv-multishot.c +602 -0
- data/vendor/liburing/test/recvsend_bundle.c +691 -0
- data/vendor/liburing/test/reg-fd-only.c +131 -0
- data/vendor/liburing/test/reg-hint.c +56 -0
- data/vendor/liburing/test/reg-reg-ring.c +90 -0
- data/vendor/liburing/test/regbuf-merge.c +91 -0
- data/vendor/liburing/test/register-restrictions.c +633 -0
- data/vendor/liburing/test/rename.c +132 -0
- data/vendor/liburing/test/ring-leak.c +283 -0
- data/vendor/liburing/test/ring-leak2.c +249 -0
- data/vendor/liburing/test/ringbuf-read.c +196 -0
- data/vendor/liburing/test/ringbuf-status.c +242 -0
- data/vendor/liburing/test/rsrc_tags.c +461 -0
- data/vendor/liburing/test/runtests-loop.sh +16 -0
- data/vendor/liburing/test/runtests-quiet.sh +11 -0
- data/vendor/liburing/test/runtests.sh +168 -0
- data/vendor/liburing/test/rw_merge_test.c +98 -0
- data/vendor/liburing/test/self.c +91 -0
- data/vendor/liburing/test/send-zerocopy.c +971 -0
- data/vendor/liburing/test/send_recv.c +412 -0
- data/vendor/liburing/test/send_recvmsg.c +444 -0
- data/vendor/liburing/test/shared-wq.c +84 -0
- data/vendor/liburing/test/short-read.c +75 -0
- data/vendor/liburing/test/shutdown.c +165 -0
- data/vendor/liburing/test/sigfd-deadlock.c +88 -0
- data/vendor/liburing/test/single-issuer.c +169 -0
- data/vendor/liburing/test/skip-cqe.c +428 -0
- data/vendor/liburing/test/socket-getsetsock-cmd.c +346 -0
- data/vendor/liburing/test/socket-io-cmd.c +237 -0
- data/vendor/liburing/test/socket-rw-eagain.c +149 -0
- data/vendor/liburing/test/socket-rw-offset.c +149 -0
- data/vendor/liburing/test/socket-rw.c +137 -0
- data/vendor/liburing/test/socket.c +408 -0
- data/vendor/liburing/test/splice.c +512 -0
- data/vendor/liburing/test/sq-full-cpp.cc +45 -0
- data/vendor/liburing/test/sq-full.c +45 -0
- data/vendor/liburing/test/sq-poll-dup.c +211 -0
- data/vendor/liburing/test/sq-poll-kthread.c +169 -0
- data/vendor/liburing/test/sq-poll-share.c +138 -0
- data/vendor/liburing/test/sq-space_left.c +159 -0
- data/vendor/liburing/test/sqpoll-disable-exit.c +196 -0
- data/vendor/liburing/test/sqpoll-exec.c +132 -0
- data/vendor/liburing/test/sqpoll-exit-hang.c +78 -0
- data/vendor/liburing/test/sqpoll-sleep.c +69 -0
- data/vendor/liburing/test/statx.c +172 -0
- data/vendor/liburing/test/stdout.c +232 -0
- data/vendor/liburing/test/submit-and-wait.c +108 -0
- data/vendor/liburing/test/submit-link-fail.c +156 -0
- data/vendor/liburing/test/submit-reuse.c +237 -0
- data/vendor/liburing/test/symlink.c +117 -0
- data/vendor/liburing/test/sync-cancel.c +235 -0
- data/vendor/liburing/test/teardowns.c +58 -0
- data/vendor/liburing/test/test.h +36 -0
- data/vendor/liburing/test/thread-exit.c +143 -0
- data/vendor/liburing/test/timeout-new.c +256 -0
- data/vendor/liburing/test/timeout.c +1798 -0
- data/vendor/liburing/test/truncate.c +186 -0
- data/vendor/liburing/test/tty-write-dpoll.c +60 -0
- data/vendor/liburing/test/unlink.c +112 -0
- data/vendor/liburing/test/version.c +25 -0
- data/vendor/liburing/test/wait-timeout.c +287 -0
- data/vendor/liburing/test/waitid.c +373 -0
- data/vendor/liburing/test/wakeup-hang.c +162 -0
- data/vendor/liburing/test/wq-aff.c +146 -0
- data/vendor/liburing/test/xattr.c +442 -0
- 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, ®, 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
|
+
}
|