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.
- checksums.yaml +7 -0
- data/.github/dependabot.yml +12 -0
- data/.github/workflows/test.yml +35 -0
- data/.gitignore +59 -0
- data/.gitmodules +3 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +11 -0
- data/Rakefile +39 -0
- data/TODO.md +0 -0
- data/examples/echo_server.rb +52 -0
- data/examples/event_loop.rb +69 -0
- data/examples/fibers.rb +105 -0
- data/examples/http_server.rb +56 -0
- data/examples/http_server_multishot.rb +57 -0
- data/examples/http_server_simpler.rb +34 -0
- data/ext/um/extconf.rb +71 -0
- data/ext/um/iou.h +101 -0
- data/ext/um/op_ctx.c +138 -0
- data/ext/um/ring.c +755 -0
- data/ext/um/um.c +267 -0
- data/ext/um/um.h +97 -0
- data/ext/um/um_class.c +175 -0
- data/ext/um/um_ext.c +11 -0
- data/ext/um/um_op.c +87 -0
- data/ext/um/um_utils.c +23 -0
- data/lib/uringmachine/version.rb +3 -0
- data/lib/uringmachine.rb +8 -0
- data/test/helper.rb +70 -0
- data/test/test_iou.rb +876 -0
- data/test/test_um.rb +168 -0
- data/uringmachine.gemspec +27 -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 +412 -0
data/ext/um/um.c
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
#include "um.h"
|
|
2
|
+
#include "ruby/thread.h"
|
|
3
|
+
#include <sys/mman.h>
|
|
4
|
+
|
|
5
|
+
static inline struct io_uring_sqe *um_get_sqe(struct um *machine, struct um_op *op) {
|
|
6
|
+
struct io_uring_sqe *sqe;
|
|
7
|
+
sqe = io_uring_get_sqe(&machine->ring);
|
|
8
|
+
if (likely(sqe)) goto done;
|
|
9
|
+
|
|
10
|
+
rb_raise(rb_eRuntimeError, "Failed to get SQE");
|
|
11
|
+
|
|
12
|
+
// TODO: retry getting SQE?
|
|
13
|
+
|
|
14
|
+
// if (likely(backend->pending_sqes))
|
|
15
|
+
// io_uring_um_immediate_submit(backend);
|
|
16
|
+
// else {
|
|
17
|
+
// VALUE resume_value = um_snooze(&backend->base);
|
|
18
|
+
// RAISE_IF_EXCEPTION(resume_value);
|
|
19
|
+
// }
|
|
20
|
+
done:
|
|
21
|
+
sqe->user_data = (long long)op;
|
|
22
|
+
sqe->flags = 0;
|
|
23
|
+
machine->unsubmitted_count++;
|
|
24
|
+
return sqe;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
inline void um_cleanup(struct um *machine) {
|
|
28
|
+
if (!machine->ring_initialized) return;
|
|
29
|
+
|
|
30
|
+
for (unsigned i = 0; i < machine->buffer_ring_count; i++) {
|
|
31
|
+
struct buf_ring_descriptor *desc = machine->buffer_rings + i;
|
|
32
|
+
io_uring_free_buf_ring(&machine->ring, desc->br, desc->buf_count, i);
|
|
33
|
+
free(desc->buf_base);
|
|
34
|
+
}
|
|
35
|
+
machine->buffer_ring_count = 0;
|
|
36
|
+
io_uring_queue_exit(&machine->ring);
|
|
37
|
+
machine->ring_initialized = 0;
|
|
38
|
+
|
|
39
|
+
um_free_linked_list(machine->runqueue_head);
|
|
40
|
+
um_free_linked_list(machine->freelist_head);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
struct wait_for_cqe_ctx {
|
|
44
|
+
struct um *machine;
|
|
45
|
+
struct io_uring_cqe *cqe;
|
|
46
|
+
int result;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
void *um_wait_for_cqe_without_gvl(void *ptr) {
|
|
50
|
+
struct wait_for_cqe_ctx *ctx = ptr;
|
|
51
|
+
if (ctx->machine->unsubmitted_count) {
|
|
52
|
+
ctx->machine->unsubmitted_count = 0;
|
|
53
|
+
ctx->result = io_uring_submit_and_wait_timeout(&ctx->machine->ring, &ctx->cqe, 1, NULL, NULL);
|
|
54
|
+
}
|
|
55
|
+
else
|
|
56
|
+
ctx->result = io_uring_wait_cqe(&ctx->machine->ring, &ctx->cqe);
|
|
57
|
+
return NULL;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
inline void um_process_cqe(struct um *machine, struct io_uring_cqe *cqe) {
|
|
61
|
+
struct um_op *op = (struct um_op *)cqe->user_data;
|
|
62
|
+
if (!op) return;
|
|
63
|
+
|
|
64
|
+
switch (op->state) {
|
|
65
|
+
case OP_submitted:
|
|
66
|
+
if (cqe->res == -ECANCELED) {
|
|
67
|
+
um_op_checkin(machine, op);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
op->state = OP_completed;
|
|
71
|
+
op->cqe_result = cqe->res;
|
|
72
|
+
op->cqe_flags = cqe->flags;
|
|
73
|
+
um_runqueue_push(machine, op);
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
case OP_abandonned:
|
|
77
|
+
// op has been abandonned by the I/O method, so we need to cleanup (check
|
|
78
|
+
// the op in to the free list).
|
|
79
|
+
um_op_checkin(machine, op);
|
|
80
|
+
default:
|
|
81
|
+
// TODO: invalid state, should raise!
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
static inline void um_wait_for_and_process_cqe(struct um *machine) {
|
|
86
|
+
struct wait_for_cqe_ctx ctx = {
|
|
87
|
+
.machine = machine,
|
|
88
|
+
.cqe = NULL
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
rb_thread_call_without_gvl(um_wait_for_cqe_without_gvl, (void *)&ctx, RUBY_UBF_IO, 0);
|
|
92
|
+
if (unlikely(ctx.result < 0)) {
|
|
93
|
+
rb_syserr_fail(-ctx.result, strerror(-ctx.result));
|
|
94
|
+
}
|
|
95
|
+
io_uring_cqe_seen(&machine->ring, ctx.cqe);
|
|
96
|
+
um_process_cqe(machine, ctx.cqe);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// copied from liburing/queue.c
|
|
100
|
+
static inline bool cq_ring_needs_flush(struct io_uring *ring) {
|
|
101
|
+
return IO_URING_READ_ONCE(*ring->sq.kflags) & IORING_SQ_CQ_OVERFLOW;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
static inline int um_process_ready_cqes(struct um *machine) {
|
|
105
|
+
unsigned total_count = 0;
|
|
106
|
+
iterate:
|
|
107
|
+
bool overflow_checked = false;
|
|
108
|
+
struct io_uring_cqe *cqe;
|
|
109
|
+
unsigned head;
|
|
110
|
+
unsigned count = 0;
|
|
111
|
+
io_uring_for_each_cqe(&machine->ring, head, cqe) {
|
|
112
|
+
++count;
|
|
113
|
+
um_process_cqe(machine, cqe);
|
|
114
|
+
}
|
|
115
|
+
io_uring_cq_advance(&machine->ring, count);
|
|
116
|
+
total_count += count;
|
|
117
|
+
|
|
118
|
+
if (overflow_checked) goto done;
|
|
119
|
+
|
|
120
|
+
if (cq_ring_needs_flush(&machine->ring)) {
|
|
121
|
+
io_uring_enter(machine->ring.ring_fd, 0, 0, IORING_ENTER_GETEVENTS, NULL);
|
|
122
|
+
overflow_checked = true;
|
|
123
|
+
goto iterate;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
done:
|
|
127
|
+
return total_count;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
static inline void um_wait_for_and_process_ready_cqes(struct um *machine) {
|
|
131
|
+
um_wait_for_and_process_cqe(machine);
|
|
132
|
+
um_process_ready_cqes(machine);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
inline VALUE um_fiber_switch(struct um *machine) {
|
|
136
|
+
struct um_op *op = 0;
|
|
137
|
+
unsigned int first_iteration = 1;
|
|
138
|
+
loop:
|
|
139
|
+
// in the case where:
|
|
140
|
+
// - first time through loop
|
|
141
|
+
// - there are SQEs waiting to be submitted
|
|
142
|
+
// - the runqueue head references the current fiber
|
|
143
|
+
// we need to submit events and check completions without blocking
|
|
144
|
+
if (
|
|
145
|
+
unlikely(
|
|
146
|
+
first_iteration && machine->unsubmitted_count &&
|
|
147
|
+
machine->runqueue_head &&
|
|
148
|
+
machine->runqueue_head->fiber == rb_fiber_current()
|
|
149
|
+
)
|
|
150
|
+
) {
|
|
151
|
+
io_uring_submit(&machine->ring);
|
|
152
|
+
um_process_ready_cqes(machine);
|
|
153
|
+
}
|
|
154
|
+
first_iteration = 0;
|
|
155
|
+
|
|
156
|
+
op = um_runqueue_shift(machine);
|
|
157
|
+
if (op) {
|
|
158
|
+
VALUE resume_value = op->resume_value;
|
|
159
|
+
if (op->state == OP_schedule) {
|
|
160
|
+
um_op_checkin(machine, op);
|
|
161
|
+
}
|
|
162
|
+
// the resume value is disregarded, we pass the fiber itself
|
|
163
|
+
VALUE v = rb_fiber_transfer(op->fiber, 1, &resume_value);
|
|
164
|
+
return v;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
um_wait_for_and_process_ready_cqes(machine);
|
|
168
|
+
goto loop;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
static inline void um_cancel_op(struct um *machine, struct um_op *op) {
|
|
172
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, NULL);
|
|
173
|
+
io_uring_prep_cancel64(sqe, (long long)op, 0);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
static inline VALUE um_await_op(struct um *machine, struct um_op *op) {
|
|
177
|
+
op->fiber = rb_fiber_current();
|
|
178
|
+
VALUE v = um_fiber_switch(machine);
|
|
179
|
+
|
|
180
|
+
int is_exception = um_value_is_exception_p(v);
|
|
181
|
+
|
|
182
|
+
if (is_exception && op->state == OP_submitted) {
|
|
183
|
+
um_cancel_op(machine, op);
|
|
184
|
+
op->state = OP_abandonned;
|
|
185
|
+
}
|
|
186
|
+
else
|
|
187
|
+
um_op_checkin(machine, op);
|
|
188
|
+
return is_exception ? um_raise_exception(v) : v;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
inline VALUE um_await(struct um *machine) {
|
|
192
|
+
VALUE v = um_fiber_switch(machine);
|
|
193
|
+
return um_value_is_exception_p(v) ? um_raise_exception(v) : v;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
inline void um_schedule(struct um *machine, VALUE fiber, VALUE value) {
|
|
197
|
+
struct um_op *op = um_op_checkout(machine);
|
|
198
|
+
op->state = OP_schedule;
|
|
199
|
+
op->fiber = fiber;
|
|
200
|
+
op->resume_value = value;
|
|
201
|
+
um_runqueue_push(machine, op);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
inline void um_interrupt(struct um *machine, VALUE fiber, VALUE value) {
|
|
205
|
+
struct um_op *op = um_runqueue_find_by_fiber(machine, fiber);
|
|
206
|
+
if (op) {
|
|
207
|
+
op->state = OP_cancelled;
|
|
208
|
+
op->resume_value = value;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
op = um_op_checkout(machine);
|
|
212
|
+
op->state = OP_schedule;
|
|
213
|
+
op->fiber = fiber;
|
|
214
|
+
op->resume_value = value;
|
|
215
|
+
um_runqueue_unshift(machine, op);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
struct timeout_ctx {
|
|
220
|
+
struct um *machine;
|
|
221
|
+
struct um_op *op;
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
VALUE um_timeout_ensure(VALUE arg) {
|
|
225
|
+
struct timeout_ctx *ctx = (struct timeout_ctx *)arg;
|
|
226
|
+
|
|
227
|
+
if (ctx->op->state == OP_submitted) {
|
|
228
|
+
// A CQE has not yet been received, we cancel the timeout and abandon the op
|
|
229
|
+
// (it will be checked in upon receiving the -ECANCELED CQE)
|
|
230
|
+
um_cancel_op(ctx->machine, ctx->op);
|
|
231
|
+
ctx->op->state == OP_abandonned;
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
// completed, so can be checked in
|
|
235
|
+
um_op_checkin(ctx->machine, ctx->op);
|
|
236
|
+
}
|
|
237
|
+
return Qnil;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
VALUE um_timeout(struct um *machine, VALUE interval, VALUE class) {
|
|
241
|
+
static ID ID_new = 0;
|
|
242
|
+
if (!ID_new) ID_new = rb_intern("new");
|
|
243
|
+
|
|
244
|
+
struct um_op *op = um_op_checkout(machine);
|
|
245
|
+
struct __kernel_timespec ts = um_double_to_timespec(NUM2DBL(interval));
|
|
246
|
+
|
|
247
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
248
|
+
io_uring_prep_timeout(sqe, &ts, 0, 0);
|
|
249
|
+
op->state = OP_submitted;
|
|
250
|
+
op->fiber = rb_fiber_current();
|
|
251
|
+
op->resume_value = rb_funcall(class, ID_new, 0);
|
|
252
|
+
|
|
253
|
+
struct timeout_ctx ctx = { .machine = machine, .op = op };
|
|
254
|
+
return rb_ensure(rb_yield, Qnil, um_timeout_ensure, (VALUE)&ctx);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
inline VALUE um_sleep(struct um *machine, double duration) {
|
|
258
|
+
struct um_op *op = um_op_checkout(machine);
|
|
259
|
+
struct __kernel_timespec ts = um_double_to_timespec(duration);
|
|
260
|
+
|
|
261
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
262
|
+
io_uring_prep_timeout(sqe, &ts, 0, 0);
|
|
263
|
+
op->state = OP_submitted;
|
|
264
|
+
|
|
265
|
+
return um_await_op(machine, op);
|
|
266
|
+
}
|
|
267
|
+
|
data/ext/um/um.h
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#ifndef UM_H
|
|
2
|
+
#define UM_H
|
|
3
|
+
|
|
4
|
+
#include "ruby.h"
|
|
5
|
+
#include <liburing.h>
|
|
6
|
+
|
|
7
|
+
// debugging
|
|
8
|
+
#define OBJ_ID(obj) (NUM2LONG(rb_funcall(obj, rb_intern("object_id"), 0)))
|
|
9
|
+
#define INSPECT(str, obj) { printf(str); VALUE s = rb_funcall(obj, rb_intern("inspect"), 0); printf(": %s\n", StringValueCStr(s)); }
|
|
10
|
+
#define CALLER() rb_funcall(rb_mKernel, rb_intern("caller"), 0)
|
|
11
|
+
#define TRACE_CALLER() INSPECT("caller: ", CALLER())
|
|
12
|
+
#define TRACE_FREE(ptr) //printf("Free %p %s:%d\n", ptr, __FILE__, __LINE__)
|
|
13
|
+
|
|
14
|
+
// branching
|
|
15
|
+
#ifndef unlikely
|
|
16
|
+
#define unlikely(cond) __builtin_expect(!!(cond), 0)
|
|
17
|
+
#endif
|
|
18
|
+
|
|
19
|
+
#ifndef likely
|
|
20
|
+
#define likely(cond) __builtin_expect(!!(cond), 1)
|
|
21
|
+
#endif
|
|
22
|
+
|
|
23
|
+
enum op_state {
|
|
24
|
+
OP_initial, // initial state
|
|
25
|
+
OP_submitted, // op has been submitted (SQE prepared)
|
|
26
|
+
OP_completed, // op has been completed (CQE processed)
|
|
27
|
+
OP_cancelled, // op is cancelled (after CQE is processed)
|
|
28
|
+
OP_abandonned, // op is abandonned by fiber (before CQE is processed)
|
|
29
|
+
OP_schedule, // the corresponding fiber is scheduled
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
struct um_op {
|
|
33
|
+
enum op_state state;
|
|
34
|
+
struct um_op *prev;
|
|
35
|
+
struct um_op *next;
|
|
36
|
+
|
|
37
|
+
VALUE fiber;
|
|
38
|
+
VALUE resume_value;
|
|
39
|
+
int cqe_result;
|
|
40
|
+
int cqe_flags;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
struct buf_ring_descriptor {
|
|
44
|
+
struct io_uring_buf_ring *br;
|
|
45
|
+
size_t br_size;
|
|
46
|
+
unsigned buf_count;
|
|
47
|
+
unsigned buf_size;
|
|
48
|
+
char *buf_base;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
#define BUFFER_RING_MAX_COUNT 10
|
|
52
|
+
|
|
53
|
+
struct um {
|
|
54
|
+
struct um_op *freelist_head;
|
|
55
|
+
struct um_op *runqueue_head;
|
|
56
|
+
struct um_op *runqueue_tail;
|
|
57
|
+
|
|
58
|
+
struct io_uring ring;
|
|
59
|
+
|
|
60
|
+
unsigned int ring_initialized;
|
|
61
|
+
unsigned int unsubmitted_count;
|
|
62
|
+
unsigned int pending_count;
|
|
63
|
+
|
|
64
|
+
struct buf_ring_descriptor buffer_rings[BUFFER_RING_MAX_COUNT];
|
|
65
|
+
unsigned int buffer_ring_count;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
extern VALUE cUM;
|
|
69
|
+
|
|
70
|
+
struct __kernel_timespec um_double_to_timespec(double value);
|
|
71
|
+
|
|
72
|
+
void um_cleanup(struct um *machine);
|
|
73
|
+
|
|
74
|
+
void um_free_linked_list(struct um_op *op);
|
|
75
|
+
VALUE um_fiber_switch(struct um *machine);
|
|
76
|
+
VALUE um_await(struct um *machine);
|
|
77
|
+
|
|
78
|
+
void um_op_checkin(struct um *machine, struct um_op *op);
|
|
79
|
+
struct um_op* um_op_checkout(struct um *machine);
|
|
80
|
+
|
|
81
|
+
VALUE um_raise_exception(VALUE v);
|
|
82
|
+
|
|
83
|
+
struct um_op *um_runqueue_find_by_fiber(struct um *machine, VALUE fiber);
|
|
84
|
+
void um_runqueue_push(struct um *machine, struct um_op *op);
|
|
85
|
+
struct um_op *um_runqueue_shift(struct um *machine);
|
|
86
|
+
void um_runqueue_unshift(struct um *machine, struct um_op *op);
|
|
87
|
+
|
|
88
|
+
int um_value_is_exception_p(VALUE v);
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
void um_schedule(struct um *machine, VALUE fiber, VALUE value);
|
|
92
|
+
void um_interrupt(struct um *machine, VALUE fiber, VALUE value);
|
|
93
|
+
VALUE um_timeout(struct um *machine, VALUE interval, VALUE class);
|
|
94
|
+
|
|
95
|
+
VALUE um_sleep(struct um *machine, double duration);
|
|
96
|
+
|
|
97
|
+
#endif // UM_H
|
data/ext/um/um_class.c
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
#include "um.h"
|
|
2
|
+
|
|
3
|
+
VALUE cUM;
|
|
4
|
+
|
|
5
|
+
static void UM_mark(void *ptr) {
|
|
6
|
+
// struct um *machine = ptr;
|
|
7
|
+
// um_runqueue_mark(machine);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
static void UM_compact(void *ptr) {
|
|
11
|
+
// struct um *machine = ptr;
|
|
12
|
+
// um_runqueue_compact(machine);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
static void UM_free(void *ptr) {
|
|
16
|
+
um_cleanup((struct um *)ptr);
|
|
17
|
+
free(ptr);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static size_t UM_size(const void *ptr) {
|
|
21
|
+
return sizeof(struct um);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static const rb_data_type_t UM_type = {
|
|
25
|
+
"UringMachine",
|
|
26
|
+
{UM_mark, UM_free, UM_size, UM_compact},
|
|
27
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
static VALUE UM_allocate(VALUE klass) {
|
|
31
|
+
struct um *machine = ALLOC(struct um);
|
|
32
|
+
|
|
33
|
+
return TypedData_Wrap_Struct(klass, &UM_type, machine);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
inline struct um *get_machine(VALUE self) {
|
|
37
|
+
struct um *machine = RTYPEDDATA_DATA(self);
|
|
38
|
+
if (!machine->ring_initialized)
|
|
39
|
+
rb_raise(rb_eRuntimeError, "Machine not initialized");
|
|
40
|
+
return machine;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
VALUE UM_initialize(VALUE self) {
|
|
44
|
+
struct um *machine = RTYPEDDATA_DATA(self);
|
|
45
|
+
|
|
46
|
+
machine->ring_initialized = 0;
|
|
47
|
+
machine->unsubmitted_count = 0;
|
|
48
|
+
machine->buffer_ring_count = 0;
|
|
49
|
+
machine->pending_count = 0;
|
|
50
|
+
machine->runqueue_head = NULL;
|
|
51
|
+
machine->runqueue_tail = NULL;
|
|
52
|
+
machine->freelist_head = NULL;
|
|
53
|
+
|
|
54
|
+
unsigned prepared_limit = 4096;
|
|
55
|
+
int flags = 0;
|
|
56
|
+
#ifdef HAVE_IORING_SETUP_SUBMIT_ALL
|
|
57
|
+
flags |= IORING_SETUP_SUBMIT_ALL;
|
|
58
|
+
#endif
|
|
59
|
+
#ifdef HAVE_IORING_SETUP_COOP_TASKRUN
|
|
60
|
+
flags |= IORING_SETUP_COOP_TASKRUN;
|
|
61
|
+
#endif
|
|
62
|
+
|
|
63
|
+
while (1) {
|
|
64
|
+
int ret = io_uring_queue_init(prepared_limit, &machine->ring, flags);
|
|
65
|
+
if (likely(!ret)) break;
|
|
66
|
+
|
|
67
|
+
// if ENOMEM is returned, try with half as much entries
|
|
68
|
+
if (unlikely(ret == -ENOMEM && prepared_limit > 64))
|
|
69
|
+
prepared_limit = prepared_limit / 2;
|
|
70
|
+
else
|
|
71
|
+
rb_syserr_fail(-ret, strerror(-ret));
|
|
72
|
+
}
|
|
73
|
+
machine->ring_initialized = 1;
|
|
74
|
+
|
|
75
|
+
return self;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
VALUE UM_pending_count(VALUE self) {
|
|
79
|
+
struct um *machine = get_machine(self);
|
|
80
|
+
return INT2FIX(machine->pending_count);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
VALUE UM_snooze(VALUE self) {
|
|
84
|
+
struct um *machine = get_machine(self);
|
|
85
|
+
um_schedule(machine, rb_fiber_current(), Qnil);
|
|
86
|
+
return um_await(machine);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
VALUE UM_yield(VALUE self) {
|
|
90
|
+
struct um *machine = get_machine(self);
|
|
91
|
+
return um_await(machine);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
VALUE UM_schedule(VALUE self, VALUE fiber, VALUE value) {
|
|
95
|
+
struct um *machine = get_machine(self);
|
|
96
|
+
um_schedule(machine, fiber, value);
|
|
97
|
+
return self;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
VALUE UM_interrupt(VALUE self, VALUE fiber, VALUE value) {
|
|
101
|
+
struct um *machine = get_machine(self);
|
|
102
|
+
um_interrupt(machine, fiber, value);
|
|
103
|
+
return self;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
VALUE UM_timeout(VALUE self, VALUE interval, VALUE class) {
|
|
107
|
+
struct um *machine = get_machine(self);
|
|
108
|
+
return um_timeout(machine, interval, class);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
VALUE UM_sleep(VALUE self, VALUE duration) {
|
|
112
|
+
struct um *machine = get_machine(self);
|
|
113
|
+
um_sleep(machine, NUM2DBL(duration));
|
|
114
|
+
return duration;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
void Init_UM(void) {
|
|
118
|
+
rb_ext_ractor_safe(true);
|
|
119
|
+
|
|
120
|
+
cUM = rb_define_class("UringMachine", rb_cObject);
|
|
121
|
+
rb_define_alloc_func(cUM, UM_allocate);
|
|
122
|
+
|
|
123
|
+
rb_define_method(cUM, "initialize", UM_initialize, 0);
|
|
124
|
+
// rb_define_method(cUM, "setup_buffer_ring", UM_setup_buffer_ring, 1);
|
|
125
|
+
|
|
126
|
+
rb_define_method(cUM, "pending_count", UM_pending_count, 0);
|
|
127
|
+
|
|
128
|
+
rb_define_method(cUM, "snooze", UM_snooze, 0);
|
|
129
|
+
rb_define_method(cUM, "yield", UM_yield, 0);
|
|
130
|
+
rb_define_method(cUM, "schedule", UM_schedule, 2);
|
|
131
|
+
rb_define_method(cUM, "interrupt", UM_interrupt, 2);
|
|
132
|
+
rb_define_method(cUM, "timeout", UM_timeout, 2);
|
|
133
|
+
|
|
134
|
+
rb_define_method(cUM, "sleep", UM_sleep, 1);
|
|
135
|
+
|
|
136
|
+
// rb_define_method(cUM, "emit", UM_emit, 1);
|
|
137
|
+
|
|
138
|
+
// rb_define_method(cUM, "prep_accept", UM_prep_accept, 1);
|
|
139
|
+
// rb_define_method(cUM, "prep_cancel", UM_prep_cancel, 1);
|
|
140
|
+
// rb_define_method(cUM, "prep_close", UM_prep_close, 1);
|
|
141
|
+
// rb_define_method(cUM, "prep_nop", UM_prep_nop, 0);
|
|
142
|
+
// rb_define_method(cUM, "prep_read", UM_prep_read, 1);
|
|
143
|
+
// rb_define_method(cUM, "prep_timeout", UM_prep_timeout, 1);
|
|
144
|
+
// rb_define_method(cUM, "prep_write", UM_prep_write, 1);
|
|
145
|
+
|
|
146
|
+
// rb_define_method(cUM, "submit", UM_submit, 0);
|
|
147
|
+
// rb_define_method(cUM, "wait_for_completion", UM_wait_for_completion, 0);
|
|
148
|
+
// rb_define_method(cUM, "process_completions", UM_process_completions, -1);
|
|
149
|
+
// rb_define_method(cUM, "process_completions_loop", UM_process_completions_loop, 0);
|
|
150
|
+
|
|
151
|
+
// SYM_accept = MAKE_SYM("accept");
|
|
152
|
+
// SYM_block = MAKE_SYM("block");
|
|
153
|
+
// SYM_buffer = MAKE_SYM("buffer");
|
|
154
|
+
// SYM_buffer_group = MAKE_SYM("buffer_group");
|
|
155
|
+
// SYM_buffer_offset = MAKE_SYM("buffer_offset");
|
|
156
|
+
// SYM_close = MAKE_SYM("close");
|
|
157
|
+
// SYM_count = MAKE_SYM("count");
|
|
158
|
+
// SYM_emit = MAKE_SYM("emit");
|
|
159
|
+
// SYM_fd = MAKE_SYM("fd");
|
|
160
|
+
// SYM_id = MAKE_SYM("id");
|
|
161
|
+
// SYM_interval = MAKE_SYM("interval");
|
|
162
|
+
// SYM_len = MAKE_SYM("len");
|
|
163
|
+
// SYM_link = MAKE_SYM("link");
|
|
164
|
+
// SYM_multishot = MAKE_SYM("multishot");
|
|
165
|
+
// SYM_op = MAKE_SYM("op");
|
|
166
|
+
// SYM_read = MAKE_SYM("read");
|
|
167
|
+
// SYM_result = MAKE_SYM("result");
|
|
168
|
+
// SYM_signal = MAKE_SYM("signal");
|
|
169
|
+
// SYM_size = MAKE_SYM("size");
|
|
170
|
+
// SYM_spec_data = MAKE_SYM("spec_data");
|
|
171
|
+
// SYM_stop = MAKE_SYM("stop");
|
|
172
|
+
// SYM_timeout = MAKE_SYM("timeout");
|
|
173
|
+
// SYM_utf8 = MAKE_SYM("utf8");
|
|
174
|
+
// SYM_write = MAKE_SYM("write");
|
|
175
|
+
}
|
data/ext/um/um_ext.c
ADDED
data/ext/um/um_op.c
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#include "um.h"
|
|
2
|
+
|
|
3
|
+
inline void um_op_clear(struct um_op *op) {
|
|
4
|
+
memset(op, 0, sizeof(struct um_op));
|
|
5
|
+
op->fiber = op->resume_value = Qnil;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
inline struct um_op *um_op_checkout(struct um *machine) {
|
|
9
|
+
machine->pending_count++;
|
|
10
|
+
|
|
11
|
+
if (machine->freelist_head) {
|
|
12
|
+
struct um_op *op = machine->freelist_head;
|
|
13
|
+
machine->freelist_head = op->next;
|
|
14
|
+
um_op_clear(op);
|
|
15
|
+
return op;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
struct um_op *op = malloc(sizeof(struct um_op));
|
|
19
|
+
um_op_clear(op);
|
|
20
|
+
return op;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
inline void um_op_checkin(struct um *machine, struct um_op *op) {
|
|
24
|
+
machine->pending_count--;
|
|
25
|
+
|
|
26
|
+
op->next = machine->freelist_head;
|
|
27
|
+
machine->freelist_head = op;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
inline struct um_op *um_runqueue_find_by_fiber(struct um *machine, VALUE fiber) {
|
|
31
|
+
struct um_op *op = machine->runqueue_head;
|
|
32
|
+
while (op) {
|
|
33
|
+
if (op->fiber == fiber) return op;
|
|
34
|
+
|
|
35
|
+
op = op->next;
|
|
36
|
+
}
|
|
37
|
+
return NULL;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
inline void um_runqueue_push(struct um *machine, struct um_op *op) {
|
|
41
|
+
if (machine->runqueue_tail) {
|
|
42
|
+
op->prev = machine->runqueue_tail;
|
|
43
|
+
machine->runqueue_tail->next = op;
|
|
44
|
+
machine->runqueue_tail = op;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
op->prev = NULL;
|
|
48
|
+
machine->runqueue_head = machine->runqueue_tail = op;
|
|
49
|
+
}
|
|
50
|
+
op->next = NULL;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
inline void um_runqueue_unshift(struct um *machine, struct um_op *op) {
|
|
54
|
+
if (machine->runqueue_head) {
|
|
55
|
+
op->next = machine->runqueue_head;
|
|
56
|
+
machine->runqueue_head->prev = op;
|
|
57
|
+
machine->runqueue_head = op;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
op->next = NULL;
|
|
61
|
+
machine->runqueue_head = machine->runqueue_tail = op;
|
|
62
|
+
}
|
|
63
|
+
op->prev = NULL;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
inline struct um_op *um_runqueue_shift(struct um *machine) {
|
|
67
|
+
struct um_op *op = machine->runqueue_head;
|
|
68
|
+
if (!op) return NULL;
|
|
69
|
+
|
|
70
|
+
op->prev = NULL;
|
|
71
|
+
if (!op->next) {
|
|
72
|
+
machine->runqueue_head = machine->runqueue_tail = NULL;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
machine->runqueue_head = op->next;
|
|
76
|
+
op->next = NULL;
|
|
77
|
+
}
|
|
78
|
+
return op;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
inline void um_free_linked_list(struct um_op *op) {
|
|
82
|
+
while (op) {
|
|
83
|
+
struct um_op *next = op->next;
|
|
84
|
+
free(op);
|
|
85
|
+
op = next;
|
|
86
|
+
}
|
|
87
|
+
}
|
data/ext/um/um_utils.c
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#include "um.h"
|
|
2
|
+
|
|
3
|
+
inline struct __kernel_timespec um_double_to_timespec(double value) {
|
|
4
|
+
double integral;
|
|
5
|
+
double fraction = modf(value, &integral);
|
|
6
|
+
struct __kernel_timespec ts;
|
|
7
|
+
ts.tv_sec = integral;
|
|
8
|
+
ts.tv_nsec = floor(fraction * 1000000000);
|
|
9
|
+
return ts;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
#define RAISE_EXCEPTION(e) rb_funcall(e, ID_invoke, 0);
|
|
13
|
+
|
|
14
|
+
inline int um_value_is_exception_p(VALUE v) {
|
|
15
|
+
return rb_obj_is_kind_of(v, rb_eException) == Qtrue;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
VALUE um_raise_exception(VALUE e) {
|
|
19
|
+
static ID ID_raise = 0;
|
|
20
|
+
if (!ID_raise) ID_raise = rb_intern("raise");
|
|
21
|
+
|
|
22
|
+
return rb_funcall(rb_mKernel, ID_raise, 1, e);
|
|
23
|
+
}
|