uringmachine 0.3 → 0.5
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 +4 -4
- data/.github/workflows/test.yml +2 -1
- data/CHANGELOG.md +23 -0
- data/README.md +128 -0
- data/TODO.md +14 -0
- data/examples/bm_snooze.rb +89 -0
- data/examples/bm_write.rb +56 -0
- data/examples/dns_client.rb +12 -0
- data/examples/echo_server.rb +18 -40
- data/examples/http_server.rb +42 -43
- data/examples/inout.rb +19 -0
- data/examples/nc.rb +36 -0
- data/examples/server_client.rb +64 -0
- data/examples/snooze.rb +44 -0
- data/examples/write_dev_null.rb +16 -0
- data/ext/um/extconf.rb +24 -23
- data/ext/um/um.c +524 -278
- data/ext/um/um.h +146 -44
- data/ext/um/um_buffer.c +49 -0
- data/ext/um/um_class.c +217 -106
- data/ext/um/um_const.c +213 -0
- data/ext/um/um_ext.c +4 -0
- data/ext/um/um_mutex_class.c +47 -0
- data/ext/um/um_op.c +86 -114
- data/ext/um/um_queue_class.c +58 -0
- data/ext/um/um_sync.c +273 -0
- data/ext/um/um_utils.c +49 -4
- data/lib/uringmachine/dns_resolver.rb +84 -0
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +28 -0
- data/supressions/ruby.supp +71 -0
- data/test/helper.rb +8 -0
- data/test/test_um.rb +685 -46
- data/vendor/liburing/.github/workflows/build.yml +29 -1
- data/vendor/liburing/.gitignore +6 -0
- data/vendor/liburing/CHANGELOG +16 -0
- data/vendor/liburing/CONTRIBUTING.md +165 -0
- data/vendor/liburing/configure +64 -0
- data/vendor/liburing/examples/Makefile +9 -1
- data/vendor/liburing/examples/kdigest.c +405 -0
- data/vendor/liburing/examples/proxy.c +75 -8
- data/vendor/liburing/examples/reg-wait.c +159 -0
- data/vendor/liburing/liburing.pc.in +1 -1
- data/vendor/liburing/liburing.spec +1 -1
- data/vendor/liburing/src/Makefile +16 -2
- data/vendor/liburing/src/include/liburing/io_uring.h +77 -0
- data/vendor/liburing/src/include/liburing/sanitize.h +39 -0
- data/vendor/liburing/src/include/liburing.h +59 -6
- data/vendor/liburing/src/int_flags.h +10 -3
- data/vendor/liburing/src/liburing-ffi.map +16 -0
- data/vendor/liburing/src/liburing.map +10 -0
- data/vendor/liburing/src/queue.c +28 -16
- data/vendor/liburing/src/register.c +106 -1
- data/vendor/liburing/src/sanitize.c +176 -0
- data/vendor/liburing/src/setup.c +47 -19
- data/vendor/liburing/src/setup.h +6 -0
- data/vendor/liburing/test/35fa71a030ca.c +7 -0
- data/vendor/liburing/test/500f9fbadef8.c +2 -0
- data/vendor/liburing/test/7ad0e4b2f83c.c +0 -25
- data/vendor/liburing/test/917257daa0fe.c +7 -0
- data/vendor/liburing/test/Makefile +38 -4
- data/vendor/liburing/test/a0908ae19763.c +7 -0
- data/vendor/liburing/test/a4c0b3decb33.c +7 -0
- data/vendor/liburing/test/accept.c +14 -4
- data/vendor/liburing/test/b19062a56726.c +7 -0
- data/vendor/liburing/test/bind-listen.c +2 -2
- data/vendor/liburing/test/buf-ring-nommap.c +10 -3
- data/vendor/liburing/test/buf-ring.c +2 -0
- data/vendor/liburing/test/cmd-discard.c +427 -0
- data/vendor/liburing/test/coredump.c +7 -0
- data/vendor/liburing/test/cq-overflow.c +13 -1
- data/vendor/liburing/test/d4ae271dfaae.c +11 -3
- data/vendor/liburing/test/defer-taskrun.c +2 -2
- data/vendor/liburing/test/defer-tw-timeout.c +4 -1
- data/vendor/liburing/test/defer.c +2 -2
- data/vendor/liburing/test/double-poll-crash.c +1 -1
- data/vendor/liburing/test/eeed8b54e0df.c +2 -0
- data/vendor/liburing/test/eventfd.c +0 -1
- data/vendor/liburing/test/exit-no-cleanup.c +11 -0
- data/vendor/liburing/test/fadvise.c +9 -26
- data/vendor/liburing/test/fdinfo.c +9 -1
- data/vendor/liburing/test/fifo-nonblock-read.c +69 -0
- data/vendor/liburing/test/file-exit-unreg.c +48 -0
- data/vendor/liburing/test/file-register.c +14 -2
- data/vendor/liburing/test/file-update.c +1 -1
- data/vendor/liburing/test/file-verify.c +27 -16
- data/vendor/liburing/test/files-exit-hang-timeout.c +1 -2
- data/vendor/liburing/test/fixed-buf-iter.c +3 -1
- data/vendor/liburing/test/fixed-hugepage.c +12 -1
- data/vendor/liburing/test/fsnotify.c +1 -0
- data/vendor/liburing/test/futex.c +16 -4
- data/vendor/liburing/test/helpers.c +47 -0
- data/vendor/liburing/test/helpers.h +6 -0
- data/vendor/liburing/test/init-mem.c +5 -3
- data/vendor/liburing/test/io-cancel.c +0 -24
- data/vendor/liburing/test/io_uring_passthrough.c +4 -0
- data/vendor/liburing/test/io_uring_register.c +38 -8
- data/vendor/liburing/test/iopoll-leak.c +4 -0
- data/vendor/liburing/test/iopoll-overflow.c +1 -1
- data/vendor/liburing/test/iopoll.c +3 -3
- data/vendor/liburing/test/kallsyms.c +203 -0
- data/vendor/liburing/test/link-timeout.c +159 -0
- data/vendor/liburing/test/linked-defer-close.c +224 -0
- data/vendor/liburing/test/madvise.c +12 -25
- data/vendor/liburing/test/min-timeout-wait.c +0 -25
- data/vendor/liburing/test/min-timeout.c +0 -25
- data/vendor/liburing/test/mkdir.c +6 -0
- data/vendor/liburing/test/msg-ring.c +8 -2
- data/vendor/liburing/test/napi-test.c +16 -3
- data/vendor/liburing/test/no-mmap-inval.c +3 -1
- data/vendor/liburing/test/nop.c +44 -0
- data/vendor/liburing/test/ooo-file-unreg.c +1 -1
- data/vendor/liburing/test/open-close.c +40 -0
- data/vendor/liburing/test/openat2.c +37 -14
- data/vendor/liburing/test/poll-many.c +13 -7
- data/vendor/liburing/test/poll-mshot-update.c +17 -10
- data/vendor/liburing/test/poll-v-poll.c +6 -3
- data/vendor/liburing/test/pollfree.c +148 -0
- data/vendor/liburing/test/read-mshot-empty.c +158 -153
- data/vendor/liburing/test/read-mshot-stdin.c +121 -0
- data/vendor/liburing/test/read-mshot.c +282 -27
- data/vendor/liburing/test/read-write.c +78 -13
- data/vendor/liburing/test/recv-msgall-stream.c +3 -0
- data/vendor/liburing/test/recv-msgall.c +5 -0
- data/vendor/liburing/test/recvsend_bundle-inc.c +680 -0
- data/vendor/liburing/test/recvsend_bundle.c +94 -31
- data/vendor/liburing/test/reg-fd-only.c +15 -5
- data/vendor/liburing/test/reg-wait.c +251 -0
- data/vendor/liburing/test/regbuf-clone.c +645 -0
- data/vendor/liburing/test/regbuf-merge.c +7 -0
- data/vendor/liburing/test/register-restrictions.c +86 -85
- data/vendor/liburing/test/rename.c +59 -1
- data/vendor/liburing/test/resize-rings.c +643 -0
- data/vendor/liburing/test/ringbuf-read.c +5 -0
- data/vendor/liburing/test/ringbuf-status.c +5 -1
- data/vendor/liburing/test/rsrc_tags.c +1 -1
- data/vendor/liburing/test/runtests.sh +16 -1
- data/vendor/liburing/test/send-zerocopy.c +59 -0
- data/vendor/liburing/test/short-read.c +1 -0
- data/vendor/liburing/test/socket.c +43 -0
- data/vendor/liburing/test/splice.c +3 -1
- data/vendor/liburing/test/sq-poll-dup.c +1 -1
- data/vendor/liburing/test/sq-poll-share.c +2 -0
- data/vendor/liburing/test/sqpoll-disable-exit.c +8 -0
- data/vendor/liburing/test/sqpoll-exit-hang.c +1 -25
- data/vendor/liburing/test/sqpoll-sleep.c +40 -33
- data/vendor/liburing/test/sqwait.c +136 -0
- data/vendor/liburing/test/statx.c +89 -0
- data/vendor/liburing/test/stdout.c +2 -0
- data/vendor/liburing/test/submit-and-wait.c +1 -25
- data/vendor/liburing/test/submit-reuse.c +4 -26
- data/vendor/liburing/test/symlink.c +12 -1
- data/vendor/liburing/test/sync-cancel.c +56 -22
- data/vendor/liburing/test/thread-exit.c +5 -0
- data/vendor/liburing/test/timeout-new.c +1 -26
- data/vendor/liburing/test/timeout.c +25 -34
- data/vendor/liburing/test/unlink.c +94 -1
- data/vendor/liburing/test/uring_cmd_ublk.c +1252 -0
- data/vendor/liburing/test/waitid.c +62 -8
- data/vendor/liburing/test/wq-aff.c +35 -0
- data/vendor/liburing/test/xfail_prep_link_timeout_out_of_scope.c +46 -0
- data/vendor/liburing/test/xfail_register_buffers_out_of_scope.c +51 -0
- metadata +37 -6
- data/examples/event_loop.rb +0 -69
- data/examples/fibers.rb +0 -105
- data/examples/http_server_multishot.rb +0 -57
- data/examples/http_server_simpler.rb +0 -34
data/ext/um/um_op.c
CHANGED
@@ -1,151 +1,123 @@
|
|
1
1
|
#include "um.h"
|
2
2
|
|
3
|
-
inline struct
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
return entry;
|
8
|
-
}
|
9
|
-
|
10
|
-
struct um_result_entry *entry = malloc(sizeof(struct um_result_entry));
|
11
|
-
return entry;
|
12
|
-
}
|
13
|
-
|
14
|
-
inline void um_result_checkin(struct um *machine, struct um_result_entry *entry) {
|
15
|
-
entry->next = machine->result_freelist;
|
16
|
-
machine->result_freelist = entry;
|
3
|
+
inline void um_op_clear(struct um *machine, struct um_op *op) {
|
4
|
+
memset(op, 0, sizeof(struct um_op));
|
5
|
+
RB_OBJ_WRITE(machine->self, &op->fiber, Qnil);
|
6
|
+
RB_OBJ_WRITE(machine->self, &op->value, Qnil);
|
17
7
|
}
|
18
8
|
|
19
|
-
inline void
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
um_result_checkin(machine, entry);
|
24
|
-
entry = next;
|
9
|
+
inline void um_op_transient_add(struct um *machine, struct um_op *op) {
|
10
|
+
if (machine->transient_head) {
|
11
|
+
op->next = machine->transient_head;
|
12
|
+
machine->transient_head->prev = op;
|
25
13
|
}
|
26
|
-
|
14
|
+
machine->transient_head = op;
|
27
15
|
}
|
28
16
|
|
29
|
-
inline void
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
if (op->results_tail) {
|
35
|
-
op->results_tail->next = entry;
|
36
|
-
op->results_tail = entry;
|
37
|
-
}
|
38
|
-
else {
|
39
|
-
op->results_head = op->results_tail = entry;
|
40
|
-
}
|
41
|
-
}
|
17
|
+
inline void um_op_transient_remove(struct um *machine, struct um_op *op) {
|
18
|
+
if (op->prev)
|
19
|
+
op->prev->next = op->next;
|
20
|
+
if (op->next)
|
21
|
+
op->next->prev = op->prev;
|
42
22
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
struct um_result_entry *entry = op->results_head;
|
47
|
-
*result = entry->result;
|
48
|
-
*flags = entry->flags;
|
49
|
-
op->results_head = entry->next;
|
50
|
-
if (!op->results_head)
|
51
|
-
op->results_tail = NULL;
|
52
|
-
um_result_checkin(machine, entry);
|
53
|
-
return 1;
|
23
|
+
if (machine->transient_head == op)
|
24
|
+
machine->transient_head = op->next;
|
54
25
|
}
|
55
26
|
|
56
|
-
inline void
|
57
|
-
|
58
|
-
|
27
|
+
inline void um_runqueue_push(struct um *machine, struct um_op *op) {
|
28
|
+
if (machine->runqueue_tail) {
|
29
|
+
op->prev = machine->runqueue_tail;
|
30
|
+
machine->runqueue_tail->next = op;
|
31
|
+
machine->runqueue_tail = op;
|
32
|
+
}
|
33
|
+
else
|
34
|
+
machine->runqueue_head = machine->runqueue_tail = op;
|
35
|
+
op->next = NULL;
|
59
36
|
}
|
60
37
|
|
61
|
-
inline struct um_op *
|
62
|
-
machine->
|
63
|
-
|
64
|
-
if (machine->op_freelist) {
|
65
|
-
struct um_op *op = machine->op_freelist;
|
66
|
-
machine->op_freelist = op->next;
|
67
|
-
um_op_clear(op);
|
68
|
-
return op;
|
69
|
-
}
|
38
|
+
inline struct um_op *um_runqueue_shift(struct um *machine) {
|
39
|
+
struct um_op *op = machine->runqueue_head;
|
40
|
+
if (!op) return NULL;
|
70
41
|
|
71
|
-
|
72
|
-
|
42
|
+
machine->runqueue_head = op->next;
|
43
|
+
if (!machine->runqueue_head)
|
44
|
+
machine->runqueue_tail = NULL;
|
73
45
|
return op;
|
74
46
|
}
|
75
47
|
|
76
|
-
inline void
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
48
|
+
inline void um_op_list_mark(struct um *machine, struct um_op *head) {
|
49
|
+
while (head) {
|
50
|
+
struct um_op *next = head->next;
|
51
|
+
rb_gc_mark_movable(head->fiber);
|
52
|
+
rb_gc_mark_movable(head->value);
|
53
|
+
head = next;
|
54
|
+
}
|
83
55
|
}
|
84
56
|
|
85
|
-
inline
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
57
|
+
inline void um_op_list_compact(struct um *machine, struct um_op *head) {
|
58
|
+
while (head) {
|
59
|
+
struct um_op *next = head->next;
|
60
|
+
head->fiber = rb_gc_location(head->fiber);
|
61
|
+
head->value = rb_gc_location(head->value);
|
62
|
+
head = next;
|
91
63
|
}
|
92
|
-
return NULL;
|
93
64
|
}
|
94
65
|
|
95
|
-
inline
|
96
|
-
if (machine->
|
97
|
-
|
98
|
-
machine->
|
99
|
-
|
100
|
-
}
|
101
|
-
else {
|
102
|
-
op->prev = NULL;
|
103
|
-
machine->runqueue_head = machine->runqueue_tail = op;
|
66
|
+
inline struct um_op_result *multishot_result_alloc(struct um *machine) {
|
67
|
+
if (machine->result_freelist) {
|
68
|
+
struct um_op_result *result = machine->result_freelist;
|
69
|
+
machine->result_freelist = result->next;
|
70
|
+
return result;
|
104
71
|
}
|
105
|
-
|
72
|
+
return malloc(sizeof(struct um_op_result));
|
73
|
+
}
|
74
|
+
|
75
|
+
inline void multishot_result_free(struct um *machine, struct um_op_result *result) {
|
76
|
+
result->next = machine->result_freelist;
|
77
|
+
machine->result_freelist = result;
|
106
78
|
}
|
107
79
|
|
108
|
-
inline void
|
109
|
-
if (
|
110
|
-
op->
|
111
|
-
|
112
|
-
|
80
|
+
inline void um_op_multishot_results_push(struct um *machine, struct um_op *op, __s32 res, __u32 flags) {
|
81
|
+
if (!op->multishot_result_count) {
|
82
|
+
op->result.res = res;
|
83
|
+
op->result.flags = flags;
|
84
|
+
op->result.next = NULL;
|
85
|
+
op->multishot_result_tail = &op->result;
|
113
86
|
}
|
114
87
|
else {
|
115
|
-
|
116
|
-
|
88
|
+
struct um_op_result *result = multishot_result_alloc(machine);
|
89
|
+
result->res = res;
|
90
|
+
result->flags = flags;
|
91
|
+
result->next = NULL;
|
92
|
+
op->multishot_result_tail->next = result;
|
93
|
+
op->multishot_result_tail = result;
|
117
94
|
}
|
118
|
-
op->
|
95
|
+
op->multishot_result_count++;
|
119
96
|
}
|
120
97
|
|
121
|
-
inline struct
|
122
|
-
|
123
|
-
if (!op) return NULL;
|
98
|
+
inline void um_op_multishot_results_clear(struct um *machine, struct um_op *op) {
|
99
|
+
if (op->multishot_result_count < 1) return;
|
124
100
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
machine->runqueue_head = op->next;
|
131
|
-
op->next = NULL;
|
101
|
+
struct um_op_result *result = op->result.next;
|
102
|
+
while (result) {
|
103
|
+
struct um_op_result *next = result->next;
|
104
|
+
multishot_result_free(machine, result);
|
105
|
+
result = next;
|
132
106
|
}
|
133
|
-
|
107
|
+
op->multishot_result_tail = NULL;
|
108
|
+
op->multishot_result_count = 0;
|
134
109
|
}
|
135
110
|
|
136
|
-
inline
|
137
|
-
|
138
|
-
struct um_op *
|
139
|
-
|
140
|
-
|
141
|
-
op = next;
|
111
|
+
inline struct um_op *um_op_alloc(struct um *machine) {
|
112
|
+
if (machine->op_freelist) {
|
113
|
+
struct um_op *op = machine->op_freelist;
|
114
|
+
machine->op_freelist = op->next;
|
115
|
+
return op;
|
142
116
|
}
|
117
|
+
return malloc(sizeof(struct um_op));
|
143
118
|
}
|
144
119
|
|
145
|
-
inline void
|
146
|
-
|
147
|
-
|
148
|
-
free(entry);
|
149
|
-
entry = next;
|
150
|
-
}
|
120
|
+
inline void um_op_free(struct um *machine, struct um_op *op) {
|
121
|
+
op->next = machine->op_freelist;
|
122
|
+
machine->op_freelist = op;
|
151
123
|
}
|
@@ -0,0 +1,58 @@
|
|
1
|
+
#include "um.h"
|
2
|
+
#include <stdlib.h>
|
3
|
+
|
4
|
+
VALUE cQueue;
|
5
|
+
|
6
|
+
static void Queue_mark(void *ptr) {
|
7
|
+
struct um_queue *queue = ptr;
|
8
|
+
um_queue_mark(queue);
|
9
|
+
}
|
10
|
+
|
11
|
+
static void Queue_compact(void *ptr) {
|
12
|
+
struct um_queue *queue = ptr;
|
13
|
+
um_queue_compact(queue);
|
14
|
+
}
|
15
|
+
|
16
|
+
static void Queue_free(void *ptr) {
|
17
|
+
struct um_queue *queue = ptr;
|
18
|
+
um_queue_free(queue);
|
19
|
+
}
|
20
|
+
|
21
|
+
static size_t Queue_size(const void *ptr) {
|
22
|
+
return sizeof(struct um_queue);
|
23
|
+
}
|
24
|
+
|
25
|
+
static const rb_data_type_t Queue_type = {
|
26
|
+
"UringMachineQueue",
|
27
|
+
{Queue_mark, Queue_free, Queue_size, Queue_compact},
|
28
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
|
29
|
+
};
|
30
|
+
|
31
|
+
static VALUE Queue_allocate(VALUE klass) {
|
32
|
+
struct um_queue *queue = malloc(sizeof(struct um_queue));
|
33
|
+
return TypedData_Wrap_Struct(klass, &Queue_type, queue);
|
34
|
+
}
|
35
|
+
|
36
|
+
inline struct um_queue *Queue_data(VALUE self) {
|
37
|
+
return RTYPEDDATA_DATA(self);
|
38
|
+
}
|
39
|
+
|
40
|
+
VALUE Queue_initialize(VALUE self) {
|
41
|
+
struct um_queue *queue = Queue_data(self);
|
42
|
+
RB_OBJ_WRITE(self, &queue->self, self);
|
43
|
+
um_queue_init(queue);
|
44
|
+
return self;
|
45
|
+
}
|
46
|
+
|
47
|
+
VALUE Queue_count(VALUE self) {
|
48
|
+
struct um_queue *queue = Queue_data(self);
|
49
|
+
return UINT2NUM(queue->count);
|
50
|
+
}
|
51
|
+
|
52
|
+
void Init_Queue(void) {
|
53
|
+
cQueue = rb_define_class_under(cUM, "Queue", rb_cObject);
|
54
|
+
rb_define_alloc_func(cQueue, Queue_allocate);
|
55
|
+
|
56
|
+
rb_define_method(cQueue, "initialize", Queue_initialize, 0);
|
57
|
+
rb_define_method(cQueue, "count", Queue_count, 0);
|
58
|
+
}
|
data/ext/um/um_sync.c
ADDED
@@ -0,0 +1,273 @@
|
|
1
|
+
#include "um.h"
|
2
|
+
#include <stdatomic.h>
|
3
|
+
#include <linux/futex.h>
|
4
|
+
|
5
|
+
#define FUTEX2_SIZE_U32 0x02
|
6
|
+
|
7
|
+
void um_futex_wait(struct um *machine, uint32_t *futex, uint32_t expect) {
|
8
|
+
struct um_op op;
|
9
|
+
um_prep_op(machine, &op, OP_FUTEX_WAIT);
|
10
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
11
|
+
io_uring_prep_futex_wait(
|
12
|
+
sqe, (uint32_t *)futex, expect, FUTEX_BITSET_MATCH_ANY,
|
13
|
+
FUTEX2_SIZE_U32, 0
|
14
|
+
);
|
15
|
+
|
16
|
+
VALUE ret = um_fiber_switch(machine);
|
17
|
+
if (!um_op_completed_p(&op))
|
18
|
+
um_cancel_and_wait(machine, &op);
|
19
|
+
else {
|
20
|
+
if (op.result.res != -EAGAIN)
|
21
|
+
um_raise_on_error_result(op.result.res);
|
22
|
+
}
|
23
|
+
|
24
|
+
RB_GC_GUARD(ret);
|
25
|
+
raise_if_exception(ret);
|
26
|
+
}
|
27
|
+
|
28
|
+
void um_futex_wake(struct um *machine, uint32_t *futex, uint32_t num_waiters) {
|
29
|
+
struct um_op op;
|
30
|
+
um_prep_op(machine, &op, OP_FUTEX_WAKE);
|
31
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
32
|
+
// submit futex_wait
|
33
|
+
io_uring_prep_futex_wake(
|
34
|
+
sqe, (uint32_t *)futex, num_waiters, FUTEX_BITSET_MATCH_ANY,
|
35
|
+
FUTEX2_SIZE_U32, 0
|
36
|
+
);
|
37
|
+
|
38
|
+
VALUE ret = um_fiber_switch(machine);
|
39
|
+
um_check_completion(machine, &op);
|
40
|
+
|
41
|
+
RB_GC_GUARD(ret);
|
42
|
+
raise_if_exception(ret);
|
43
|
+
}
|
44
|
+
|
45
|
+
void um_futex_wake_transient(struct um *machine, uint32_t *futex, uint32_t num_waiters) {
|
46
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, NULL);
|
47
|
+
io_uring_prep_futex_wake(
|
48
|
+
sqe, (uint32_t *)futex, num_waiters, FUTEX_BITSET_MATCH_ANY,
|
49
|
+
FUTEX2_SIZE_U32, 0
|
50
|
+
);
|
51
|
+
}
|
52
|
+
|
53
|
+
|
54
|
+
#define MUTEX_LOCKED 1
|
55
|
+
#define MUTEX_UNLOCKED 0
|
56
|
+
|
57
|
+
void um_mutex_init(struct um_mutex *mutex) {
|
58
|
+
mutex->state = MUTEX_UNLOCKED;
|
59
|
+
}
|
60
|
+
|
61
|
+
inline void um_mutex_lock(struct um *machine, uint32_t *state) {
|
62
|
+
while (*state == MUTEX_LOCKED) {
|
63
|
+
um_futex_wait(machine, state, MUTEX_LOCKED);
|
64
|
+
}
|
65
|
+
*state = MUTEX_LOCKED;
|
66
|
+
}
|
67
|
+
|
68
|
+
inline void um_mutex_unlock(struct um *machine, uint32_t *state) {
|
69
|
+
*state = MUTEX_UNLOCKED;
|
70
|
+
// Wake up 1 waiting fiber
|
71
|
+
um_futex_wake(machine, state, 1);
|
72
|
+
}
|
73
|
+
|
74
|
+
struct sync_ctx {
|
75
|
+
struct um *machine;
|
76
|
+
uint32_t *state;
|
77
|
+
};
|
78
|
+
|
79
|
+
VALUE synchronize_begin(VALUE arg) {
|
80
|
+
struct sync_ctx *ctx = (struct sync_ctx *)arg;
|
81
|
+
um_mutex_lock(ctx->machine, ctx->state);
|
82
|
+
return rb_yield(Qnil);
|
83
|
+
}
|
84
|
+
|
85
|
+
VALUE synchronize_ensure(VALUE arg) {
|
86
|
+
struct sync_ctx *ctx = (struct sync_ctx *)arg;
|
87
|
+
um_mutex_unlock(ctx->machine, ctx->state);
|
88
|
+
return Qnil;
|
89
|
+
}
|
90
|
+
|
91
|
+
inline VALUE um_mutex_synchronize(struct um *machine, uint32_t *state) {
|
92
|
+
struct sync_ctx ctx = { .machine = machine, .state = state };
|
93
|
+
return rb_ensure(synchronize_begin, (VALUE)&ctx, synchronize_ensure, (VALUE)&ctx);
|
94
|
+
}
|
95
|
+
|
96
|
+
#define QUEUE_EMPTY 0
|
97
|
+
#define QUEUE_READY 1
|
98
|
+
|
99
|
+
inline void um_queue_init(struct um_queue *queue) {
|
100
|
+
queue->head = queue->tail = queue->free_head = NULL;
|
101
|
+
queue->state = QUEUE_EMPTY;
|
102
|
+
queue->count = 0;
|
103
|
+
}
|
104
|
+
|
105
|
+
inline void um_queue_free(struct um_queue *queue) {
|
106
|
+
struct um_queue_entry *entry = queue->head;
|
107
|
+
while (entry) {
|
108
|
+
struct um_queue_entry *next = entry->next;
|
109
|
+
free(entry);
|
110
|
+
entry = next;
|
111
|
+
}
|
112
|
+
|
113
|
+
entry = queue->free_head;
|
114
|
+
while (entry) {
|
115
|
+
struct um_queue_entry *next = entry->next;
|
116
|
+
free(entry);
|
117
|
+
entry = next;
|
118
|
+
}
|
119
|
+
|
120
|
+
free(queue);
|
121
|
+
}
|
122
|
+
|
123
|
+
inline void um_queue_mark(struct um_queue *queue) {
|
124
|
+
rb_gc_mark_movable(queue->self);
|
125
|
+
struct um_queue_entry *entry = queue->head;
|
126
|
+
while (entry) {
|
127
|
+
rb_gc_mark_movable(entry->value);
|
128
|
+
entry = entry->next;
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
inline void um_queue_compact(struct um_queue *queue) {
|
133
|
+
queue->self = rb_gc_location(queue->self);
|
134
|
+
struct um_queue_entry *entry = queue->head;
|
135
|
+
while (entry) {
|
136
|
+
entry->value = rb_gc_location(entry->value);
|
137
|
+
entry = entry->next;
|
138
|
+
}
|
139
|
+
}
|
140
|
+
|
141
|
+
inline struct um_queue_entry *um_queue_entry_checkout(struct um_queue *queue) {
|
142
|
+
struct um_queue_entry *entry = queue->free_head;
|
143
|
+
if (entry) {
|
144
|
+
queue->free_head = entry->next;
|
145
|
+
}
|
146
|
+
else
|
147
|
+
entry = malloc(sizeof(struct um_queue_entry));
|
148
|
+
return entry;
|
149
|
+
}
|
150
|
+
|
151
|
+
inline void um_queue_entry_checkin(struct um_queue *queue, struct um_queue_entry *entry) {
|
152
|
+
entry->next = queue->free_head;
|
153
|
+
queue->free_head = entry;
|
154
|
+
}
|
155
|
+
|
156
|
+
static inline void queue_add_head(struct um_queue *queue, VALUE value) {
|
157
|
+
struct um_queue_entry *entry = um_queue_entry_checkout(queue);
|
158
|
+
|
159
|
+
entry->next = queue->head;
|
160
|
+
if (queue->head) {
|
161
|
+
queue->head->prev = entry;
|
162
|
+
queue->head = entry;
|
163
|
+
}
|
164
|
+
else
|
165
|
+
queue->head = queue->tail = entry;
|
166
|
+
entry->prev = NULL;
|
167
|
+
RB_OBJ_WRITE(queue->self, &entry->value, value);
|
168
|
+
}
|
169
|
+
|
170
|
+
static inline void queue_add_tail(struct um_queue *queue, VALUE value) {
|
171
|
+
struct um_queue_entry *entry = um_queue_entry_checkout(queue);
|
172
|
+
|
173
|
+
entry->prev = queue->tail;
|
174
|
+
if (queue->tail) {
|
175
|
+
queue->tail->next = entry;
|
176
|
+
queue->tail = entry;
|
177
|
+
}
|
178
|
+
else
|
179
|
+
queue->head = queue->tail = entry;
|
180
|
+
entry->next = NULL;
|
181
|
+
RB_OBJ_WRITE(queue->self, &entry->value, value);
|
182
|
+
}
|
183
|
+
|
184
|
+
VALUE queue_remove_head(struct um_queue *queue) {
|
185
|
+
struct um_queue_entry *entry = queue->head;
|
186
|
+
queue->head = entry->next;
|
187
|
+
if (!queue->head) queue->tail = NULL;
|
188
|
+
|
189
|
+
VALUE v = entry->value;
|
190
|
+
um_queue_entry_checkin(queue, entry);
|
191
|
+
return v;
|
192
|
+
|
193
|
+
}
|
194
|
+
|
195
|
+
VALUE queue_remove_tail(struct um_queue *queue) {
|
196
|
+
struct um_queue_entry *entry = queue->tail;
|
197
|
+
queue->tail = entry->prev;
|
198
|
+
if (!queue->tail) queue->head = NULL;
|
199
|
+
|
200
|
+
VALUE v = entry->value;
|
201
|
+
um_queue_entry_checkin(queue, entry);
|
202
|
+
return v;
|
203
|
+
}
|
204
|
+
|
205
|
+
static inline VALUE um_queue_add(struct um *machine, struct um_queue *queue, VALUE value, int add_head) {
|
206
|
+
if (add_head) queue_add_head(queue, value);
|
207
|
+
else queue_add_tail(queue, value);
|
208
|
+
|
209
|
+
queue->count++;
|
210
|
+
|
211
|
+
queue->state = QUEUE_READY;
|
212
|
+
if (queue->num_waiters)
|
213
|
+
um_futex_wake_transient(machine, &queue->state, 1);
|
214
|
+
return queue->self;
|
215
|
+
}
|
216
|
+
|
217
|
+
VALUE um_queue_push(struct um *machine, struct um_queue *queue, VALUE value) {
|
218
|
+
return um_queue_add(machine, queue, value, false);
|
219
|
+
}
|
220
|
+
|
221
|
+
VALUE um_queue_unshift(struct um *machine, struct um_queue *queue, VALUE value) {
|
222
|
+
return um_queue_add(machine, queue, value, true);
|
223
|
+
}
|
224
|
+
|
225
|
+
enum queue_op { QUEUE_POP, QUEUE_SHIFT };
|
226
|
+
|
227
|
+
struct queue_wait_ctx {
|
228
|
+
struct um *machine;
|
229
|
+
struct um_queue *queue;
|
230
|
+
enum queue_op op;
|
231
|
+
};
|
232
|
+
|
233
|
+
VALUE um_queue_remove_begin(VALUE arg) {
|
234
|
+
struct queue_wait_ctx *ctx = (struct queue_wait_ctx *)arg;
|
235
|
+
|
236
|
+
ctx->queue->num_waiters++;
|
237
|
+
while (ctx->queue->state == QUEUE_EMPTY) {
|
238
|
+
um_futex_wait(ctx->machine, &ctx->queue->state, QUEUE_EMPTY);
|
239
|
+
}
|
240
|
+
|
241
|
+
if (ctx->queue->state != QUEUE_READY)
|
242
|
+
rb_raise(rb_eRuntimeError, "Internal error: queue should be in ready state!");
|
243
|
+
if (!ctx->queue->tail)
|
244
|
+
rb_raise(rb_eRuntimeError, "Internal error: queue should be in ready state!");
|
245
|
+
|
246
|
+
ctx->queue->count--;
|
247
|
+
return (ctx->op == QUEUE_POP ? queue_remove_tail : queue_remove_head)(ctx->queue);
|
248
|
+
}
|
249
|
+
|
250
|
+
VALUE um_queue_remove_ensure(VALUE arg) {
|
251
|
+
struct queue_wait_ctx *ctx = (struct queue_wait_ctx *)arg;
|
252
|
+
|
253
|
+
ctx->queue->num_waiters--;
|
254
|
+
|
255
|
+
if (ctx->queue->num_waiters && ctx->queue->tail) {
|
256
|
+
um_futex_wake_transient(ctx->machine, &ctx->queue->state, 1);
|
257
|
+
}
|
258
|
+
else if (!ctx->queue->tail) {
|
259
|
+
ctx->queue->state = QUEUE_EMPTY;
|
260
|
+
}
|
261
|
+
|
262
|
+
return Qnil;
|
263
|
+
}
|
264
|
+
|
265
|
+
VALUE um_queue_pop(struct um *machine, struct um_queue *queue) {
|
266
|
+
struct queue_wait_ctx ctx = { .machine = machine, .queue = queue, .op = QUEUE_POP };
|
267
|
+
return rb_ensure(um_queue_remove_begin, (VALUE)&ctx, um_queue_remove_ensure, (VALUE)&ctx);
|
268
|
+
}
|
269
|
+
|
270
|
+
VALUE um_queue_shift(struct um *machine, struct um_queue *queue) {
|
271
|
+
struct queue_wait_ctx ctx = { .machine = machine, .queue = queue, .op = QUEUE_SHIFT };
|
272
|
+
return rb_ensure(um_queue_remove_begin, (VALUE)&ctx, um_queue_remove_ensure, (VALUE)&ctx);
|
273
|
+
}
|
data/ext/um/um_utils.c
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
#include "um.h"
|
2
|
+
#include <sys/mman.h>
|
3
|
+
#include <stdlib.h>
|
2
4
|
|
3
5
|
inline struct __kernel_timespec um_double_to_timespec(double value) {
|
4
6
|
double integral;
|
@@ -22,7 +24,7 @@ inline VALUE um_raise_exception(VALUE e) {
|
|
22
24
|
return rb_funcall(rb_mKernel, ID_raise, 1, e);
|
23
25
|
}
|
24
26
|
|
25
|
-
inline void
|
27
|
+
inline void um_raise_on_error_result(int result) {
|
26
28
|
if (unlikely(result < 0)) rb_syserr_fail(-result, strerror(-result));
|
27
29
|
}
|
28
30
|
|
@@ -46,13 +48,56 @@ static inline void adjust_read_buffer_len(VALUE buffer, int result, int ofs) {
|
|
46
48
|
rb_str_set_len(buffer, len + (unsigned)ofs);
|
47
49
|
}
|
48
50
|
|
49
|
-
inline void um_update_read_buffer(struct um *machine, VALUE buffer, int buffer_offset,
|
51
|
+
inline void um_update_read_buffer(struct um *machine, VALUE buffer, int buffer_offset, __s32 result, __u32 flags) {
|
50
52
|
if (!result) return;
|
51
53
|
|
52
54
|
adjust_read_buffer_len(buffer, result, buffer_offset);
|
53
55
|
}
|
54
56
|
|
55
|
-
|
57
|
+
int um_setup_buffer_ring(struct um *machine, unsigned size, unsigned count) {
|
58
|
+
if (machine->buffer_ring_count == BUFFER_RING_MAX_COUNT)
|
59
|
+
rb_raise(rb_eRuntimeError, "Cannot setup more than BUFFER_RING_MAX_COUNT buffer rings");
|
60
|
+
|
61
|
+
struct buf_ring_descriptor *desc = machine->buffer_rings + machine->buffer_ring_count;
|
62
|
+
desc->buf_count = count;
|
63
|
+
desc->buf_size = size;
|
64
|
+
|
65
|
+
desc->br_size = sizeof(struct io_uring_buf) * desc->buf_count;
|
66
|
+
void *mapped = mmap(
|
67
|
+
NULL, desc->br_size, PROT_READ | PROT_WRITE,
|
68
|
+
MAP_ANONYMOUS | MAP_PRIVATE, 0, 0
|
69
|
+
);
|
70
|
+
if (mapped == MAP_FAILED)
|
71
|
+
rb_raise(rb_eRuntimeError, "Failed to allocate buffer ring");
|
72
|
+
|
73
|
+
desc->br = (struct io_uring_buf_ring *)mapped;
|
74
|
+
io_uring_buf_ring_init(desc->br);
|
75
|
+
|
76
|
+
unsigned bg_id = machine->buffer_ring_count;
|
77
|
+
int ret;
|
78
|
+
desc->br = io_uring_setup_buf_ring(&machine->ring, count, bg_id, 0, &ret);
|
79
|
+
if (!desc->br) {
|
80
|
+
munmap(desc->br, desc->br_size);
|
81
|
+
rb_syserr_fail(ret, strerror(ret));
|
82
|
+
}
|
83
|
+
|
84
|
+
if (posix_memalign(&desc->buf_base, 4096, desc->buf_count * desc->buf_size)) {
|
85
|
+
io_uring_free_buf_ring(&machine->ring, desc->br, desc->buf_count, bg_id);
|
86
|
+
rb_raise(rb_eRuntimeError, "Failed to allocate buffers");
|
87
|
+
}
|
88
|
+
|
89
|
+
desc->buf_mask = io_uring_buf_ring_mask(desc->buf_count);
|
90
|
+
void *ptr = desc->buf_base;
|
91
|
+
for (unsigned i = 0; i < desc->buf_count; i++) {
|
92
|
+
io_uring_buf_ring_add(desc->br, ptr, desc->buf_size, i, desc->buf_mask, i);
|
93
|
+
ptr += desc->buf_size;
|
94
|
+
}
|
95
|
+
io_uring_buf_ring_advance(desc->br, desc->buf_count);
|
96
|
+
machine->buffer_ring_count++;
|
97
|
+
return bg_id;
|
98
|
+
}
|
99
|
+
|
100
|
+
inline VALUE um_get_string_from_buffer_ring(struct um *machine, int bgid, __s32 result, __u32 flags) {
|
56
101
|
if (!result) return Qnil;
|
57
102
|
|
58
103
|
unsigned buf_idx = flags >> IORING_CQE_BUFFER_SHIFT;
|
@@ -64,7 +109,7 @@ inline VALUE get_string_from_buffer_ring(struct um *machine, int bgid, int resul
|
|
64
109
|
|
65
110
|
// add buffer back to buffer ring
|
66
111
|
io_uring_buf_ring_add(
|
67
|
-
desc->br, src, desc->buf_size, buf_idx,
|
112
|
+
desc->br, src, desc->buf_size, buf_idx, desc->buf_mask, 0
|
68
113
|
);
|
69
114
|
io_uring_buf_ring_advance(desc->br, 1);
|
70
115
|
|