uringmachine 0.7 → 0.8.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/.github/workflows/test.yml +1 -1
- data/CHANGELOG.md +8 -0
- data/TODO.md +8 -0
- data/examples/bm_http_parse.rb +3 -3
- data/examples/bm_queue.rb +2 -2
- data/examples/bm_write.rb +3 -3
- data/examples/pg.rb +1 -1
- data/examples/server_client.rb +2 -2
- data/examples/snooze.rb +1 -1
- data/examples/stream.rb +1 -1
- data/ext/um/extconf.rb +0 -57
- data/ext/um/um.c +17 -39
- data/ext/um/um.h +1 -3
- data/ext/um/um_class.c +0 -2
- data/ext/um/um_const.c +3 -3
- data/ext/um/um_op.c +1 -1
- data/ext/um/um_sync.c +5 -5
- data/lib/uringmachine/actor.rb +20 -11
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +64 -9
- data/test/helper.rb +1 -1
- data/test/test_actor.rb +10 -8
- data/test/test_async_op.rb +5 -5
- data/test/test_fiber.rb +174 -0
- data/test/test_um.rb +80 -13
- data/uringmachine.gemspec +1 -1
- metadata +5 -10
- data/ext/um/um_ssl.c +0 -850
- data/ext/um/um_ssl.h +0 -22
- data/ext/um/um_ssl_class.c +0 -138
- data/lib/uringmachine/ssl/context_builder.rb +0 -96
- data/lib/uringmachine/ssl.rb +0 -394
- data/test/test_ssl.rb +0 -155
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7fdbc29b1e4c910d05eef327345a52faafd92566d7bdddaad81396bcf1f4767d
|
4
|
+
data.tar.gz: 4729a2ca7640fd58d0d83cc008db6e3431edfcdf04e396bce9981465a8e4e0a9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 56c03563909bd5acd8466a0ef255cd2a791c9907e7fa9ab0a88d9be22f4db895cfb85f0ed5fc0883d0e583c216e238e954a74623f6d231f38c51de2f65316af8
|
7
|
+
data.tar.gz: 1471eea52c8edb8bab45e4fa058191c13e1c88a39bd728c1be5f72998058724ab7fb8a699d279fe5ace36fec6dc5eaca5361a4265b909d078cf5549dd3a19af2
|
data/.github/workflows/test.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/TODO.md
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# ops
|
2
|
+
|
1
3
|
- [ ] multishot timeout
|
2
4
|
- [v] machine.periodically(interval) { ... }
|
3
5
|
- [ ] machine.prep_timeout_multishot(interval)
|
@@ -15,3 +17,9 @@
|
|
15
17
|
- madvise
|
16
18
|
- getxattr / setxattr
|
17
19
|
- send_bundle / recv_bundle (kernel >= 6.10)
|
20
|
+
|
21
|
+
# actors
|
22
|
+
|
23
|
+
When doing a `call`, we need to provide a mailbox for the response. can this be
|
24
|
+
automatic?
|
25
|
+
|
data/examples/bm_http_parse.rb
CHANGED
@@ -43,7 +43,7 @@ def parse_http_parser
|
|
43
43
|
headers['protocol'] = parser.http_version
|
44
44
|
$machine.schedule(current_fiber, headers)
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
$machine.write(w.fileno, HTTP_MSG)
|
48
48
|
$machine.yield
|
49
49
|
ensure
|
@@ -89,7 +89,7 @@ def parse_headers(fd)
|
|
89
89
|
while true
|
90
90
|
line = get_line(fd, sio, buffer)
|
91
91
|
break if line.empty?
|
92
|
-
|
92
|
+
|
93
93
|
m = line.match(RE_HEADER_LINE)
|
94
94
|
raise "Invalid header" if !m
|
95
95
|
|
@@ -111,7 +111,7 @@ def parse_http_stringio
|
|
111
111
|
puts e.backtrace.join("\n")
|
112
112
|
exit!
|
113
113
|
end
|
114
|
-
|
114
|
+
|
115
115
|
$machine.write(w.fileno, HTTP_MSG)
|
116
116
|
$machine.yield
|
117
117
|
ensure
|
data/examples/bm_queue.rb
CHANGED
@@ -18,14 +18,14 @@ NUM_CONSUMERS = 10
|
|
18
18
|
def run_threads
|
19
19
|
queue = Queue.new
|
20
20
|
done = Queue.new
|
21
|
-
|
21
|
+
|
22
22
|
NUM_PRODUCERS.times do
|
23
23
|
Thread.new do
|
24
24
|
COUNT.times { queue << rand(1000) }
|
25
25
|
done << true
|
26
26
|
end
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
total = 0
|
30
30
|
NUM_CONSUMERS.times do
|
31
31
|
Thread.new do
|
data/examples/bm_write.rb
CHANGED
@@ -18,7 +18,7 @@ FN = '/tmp/bm_write'
|
|
18
18
|
def run_io_write(num_threads)
|
19
19
|
FileUtils.rm(FN) rescue nil
|
20
20
|
fio = File.open(FN, 'w')
|
21
|
-
|
21
|
+
|
22
22
|
threads = num_threads.times.map do |i|
|
23
23
|
Thread.new do
|
24
24
|
ITERATIONS.times { fio.write(BUF) }
|
@@ -33,13 +33,13 @@ def run_um_write(num_fibers)
|
|
33
33
|
FileUtils.rm(FN) rescue nil
|
34
34
|
fio = File.open(FN, 'w')
|
35
35
|
fd = fio.fileno
|
36
|
-
|
36
|
+
|
37
37
|
machine = UringMachine.new
|
38
38
|
done = UringMachine::Queue.new
|
39
39
|
num_fibers.times do
|
40
40
|
machine.spin do
|
41
41
|
ITERATIONS.times { machine.write(fd, BUF) }
|
42
|
-
machine.push(done, true)
|
42
|
+
machine.push(done, true)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
num_fibers.times { machine.pop(done) }
|
data/examples/pg.rb
CHANGED
data/examples/server_client.rb
CHANGED
@@ -31,7 +31,7 @@ def run_client
|
|
31
31
|
@machine.send(fd, msg, msg.bytesize, 0)
|
32
32
|
res = @machine.recv(fd, buf, 8192, 0)
|
33
33
|
@counter += 2
|
34
|
-
|
34
|
+
|
35
35
|
break if res == 0
|
36
36
|
raise "Got #{res} bytes instead of #{msg.bytesize}" if res != msg.bytesize
|
37
37
|
end
|
@@ -59,6 +59,6 @@ end
|
|
59
59
|
|
60
60
|
t0 = Time.now
|
61
61
|
@machine.sleep 3
|
62
|
-
t1 = Time.now
|
62
|
+
t1 = Time.now
|
63
63
|
elapsed = t1 - t0
|
64
64
|
puts "Did #{@counter} ops in #{elapsed} seconds (#{(@counter / elapsed)} ops/s)"
|
data/examples/snooze.rb
CHANGED
data/examples/stream.rb
CHANGED
data/ext/um/extconf.rb
CHANGED
@@ -6,61 +6,6 @@ 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
|
-
|
64
9
|
KERNEL_INFO_RE = /Linux (\d)\.(\d+)(?:\.)?((?:\d+\.?)*)(?:\-)?([\w\-]+)?/
|
65
10
|
def get_config
|
66
11
|
if RUBY_PLATFORM !~ /linux/
|
@@ -90,8 +35,6 @@ def get_config
|
|
90
35
|
}
|
91
36
|
end
|
92
37
|
|
93
|
-
# config_ssl
|
94
|
-
|
95
38
|
config = get_config
|
96
39
|
puts "Building UringMachine (\n#{config.map { |(k, v)| " #{k}: #{v}\n"}.join})"
|
97
40
|
|
data/ext/um/um.c
CHANGED
@@ -89,7 +89,7 @@ static inline void um_process_cqe(struct um *machine, struct io_uring_cqe *cqe)
|
|
89
89
|
}
|
90
90
|
|
91
91
|
if (op->flags & OP_F_ASYNC) return;
|
92
|
-
|
92
|
+
|
93
93
|
um_runqueue_push(machine, op);
|
94
94
|
}
|
95
95
|
|
@@ -127,6 +127,7 @@ done:
|
|
127
127
|
struct wait_for_cqe_ctx {
|
128
128
|
struct um *machine;
|
129
129
|
struct io_uring_cqe *cqe;
|
130
|
+
int wait_nr;
|
130
131
|
int result;
|
131
132
|
};
|
132
133
|
|
@@ -140,16 +141,19 @@ void *um_wait_for_cqe_without_gvl(void *ptr) {
|
|
140
141
|
// NULL.
|
141
142
|
//
|
142
143
|
// https://github.com/axboe/liburing/issues/1280
|
143
|
-
int res = io_uring_submit_and_wait_timeout(&ctx->machine->ring, &ctx->cqe,
|
144
|
+
int res = io_uring_submit_and_wait_timeout(&ctx->machine->ring, &ctx->cqe, ctx->wait_nr, NULL, NULL);
|
144
145
|
ctx->result = (res > 0 && !ctx->cqe) ? -EINTR : res;
|
145
146
|
}
|
146
147
|
else
|
147
|
-
ctx->result =
|
148
|
+
ctx->result = io_uring_wait_cqes(&ctx->machine->ring, &ctx->cqe, ctx->wait_nr, NULL, NULL);
|
148
149
|
return NULL;
|
149
150
|
}
|
150
151
|
|
151
|
-
|
152
|
-
|
152
|
+
// Waits for the given minimum number of completion entries. The wait_nr is
|
153
|
+
// either 1 - where we wait for at least one CQE to be ready, or 0, where we
|
154
|
+
// don't wait, and just process any CQEs that already ready.
|
155
|
+
static inline void um_wait_for_and_process_ready_cqes(struct um *machine, int wait_nr) {
|
156
|
+
struct wait_for_cqe_ctx ctx = { .machine = machine, .cqe = NULL, .wait_nr = wait_nr };
|
153
157
|
rb_thread_call_without_gvl(um_wait_for_cqe_without_gvl, (void *)&ctx, RUBY_UBF_IO, 0);
|
154
158
|
|
155
159
|
if (unlikely(ctx.result < 0 && ctx.result != -EINTR))
|
@@ -187,18 +191,19 @@ inline VALUE um_fiber_switch(struct um *machine) {
|
|
187
191
|
if (machine->pending_count > 0) {
|
188
192
|
// if yes, process completions, get runqueue head, put original op
|
189
193
|
// back on runqueue.
|
190
|
-
|
194
|
+
// um_process_ready_cqes(machine);
|
195
|
+
um_wait_for_and_process_ready_cqes(machine, 0);
|
191
196
|
struct um_op *op2 = um_runqueue_shift(machine);
|
192
197
|
if (likely(op2 && op2 != op)) {
|
193
198
|
um_runqueue_push(machine, op);
|
194
|
-
op = op2;
|
199
|
+
op = op2;
|
195
200
|
}
|
196
201
|
}
|
197
202
|
}
|
198
203
|
return process_runqueue_op(machine, op);
|
199
204
|
}
|
200
205
|
|
201
|
-
um_wait_for_and_process_ready_cqes(machine);
|
206
|
+
um_wait_for_and_process_ready_cqes(machine, 1);
|
202
207
|
}
|
203
208
|
}
|
204
209
|
|
@@ -320,45 +325,18 @@ VALUE um_sleep(struct um *machine, double duration) {
|
|
320
325
|
return raise_if_exception(ret);
|
321
326
|
}
|
322
327
|
|
323
|
-
// VALUE um_periodically(struct um *machine, double interval) {
|
324
|
-
// struct um_op op;
|
325
|
-
// VALUE ret = Qnil;
|
326
|
-
// um_prep_op(machine, &op, OP_SLEEP_MULTISHOT);
|
327
|
-
// op.ts = um_double_to_timespec(interval);
|
328
|
-
// op.flags |= OP_F_MULTISHOT;
|
329
|
-
// struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
330
|
-
// io_uring_prep_timeout(sqe, &op.ts, 0, IORING_TIMEOUT_MULTISHOT);
|
331
|
-
|
332
|
-
// while (true) {
|
333
|
-
// ret = um_fiber_switch(machine);
|
334
|
-
|
335
|
-
// if (!um_op_completed_p(&op)) {
|
336
|
-
// um_cancel_and_wait(machine, &op);
|
337
|
-
// break;
|
338
|
-
// }
|
339
|
-
// else {
|
340
|
-
// if (op.result.res != -ETIME) um_raise_on_error_result(op.result.res);
|
341
|
-
// ret = DBL2NUM(interval);
|
342
|
-
// }
|
343
|
-
// }
|
344
|
-
|
345
|
-
// RB_GC_GUARD(ret);
|
346
|
-
// return raise_if_exception(ret);
|
347
|
-
|
348
|
-
// }
|
349
|
-
|
350
328
|
inline VALUE um_read(struct um *machine, int fd, VALUE buffer, int maxlen, int buffer_offset) {
|
351
329
|
struct um_op op;
|
352
330
|
um_prep_op(machine, &op, OP_READ);
|
353
331
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
354
332
|
void *ptr = um_prepare_read_buffer(buffer, maxlen, buffer_offset);
|
355
333
|
io_uring_prep_read(sqe, fd, ptr, maxlen, -1);
|
356
|
-
|
334
|
+
|
357
335
|
VALUE ret = um_fiber_switch(machine);
|
358
336
|
if (um_check_completion(machine, &op)) {
|
359
337
|
um_update_read_buffer(machine, buffer, buffer_offset, op.result.res, op.result.flags);
|
360
338
|
ret = INT2NUM(op.result.res);
|
361
|
-
|
339
|
+
|
362
340
|
}
|
363
341
|
|
364
342
|
RB_GC_GUARD(buffer);
|
@@ -652,7 +630,7 @@ VALUE multishot_ensure(VALUE arg) {
|
|
652
630
|
VALUE um_accept_each(struct um *machine, int fd) {
|
653
631
|
struct um_op op;
|
654
632
|
um_prep_op(machine, &op, OP_ACCEPT_MULTISHOT);
|
655
|
-
|
633
|
+
|
656
634
|
struct op_ctx ctx = { .machine = machine, .op = &op, .fd = fd, .read_buf = NULL };
|
657
635
|
return rb_ensure(accept_each_begin, (VALUE)&ctx, multishot_ensure, (VALUE)&ctx);
|
658
636
|
}
|
@@ -803,7 +781,7 @@ VALUE um_periodically(struct um *machine, double interval) {
|
|
803
781
|
struct um_op op;
|
804
782
|
um_prep_op(machine, &op, OP_SLEEP_MULTISHOT);
|
805
783
|
op.ts = um_double_to_timespec(interval);
|
806
|
-
|
784
|
+
|
807
785
|
struct op_ctx ctx = { .machine = machine, .op = &op, .ts = op.ts, .read_buf = NULL };
|
808
786
|
return rb_ensure(periodically_begin, (VALUE)&ctx, multishot_ensure, (VALUE)&ctx);
|
809
787
|
}
|
data/ext/um/um.h
CHANGED
@@ -135,7 +135,7 @@ struct um_queue {
|
|
135
135
|
struct um_queue_entry *head;
|
136
136
|
struct um_queue_entry *tail;
|
137
137
|
struct um_queue_entry *free_head;
|
138
|
-
|
138
|
+
|
139
139
|
uint32_t num_waiters;
|
140
140
|
uint32_t state;
|
141
141
|
uint32_t count;
|
@@ -246,6 +246,4 @@ VALUE um_queue_shift(struct um *machine, struct um_queue *queue);
|
|
246
246
|
|
247
247
|
void um_define_net_constants(VALUE mod);
|
248
248
|
|
249
|
-
// void Init_micro_ssl(VALUE mod);
|
250
|
-
|
251
249
|
#endif // UM_H
|
data/ext/um/um_class.c
CHANGED
data/ext/um/um_const.c
CHANGED
@@ -159,7 +159,7 @@ void um_define_net_constants(VALUE mod) {
|
|
159
159
|
DEF_CONST_INT(mod, TCP_THIN_LINEAR_TIMEOUTS);
|
160
160
|
DEF_CONST_INT(mod, TCP_TIMESTAMP);
|
161
161
|
DEF_CONST_INT(mod, TCP_USER_TIMEOUT);
|
162
|
-
|
162
|
+
|
163
163
|
DEF_CONST_INT(mod, UDP_CORK);
|
164
164
|
|
165
165
|
DEF_CONST_INT(mod, AI_PASSIVE);
|
@@ -169,7 +169,7 @@ void um_define_net_constants(VALUE mod) {
|
|
169
169
|
DEF_CONST_INT(mod, AI_ALL);
|
170
170
|
DEF_CONST_INT(mod, AI_ADDRCONFIG);
|
171
171
|
DEF_CONST_INT(mod, AI_V4MAPPED);
|
172
|
-
|
172
|
+
|
173
173
|
DEF_CONST_INT(mod, NI_MAXHOST);
|
174
174
|
DEF_CONST_INT(mod, NI_MAXSERV);
|
175
175
|
DEF_CONST_INT(mod, NI_NOFQDN);
|
@@ -177,7 +177,7 @@ void um_define_net_constants(VALUE mod) {
|
|
177
177
|
DEF_CONST_INT(mod, NI_NAMEREQD);
|
178
178
|
DEF_CONST_INT(mod, NI_NUMERICSERV);
|
179
179
|
DEF_CONST_INT(mod, NI_DGRAM);
|
180
|
-
|
180
|
+
|
181
181
|
DEF_CONST_INT(mod, SHUT_RD);
|
182
182
|
DEF_CONST_INT(mod, SHUT_WR);
|
183
183
|
DEF_CONST_INT(mod, SHUT_RDWR);
|
data/ext/um/um_op.c
CHANGED
@@ -66,7 +66,7 @@ inline void um_op_list_compact(struct um *machine, struct um_op *head) {
|
|
66
66
|
}
|
67
67
|
}
|
68
68
|
|
69
|
-
inline struct um_op_result *multishot_result_alloc(struct um *machine) {
|
69
|
+
inline struct um_op_result *multishot_result_alloc(struct um *machine) {
|
70
70
|
if (machine->result_freelist) {
|
71
71
|
struct um_op_result *result = machine->result_freelist;
|
72
72
|
machine->result_freelist = result->next;
|
data/ext/um/um_sync.c
CHANGED
@@ -12,7 +12,7 @@ void um_futex_wait(struct um *machine, uint32_t *futex, uint32_t expect) {
|
|
12
12
|
sqe, (uint32_t *)futex, expect, FUTEX_BITSET_MATCH_ANY,
|
13
13
|
FUTEX2_SIZE_U32, 0
|
14
14
|
);
|
15
|
-
|
15
|
+
|
16
16
|
VALUE ret = um_fiber_switch(machine);
|
17
17
|
if (!um_op_completed_p(&op))
|
18
18
|
um_cancel_and_wait(machine, &op);
|
@@ -157,7 +157,7 @@ static inline void queue_add_head(struct um_queue *queue, VALUE value) {
|
|
157
157
|
struct um_queue_entry *entry = um_queue_entry_checkout(queue);
|
158
158
|
|
159
159
|
entry->next = queue->head;
|
160
|
-
if (queue->head) {
|
160
|
+
if (queue->head) {
|
161
161
|
queue->head->prev = entry;
|
162
162
|
queue->head = entry;
|
163
163
|
}
|
@@ -171,7 +171,7 @@ static inline void queue_add_tail(struct um_queue *queue, VALUE value) {
|
|
171
171
|
struct um_queue_entry *entry = um_queue_entry_checkout(queue);
|
172
172
|
|
173
173
|
entry->prev = queue->tail;
|
174
|
-
if (queue->tail) {
|
174
|
+
if (queue->tail) {
|
175
175
|
queue->tail->next = entry;
|
176
176
|
queue->tail = entry;
|
177
177
|
}
|
@@ -205,7 +205,7 @@ VALUE queue_remove_tail(struct um_queue *queue) {
|
|
205
205
|
static inline VALUE um_queue_add(struct um *machine, struct um_queue *queue, VALUE value, int add_head) {
|
206
206
|
if (add_head) queue_add_head(queue, value);
|
207
207
|
else queue_add_tail(queue, value);
|
208
|
-
|
208
|
+
|
209
209
|
queue->count++;
|
210
210
|
|
211
211
|
queue->state = QUEUE_READY;
|
@@ -232,7 +232,7 @@ struct queue_wait_ctx {
|
|
232
232
|
|
233
233
|
VALUE um_queue_remove_begin(VALUE arg) {
|
234
234
|
struct queue_wait_ctx *ctx = (struct queue_wait_ctx *)arg;
|
235
|
-
|
235
|
+
|
236
236
|
ctx->queue->num_waiters++;
|
237
237
|
while (ctx->queue->state == QUEUE_EMPTY) {
|
238
238
|
um_futex_wait(ctx->machine, &ctx->queue->state, QUEUE_EMPTY);
|
data/lib/uringmachine/actor.rb
CHANGED
@@ -10,10 +10,23 @@ class UringMachine
|
|
10
10
|
actor
|
11
11
|
end
|
12
12
|
|
13
|
+
def spin_thread_actor(mod, *a, **k)
|
14
|
+
machine = UM.new
|
15
|
+
target = Object.new.extend(mod)
|
16
|
+
mailbox = UM::Queue.new
|
17
|
+
actor = Actor.new
|
18
|
+
thread = Thread.new do
|
19
|
+
actor.run(machine, target, mailbox)
|
20
|
+
end
|
21
|
+
target.setup(*a, **k)
|
22
|
+
snooze
|
23
|
+
actor
|
24
|
+
end
|
25
|
+
|
13
26
|
class Actor < Fiber
|
14
27
|
def run(machine, target, mailbox)
|
15
28
|
@machine = machine
|
16
|
-
@target = target
|
29
|
+
@target = target
|
17
30
|
@mailbox = mailbox
|
18
31
|
while (msg = machine.shift(mailbox))
|
19
32
|
process_message(msg)
|
@@ -23,30 +36,26 @@ class UringMachine
|
|
23
36
|
end
|
24
37
|
|
25
38
|
def cast(sym, *a, **k)
|
26
|
-
|
39
|
+
@machine.push @mailbox, [:cast, nil, sym, a, k]
|
27
40
|
self
|
28
41
|
end
|
29
42
|
|
30
|
-
def call(sym, *a, **k)
|
31
|
-
|
32
|
-
@machine.
|
43
|
+
def call(response_mailbox, sym, *a, **k)
|
44
|
+
@machine.push @mailbox, [:call, response_mailbox, sym, a, k]
|
45
|
+
@machine.shift response_mailbox
|
33
46
|
end
|
34
47
|
|
35
48
|
private
|
36
49
|
|
37
50
|
def process_message(msg)
|
38
|
-
type,
|
51
|
+
type, response_mailbox, sym, args, kwargs = msg
|
39
52
|
case type
|
40
53
|
when :cast
|
41
54
|
@target.send(sym, *args, **kwargs)
|
42
55
|
when :call
|
43
56
|
res = @target.send(sym, *args, **kwargs)
|
44
|
-
@machine.
|
57
|
+
@machine.push(response_mailbox, res)
|
45
58
|
end
|
46
59
|
end
|
47
|
-
|
48
|
-
def <<(msg)
|
49
|
-
@machine.push(@mailbox, msg)
|
50
|
-
end
|
51
60
|
end
|
52
61
|
end
|
data/lib/uringmachine/version.rb
CHANGED
data/lib/uringmachine.rb
CHANGED
@@ -12,30 +12,85 @@ class UringMachine
|
|
12
12
|
@@fiber_map
|
13
13
|
end
|
14
14
|
|
15
|
+
class Terminate < Exception
|
16
|
+
end
|
17
|
+
|
15
18
|
def spin(value = nil, fiber_class = Fiber, &block)
|
16
19
|
f = fiber_class.new do |resume_value|
|
17
|
-
block.(resume_value)
|
20
|
+
f.set_result block.(resume_value)
|
18
21
|
rescue Exception => e
|
19
|
-
|
20
|
-
STDERR.puts e.backtrace.join("\n")
|
21
|
-
exit
|
22
|
+
f.set_result e
|
22
23
|
ensure
|
24
|
+
f.mark_as_done
|
25
|
+
# cleanup
|
23
26
|
@@fiber_map.delete(f)
|
24
|
-
|
27
|
+
self.notify_done_listeners(f)
|
28
|
+
# transfer control to other fibers
|
25
29
|
self.yield
|
26
|
-
p :bad_bad_bad
|
27
30
|
end
|
28
|
-
schedule(f, value)
|
31
|
+
self.schedule(f, value)
|
29
32
|
@@fiber_map[f] = true
|
30
33
|
f
|
31
34
|
end
|
32
35
|
|
36
|
+
def join(*fibers)
|
37
|
+
results = fibers.inject({}) { |h, f| h[f] = nil; h }
|
38
|
+
queue = nil
|
39
|
+
pending = nil
|
40
|
+
fibers.each do |f|
|
41
|
+
if f.done?
|
42
|
+
results[f] = f.result
|
43
|
+
else
|
44
|
+
(pending ||= []) << f
|
45
|
+
queue ||= UM::Queue.new
|
46
|
+
f.add_done_listener(queue)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
return results.values if !pending
|
50
|
+
|
51
|
+
while !pending.empty?
|
52
|
+
f = self.shift(queue)
|
53
|
+
pending.delete(f)
|
54
|
+
results[f] = f.result
|
55
|
+
end
|
56
|
+
results.values
|
57
|
+
end
|
58
|
+
|
33
59
|
def resolve(hostname, type = :A)
|
34
60
|
@resolver ||= DNSResolver.new(self)
|
35
61
|
@resolver.resolve(hostname, type)
|
36
62
|
end
|
37
63
|
|
38
|
-
|
39
|
-
|
64
|
+
private
|
65
|
+
|
66
|
+
def notify_done_listeners(fiber)
|
67
|
+
listeners = fiber.done_listeners
|
68
|
+
return if !listeners
|
69
|
+
|
70
|
+
listeners.each { self.push(it, fiber) }
|
71
|
+
end
|
72
|
+
|
73
|
+
module FiberExtensions
|
74
|
+
attr_reader :result, :done, :done_listeners
|
75
|
+
|
76
|
+
def mark_as_done
|
77
|
+
@done = true
|
78
|
+
end
|
79
|
+
|
80
|
+
def set_result(value)
|
81
|
+
@result = value
|
82
|
+
end
|
83
|
+
|
84
|
+
def done?
|
85
|
+
@done
|
86
|
+
end
|
87
|
+
|
88
|
+
def add_done_listener(queue)
|
89
|
+
(@done_listeners ||= []) << queue
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class ::Fiber
|
94
|
+
include UringMachine::FiberExtensions
|
40
95
|
end
|
41
96
|
end
|