uringmachine 0.5 → 0.5.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 +4 -4
- data/CHANGELOG.md +2 -0
- data/examples/bm_sqlite.rb +89 -0
- data/examples/http_server.rb +1 -1
- data/examples/pg.rb +85 -0
- data/examples/stream.rb +85 -0
- data/ext/um/extconf.rb +57 -0
- data/ext/um/um.c +5 -5
- data/ext/um/um.h +23 -4
- data/ext/um/um_async_op.c +40 -0
- data/ext/um/um_async_op_class.c +136 -0
- data/ext/um/um_class.c +39 -31
- data/ext/um/um_const.c +145 -9
- data/ext/um/um_ext.c +4 -0
- data/ext/um/um_op.c +5 -2
- data/ext/um/um_ssl.c +850 -0
- data/ext/um/um_ssl.h +22 -0
- data/ext/um/um_ssl_class.c +138 -0
- data/lib/uringmachine/ssl/context_builder.rb +96 -0
- data/lib/uringmachine/ssl.rb +394 -0
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +8 -0
- data/test/helper.rb +6 -0
- data/test/test_async_op.rb +119 -0
- data/test/test_ssl.rb +155 -0
- data/test/test_um.rb +0 -2
- data/uringmachine.gemspec +3 -2
- metadata +32 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0b063db46fac29472c42866eb1864c731b24fc0846fe424eec06213bba8fde0a
|
4
|
+
data.tar.gz: a535fabf5d16107de8d3823766d9ff0d7d22d0702c5401e263eb925eb222dd5d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94ad9e942e84e87f0acbd75007962c3df5ea259de77ef4e590ff91dc4ea614dcd22e7db3da1954be05b11951e621f0cf58858391b677e109e97590bb0f8e3dee
|
7
|
+
data.tar.gz: 4c77e826fb33fc879de748b877eec9a6d49f6927b8167377b4191c30b9aa2b638dbd0cc76a77ec0a17daec648d2587ca4357f367501391aad06c7532606e85b2
|
data/CHANGELOG.md
CHANGED
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/inline'
|
4
|
+
|
5
|
+
gemfile do
|
6
|
+
source 'https://rubygems.org'
|
7
|
+
gem 'uringmachine', path: '..'
|
8
|
+
gem 'extralite'
|
9
|
+
gem 'benchmark-ips'
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'uringmachine'
|
13
|
+
require 'extralite'
|
14
|
+
|
15
|
+
class UM::Actor < Fiber
|
16
|
+
def initialize(machine, target)
|
17
|
+
@machine = machine
|
18
|
+
@target = target
|
19
|
+
@mailbox = UM::Queue.new
|
20
|
+
super { act }
|
21
|
+
end
|
22
|
+
|
23
|
+
def act
|
24
|
+
while (sym, a, k, peer = @machine.shift(@mailbox))
|
25
|
+
|
26
|
+
begin
|
27
|
+
ret = @target.send(sym, *a, **k)
|
28
|
+
@machine.schedule(peer, ret)
|
29
|
+
rescue => e
|
30
|
+
@machine.schedule(peer, e)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
rescue Exception => e
|
34
|
+
# handle unhandled exceptions
|
35
|
+
ensure
|
36
|
+
@machine.fiber_map.delete(self)
|
37
|
+
@machine.yield
|
38
|
+
end
|
39
|
+
|
40
|
+
def method_missing(sym, *a, **k)
|
41
|
+
@machine.push(@mailbox, [sym, a, k, Fiber.current])
|
42
|
+
ret = @machine.yield
|
43
|
+
raise(ret) if ret.is_a?(Exception)
|
44
|
+
ret
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class UM
|
49
|
+
def spin_actor(target)
|
50
|
+
f = UM::Actor.new(self, target)
|
51
|
+
schedule(f, nil)
|
52
|
+
@@fiber_map[f] = true
|
53
|
+
f
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class Locker
|
58
|
+
def initialize(machine, target)
|
59
|
+
@machine = machine
|
60
|
+
@target = target
|
61
|
+
@mutex = UM::Mutex.new
|
62
|
+
end
|
63
|
+
|
64
|
+
def method_missing(sym, *a, **k)
|
65
|
+
@machine.synchronize(@mutex) { @target.send(sym, *a, **k) }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
PATH = '/tmp/foo'
|
71
|
+
|
72
|
+
$machine = UM.new
|
73
|
+
$raw_db = Extralite::Database.new(PATH)
|
74
|
+
$actor_db = $machine.spin_actor(Extralite::Database.new(PATH))
|
75
|
+
$locker_db = Locker.new($machine, Extralite::Database.new(PATH))
|
76
|
+
|
77
|
+
[$raw_db, $actor_db, $locker_db].each do |db|
|
78
|
+
p db.query('select 1')
|
79
|
+
end
|
80
|
+
|
81
|
+
bm = Benchmark.ips do |x|
|
82
|
+
x.config(:time => 5, :warmup => 2)
|
83
|
+
|
84
|
+
x.report("raw") { $raw_db.query('select 1') }
|
85
|
+
x.report("actor") { $actor_db.query('select 1') }
|
86
|
+
x.report("locker") { $locker_db.query('select 1') }
|
87
|
+
|
88
|
+
x.compare!
|
89
|
+
end
|
data/examples/http_server.rb
CHANGED
@@ -35,7 +35,7 @@ end
|
|
35
35
|
|
36
36
|
server_fd = @machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
|
37
37
|
@machine.setsockopt(server_fd, UM::SOL_SOCKET, UM::SO_REUSEADDR, true)
|
38
|
-
@machine.bind(server_fd, '
|
38
|
+
@machine.bind(server_fd, '0.0.0.0', 1234)
|
39
39
|
@machine.listen(server_fd, UM::SOMAXCONN)
|
40
40
|
puts 'Listening on port 1234'
|
41
41
|
|
data/examples/pg.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../lib/uringmachine'
|
4
|
+
|
5
|
+
@machine = UM.new
|
6
|
+
|
7
|
+
class UM::Stream
|
8
|
+
def initialize(machine, fd)
|
9
|
+
@machine, @fd, @bgid = machine, fd
|
10
|
+
@buffer = +''
|
11
|
+
@ofs_head = 0
|
12
|
+
@ofs_tail = 0
|
13
|
+
end
|
14
|
+
|
15
|
+
def feed
|
16
|
+
if (@ofs_head == @ofs_tail) && (@ofs_head >= 4096)
|
17
|
+
@buffer = +''
|
18
|
+
@ofs_head = @ofs_tail = 0
|
19
|
+
end
|
20
|
+
ret = @machine.read(@fd, @buffer, 65536, @ofs_tail)
|
21
|
+
if ret == 0
|
22
|
+
@eof = true
|
23
|
+
return false
|
24
|
+
end
|
25
|
+
|
26
|
+
@ofs_tail += ret
|
27
|
+
true
|
28
|
+
end
|
29
|
+
|
30
|
+
def read(len)
|
31
|
+
if @ofs_head + len > @ofs_tail
|
32
|
+
feed
|
33
|
+
end
|
34
|
+
|
35
|
+
str = @buffer[@ofs_head, len]
|
36
|
+
@ofs_head += str.bytesize
|
37
|
+
str
|
38
|
+
end
|
39
|
+
|
40
|
+
def gets(sep = $/, _limit = nil, _chomp: nil)
|
41
|
+
if sep.is_a?(Integer)
|
42
|
+
sep = $/
|
43
|
+
_limit = sep
|
44
|
+
end
|
45
|
+
sep_size = sep.bytesize
|
46
|
+
|
47
|
+
while true
|
48
|
+
idx = @buffer.index(sep, @ofs_head)
|
49
|
+
if idx
|
50
|
+
str = @buffer[@ofs_head, idx + sep_size]
|
51
|
+
@ofs_head += str.bytesize
|
52
|
+
return str
|
53
|
+
end
|
54
|
+
|
55
|
+
return nil if !feed
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
$machine = UringMachine.new
|
61
|
+
|
62
|
+
server_fd = @machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
|
63
|
+
$machine.setsockopt(server_fd, UM::SOL_SOCKET, UM::SO_REUSEADDR, true)
|
64
|
+
$machine.bind(server_fd, '127.0.0.1', 1234)
|
65
|
+
$machine.listen(server_fd, UM::SOMAXCONN)
|
66
|
+
puts 'Listening on port 1234'
|
67
|
+
|
68
|
+
def handle_connection(fd)
|
69
|
+
stream = UM::Stream.new($machine, fd)
|
70
|
+
|
71
|
+
while (l = stream.gets)
|
72
|
+
$machine.write(fd, "You said: #{l}")
|
73
|
+
end
|
74
|
+
rescue Exception => e
|
75
|
+
puts "Got error #{e.inspect}, closing connection"
|
76
|
+
$machine.close(fd) rescue nil
|
77
|
+
end
|
78
|
+
|
79
|
+
main = Fiber.current
|
80
|
+
trap('SIGINT') { $machine.spin { $machine.schedule(main, SystemExit.new) } }
|
81
|
+
|
82
|
+
$machine.accept_each(server_fd) do |fd|
|
83
|
+
puts "Connection accepted fd #{fd}"
|
84
|
+
$machine.spin(fd) { handle_connection(_1) }
|
85
|
+
end
|
data/examples/stream.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../lib/uringmachine'
|
4
|
+
|
5
|
+
@machine = UM.new
|
6
|
+
|
7
|
+
class UM::Stream
|
8
|
+
def initialize(machine, fd)
|
9
|
+
@machine, @fd, @bgid = machine, fd
|
10
|
+
@buffer = +''
|
11
|
+
@ofs_head = 0
|
12
|
+
@ofs_tail = 0
|
13
|
+
end
|
14
|
+
|
15
|
+
def feed
|
16
|
+
if (@ofs_head == @ofs_tail) && (@ofs_head >= 4096)
|
17
|
+
@buffer = +''
|
18
|
+
@ofs_head = @ofs_tail = 0
|
19
|
+
end
|
20
|
+
ret = @machine.read(@fd, @buffer, 65536, @ofs_tail)
|
21
|
+
if ret == 0
|
22
|
+
@eof = true
|
23
|
+
return false
|
24
|
+
end
|
25
|
+
|
26
|
+
@ofs_tail += ret
|
27
|
+
true
|
28
|
+
end
|
29
|
+
|
30
|
+
def read(len)
|
31
|
+
if @ofs_head + len > @ofs_tail
|
32
|
+
feed
|
33
|
+
end
|
34
|
+
|
35
|
+
str = @buffer[@ofs_head, len]
|
36
|
+
@ofs_head += str.bytesize
|
37
|
+
str
|
38
|
+
end
|
39
|
+
|
40
|
+
def gets(sep = $/, _limit = nil, _chomp: nil)
|
41
|
+
if sep.is_a?(Integer)
|
42
|
+
sep = $/
|
43
|
+
_limit = sep
|
44
|
+
end
|
45
|
+
sep_size = sep.bytesize
|
46
|
+
|
47
|
+
while true
|
48
|
+
idx = @buffer.index(sep, @ofs_head)
|
49
|
+
if idx
|
50
|
+
str = @buffer[@ofs_head, idx + sep_size]
|
51
|
+
@ofs_head += str.bytesize
|
52
|
+
return str
|
53
|
+
end
|
54
|
+
|
55
|
+
return nil if !feed
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
$machine = UringMachine.new
|
61
|
+
|
62
|
+
server_fd = @machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
|
63
|
+
$machine.setsockopt(server_fd, UM::SOL_SOCKET, UM::SO_REUSEADDR, true)
|
64
|
+
$machine.bind(server_fd, '127.0.0.1', 1234)
|
65
|
+
$machine.listen(server_fd, UM::SOMAXCONN)
|
66
|
+
puts 'Listening on port 1234'
|
67
|
+
|
68
|
+
def handle_connection(fd)
|
69
|
+
stream = UM::Stream.new($machine, fd)
|
70
|
+
|
71
|
+
while (l = stream.gets)
|
72
|
+
$machine.write(fd, "You said: #{l}")
|
73
|
+
end
|
74
|
+
rescue Exception => e
|
75
|
+
puts "Got error #{e.inspect}, closing connection"
|
76
|
+
$machine.close(fd) rescue nil
|
77
|
+
end
|
78
|
+
|
79
|
+
main = Fiber.current
|
80
|
+
trap('SIGINT') { $machine.spin { $machine.schedule(main, SystemExit.new) } }
|
81
|
+
|
82
|
+
$machine.accept_each(server_fd) do |fd|
|
83
|
+
puts "Connection accepted fd #{fd}"
|
84
|
+
$machine.spin(fd) { handle_connection(_1) }
|
85
|
+
end
|
data/ext/um/extconf.rb
CHANGED
@@ -6,6 +6,61 @@ require 'rbconfig'
|
|
6
6
|
|
7
7
|
dir_config 'um_ext'
|
8
8
|
|
9
|
+
def config_ssl
|
10
|
+
# don't use pkg_config('openssl') if '--with-openssl-dir' is used
|
11
|
+
has_openssl_dir = dir_config('openssl').any? ||
|
12
|
+
RbConfig::CONFIG['configure_args']&.include?('openssl')
|
13
|
+
|
14
|
+
found_pkg_config = !has_openssl_dir && pkg_config('openssl')
|
15
|
+
|
16
|
+
found_ssl = if !$mingw && found_pkg_config
|
17
|
+
puts '──── Using OpenSSL pkgconfig (openssl.pc) ────'
|
18
|
+
true
|
19
|
+
elsif have_library('libcrypto', 'BIO_read') && have_library('libssl', 'SSL_CTX_new')
|
20
|
+
true
|
21
|
+
elsif %w'crypto libeay32'.find {|crypto| have_library(crypto, 'BIO_read')} &&
|
22
|
+
%w'ssl ssleay32'.find {|ssl| have_library(ssl, 'SSL_CTX_new')}
|
23
|
+
true
|
24
|
+
else
|
25
|
+
puts '** Puma will be compiled without SSL support'
|
26
|
+
false
|
27
|
+
end
|
28
|
+
|
29
|
+
if found_ssl
|
30
|
+
have_header "openssl/bio.h"
|
31
|
+
|
32
|
+
ssl_h = "openssl/ssl.h".freeze
|
33
|
+
|
34
|
+
puts "\n──── Below are yes for 1.0.2 & later ────"
|
35
|
+
have_func "DTLS_method" , ssl_h
|
36
|
+
have_func "SSL_CTX_set_session_cache_mode(NULL, 0)", ssl_h
|
37
|
+
|
38
|
+
puts "\n──── Below are yes for 1.1.0 & later ────"
|
39
|
+
have_func "TLS_server_method" , ssl_h
|
40
|
+
have_func "SSL_CTX_set_min_proto_version(NULL, 0)" , ssl_h
|
41
|
+
|
42
|
+
puts "\n──── Below is yes for 1.1.0 and later, but isn't documented until 3.0.0 ────"
|
43
|
+
# https://github.com/openssl/openssl/blob/OpenSSL_1_1_0/include/openssl/ssl.h#L1159
|
44
|
+
have_func "SSL_CTX_set_dh_auto(NULL, 0)" , ssl_h
|
45
|
+
|
46
|
+
puts "\n──── Below is yes for 1.1.1 & later ────"
|
47
|
+
have_func "SSL_CTX_set_ciphersuites(NULL, \"\")" , ssl_h
|
48
|
+
|
49
|
+
puts "\n──── Below is yes for 3.0.0 & later ────"
|
50
|
+
have_func "SSL_get1_peer_certificate" , ssl_h
|
51
|
+
|
52
|
+
puts ''
|
53
|
+
|
54
|
+
# Random.bytes available in Ruby 2.5 and later, Random::DEFAULT deprecated in 3.0
|
55
|
+
if Random.respond_to?(:bytes)
|
56
|
+
$defs.push "-DHAVE_RANDOM_BYTES"
|
57
|
+
puts "checking for Random.bytes... yes"
|
58
|
+
else
|
59
|
+
puts "checking for Random.bytes... no"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
9
64
|
KERNEL_INFO_RE = /Linux (\d)\.(\d+)(?:\.)?((?:\d+\.?)*)(?:\-)?([\w\-]+)?/
|
10
65
|
def get_config
|
11
66
|
if RUBY_PLATFORM !~ /linux/
|
@@ -35,6 +90,8 @@ def get_config
|
|
35
90
|
}
|
36
91
|
end
|
37
92
|
|
93
|
+
config_ssl
|
94
|
+
|
38
95
|
config = get_config
|
39
96
|
puts "Building UringMachine (\n#{config.map { |(k, v)| " #{k}: #{v}\n"}.join})"
|
40
97
|
|
data/ext/um/um.c
CHANGED
@@ -5,7 +5,6 @@ void um_setup(VALUE self, struct um *machine) {
|
|
5
5
|
memset(machine, 0, sizeof(struct um));
|
6
6
|
|
7
7
|
RB_OBJ_WRITE(self, &machine->self, self);
|
8
|
-
RB_OBJ_WRITE(self, &machine->poll_fiber, Qnil);
|
9
8
|
|
10
9
|
unsigned prepared_limit = 4096;
|
11
10
|
unsigned flags = IORING_SETUP_SUBMIT_ALL | IORING_SETUP_COOP_TASKRUN;
|
@@ -76,7 +75,7 @@ static inline void um_process_cqe(struct um *machine, struct io_uring_cqe *cqe)
|
|
76
75
|
if (unlikely((cqe->res == -ECANCELED) && (op->flags & OP_F_IGNORE_CANCELED))) return;
|
77
76
|
|
78
77
|
op->flags |= OP_F_COMPLETED;
|
79
|
-
if (
|
78
|
+
if (op->flags & OP_F_TRANSIENT)
|
80
79
|
um_op_transient_remove(machine, op);
|
81
80
|
|
82
81
|
if (op->flags & OP_F_MULTISHOT) {
|
@@ -89,7 +88,8 @@ static inline void um_process_cqe(struct um *machine, struct io_uring_cqe *cqe)
|
|
89
88
|
op->result.flags = cqe->flags;
|
90
89
|
}
|
91
90
|
|
92
|
-
|
91
|
+
if (!(op->flags & OP_F_ASYNC))
|
92
|
+
um_runqueue_push(machine, op);
|
93
93
|
}
|
94
94
|
|
95
95
|
// copied from liburing/queue.c
|
@@ -181,7 +181,7 @@ inline VALUE um_fiber_switch(struct um *machine) {
|
|
181
181
|
}
|
182
182
|
}
|
183
183
|
|
184
|
-
|
184
|
+
void um_submit_cancel_op(struct um *machine, struct um_op *op) {
|
185
185
|
struct io_uring_sqe *sqe = um_get_sqe(machine, NULL);
|
186
186
|
io_uring_prep_cancel64(sqe, (long long)op, 0);
|
187
187
|
}
|
@@ -261,7 +261,7 @@ VALUE um_timeout(struct um *machine, VALUE interval, VALUE class) {
|
|
261
261
|
static ID ID_new = 0;
|
262
262
|
if (!ID_new) ID_new = rb_intern("new");
|
263
263
|
|
264
|
-
struct um_op *op =
|
264
|
+
struct um_op *op = um_op_alloc(machine);
|
265
265
|
um_prep_op(machine, op, OP_TIMEOUT);
|
266
266
|
op->ts = um_double_to_timespec(NUM2DBL(interval));
|
267
267
|
RB_OBJ_WRITE(machine->self, &op->fiber, rb_fiber_current());
|
data/ext/um/um.h
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#ifndef UM_H
|
2
2
|
#define UM_H
|
3
3
|
|
4
|
-
#include
|
4
|
+
#include <ruby.h>
|
5
5
|
#include <liburing.h>
|
6
6
|
|
7
7
|
// debugging
|
@@ -48,8 +48,9 @@ enum op_kind {
|
|
48
48
|
|
49
49
|
#define OP_F_COMPLETED (1U << 0)
|
50
50
|
#define OP_F_TRANSIENT (1U << 1)
|
51
|
-
#define
|
52
|
-
#define
|
51
|
+
#define OP_F_ASYNC (1U << 2)
|
52
|
+
#define OP_F_IGNORE_CANCELED (1U << 3)
|
53
|
+
#define OP_F_MULTISHOT (1U << 4)
|
53
54
|
|
54
55
|
struct um_op_result {
|
55
56
|
__s32 res;
|
@@ -66,6 +67,7 @@ struct um_op {
|
|
66
67
|
|
67
68
|
VALUE fiber;
|
68
69
|
VALUE value;
|
70
|
+
VALUE async_op;
|
69
71
|
|
70
72
|
struct um_op_result result;
|
71
73
|
struct um_op_result *multishot_result_tail;
|
@@ -93,7 +95,6 @@ struct buf_ring_descriptor {
|
|
93
95
|
|
94
96
|
struct um {
|
95
97
|
VALUE self;
|
96
|
-
VALUE poll_fiber;
|
97
98
|
|
98
99
|
struct um_buffer *buffer_freelist;
|
99
100
|
|
@@ -137,10 +138,19 @@ struct um_queue {
|
|
137
138
|
uint32_t count;
|
138
139
|
};
|
139
140
|
|
141
|
+
struct um_async_op {
|
142
|
+
VALUE self;
|
143
|
+
|
144
|
+
struct um *machine;
|
145
|
+
struct um_op *op;
|
146
|
+
};
|
147
|
+
|
140
148
|
extern VALUE cUM;
|
141
149
|
extern VALUE cMutex;
|
142
150
|
extern VALUE cQueue;
|
151
|
+
extern VALUE cAsyncOp;
|
143
152
|
|
153
|
+
struct um *um_get_machine(VALUE self);
|
144
154
|
void um_setup(VALUE self, struct um *machine);
|
145
155
|
void um_teardown(struct um *machine);
|
146
156
|
|
@@ -179,6 +189,7 @@ struct io_uring_sqe *um_get_sqe(struct um *machine, struct um_op *op);
|
|
179
189
|
|
180
190
|
VALUE um_fiber_switch(struct um *machine);
|
181
191
|
VALUE um_await(struct um *machine);
|
192
|
+
void um_submit_cancel_op(struct um *machine, struct um_op *op);
|
182
193
|
void um_cancel_and_wait(struct um *machine, struct um_op *op);
|
183
194
|
int um_check_completion(struct um *machine, struct um_op *op);
|
184
195
|
|
@@ -207,6 +218,12 @@ VALUE um_listen(struct um *machine, int fd, int backlog);
|
|
207
218
|
VALUE um_getsockopt(struct um *machine, int fd, int level, int opt);
|
208
219
|
VALUE um_setsockopt(struct um *machine, int fd, int level, int opt, int value);
|
209
220
|
|
221
|
+
void um_async_op_set(VALUE self, struct um *machine, struct um_op *op);
|
222
|
+
VALUE um_async_op_await(struct um_async_op *async_op);
|
223
|
+
void um_async_op_cancel(struct um_async_op *async_op);
|
224
|
+
|
225
|
+
VALUE um_prep_timeout(struct um *machine, double interval);
|
226
|
+
|
210
227
|
struct um_mutex *Mutex_data(VALUE self);
|
211
228
|
struct um_queue *Queue_data(VALUE self);
|
212
229
|
|
@@ -224,4 +241,6 @@ VALUE um_queue_shift(struct um *machine, struct um_queue *queue);
|
|
224
241
|
|
225
242
|
void um_define_net_constants(VALUE mod);
|
226
243
|
|
244
|
+
// void Init_micro_ssl(VALUE mod);
|
245
|
+
|
227
246
|
#endif // UM_H
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#include "um.h"
|
2
|
+
#include <stdlib.h>
|
3
|
+
|
4
|
+
VALUE um_prep_timeout(struct um *machine, double interval) {
|
5
|
+
static ID ID_new = 0;
|
6
|
+
if (!ID_new) ID_new = rb_intern("new");
|
7
|
+
|
8
|
+
struct um_op *op = malloc(sizeof(struct um_op));
|
9
|
+
um_prep_op(machine, op, OP_TIMEOUT);
|
10
|
+
op->ts = um_double_to_timespec(interval);
|
11
|
+
op->flags = OP_F_TRANSIENT | OP_F_ASYNC;
|
12
|
+
|
13
|
+
VALUE obj = rb_funcall(cAsyncOp, rb_intern_const("new"), 0);
|
14
|
+
um_async_op_set(obj, machine, op);
|
15
|
+
|
16
|
+
RB_OBJ_WRITE(machine->self, &op->async_op, obj);
|
17
|
+
|
18
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
19
|
+
io_uring_prep_timeout(sqe, &op->ts, 0, 0);
|
20
|
+
|
21
|
+
um_op_transient_add(machine, op);
|
22
|
+
|
23
|
+
return obj;
|
24
|
+
}
|
25
|
+
|
26
|
+
VALUE um_async_op_await(struct um_async_op *async_op) {
|
27
|
+
RB_OBJ_WRITE(async_op->machine->self, &async_op->op->fiber, rb_fiber_current());
|
28
|
+
async_op->op->flags &= ~OP_F_ASYNC;
|
29
|
+
|
30
|
+
VALUE ret = um_fiber_switch(async_op->machine);
|
31
|
+
if (!um_op_completed_p(async_op->op))
|
32
|
+
um_cancel_and_wait(async_op->machine, async_op->op);
|
33
|
+
|
34
|
+
raise_if_exception(ret);
|
35
|
+
return INT2NUM(async_op->op->result.res);
|
36
|
+
}
|
37
|
+
|
38
|
+
void um_async_op_cancel(struct um_async_op *async_op) {
|
39
|
+
um_submit_cancel_op(async_op->machine, async_op->op);
|
40
|
+
}
|
@@ -0,0 +1,136 @@
|
|
1
|
+
#include "um.h"
|
2
|
+
#include <stdlib.h>
|
3
|
+
|
4
|
+
VALUE cAsyncOp;
|
5
|
+
|
6
|
+
VALUE SYM_timeout;
|
7
|
+
|
8
|
+
static void AsyncOp_mark(void *ptr) {
|
9
|
+
struct um_async_op *async_op = ptr;
|
10
|
+
rb_gc_mark_movable(async_op->self);
|
11
|
+
rb_gc_mark_movable(async_op->machine->self);
|
12
|
+
}
|
13
|
+
|
14
|
+
static void AsyncOp_compact(void *ptr) {
|
15
|
+
struct um_async_op *async_op = ptr;
|
16
|
+
async_op->self = rb_gc_location(async_op->self);
|
17
|
+
}
|
18
|
+
|
19
|
+
static size_t AsyncOp_size(const void *ptr) {
|
20
|
+
return sizeof(struct um_async_op);
|
21
|
+
}
|
22
|
+
|
23
|
+
static void AsyncOp_free(void *ptr) {
|
24
|
+
struct um_async_op *async_op = ptr;
|
25
|
+
um_op_free(async_op->machine, async_op->op);
|
26
|
+
free(ptr);
|
27
|
+
}
|
28
|
+
|
29
|
+
static const rb_data_type_t AsyncOp_type = {
|
30
|
+
"UringMachine::AsyncOp",
|
31
|
+
{AsyncOp_mark, AsyncOp_free, AsyncOp_size, AsyncOp_compact},
|
32
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
|
33
|
+
};
|
34
|
+
|
35
|
+
static VALUE AsyncOp_allocate(VALUE klass) {
|
36
|
+
struct um_async_op *async_op = malloc(sizeof(struct um_async_op));
|
37
|
+
return TypedData_Wrap_Struct(klass, &AsyncOp_type, async_op);
|
38
|
+
}
|
39
|
+
|
40
|
+
inline struct um_async_op *AsyncOp_data(VALUE self) {
|
41
|
+
return RTYPEDDATA_DATA(self);
|
42
|
+
}
|
43
|
+
|
44
|
+
VALUE AsyncOp_initialize(VALUE self) {
|
45
|
+
struct um_async_op *async_op = AsyncOp_data(self);
|
46
|
+
memset(async_op, 0, sizeof(struct um_async_op));
|
47
|
+
async_op->self = self;
|
48
|
+
return self;
|
49
|
+
}
|
50
|
+
|
51
|
+
void um_async_op_set(VALUE self, struct um *machine, struct um_op *op) {
|
52
|
+
struct um_async_op *async_op = AsyncOp_data(self);
|
53
|
+
async_op->machine = machine;
|
54
|
+
async_op->op = op;
|
55
|
+
}
|
56
|
+
|
57
|
+
inline void raise_on_missing_op(struct um_async_op *async_op) {
|
58
|
+
if (!async_op->op)
|
59
|
+
rb_raise(rb_eRuntimeError, "Missing op");
|
60
|
+
}
|
61
|
+
|
62
|
+
inline int async_op_is_done(struct um_async_op *async_op) {
|
63
|
+
return (async_op->op->flags & OP_F_COMPLETED);
|
64
|
+
}
|
65
|
+
|
66
|
+
VALUE AsyncOp_kind(VALUE self) {
|
67
|
+
struct um_async_op *async_op = AsyncOp_data(self);
|
68
|
+
raise_on_missing_op(async_op);
|
69
|
+
|
70
|
+
switch(async_op->op->kind) {
|
71
|
+
case OP_TIMEOUT:
|
72
|
+
return SYM_timeout;
|
73
|
+
default:
|
74
|
+
rb_raise(rb_eRuntimeError, "Invalid op kind");
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
VALUE AsyncOp_done_p(VALUE self) {
|
79
|
+
struct um_async_op *async_op = AsyncOp_data(self);
|
80
|
+
raise_on_missing_op(async_op);
|
81
|
+
|
82
|
+
return async_op_is_done(async_op) ? Qtrue : Qfalse;
|
83
|
+
}
|
84
|
+
|
85
|
+
VALUE AsyncOp_result(VALUE self) {
|
86
|
+
struct um_async_op *async_op = AsyncOp_data(self);
|
87
|
+
raise_on_missing_op(async_op);
|
88
|
+
|
89
|
+
return async_op_is_done(async_op) ? INT2NUM(async_op->op->result.res) : Qnil;
|
90
|
+
}
|
91
|
+
|
92
|
+
VALUE AsyncOp_cancelled_p(VALUE self) {
|
93
|
+
struct um_async_op *async_op = AsyncOp_data(self);
|
94
|
+
raise_on_missing_op(async_op);
|
95
|
+
|
96
|
+
if (!async_op_is_done(async_op)) return Qnil;
|
97
|
+
|
98
|
+
return (async_op->op->result.res == -ECANCELED) ? Qtrue : Qfalse;
|
99
|
+
}
|
100
|
+
|
101
|
+
VALUE AsyncOp_await(VALUE self) {
|
102
|
+
struct um_async_op *async_op = AsyncOp_data(self);
|
103
|
+
raise_on_missing_op(async_op);
|
104
|
+
|
105
|
+
if (async_op_is_done(async_op))
|
106
|
+
return INT2NUM(async_op->op->result.res);
|
107
|
+
|
108
|
+
return um_async_op_await(async_op);
|
109
|
+
}
|
110
|
+
|
111
|
+
VALUE AsyncOp_cancel(VALUE self) {
|
112
|
+
struct um_async_op *async_op = AsyncOp_data(self);
|
113
|
+
raise_on_missing_op(async_op);
|
114
|
+
|
115
|
+
if (!async_op_is_done(async_op))
|
116
|
+
um_async_op_cancel(async_op);
|
117
|
+
|
118
|
+
return self;
|
119
|
+
}
|
120
|
+
|
121
|
+
void Init_AsyncOp(void) {
|
122
|
+
cAsyncOp = rb_define_class_under(cUM, "AsyncOp", rb_cObject);
|
123
|
+
rb_define_alloc_func(cAsyncOp, AsyncOp_allocate);
|
124
|
+
|
125
|
+
rb_define_method(cAsyncOp, "initialize", AsyncOp_initialize, 0);
|
126
|
+
rb_define_method(cAsyncOp, "kind", AsyncOp_kind, 0);
|
127
|
+
rb_define_method(cAsyncOp, "done?", AsyncOp_done_p, 0);
|
128
|
+
rb_define_method(cAsyncOp, "result", AsyncOp_result, 0);
|
129
|
+
rb_define_method(cAsyncOp, "cancelled?", AsyncOp_cancelled_p, 0);
|
130
|
+
|
131
|
+
rb_define_method(cAsyncOp, "await", AsyncOp_await, 0);
|
132
|
+
rb_define_method(cAsyncOp, "join", AsyncOp_await, 0);
|
133
|
+
rb_define_method(cAsyncOp, "cancel", AsyncOp_cancel, 0);
|
134
|
+
|
135
|
+
SYM_timeout = ID2SYM(rb_intern("timeout"));
|
136
|
+
}
|