uringmachine 0.25.0 → 0.27.0
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/CHANGELOG.md +9 -0
- data/TODO.md +17 -19
- data/docs/wroclove.rb.md +52 -0
- data/ext/um/um.c +469 -364
- data/ext/um/um.h +46 -22
- data/ext/um/um_async_op.c +9 -8
- data/ext/um/um_async_op_class.c +3 -3
- data/ext/um/um_class.c +215 -75
- data/ext/um/um_op.c +18 -2
- data/ext/um/um_ssl.c +1 -1
- data/ext/um/um_sync.c +18 -11
- data/ext/um/um_utils.c +14 -4
- data/grant-2025/tasks.md +2 -2
- data/lib/uringmachine/version.rb +1 -1
- data/test/test_async_op.rb +3 -2
- data/test/test_fiber_scheduler.rb +4 -1
- data/test/test_um.rb +410 -27
- metadata +2 -1
data/ext/um/um_op.c
CHANGED
|
@@ -18,9 +18,11 @@ const char * um_op_kind_name(enum um_op_kind kind) {
|
|
|
18
18
|
case OP_STATX: return "OP_STATX";
|
|
19
19
|
case OP_ACCEPT: return "OP_ACCEPT";
|
|
20
20
|
case OP_RECV: return "OP_RECV";
|
|
21
|
+
case OP_RECVMSG: return "OP_RECVMSG";
|
|
21
22
|
case OP_SEND: return "OP_SEND";
|
|
22
|
-
case OP_SENDV: return "OP_SENDV";
|
|
23
23
|
case OP_SEND_BUNDLE: return "OP_SEND_BUNDLE";
|
|
24
|
+
case OP_SENDMSG: return "OP_SENDMSG";
|
|
25
|
+
case OP_SENDV: return "OP_SENDV";
|
|
24
26
|
case OP_SOCKET: return "OP_SOCKET";
|
|
25
27
|
case OP_CONNECT: return "OP_CONNECT";
|
|
26
28
|
case OP_BIND: return "OP_BIND";
|
|
@@ -37,7 +39,6 @@ const char * um_op_kind_name(enum um_op_kind kind) {
|
|
|
37
39
|
case OP_READ_MULTISHOT: return "OP_READ_MULTISHOT";
|
|
38
40
|
case OP_RECV_MULTISHOT: return "OP_RECV_MULTISHOT";
|
|
39
41
|
case OP_TIMEOUT_MULTISHOT: return "OP_TIMEOUT_MULTISHOT";
|
|
40
|
-
case OP_SLEEP_MULTISHOT: return "OP_SLEEP_MULTISHOT";
|
|
41
42
|
default: return "UNKNOWN_OP_KIND";
|
|
42
43
|
}
|
|
43
44
|
}
|
|
@@ -59,6 +60,7 @@ inline void um_op_transient_add(struct um *machine, struct um_op *op) {
|
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
inline void um_op_transient_remove(struct um *machine, struct um_op *op) {
|
|
63
|
+
op->flags &= ~OP_F_TRANSIENT;
|
|
62
64
|
if (op->prev)
|
|
63
65
|
op->prev->next = op->next;
|
|
64
66
|
if (op->next)
|
|
@@ -185,3 +187,17 @@ inline void um_op_free(struct um *machine, struct um_op *op) {
|
|
|
185
187
|
machine->op_freelist = op;
|
|
186
188
|
machine->metrics.ops_free++;
|
|
187
189
|
}
|
|
190
|
+
|
|
191
|
+
inline struct um_op *um_op_acquire(struct um *machine) {
|
|
192
|
+
return um_op_alloc(machine);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
inline void um_op_release(struct um *machine, struct um_op *op) {
|
|
196
|
+
op->ref_count--;
|
|
197
|
+
if (op->ref_count) return;
|
|
198
|
+
|
|
199
|
+
if (op->flags & OP_F_FREE_IOVECS) free(op->iovecs);
|
|
200
|
+
if (op->flags & OP_F_MULTISHOT)
|
|
201
|
+
um_op_multishot_results_clear(machine, op);
|
|
202
|
+
um_op_free(machine, op);
|
|
203
|
+
}
|
data/ext/um/um_ssl.c
CHANGED
|
@@ -97,7 +97,7 @@ int um_ssl_write(struct um *machine, VALUE ssl_obj, VALUE buf, int len) {
|
|
|
97
97
|
SSL *ssl = RTYPEDDATA_GET_DATA(ssl_obj);
|
|
98
98
|
const void *base;
|
|
99
99
|
size_t size;
|
|
100
|
-
um_get_buffer_bytes_for_writing(buf, &base, &size);
|
|
100
|
+
um_get_buffer_bytes_for_writing(buf, &base, &size, true);
|
|
101
101
|
if ((len == (int)-1) || (len > (int)size)) len = (int)size;
|
|
102
102
|
if (unlikely(!len)) return INT2NUM(0);
|
|
103
103
|
|
data/ext/um/um_sync.c
CHANGED
|
@@ -6,35 +6,42 @@
|
|
|
6
6
|
|
|
7
7
|
// The value argument is the current (known) futex value.
|
|
8
8
|
void um_futex_wait(struct um *machine, uint32_t *futex, uint32_t value) {
|
|
9
|
-
struct um_op op;
|
|
10
|
-
um_prep_op(machine,
|
|
11
|
-
struct io_uring_sqe *sqe = um_get_sqe(machine,
|
|
9
|
+
struct um_op *op = um_op_acquire(machine);
|
|
10
|
+
um_prep_op(machine, op, OP_FUTEX_WAIT, 2, 0);
|
|
11
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
12
12
|
io_uring_prep_futex_wait(
|
|
13
13
|
sqe, (uint32_t *)futex, value, FUTEX_BITSET_MATCH_ANY, FUTEX2_SIZE_U32, 0
|
|
14
14
|
);
|
|
15
15
|
|
|
16
16
|
VALUE ret = um_yield(machine);
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
|
|
18
|
+
if (unlikely(!OP_CQE_DONE_P(op)))
|
|
19
|
+
um_cancel_op_and_await_cqe(machine, op);
|
|
19
20
|
else {
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
int res = op->result.res;
|
|
22
|
+
if (res != -EAGAIN) {
|
|
23
|
+
um_op_release(machine, op);
|
|
24
|
+
um_raise_on_error_result(res);
|
|
25
|
+
}
|
|
22
26
|
}
|
|
27
|
+
um_op_release(machine, op);
|
|
23
28
|
|
|
24
29
|
RAISE_IF_EXCEPTION(ret);
|
|
25
30
|
RB_GC_GUARD(ret);
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
void um_futex_wake(struct um *machine, uint32_t *futex, uint32_t num_waiters) {
|
|
29
|
-
struct um_op op;
|
|
30
|
-
um_prep_op(machine,
|
|
31
|
-
struct io_uring_sqe *sqe = um_get_sqe(machine,
|
|
34
|
+
struct um_op *op = um_op_acquire(machine);
|
|
35
|
+
um_prep_op(machine, op, OP_FUTEX_WAKE, 2, 0);
|
|
36
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
32
37
|
io_uring_prep_futex_wake(
|
|
33
38
|
sqe, (uint32_t *)futex, num_waiters, FUTEX_BITSET_MATCH_ANY, FUTEX2_SIZE_U32, 0
|
|
34
39
|
);
|
|
35
40
|
|
|
36
41
|
VALUE ret = um_yield(machine);
|
|
37
|
-
|
|
42
|
+
|
|
43
|
+
um_verify_op_completion(machine, op, true);
|
|
44
|
+
um_op_release(machine, op);
|
|
38
45
|
|
|
39
46
|
RAISE_IF_EXCEPTION(ret);
|
|
40
47
|
RB_GC_GUARD(ret);
|
data/ext/um/um_utils.c
CHANGED
|
@@ -98,15 +98,21 @@ inline void um_update_read_buffer(VALUE buffer, ssize_t buffer_offset, __s32 res
|
|
|
98
98
|
adjust_read_buffer_len(buffer, result, buffer_offset);
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
// returns false if buffer is invalid and raise_on_bad_buffer is false
|
|
102
|
+
inline int um_get_buffer_bytes_for_writing(VALUE buffer, const void **base, size_t *size, int raise_on_bad_buffer) {
|
|
102
103
|
if (TYPE(buffer) == T_STRING) {
|
|
103
104
|
*base = RSTRING_PTR(buffer);
|
|
104
105
|
*size = RSTRING_LEN(buffer);
|
|
105
106
|
}
|
|
106
107
|
else if (IO_BUFFER_P(buffer))
|
|
107
108
|
rb_io_buffer_get_bytes_for_reading(buffer, base, size); // reading *from* buffer
|
|
108
|
-
else
|
|
109
|
-
|
|
109
|
+
else {
|
|
110
|
+
if (raise_on_bad_buffer)
|
|
111
|
+
um_raise_internal_error("Invalid buffer provided");
|
|
112
|
+
else
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
return true;
|
|
110
116
|
}
|
|
111
117
|
|
|
112
118
|
int um_setup_buffer_ring(struct um *machine, unsigned size, unsigned count) {
|
|
@@ -204,7 +210,11 @@ inline struct iovec *um_alloc_iovecs_for_writing(int argc, VALUE *argv, size_t *
|
|
|
204
210
|
size_t len = 0;
|
|
205
211
|
|
|
206
212
|
for (int i = 0; i < argc; i++) {
|
|
207
|
-
um_get_buffer_bytes_for_writing(argv[i], (const void **)&iovecs[i].iov_base, &iovecs[i].iov_len);
|
|
213
|
+
int ok = um_get_buffer_bytes_for_writing(argv[i], (const void **)&iovecs[i].iov_base, &iovecs[i].iov_len, false);
|
|
214
|
+
if (unlikely(!ok)) {
|
|
215
|
+
free(iovecs);
|
|
216
|
+
um_raise_internal_error("Invalid buffer provided");
|
|
217
|
+
}
|
|
208
218
|
len += iovecs[i].iov_len;
|
|
209
219
|
}
|
|
210
220
|
if (total_len) *total_len = len;
|
data/grant-2025/tasks.md
CHANGED
|
@@ -129,10 +129,10 @@
|
|
|
129
129
|
|
|
130
130
|
- [v] Postgres test
|
|
131
131
|
|
|
132
|
-
- [
|
|
132
|
+
- [v] Ruby Fiber::Scheduler interface
|
|
133
133
|
- [v] Make a PR for resetting the scheduler and resetting the fiber non-blocking flag.
|
|
134
134
|
- [v] hook for close
|
|
135
|
-
- [
|
|
135
|
+
- [x] hooks for send/recv/sendmsg/recvmsg (Ruby core PR pending for send/recv)
|
|
136
136
|
|
|
137
137
|
- [v] SSL
|
|
138
138
|
- [v] setup custom BIO
|
data/lib/uringmachine/version.rb
CHANGED
data/test/test_async_op.rb
CHANGED
|
@@ -51,11 +51,12 @@ class AsyncOpTest < UMBaseTest
|
|
|
51
51
|
@op.cancel
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
assert_raises(Errno::ECANCELED) {
|
|
55
|
+
@op.await
|
|
56
|
+
}
|
|
55
57
|
|
|
56
58
|
assert_equal 0, machine.metrics[:ops_pending]
|
|
57
59
|
assert_equal true, @op.done?
|
|
58
|
-
assert_equal (-ECANCELED), res
|
|
59
60
|
assert_equal true, @op.cancelled?
|
|
60
61
|
end
|
|
61
62
|
|
|
@@ -393,9 +393,12 @@ class FiberSchedulerTest < UMBaseTest
|
|
|
393
393
|
sleep 0.001
|
|
394
394
|
buf = IO.read(fn)
|
|
395
395
|
end
|
|
396
|
-
assert_equal 2, machine.metrics[:total_ops]
|
|
397
396
|
|
|
398
397
|
@scheduler.join
|
|
398
|
+
metrics = machine.metrics
|
|
399
|
+
assert_in_range 5..12, metrics[:total_ops]
|
|
400
|
+
assert_equal 0, metrics[:ops_pending]
|
|
401
|
+
assert_equal 256, metrics[:ops_free]
|
|
399
402
|
assert_equal 'foobar', buf
|
|
400
403
|
assert_equal({
|
|
401
404
|
fiber: 2,
|