uringmachine 0.31.0 → 0.33.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/README.md +36 -37
- data/TODO.md +40 -59
- data/benchmark/bm_io_pipe.rb +2 -2
- data/benchmark/common.rb +16 -16
- data/benchmark/gets.rb +7 -7
- data/benchmark/gets_concurrent.rb +12 -12
- data/benchmark/http_parse.rb +11 -11
- data/benchmark/http_server_accept_queue.rb +7 -7
- data/benchmark/http_server_multi_accept.rb +7 -7
- data/benchmark/http_server_multi_ractor.rb +7 -7
- data/benchmark/http_server_single_thread.rb +8 -8
- data/benchmark/openssl.rb +4 -4
- data/docs/um_api.md +4 -9
- data/examples/fiber_concurrency_io.rb +1 -1
- data/examples/fiber_concurrency_um.rb +16 -0
- data/examples/io_uring_simple.c +13 -4
- data/examples/pg.rb +2 -2
- data/examples/um_cancellation.rb +20 -0
- data/examples/um_fiber_scheduler.rb +10 -0
- data/examples/um_io.rb +19 -0
- data/examples/um_mo.c +32 -0
- data/examples/um_multishot.rb +15 -0
- data/examples/um_ssl.rb +11 -0
- data/ext/um/um.c +21 -76
- data/ext/um/um.h +22 -41
- data/ext/um/um_class.c +11 -65
- data/ext/um/um_ext.c +2 -4
- data/ext/um/{um_connection.c → um_io.c} +209 -210
- data/ext/um/{um_connection_class.c → um_io_class.c} +102 -102
- data/ext/um/um_op.c +0 -1
- data/ext/um/um_utils.c +0 -86
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +12 -12
- data/test/{test_connection.rb → test_io.rb} +63 -63
- data/test/test_um.rb +17 -95
- metadata +13 -6
|
@@ -12,8 +12,8 @@ require 'uringmachine'
|
|
|
12
12
|
RE_REQUEST_LINE = /^([a-z]+)\s+([^\s]+)\s+(http\/[0-9\.]{1,3})/i
|
|
13
13
|
RE_HEADER_LINE = /^([a-z0-9\-]+)\:\s+(.+)/i
|
|
14
14
|
|
|
15
|
-
def
|
|
16
|
-
line =
|
|
15
|
+
def io_get_request_line(io, buf)
|
|
16
|
+
line = io.read_line(0)
|
|
17
17
|
m = line&.match(RE_REQUEST_LINE)
|
|
18
18
|
return nil if !m
|
|
19
19
|
|
|
@@ -26,12 +26,12 @@ end
|
|
|
26
26
|
|
|
27
27
|
class InvalidHeadersError < StandardError; end
|
|
28
28
|
|
|
29
|
-
def get_headers(
|
|
30
|
-
headers =
|
|
29
|
+
def get_headers(io, buf)
|
|
30
|
+
headers = io_get_request_line(io, buf)
|
|
31
31
|
return nil if !headers
|
|
32
32
|
|
|
33
33
|
while true
|
|
34
|
-
line =
|
|
34
|
+
line = io.read_line(0)
|
|
35
35
|
break if line.empty?
|
|
36
36
|
|
|
37
37
|
m = line.match(RE_HEADER_LINE)
|
|
@@ -52,11 +52,11 @@ end
|
|
|
52
52
|
|
|
53
53
|
def handle_connection(machine, fd)
|
|
54
54
|
machine.setsockopt(fd, UM::IPPROTO_TCP, UM::TCP_NODELAY, true)
|
|
55
|
-
|
|
55
|
+
io = UM::IO.new(machine, fd)
|
|
56
56
|
buf = String.new(capacity: 65536)
|
|
57
57
|
|
|
58
58
|
while true
|
|
59
|
-
headers = get_headers(
|
|
59
|
+
headers = get_headers(io, buf)
|
|
60
60
|
break if !headers
|
|
61
61
|
|
|
62
62
|
send_response(machine, fd)
|
|
@@ -77,4 +77,4 @@ machine.bind(fd, '127.0.0.1', PORT)
|
|
|
77
77
|
machine.listen(fd, 128)
|
|
78
78
|
|
|
79
79
|
puts "Listening on localhost:#{PORT}"
|
|
80
|
-
machine.accept_each(fd) { |
|
|
80
|
+
machine.accept_each(fd) { | io| machine.spin { handle_connection(machine, io) } }
|
data/benchmark/openssl.rb
CHANGED
|
@@ -81,7 +81,7 @@ end
|
|
|
81
81
|
@um.ssl_set_bio(@ssl_conn)
|
|
82
82
|
@ssl_conn.connect
|
|
83
83
|
|
|
84
|
-
@
|
|
84
|
+
@io = @um.io(@ssl_conn)
|
|
85
85
|
|
|
86
86
|
@msg = 'abc' * 1000
|
|
87
87
|
@msg_newline = @msg + "\n"
|
|
@@ -91,15 +91,15 @@ def do_io(ssl)
|
|
|
91
91
|
ssl.gets
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
-
def
|
|
94
|
+
def do_io_io(ssl, um, io)
|
|
95
95
|
um.ssl_write(ssl, @msg_newline, 0)
|
|
96
|
-
|
|
96
|
+
io.read_line(0)
|
|
97
97
|
end
|
|
98
98
|
|
|
99
99
|
Benchmark.ips do |x|
|
|
100
100
|
x.report('stock') { do_io(@ssl_stock) }
|
|
101
101
|
x.report('UM BIO') { do_io(@ssl_um) }
|
|
102
|
-
x.report('UM
|
|
102
|
+
x.report('UM::IO') { do_io_io(@ssl_conn, @um, @io) }
|
|
103
103
|
|
|
104
104
|
x.compare!(order: :baseline)
|
|
105
105
|
end
|
data/docs/um_api.md
CHANGED
|
@@ -43,26 +43,21 @@
|
|
|
43
43
|
- `pop(queue)` - removes and returns a value off the end of the given queue.
|
|
44
44
|
- `prep_timeout(interval)` - returns a timeout AsyncOp with the given interval.
|
|
45
45
|
- `push(queue, value)` - adds the given value to the end of the given queue.
|
|
46
|
-
- `read_each(fd
|
|
47
|
-
|
|
48
|
-
block.
|
|
46
|
+
- `read_each(fd) { |data| ... }` - reads repeatedly from the given fd, yielding
|
|
47
|
+
each chunk of data to the given block.
|
|
49
48
|
- `read(fd, buffer[, maxlen[, buffer_offset[, file_offset]]])` - reads from the
|
|
50
49
|
given fd int o the given buffer (String or IO::Buffer).
|
|
51
|
-
- `recv_each(fd,
|
|
52
|
-
|
|
50
|
+
- `recv_each(fd, flags)` - receives repeatedly from the given fd with the given
|
|
51
|
+
flags.
|
|
53
52
|
- `recv(fd, buffer, maxlen, flags)` - receives from the given fd into the given
|
|
54
53
|
buffer.
|
|
55
54
|
- `schedule(fiber, value)` - adds the given fiber to the runqueue with the given
|
|
56
55
|
resume value.
|
|
57
56
|
- `select(rfds, wfds, efds)` - selects ready fds from the given readable,
|
|
58
57
|
writable and exeptable fds.
|
|
59
|
-
- `send_bundle(fd, bgid, *strings)` - sends a bundle of buffers to the given fd
|
|
60
|
-
using the given buffer group id.
|
|
61
58
|
- `send(fd, buffer, len, flags)` - sends to the given fd from the given buffer.
|
|
62
59
|
- `sendv(fd, *buffers)` - sends multiple buffers to the given fd.
|
|
63
60
|
- `setsockopt(fd, level, opt, value)` - sets a socket option.
|
|
64
|
-
- `setup_buffer_ring(size, count)` - sets up a buffer ring and returns the
|
|
65
|
-
buffer group id.
|
|
66
61
|
- `shift(queue)` - removes and returns a value from the head of given queue.
|
|
67
62
|
- `shutdown_async(fd, how)` - shuts down the given socket fd without blocking.
|
|
68
63
|
- `shutdown(fd, how)` - shuts down the given socket fd.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'uringmachine'
|
|
2
|
+
|
|
3
|
+
machine = UM.new
|
|
4
|
+
|
|
5
|
+
reader = machine.spin {
|
|
6
|
+
input = +''
|
|
7
|
+
machine.read(UM::STDIN_FILENO, input, 256)
|
|
8
|
+
machine.write(UM::STDOUT_FILENO, "Got: #{input}")
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
sleeper = machine.spin {
|
|
12
|
+
machine.sleep(5)
|
|
13
|
+
machine.write(UM::STDOUT_FILENO, "5 seconds have elapsed!")
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
machine.join(reader, sleeper)
|
data/examples/io_uring_simple.c
CHANGED
|
@@ -7,6 +7,7 @@ int ret;
|
|
|
7
7
|
char buf[100];
|
|
8
8
|
|
|
9
9
|
ret = io_uring_queue_init(8, &ring, 0);
|
|
10
|
+
|
|
10
11
|
sqe = io_uring_get_sqe(&ring);
|
|
11
12
|
io_uring_prep_read(sqe, STDIN_FILENO, buf, 100, 0);
|
|
12
13
|
sqe->user_data = 42;
|
|
@@ -14,11 +15,19 @@ io_uring_submit(&ring);
|
|
|
14
15
|
|
|
15
16
|
...
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
sqe = io_uring_get_sqe(&ring);
|
|
19
|
+
io_uring_prep_cancel(sqe, 42, IORING_ASYNC_CANCEL_USERDATA);
|
|
20
|
+
sqe->flags = IOSQE_CQE_SKIP_SUCCESS;
|
|
21
|
+
io_uring_submit(&ring);
|
|
22
|
+
|
|
23
|
+
if (!io_uring_wait_cqe(&ring, &cqe)) {
|
|
19
24
|
if (cqe->user_data == 42) {
|
|
20
|
-
|
|
21
|
-
|
|
25
|
+
if (cqe->res == -ECANCELED)
|
|
26
|
+
printf("Cancelled!\n");
|
|
27
|
+
else {
|
|
28
|
+
int len = cqe->res;
|
|
29
|
+
printf("Got %d bytes\n", len);
|
|
30
|
+
}
|
|
22
31
|
}
|
|
23
32
|
io_uring_cqe_seen(&ring, cqe);
|
|
24
33
|
}
|
data/examples/pg.rb
CHANGED
|
@@ -66,9 +66,9 @@ $machine.listen(server_fd, UM::SOMAXCONN)
|
|
|
66
66
|
puts 'Listening on port 1234'
|
|
67
67
|
|
|
68
68
|
def handle_connection(fd)
|
|
69
|
-
|
|
69
|
+
io = UM::IO.new($machine, fd)
|
|
70
70
|
|
|
71
|
-
while (l =
|
|
71
|
+
while (l = io.gets)
|
|
72
72
|
$machine.write(fd, "You said: #{l}")
|
|
73
73
|
end
|
|
74
74
|
rescue Exception => e
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
f = machine.spin do
|
|
2
|
+
buf = +''
|
|
3
|
+
machine.read(fd, buf, 256)
|
|
4
|
+
machine.write(UM::STDOUT_FILENO, "Got: #{buf}")
|
|
5
|
+
rescue UM::Terminate
|
|
6
|
+
machine.write(UM::STDOUT_FILENO, "Cancelled")
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
machine.sleep(0.1)
|
|
10
|
+
machine.schedule(f, UM::Terminate.new)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# read with timeout
|
|
16
|
+
input = +''
|
|
17
|
+
machine.timeout(timeout, TimeoutError) {
|
|
18
|
+
machine.read(fd, input, 256)
|
|
19
|
+
}
|
|
20
|
+
|
data/examples/um_io.rb
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
io = machine.io(fd)
|
|
2
|
+
|
|
3
|
+
# parse an incoming HTTP request
|
|
4
|
+
line = io.read_line(4096)
|
|
5
|
+
m = line.match(/^([a-z]+)\s+([^\s]+)\s+(http\/1\.1)/i)
|
|
6
|
+
headers = {
|
|
7
|
+
':method' => m[1].downcase,
|
|
8
|
+
':path' => m[2],
|
|
9
|
+
':protocol' => m[3].downcase
|
|
10
|
+
}
|
|
11
|
+
while true
|
|
12
|
+
line = io.read_line(4096)
|
|
13
|
+
break if line.empty?
|
|
14
|
+
|
|
15
|
+
m = line.match(/^([a-z0-9\-]+)\:\s+(.+)/i)
|
|
16
|
+
headers[m[1].downcase] = m[2]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
io.write("HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo")
|
data/examples/um_mo.c
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
VALUE um_sleep(struct um *machine, double duration) {
|
|
2
|
+
struct um_op *op = um_op_acquire(machine);
|
|
3
|
+
op->fiber = rb_fiber_current();
|
|
4
|
+
op->ts = um_double_to_timespec(duration);
|
|
5
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
6
|
+
io_uring_prep_timeout(sqe, &op->ts, 0, 0);
|
|
7
|
+
|
|
8
|
+
VALUE ret = um_switch(machine);
|
|
9
|
+
if (um_verify_op_completion(machine, op)) ret = DBL2NUM(duration);
|
|
10
|
+
um_op_release(machine, op);
|
|
11
|
+
|
|
12
|
+
RAISE_IF_EXCEPTION(ret);
|
|
13
|
+
return ret;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
VALUE um_switch(struct um *machine) {
|
|
17
|
+
while (true) {
|
|
18
|
+
struct um_op *op = um_runqueue_shift(machine);
|
|
19
|
+
if (op) return rb_fiber_transfer(op->fiber, 1, &op->value);
|
|
20
|
+
|
|
21
|
+
um_wait_for_and_process_ready_cqes(machine);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
void um_process_cqe(struct um *machine, struct io_uring_cqe *cqe) {
|
|
26
|
+
struct um_op *op = (struct um_op *)cqe->user_data;
|
|
27
|
+
if (op) {
|
|
28
|
+
op->result.res = cqe->res;
|
|
29
|
+
op->result.flags = cqe->flags;
|
|
30
|
+
um_runqueue_push(machine, op);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# singleshot accept
|
|
2
|
+
while (fd = machine.accept(server_fd))
|
|
3
|
+
handle_connection(fd)
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
# multishot accept
|
|
7
|
+
machine.accept_each(server_fd) { handle_connection(it) }
|
|
8
|
+
|
|
9
|
+
# multishot timeout
|
|
10
|
+
machine.periodically(5) { ... }
|
|
11
|
+
|
|
12
|
+
# multishot recv
|
|
13
|
+
machine.recv_each(fd, 0) { |data|
|
|
14
|
+
machine.write(UM::STDOUT_FILENO, "Got: #{data}\n")
|
|
15
|
+
}
|
data/examples/um_ssl.rb
ADDED
data/ext/um/um.c
CHANGED
|
@@ -49,12 +49,6 @@ inline void um_teardown(struct um *machine) {
|
|
|
49
49
|
if (machine->sidecar_mode) um_sidecar_teardown(machine);
|
|
50
50
|
if (machine->sidecar_signal) free(machine->sidecar_signal);
|
|
51
51
|
|
|
52
|
-
for (unsigned i = 0; i < machine->buffer_ring_count; i++) {
|
|
53
|
-
struct buf_ring_descriptor *desc = machine->buffer_rings + i;
|
|
54
|
-
io_uring_free_buf_ring(&machine->ring, desc->br, desc->buf_count, i);
|
|
55
|
-
free(desc->buf_base);
|
|
56
|
-
}
|
|
57
|
-
machine->buffer_ring_count = 0;
|
|
58
52
|
io_uring_queue_exit(&machine->ring);
|
|
59
53
|
machine->ring_initialized = 0;
|
|
60
54
|
|
|
@@ -523,7 +517,6 @@ struct op_ctx {
|
|
|
523
517
|
struct um *machine;
|
|
524
518
|
struct um_op *op;
|
|
525
519
|
int fd;
|
|
526
|
-
int bgid;
|
|
527
520
|
|
|
528
521
|
struct um_queue *queue;
|
|
529
522
|
void *read_buf;
|
|
@@ -870,25 +863,6 @@ VALUE um_sendv(struct um *machine, int fd, int argc, VALUE *argv) {
|
|
|
870
863
|
return ret;
|
|
871
864
|
}
|
|
872
865
|
|
|
873
|
-
VALUE um_send_bundle(struct um *machine, int fd, int bgid, VALUE strings) {
|
|
874
|
-
um_add_strings_to_buffer_ring(machine, bgid, strings);
|
|
875
|
-
struct um_op *op = um_op_acquire(machine);
|
|
876
|
-
um_prep_op(machine, op, OP_SEND_BUNDLE, 2, 0);
|
|
877
|
-
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
878
|
-
io_uring_prep_send_bundle(sqe, fd, 0, MSG_NOSIGNAL | MSG_WAITALL);
|
|
879
|
-
sqe->flags |= IOSQE_BUFFER_SELECT;
|
|
880
|
-
sqe->buf_group = bgid;
|
|
881
|
-
|
|
882
|
-
VALUE ret = um_yield(machine);
|
|
883
|
-
|
|
884
|
-
if (likely(um_verify_op_completion(machine, op, true))) ret = INT2NUM(op->result.res);
|
|
885
|
-
um_op_release(machine, op);
|
|
886
|
-
|
|
887
|
-
RAISE_IF_EXCEPTION(ret);
|
|
888
|
-
RB_GC_GUARD(ret);
|
|
889
|
-
return ret;
|
|
890
|
-
}
|
|
891
|
-
|
|
892
866
|
VALUE um_recv(struct um *machine, int fd, VALUE buffer, size_t maxlen, int flags) {
|
|
893
867
|
void *ptr = um_prepare_read_buffer(buffer, maxlen, 0);
|
|
894
868
|
struct um_op *op = um_op_acquire(machine);
|
|
@@ -1461,72 +1435,44 @@ VALUE um_accept_into_queue(struct um *machine, int fd, VALUE queue) {
|
|
|
1461
1435
|
return rb_ensure(accept_into_queue_start, (VALUE)&ctx, multishot_complete, (VALUE)&ctx);
|
|
1462
1436
|
}
|
|
1463
1437
|
|
|
1464
|
-
int um_read_each_singleshot_loop(struct op_ctx *ctx) {
|
|
1465
|
-
struct buf_ring_descriptor *desc = ctx->machine->buffer_rings + ctx->bgid;
|
|
1466
|
-
ctx->read_maxlen = desc->buf_size;
|
|
1467
|
-
ctx->read_buf = malloc(desc->buf_size);
|
|
1468
|
-
int total = 0;
|
|
1469
|
-
|
|
1470
|
-
while (1) {
|
|
1471
|
-
um_prep_op(ctx->machine, ctx->op, OP_READ, 2, 0);
|
|
1472
|
-
struct io_uring_sqe *sqe = um_get_sqe(ctx->machine, ctx->op);
|
|
1473
|
-
io_uring_prep_read(sqe, ctx->fd, ctx->read_buf, ctx->read_maxlen, -1);
|
|
1474
|
-
|
|
1475
|
-
VALUE ret = um_yield(ctx->machine);
|
|
1476
|
-
|
|
1477
|
-
if (likely(um_verify_op_completion(ctx->machine, ctx->op, true))) {
|
|
1478
|
-
VALUE buf = rb_str_new(ctx->read_buf, ctx->op->result.res);
|
|
1479
|
-
total += ctx->op->result.res;
|
|
1480
|
-
rb_yield(buf);
|
|
1481
|
-
RB_GC_GUARD(buf);
|
|
1482
|
-
}
|
|
1483
|
-
else {
|
|
1484
|
-
RAISE_IF_EXCEPTION(ret);
|
|
1485
|
-
return 0;
|
|
1486
|
-
}
|
|
1487
|
-
RB_GC_GUARD(ret);
|
|
1488
|
-
}
|
|
1489
|
-
return 0;
|
|
1490
|
-
}
|
|
1491
|
-
|
|
1492
1438
|
// // returns true if more results are expected
|
|
1493
|
-
int read_recv_each_multishot_process_result(struct op_ctx *ctx, struct um_op_result *result, int *total) {
|
|
1439
|
+
inline int read_recv_each_multishot_process_result(struct op_ctx *ctx, struct um_op_result *result, int *total) {
|
|
1494
1440
|
if (result->res == 0)
|
|
1495
1441
|
return false;
|
|
1496
1442
|
|
|
1497
1443
|
*total += result->res;
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
// if the F_MORE flag is absent, then switch to single shot mode.
|
|
1505
|
-
if (unlikely(!(result->flags & IORING_CQE_F_MORE))) {
|
|
1506
|
-
*total += um_read_each_singleshot_loop(ctx);
|
|
1507
|
-
return false;
|
|
1444
|
+
if (likely(result->segment)) {
|
|
1445
|
+
VALUE buf = rb_str_new(result->segment->ptr, result->segment->len);
|
|
1446
|
+
um_segment_checkin(ctx->machine, result->segment);
|
|
1447
|
+
result->segment = NULL;
|
|
1448
|
+
rb_yield(buf);
|
|
1449
|
+
RB_GC_GUARD(buf);
|
|
1508
1450
|
}
|
|
1509
1451
|
|
|
1510
1452
|
return true;
|
|
1511
1453
|
}
|
|
1512
1454
|
|
|
1513
|
-
void read_recv_each_prep(struct io_uring_sqe *sqe, struct op_ctx *ctx) {
|
|
1455
|
+
static inline void read_recv_each_prep(struct io_uring_sqe *sqe, struct op_ctx *ctx) {
|
|
1456
|
+
bp_ensure_commit_level(ctx->machine);
|
|
1457
|
+
ctx->op->bp_commit_level = ctx->machine->bp_commit_level;
|
|
1458
|
+
|
|
1514
1459
|
switch (ctx->op->kind) {
|
|
1515
1460
|
case OP_READ_MULTISHOT:
|
|
1516
|
-
io_uring_prep_read_multishot(sqe, ctx->fd, 0, -1,
|
|
1461
|
+
io_uring_prep_read_multishot(sqe, ctx->fd, 0, -1, BP_BGID);
|
|
1517
1462
|
return;
|
|
1518
1463
|
case OP_RECV_MULTISHOT:
|
|
1519
1464
|
io_uring_prep_recv_multishot(sqe, ctx->fd, NULL, 0, 0);
|
|
1520
|
-
sqe->buf_group =
|
|
1465
|
+
sqe->buf_group = BP_BGID;
|
|
1521
1466
|
sqe->flags |= IOSQE_BUFFER_SELECT;
|
|
1522
1467
|
return;
|
|
1523
1468
|
default:
|
|
1524
|
-
|
|
1469
|
+
um_raise_internal_error("Invalid multishot op");
|
|
1525
1470
|
}
|
|
1526
1471
|
}
|
|
1527
1472
|
|
|
1528
1473
|
VALUE read_recv_each_start(VALUE arg) {
|
|
1529
1474
|
struct op_ctx *ctx = (struct op_ctx *)arg;
|
|
1475
|
+
|
|
1530
1476
|
struct io_uring_sqe *sqe = um_get_sqe(ctx->machine, ctx->op);
|
|
1531
1477
|
read_recv_each_prep(sqe, ctx);
|
|
1532
1478
|
int total = 0;
|
|
@@ -1558,19 +1504,19 @@ VALUE read_recv_each_start(VALUE arg) {
|
|
|
1558
1504
|
return Qnil;
|
|
1559
1505
|
}
|
|
1560
1506
|
|
|
1561
|
-
VALUE um_read_each(struct um *machine, int fd
|
|
1507
|
+
VALUE um_read_each(struct um *machine, int fd) {
|
|
1562
1508
|
struct um_op *op = um_op_acquire(machine);
|
|
1563
|
-
um_prep_op(machine, op, OP_READ_MULTISHOT, 2, OP_F_MULTISHOT);
|
|
1509
|
+
um_prep_op(machine, op, OP_READ_MULTISHOT, 2, OP_F_MULTISHOT | OP_F_BUFFER_POOL);
|
|
1564
1510
|
|
|
1565
|
-
struct op_ctx ctx = { .machine = machine, .op = op, .fd = fd, .
|
|
1511
|
+
struct op_ctx ctx = { .machine = machine, .op = op, .fd = fd, .read_buf = NULL };
|
|
1566
1512
|
return rb_ensure(read_recv_each_start, (VALUE)&ctx, multishot_complete, (VALUE)&ctx);
|
|
1567
1513
|
}
|
|
1568
1514
|
|
|
1569
|
-
VALUE um_recv_each(struct um *machine, int fd, int
|
|
1515
|
+
VALUE um_recv_each(struct um *machine, int fd, int flags) {
|
|
1570
1516
|
struct um_op *op = um_op_acquire(machine);
|
|
1571
|
-
um_prep_op(machine, op, OP_RECV_MULTISHOT, 2, OP_F_MULTISHOT);
|
|
1517
|
+
um_prep_op(machine, op, OP_RECV_MULTISHOT, 2, OP_F_MULTISHOT | OP_F_BUFFER_POOL);
|
|
1572
1518
|
|
|
1573
|
-
struct op_ctx ctx = { .machine = machine, .op = op, .fd = fd, .
|
|
1519
|
+
struct op_ctx ctx = { .machine = machine, .op = op, .fd = fd, .read_buf = NULL, .flags = flags };
|
|
1574
1520
|
return rb_ensure(read_recv_each_start, (VALUE)&ctx, multishot_complete, (VALUE)&ctx);
|
|
1575
1521
|
}
|
|
1576
1522
|
|
|
@@ -1623,7 +1569,6 @@ extern VALUE SYM_ops_free;
|
|
|
1623
1569
|
extern VALUE SYM_ops_transient;
|
|
1624
1570
|
extern VALUE SYM_time_total_cpu;
|
|
1625
1571
|
extern VALUE SYM_time_total_wait;
|
|
1626
|
-
extern VALUE SYM_buffer_groups;
|
|
1627
1572
|
extern VALUE SYM_buffers_allocated;
|
|
1628
1573
|
extern VALUE SYM_buffers_free;
|
|
1629
1574
|
extern VALUE SYM_segments_free;
|
data/ext/um/um.h
CHANGED
|
@@ -56,7 +56,6 @@ enum um_op_kind {
|
|
|
56
56
|
OP_RECV,
|
|
57
57
|
OP_RECVMSG,
|
|
58
58
|
OP_SEND,
|
|
59
|
-
OP_SEND_BUNDLE,
|
|
60
59
|
OP_SENDMSG,
|
|
61
60
|
OP_SENDV,
|
|
62
61
|
OP_SOCKET,
|
|
@@ -80,12 +79,12 @@ enum um_op_kind {
|
|
|
80
79
|
OP_TIMEOUT_MULTISHOT,
|
|
81
80
|
};
|
|
82
81
|
|
|
83
|
-
enum
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
82
|
+
enum um_io_mode {
|
|
83
|
+
IO_FD,
|
|
84
|
+
IO_SOCKET,
|
|
85
|
+
IO_SSL,
|
|
86
|
+
IO_STRING,
|
|
87
|
+
IO_IO_BUFFER
|
|
89
88
|
};
|
|
90
89
|
|
|
91
90
|
#define OP_F_CQE_SEEN (1U << 0) // CQE has been seen
|
|
@@ -168,15 +167,6 @@ struct um_op {
|
|
|
168
167
|
};
|
|
169
168
|
};
|
|
170
169
|
|
|
171
|
-
struct buf_ring_descriptor {
|
|
172
|
-
struct io_uring_buf_ring *br;
|
|
173
|
-
size_t br_size;
|
|
174
|
-
unsigned buf_count;
|
|
175
|
-
unsigned buf_size;
|
|
176
|
-
unsigned buf_mask;
|
|
177
|
-
void *buf_base;
|
|
178
|
-
};
|
|
179
|
-
|
|
180
170
|
struct um_metrics {
|
|
181
171
|
ulong total_ops; // total ops submitted
|
|
182
172
|
ulong total_switches; // total fiber switches
|
|
@@ -199,8 +189,6 @@ struct um_metrics {
|
|
|
199
189
|
double time_first_cpu; // last seen time stamp
|
|
200
190
|
};
|
|
201
191
|
|
|
202
|
-
#define BUFFER_RING_MAX_COUNT 10
|
|
203
|
-
|
|
204
192
|
struct um {
|
|
205
193
|
VALUE self;
|
|
206
194
|
|
|
@@ -216,13 +204,9 @@ struct um {
|
|
|
216
204
|
pthread_t sidecar_thread;
|
|
217
205
|
uint32_t *sidecar_signal;
|
|
218
206
|
|
|
219
|
-
uint buffer_ring_count; // number of registered buffer rings
|
|
220
|
-
|
|
221
207
|
uint size; // size of SQ
|
|
222
208
|
uint sqpoll_mode; // SQPOLL mode enabled
|
|
223
209
|
|
|
224
|
-
struct buf_ring_descriptor buffer_rings[BUFFER_RING_MAX_COUNT];
|
|
225
|
-
|
|
226
210
|
struct um_op *transient_head; // list of pending transient ops
|
|
227
211
|
VALUE pending_fibers; // set containing pending fibers
|
|
228
212
|
|
|
@@ -272,11 +256,11 @@ struct um_async_op {
|
|
|
272
256
|
struct um_op *op;
|
|
273
257
|
};
|
|
274
258
|
|
|
275
|
-
struct
|
|
259
|
+
struct um_io {
|
|
276
260
|
VALUE self;
|
|
277
261
|
struct um *machine;
|
|
278
262
|
|
|
279
|
-
enum
|
|
263
|
+
enum um_io_mode mode;
|
|
280
264
|
union {
|
|
281
265
|
int fd;
|
|
282
266
|
VALUE target;
|
|
@@ -304,7 +288,7 @@ extern VALUE eUMError;
|
|
|
304
288
|
extern VALUE cMutex;
|
|
305
289
|
extern VALUE cQueue;
|
|
306
290
|
extern VALUE cAsyncOp;
|
|
307
|
-
extern VALUE
|
|
291
|
+
extern VALUE eIORESPError;
|
|
308
292
|
|
|
309
293
|
struct um *um_get_machine(VALUE self);
|
|
310
294
|
void um_setup(VALUE self, struct um *machine, uint size, uint sqpoll_timeout_msec, int sidecar_mode);
|
|
@@ -351,9 +335,7 @@ void um_raise_on_error_result(int result);
|
|
|
351
335
|
int um_get_buffer_bytes_for_writing(VALUE buffer, const void **base, size_t *size, int raise_on_bad_buffer);
|
|
352
336
|
void * um_prepare_read_buffer(VALUE buffer, ssize_t len, ssize_t ofs);
|
|
353
337
|
void um_update_read_buffer(VALUE buffer, ssize_t buffer_offset, __s32 result);
|
|
354
|
-
|
|
355
|
-
VALUE um_read_from_buffer_ring(struct um *machine, int bgid, __s32 result, __u32 flags);
|
|
356
|
-
void um_add_strings_to_buffer_ring(struct um *machine, int bgid, VALUE strings);
|
|
338
|
+
|
|
357
339
|
struct iovec *um_alloc_iovecs_for_writing(int argc, VALUE *argv, size_t *total_len);
|
|
358
340
|
void um_advance_iovecs_for_writing(struct iovec **ptr, int *len, size_t adv);
|
|
359
341
|
|
|
@@ -376,7 +358,7 @@ VALUE um_sleep(struct um *machine, double duration);
|
|
|
376
358
|
VALUE um_periodically(struct um *machine, double interval);
|
|
377
359
|
VALUE um_read(struct um *machine, int fd, VALUE buffer, size_t maxlen, ssize_t buffer_offset, __u64 file_offset);
|
|
378
360
|
size_t um_read_raw(struct um *machine, int fd, char *buffer, size_t maxlen);
|
|
379
|
-
VALUE um_read_each(struct um *machine, int fd
|
|
361
|
+
VALUE um_read_each(struct um *machine, int fd);
|
|
380
362
|
VALUE um_write(struct um *machine, int fd, VALUE buffer, size_t len, __u64 file_offset);
|
|
381
363
|
size_t um_write_raw(struct um *machine, int fd, const char *buffer, size_t len);
|
|
382
364
|
VALUE um_writev(struct um *machine, int fd, int argc, VALUE *argv);
|
|
@@ -405,9 +387,8 @@ VALUE um_connect(struct um *machine, int fd, const struct sockaddr *addr, sockle
|
|
|
405
387
|
VALUE um_send(struct um *machine, int fd, VALUE buffer, size_t len, int flags);
|
|
406
388
|
size_t um_send_raw(struct um *machine, int fd, const char *buffer, size_t len, int flags);
|
|
407
389
|
VALUE um_sendv(struct um *machine, int fd, int argc, VALUE *argv);
|
|
408
|
-
VALUE um_send_bundle(struct um *machine, int fd, int bgid, VALUE strings);
|
|
409
390
|
VALUE um_recv(struct um *machine, int fd, VALUE buffer, size_t maxlen, int flags);
|
|
410
|
-
VALUE um_recv_each(struct um *machine, int fd, int
|
|
391
|
+
VALUE um_recv_each(struct um *machine, int fd, int flags);
|
|
411
392
|
VALUE um_bind(struct um *machine, int fd, struct sockaddr *addr, socklen_t addrlen);
|
|
412
393
|
VALUE um_listen(struct um *machine, int fd, int backlog);
|
|
413
394
|
VALUE um_getsockopt(struct um *machine, int fd, int level, int opt);
|
|
@@ -438,16 +419,16 @@ VALUE um_queue_pop(struct um *machine, struct um_queue *queue);
|
|
|
438
419
|
VALUE um_queue_unshift(struct um *machine, struct um_queue *queue, VALUE value);
|
|
439
420
|
VALUE um_queue_shift(struct um *machine, struct um_queue *queue);
|
|
440
421
|
|
|
441
|
-
void
|
|
442
|
-
void
|
|
443
|
-
VALUE
|
|
444
|
-
VALUE
|
|
445
|
-
VALUE
|
|
446
|
-
void
|
|
447
|
-
void
|
|
448
|
-
size_t
|
|
449
|
-
VALUE
|
|
450
|
-
VALUE resp_read(struct
|
|
422
|
+
void io_teardown(struct um_io *io);
|
|
423
|
+
void io_clear(struct um_io *io);
|
|
424
|
+
VALUE io_read_line(struct um_io *io, VALUE out_buffer, size_t maxlen);
|
|
425
|
+
VALUE io_read(struct um_io *io, VALUE out_buffer, ssize_t len, size_t inc, int safe_inc);
|
|
426
|
+
VALUE io_read_to_delim(struct um_io *io, VALUE out_buffer, VALUE delim, ssize_t maxlen);
|
|
427
|
+
void io_skip(struct um_io *io, size_t inc, int safe_inc);
|
|
428
|
+
void io_read_each(struct um_io *io);
|
|
429
|
+
size_t io_write_raw(struct um_io *io, const char *buffer, size_t len);
|
|
430
|
+
VALUE io_writev(struct um_io *io, int argc, VALUE *argv);
|
|
431
|
+
VALUE resp_read(struct um_io *io, VALUE out_buffer);
|
|
451
432
|
void resp_encode(struct um_write_buffer *buf, VALUE obj);
|
|
452
433
|
void resp_encode_cmd(struct um_write_buffer *buf, int argc, VALUE *argv);
|
|
453
434
|
|