uringmachine 0.30.0 → 0.31.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 +12 -4
- data/README.md +46 -38
- data/TODO.md +56 -2
- data/benchmark/gets.rb +7 -7
- data/benchmark/gets_concurrent.rb +10 -10
- data/benchmark/http_parse.rb +14 -14
- data/benchmark/http_server_accept_queue.rb +11 -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 +7 -7
- data/benchmark/openssl.rb +50 -22
- data/docs/design/buffer_pool.md +1 -1
- data/examples/fiber_concurrency_io.rb +52 -0
- data/examples/fiber_concurrency_naive.rb +26 -0
- data/examples/fiber_concurrency_runqueue.rb +33 -0
- data/examples/io_uring_simple.c +24 -0
- data/examples/pg.rb +2 -2
- data/examples/stream.rb +2 -2
- data/ext/um/um.c +20 -3
- data/ext/um/um.h +24 -18
- data/ext/um/um_connection.c +775 -0
- data/ext/um/um_connection_class.c +394 -0
- data/ext/um/um_ssl.c +37 -2
- data/ext/um/um_utils.c +1 -1
- data/grant-2025/final-report.md +2 -0
- data/grant-2025/journal.md +1 -1
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +16 -16
- data/test/{test_stream.rb → test_connection.rb} +290 -153
- data/test/test_um.rb +18 -18
- metadata +10 -6
- data/ext/um/um_stream.c +0 -706
- data/ext/um/um_stream_class.c +0 -317
data/benchmark/openssl.rb
CHANGED
|
@@ -24,54 +24,82 @@ Socket.do_not_reverse_lookup = true
|
|
|
24
24
|
tcps = TCPServer.new("127.0.0.1", 0)
|
|
25
25
|
port = tcps.connect_address.ip_port
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
Thread.new do
|
|
30
|
-
Thread.current.report_on_exception = false
|
|
31
|
-
loop do
|
|
32
|
-
begin
|
|
33
|
-
ssl = ssls.accept
|
|
34
|
-
rescue OpenSSL::SSL::SSLError, IOError, Errno::EBADF, Errno::EINVAL,
|
|
35
|
-
Errno::ECONNABORTED, Errno::ENOTSOCK, Errno::ECONNRESET
|
|
36
|
-
retry
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
Thread.new do
|
|
40
|
-
Thread.current.report_on_exception = false
|
|
27
|
+
pid = fork do
|
|
28
|
+
ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx)
|
|
41
29
|
|
|
30
|
+
Thread.new do
|
|
31
|
+
Thread.current.report_on_exception = false
|
|
32
|
+
loop do
|
|
42
33
|
begin
|
|
43
|
-
|
|
44
|
-
|
|
34
|
+
ssl = ssls.accept
|
|
35
|
+
rescue OpenSSL::SSL::SSLError, IOError, Errno::EBADF, Errno::EINVAL,
|
|
36
|
+
Errno::ECONNABORTED, Errno::ENOTSOCK, Errno::ECONNRESET
|
|
37
|
+
retry
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
Thread.new do
|
|
41
|
+
Thread.current.report_on_exception = false
|
|
42
|
+
|
|
43
|
+
begin
|
|
44
|
+
while line = ssl.gets
|
|
45
|
+
ssl.write(line)
|
|
46
|
+
end
|
|
47
|
+
ensure
|
|
48
|
+
ssl.close
|
|
45
49
|
end
|
|
46
|
-
|
|
47
|
-
ssl.close
|
|
50
|
+
true
|
|
48
51
|
end
|
|
49
|
-
true
|
|
50
52
|
end
|
|
51
53
|
end
|
|
54
|
+
sleep
|
|
55
|
+
rescue Interrupt
|
|
52
56
|
end
|
|
53
57
|
|
|
54
|
-
|
|
58
|
+
at_exit {
|
|
59
|
+
Process.kill('SIGINT', pid)
|
|
60
|
+
Process.wait(pid)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
begin
|
|
64
|
+
@ssl_stock = OpenSSL::SSL::SSLSocket.open("127.0.0.1", port)
|
|
65
|
+
rescue => e
|
|
66
|
+
p e
|
|
67
|
+
exit!
|
|
68
|
+
end
|
|
55
69
|
@ssl_stock.sync_close = true
|
|
56
70
|
@ssl_stock.connect
|
|
57
71
|
|
|
58
|
-
um = UM.new
|
|
72
|
+
@um = UM.new
|
|
59
73
|
|
|
60
74
|
@ssl_um = OpenSSL::SSL::SSLSocket.open("127.0.0.1", port)
|
|
61
75
|
@ssl_um.sync_close = true
|
|
62
|
-
um.ssl_set_bio(@ssl_um)
|
|
76
|
+
@um.ssl_set_bio(@ssl_um)
|
|
63
77
|
@ssl_um.connect
|
|
64
78
|
|
|
79
|
+
@ssl_conn = OpenSSL::SSL::SSLSocket.open("127.0.0.1", port)
|
|
80
|
+
@ssl_conn.sync_close = true
|
|
81
|
+
@um.ssl_set_bio(@ssl_conn)
|
|
82
|
+
@ssl_conn.connect
|
|
83
|
+
|
|
84
|
+
@conn = @um.connection(@ssl_conn, :ssl)
|
|
85
|
+
|
|
65
86
|
@msg = 'abc' * 1000
|
|
87
|
+
@msg_newline = @msg + "\n"
|
|
66
88
|
|
|
67
89
|
def do_io(ssl)
|
|
68
90
|
ssl.puts @msg
|
|
69
91
|
ssl.gets
|
|
70
92
|
end
|
|
71
93
|
|
|
94
|
+
def do_io_connection(ssl, um, conn)
|
|
95
|
+
um.ssl_write(ssl, @msg_newline, 0)
|
|
96
|
+
conn.read_line(0)
|
|
97
|
+
end
|
|
98
|
+
|
|
72
99
|
Benchmark.ips do |x|
|
|
73
100
|
x.report('stock') { do_io(@ssl_stock) }
|
|
74
101
|
x.report('UM BIO') { do_io(@ssl_um) }
|
|
102
|
+
x.report('UM Stream') { do_io_connection(@ssl_conn, @um, @conn) }
|
|
75
103
|
|
|
76
104
|
x.compare!(order: :baseline)
|
|
77
105
|
end
|
data/docs/design/buffer_pool.md
CHANGED
|
@@ -78,7 +78,7 @@ buffers, to using managed buffers from the buffer pool.
|
|
|
78
78
|
```ruby
|
|
79
79
|
machine.stream_recv(fd) do |stream|
|
|
80
80
|
loop do
|
|
81
|
-
line = stream.
|
|
81
|
+
line = stream.read_line(max: 60)
|
|
82
82
|
if (size = parse_size(line))
|
|
83
83
|
data = stream.read(size)
|
|
84
84
|
process_data(data)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
@runqueue = []
|
|
2
|
+
@active_reads = {}; @active_timers = {}
|
|
3
|
+
|
|
4
|
+
def fiber_switch
|
|
5
|
+
while true
|
|
6
|
+
next_fiber, value = @runqueue.shift
|
|
7
|
+
return next_fiber.transfer value if next_fiber
|
|
8
|
+
|
|
9
|
+
process_events
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def process_events
|
|
14
|
+
shortest_timeout = @active_timers.values.min - Time.now
|
|
15
|
+
process_reads(shortest_timeout)
|
|
16
|
+
now = Time.now
|
|
17
|
+
@active_timers.select { |_, t| t <= now }.keys.each {
|
|
18
|
+
@runqueue << it
|
|
19
|
+
@active_timers.delete(it)
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def process_reads(timeout)
|
|
24
|
+
r, _ = IO.select(@active_reads.keys, [], [], timeout)
|
|
25
|
+
r&.each { |io|
|
|
26
|
+
@runqueue << [@active_reads[io], io.readpartial(256)]
|
|
27
|
+
@active_reads.delete(io)
|
|
28
|
+
}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def do_read(io)
|
|
32
|
+
@active_reads[io] = Fiber.current
|
|
33
|
+
fiber_switch
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def do_sleep(time)
|
|
37
|
+
fiber = Fiber.current
|
|
38
|
+
@active_timers[fiber] = Time.now + time
|
|
39
|
+
fiber_switch
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
@runqueue << Fiber.new {
|
|
43
|
+
input = do_read(STDIN)
|
|
44
|
+
puts "Got: #{input}"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@runqueue << Fiber.new {
|
|
48
|
+
do_sleep(5)
|
|
49
|
+
puts "5 seconds have elapsed!"
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
fiber_switch
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
@fiber1 = Fiber.new {
|
|
2
|
+
count = 0
|
|
3
|
+
# read from STDIN
|
|
4
|
+
while true
|
|
5
|
+
count += 1
|
|
6
|
+
input = STDIN.read_nonblock(256, exception: false)
|
|
7
|
+
if input == :wait_readable
|
|
8
|
+
@fiber2.transfer
|
|
9
|
+
else
|
|
10
|
+
break
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
puts "Got: #{input} after #{count} tries"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@fiber2 = Fiber.new {
|
|
17
|
+
last = Time.now
|
|
18
|
+
|
|
19
|
+
# sleep
|
|
20
|
+
while Time.now < last + 5
|
|
21
|
+
@fiber1.transfer
|
|
22
|
+
end
|
|
23
|
+
STDOUT << "5 seconds have elapsed!\n"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@fiber1.transfer
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
@runqueue = []
|
|
2
|
+
def fiber_switch
|
|
3
|
+
next_fiber = @runqueue.shift
|
|
4
|
+
@runqueue << Fiber.current
|
|
5
|
+
next_fiber.transfer
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
@runqueue << Fiber.new {
|
|
9
|
+
count = 0
|
|
10
|
+
# read from STDIN
|
|
11
|
+
while true
|
|
12
|
+
count += 1
|
|
13
|
+
input = STDIN.read_nonblock(256, exception: false)
|
|
14
|
+
if input == :wait_readable
|
|
15
|
+
fiber_switch
|
|
16
|
+
else
|
|
17
|
+
break
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
puts "Got: #{input} after #{count} tries"
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@runqueue << Fiber.new {
|
|
24
|
+
last = Time.now
|
|
25
|
+
|
|
26
|
+
# sleep
|
|
27
|
+
while Time.now < last + 10
|
|
28
|
+
fiber_switch
|
|
29
|
+
end
|
|
30
|
+
STDOUT << "10 seconds have elapsed!\n"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@runqueue.shift.transfer
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#include <liburing.h>
|
|
2
|
+
|
|
3
|
+
struct io_uring ring;
|
|
4
|
+
struct io_uring_sqe *sqe;
|
|
5
|
+
struct io_uring_cqe *cqe;
|
|
6
|
+
int ret;
|
|
7
|
+
char buf[100];
|
|
8
|
+
|
|
9
|
+
ret = io_uring_queue_init(8, &ring, 0);
|
|
10
|
+
sqe = io_uring_get_sqe(&ring);
|
|
11
|
+
io_uring_prep_read(sqe, STDIN_FILENO, buf, 100, 0);
|
|
12
|
+
sqe->user_data = 42;
|
|
13
|
+
io_uring_submit(&ring);
|
|
14
|
+
|
|
15
|
+
...
|
|
16
|
+
|
|
17
|
+
ret = io_uring_wait_cqe(&ring, &cqe);
|
|
18
|
+
if (!ret) {
|
|
19
|
+
if (cqe->user_data == 42) {
|
|
20
|
+
int len = cqe->res;
|
|
21
|
+
printf("Got: %d\n", len);
|
|
22
|
+
}
|
|
23
|
+
io_uring_cqe_seen(&ring, cqe);
|
|
24
|
+
}
|
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
|
+
conn = UM::Connection.new($machine, fd)
|
|
70
70
|
|
|
71
|
-
while (l =
|
|
71
|
+
while (l = conn.gets)
|
|
72
72
|
$machine.write(fd, "You said: #{l}")
|
|
73
73
|
end
|
|
74
74
|
rescue Exception => e
|
data/examples/stream.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
|
+
conn = UM::Stream.new($machine, fd)
|
|
70
70
|
|
|
71
|
-
while (l =
|
|
71
|
+
while (l = conn.gets)
|
|
72
72
|
$machine.write(fd, "You said: #{l}")
|
|
73
73
|
end
|
|
74
74
|
rescue Exception => e
|
data/ext/um/um.c
CHANGED
|
@@ -652,11 +652,11 @@ VALUE um_write(struct um *machine, int fd, VALUE buffer, size_t len, __u64 file_
|
|
|
652
652
|
return ret;
|
|
653
653
|
}
|
|
654
654
|
|
|
655
|
-
size_t um_write_raw(struct um *machine, int fd, const char *buffer, size_t
|
|
655
|
+
size_t um_write_raw(struct um *machine, int fd, const char *buffer, size_t len) {
|
|
656
656
|
struct um_op *op = um_op_acquire(machine);
|
|
657
657
|
um_prep_op(machine, op, OP_WRITE, 2, 0);
|
|
658
658
|
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
659
|
-
io_uring_prep_write(sqe, fd, buffer,
|
|
659
|
+
io_uring_prep_write(sqe, fd, buffer, len, 0);
|
|
660
660
|
|
|
661
661
|
int res = 0;
|
|
662
662
|
VALUE ret = um_yield(machine);
|
|
@@ -831,6 +831,23 @@ VALUE um_send(struct um *machine, int fd, VALUE buffer, size_t len, int flags) {
|
|
|
831
831
|
return ret;
|
|
832
832
|
}
|
|
833
833
|
|
|
834
|
+
size_t um_send_raw(struct um *machine, int fd, const char *buffer, size_t len, int flags) {
|
|
835
|
+
struct um_op *op = um_op_acquire(machine);
|
|
836
|
+
um_prep_op(machine, op, OP_SEND, 2, 0);
|
|
837
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
838
|
+
io_uring_prep_send(sqe, fd, buffer, len, flags);
|
|
839
|
+
|
|
840
|
+
int res = 0;
|
|
841
|
+
VALUE ret = um_yield(machine);
|
|
842
|
+
|
|
843
|
+
if (likely(um_verify_op_completion(machine, op, true))) res = op->result.res;
|
|
844
|
+
um_op_release(machine, op);
|
|
845
|
+
|
|
846
|
+
RAISE_IF_EXCEPTION(ret);
|
|
847
|
+
RB_GC_GUARD(ret);
|
|
848
|
+
return res;
|
|
849
|
+
}
|
|
850
|
+
|
|
834
851
|
// for some reason we don't get this define from liburing/io_uring.h
|
|
835
852
|
#define IORING_SEND_VECTORIZED (1U << 5)
|
|
836
853
|
|
|
@@ -1478,7 +1495,7 @@ int read_recv_each_multishot_process_result(struct op_ctx *ctx, struct um_op_res
|
|
|
1478
1495
|
return false;
|
|
1479
1496
|
|
|
1480
1497
|
*total += result->res;
|
|
1481
|
-
VALUE buf =
|
|
1498
|
+
VALUE buf = um_read_from_buffer_ring(ctx->machine, ctx->bgid, result->res, result->flags);
|
|
1482
1499
|
rb_yield(buf);
|
|
1483
1500
|
RB_GC_GUARD(buf);
|
|
1484
1501
|
|
data/ext/um/um.h
CHANGED
|
@@ -80,12 +80,12 @@ enum um_op_kind {
|
|
|
80
80
|
OP_TIMEOUT_MULTISHOT,
|
|
81
81
|
};
|
|
82
82
|
|
|
83
|
-
enum
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
83
|
+
enum um_connection_mode {
|
|
84
|
+
CONNECTION_FD,
|
|
85
|
+
CONNECTION_SOCKET,
|
|
86
|
+
CONNECTION_SSL,
|
|
87
|
+
CONNECTION_STRING,
|
|
88
|
+
CONNECTION_IO_BUFFER
|
|
89
89
|
};
|
|
90
90
|
|
|
91
91
|
#define OP_F_CQE_SEEN (1U << 0) // CQE has been seen
|
|
@@ -272,11 +272,11 @@ struct um_async_op {
|
|
|
272
272
|
struct um_op *op;
|
|
273
273
|
};
|
|
274
274
|
|
|
275
|
-
struct
|
|
275
|
+
struct um_connection {
|
|
276
276
|
VALUE self;
|
|
277
277
|
struct um *machine;
|
|
278
278
|
|
|
279
|
-
enum
|
|
279
|
+
enum um_connection_mode mode;
|
|
280
280
|
union {
|
|
281
281
|
int fd;
|
|
282
282
|
VALUE target;
|
|
@@ -304,7 +304,7 @@ extern VALUE eUMError;
|
|
|
304
304
|
extern VALUE cMutex;
|
|
305
305
|
extern VALUE cQueue;
|
|
306
306
|
extern VALUE cAsyncOp;
|
|
307
|
-
extern VALUE
|
|
307
|
+
extern VALUE eConnectionRESPError;
|
|
308
308
|
|
|
309
309
|
struct um *um_get_machine(VALUE self);
|
|
310
310
|
void um_setup(VALUE self, struct um *machine, uint size, uint sqpoll_timeout_msec, int sidecar_mode);
|
|
@@ -352,7 +352,7 @@ int um_get_buffer_bytes_for_writing(VALUE buffer, const void **base, size_t *siz
|
|
|
352
352
|
void * um_prepare_read_buffer(VALUE buffer, ssize_t len, ssize_t ofs);
|
|
353
353
|
void um_update_read_buffer(VALUE buffer, ssize_t buffer_offset, __s32 result);
|
|
354
354
|
int um_setup_buffer_ring(struct um *machine, unsigned size, unsigned count);
|
|
355
|
-
VALUE
|
|
355
|
+
VALUE um_read_from_buffer_ring(struct um *machine, int bgid, __s32 result, __u32 flags);
|
|
356
356
|
void um_add_strings_to_buffer_ring(struct um *machine, int bgid, VALUE strings);
|
|
357
357
|
struct iovec *um_alloc_iovecs_for_writing(int argc, VALUE *argv, size_t *total_len);
|
|
358
358
|
void um_advance_iovecs_for_writing(struct iovec **ptr, int *len, size_t adv);
|
|
@@ -378,7 +378,7 @@ VALUE um_read(struct um *machine, int fd, VALUE buffer, size_t maxlen, ssize_t b
|
|
|
378
378
|
size_t um_read_raw(struct um *machine, int fd, char *buffer, size_t maxlen);
|
|
379
379
|
VALUE um_read_each(struct um *machine, int fd, int bgid);
|
|
380
380
|
VALUE um_write(struct um *machine, int fd, VALUE buffer, size_t len, __u64 file_offset);
|
|
381
|
-
size_t um_write_raw(struct um *machine, int fd, const char *buffer, size_t
|
|
381
|
+
size_t um_write_raw(struct um *machine, int fd, const char *buffer, size_t len);
|
|
382
382
|
VALUE um_writev(struct um *machine, int fd, int argc, VALUE *argv);
|
|
383
383
|
VALUE um_write_async(struct um *machine, int fd, VALUE buffer, size_t len, __u64 file_offset);
|
|
384
384
|
VALUE um_close(struct um *machine, int fd);
|
|
@@ -403,6 +403,7 @@ VALUE um_accept_into_queue(struct um *machine, int fd, VALUE queue);
|
|
|
403
403
|
VALUE um_socket(struct um *machine, int domain, int type, int protocol, uint flags);
|
|
404
404
|
VALUE um_connect(struct um *machine, int fd, const struct sockaddr *addr, socklen_t addrlen);
|
|
405
405
|
VALUE um_send(struct um *machine, int fd, VALUE buffer, size_t len, int flags);
|
|
406
|
+
size_t um_send_raw(struct um *machine, int fd, const char *buffer, size_t len, int flags);
|
|
406
407
|
VALUE um_sendv(struct um *machine, int fd, int argc, VALUE *argv);
|
|
407
408
|
VALUE um_send_bundle(struct um *machine, int fd, int bgid, VALUE strings);
|
|
408
409
|
VALUE um_recv(struct um *machine, int fd, VALUE buffer, size_t maxlen, int flags);
|
|
@@ -437,13 +438,16 @@ VALUE um_queue_pop(struct um *machine, struct um_queue *queue);
|
|
|
437
438
|
VALUE um_queue_unshift(struct um *machine, struct um_queue *queue, VALUE value);
|
|
438
439
|
VALUE um_queue_shift(struct um *machine, struct um_queue *queue);
|
|
439
440
|
|
|
440
|
-
void
|
|
441
|
-
void
|
|
442
|
-
VALUE
|
|
443
|
-
VALUE
|
|
444
|
-
|
|
445
|
-
void
|
|
446
|
-
|
|
441
|
+
void connection_teardown(struct um_connection *conn);
|
|
442
|
+
void connection_clear(struct um_connection *conn);
|
|
443
|
+
VALUE connection_read_line(struct um_connection *conn, VALUE out_buffer, size_t maxlen);
|
|
444
|
+
VALUE connection_read(struct um_connection *conn, VALUE out_buffer, ssize_t len, size_t inc, int safe_inc);
|
|
445
|
+
VALUE connection_read_to_delim(struct um_connection *conn, VALUE out_buffer, VALUE delim, ssize_t maxlen);
|
|
446
|
+
void connection_skip(struct um_connection *conn, size_t inc, int safe_inc);
|
|
447
|
+
void connection_read_each(struct um_connection *conn);
|
|
448
|
+
size_t connection_write_raw(struct um_connection *conn, const char *buffer, size_t len);
|
|
449
|
+
VALUE connection_writev(struct um_connection *conn, int argc, VALUE *argv);
|
|
450
|
+
VALUE resp_read(struct um_connection *conn, VALUE out_buffer);
|
|
447
451
|
void resp_encode(struct um_write_buffer *buf, VALUE obj);
|
|
448
452
|
void resp_encode_cmd(struct um_write_buffer *buf, int argc, VALUE *argv);
|
|
449
453
|
|
|
@@ -463,6 +467,8 @@ void um_ssl_set_bio(struct um *machine, VALUE ssl_obj);
|
|
|
463
467
|
int um_ssl_read(struct um *machine, VALUE ssl, VALUE buf, size_t maxlen);
|
|
464
468
|
int um_ssl_read_raw(struct um *machine, VALUE ssl_obj, char *ptr, size_t maxlen);
|
|
465
469
|
int um_ssl_write(struct um *machine, VALUE ssl, VALUE buf, size_t len);
|
|
470
|
+
int um_ssl_write_raw(struct um *machine, VALUE ssl, const char *buffer, size_t len);
|
|
471
|
+
int um_ssl_writev(struct um *machine, VALUE ssl, int argc, VALUE *argv);
|
|
466
472
|
|
|
467
473
|
void bp_setup(struct um *machine);
|
|
468
474
|
void bp_teardown(struct um *machine);
|