polyphony 0.59 → 0.62
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 +24 -0
- data/Gemfile.lock +15 -29
- data/examples/core/message_based_supervision.rb +51 -0
- data/examples/io/echo_server.rb +16 -7
- data/ext/polyphony/backend_common.c +83 -16
- data/ext/polyphony/backend_common.h +15 -3
- data/ext/polyphony/backend_io_uring.c +58 -25
- data/ext/polyphony/backend_io_uring_context.c +10 -1
- data/ext/polyphony/backend_io_uring_context.h +5 -3
- data/ext/polyphony/backend_libev.c +52 -20
- data/ext/polyphony/extconf.rb +2 -2
- data/ext/polyphony/fiber.c +1 -32
- data/ext/polyphony/polyphony.c +12 -12
- data/ext/polyphony/polyphony.h +4 -5
- data/ext/polyphony/queue.c +12 -12
- data/ext/polyphony/runqueue.c +11 -19
- data/ext/polyphony/runqueue.h +2 -2
- data/ext/polyphony/thread.c +0 -18
- data/lib/polyphony/core/timer.rb +2 -2
- data/lib/polyphony/extensions/fiber.rb +100 -80
- data/lib/polyphony/extensions/io.rb +10 -9
- data/lib/polyphony/extensions/openssl.rb +14 -4
- data/lib/polyphony/extensions/socket.rb +15 -15
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +0 -7
- data/test/test_backend.rb +43 -6
- data/test/test_ext.rb +1 -1
- data/test/test_fiber.rb +106 -18
- data/test/test_global_api.rb +1 -1
- data/test/test_io.rb +29 -0
- data/test/test_supervise.rb +100 -100
- data/test/test_thread_pool.rb +1 -1
- data/test/test_trace.rb +5 -4
- metadata +4 -107
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2cea172818871812ebbafcbee0a4b98d130a351f904d7732a02400ef363eac62
|
4
|
+
data.tar.gz: f4ef85515436a463d3732f04bbef457426f267fac01f5c5c28619e42334cd745
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 489b813f1bb2d7d97f87a60024b0665761571c4227e4fab6c733dcdb62b6ee98760473202c9154eb39a4b544663f759e4da6e70603d483e9f2ec2a64363cd4e1
|
7
|
+
data.tar.gz: 05b232d7d67120e0983e60855c928beac6e91271fafc87586da7cc7543128fe326be04d126154ac7e0b0c0b249bf41ca90ab902f79f4a5fbf00cad498061f7e7
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,27 @@
|
|
1
|
+
## 0.62 2021-07-21
|
2
|
+
|
3
|
+
- Add `runqueue_size` to backend stats
|
4
|
+
|
5
|
+
## 0.61 2021-07-20
|
6
|
+
|
7
|
+
- Add more statistics, move stats to `Backend#stats`
|
8
|
+
|
9
|
+
## 0.60 2021-07-15
|
10
|
+
|
11
|
+
|
12
|
+
- Fix linux version detection (for kernel version > 5.9)
|
13
|
+
- Fix op ctx leak in io_uring backend (when polling for I/O readiness)
|
14
|
+
- Add support for appending to buffer in `Backend#read`, `Backend#recv` methods
|
15
|
+
- Improve anti-event starvation mechanism
|
16
|
+
- Redesign fiber monitoring mechanism
|
17
|
+
- Implement `Fiber#attach`
|
18
|
+
- Add optional maxlen argument to `IO#read_loop`, `Socket#recv_loop` (#60)
|
19
|
+
- Implement `Fiber#detach` (#52)
|
20
|
+
|
21
|
+
## 0.59.1 2021-06-28
|
22
|
+
|
23
|
+
- Accept fiber tag in `Polyphony::Timer.new`
|
24
|
+
|
1
25
|
## 0.59 2021-06-28
|
2
26
|
|
3
27
|
- Redesign tracing mechanism and API - now completely separated from Ruby core
|
data/Gemfile.lock
CHANGED
@@ -1,27 +1,25 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
polyphony (0.
|
4
|
+
polyphony (0.62)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
9
|
ansi (1.5.0)
|
10
|
-
ast (2.4.
|
10
|
+
ast (2.4.2)
|
11
11
|
builder (3.2.4)
|
12
12
|
coderay (1.1.3)
|
13
|
-
docile (1.
|
14
|
-
hiredis (0.6.3)
|
15
|
-
http_parser.rb (0.6.0)
|
13
|
+
docile (1.4.0)
|
16
14
|
httparty (0.17.1)
|
17
15
|
mime-types (~> 3.0)
|
18
16
|
multi_xml (>= 0.5.2)
|
19
|
-
json (2.
|
17
|
+
json (2.5.1)
|
20
18
|
localhost (1.1.8)
|
21
19
|
method_source (1.0.0)
|
22
20
|
mime-types (3.3.1)
|
23
21
|
mime-types-data (~> 3.2015)
|
24
|
-
mime-types-data (3.
|
22
|
+
mime-types-data (3.2021.0704)
|
25
23
|
minitest (5.14.4)
|
26
24
|
minitest-reporters (1.4.2)
|
27
25
|
ansi
|
@@ -30,22 +28,18 @@ GEM
|
|
30
28
|
ruby-progressbar
|
31
29
|
msgpack (1.4.2)
|
32
30
|
multi_xml (0.6.0)
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
ast (~> 2.4.0)
|
37
|
-
pg (1.1.4)
|
31
|
+
parallel (1.20.1)
|
32
|
+
parser (3.0.2.0)
|
33
|
+
ast (~> 2.4.1)
|
38
34
|
pry (0.13.1)
|
39
35
|
coderay (~> 1.1)
|
40
36
|
method_source (~> 1.0)
|
41
|
-
rack (2.2.3)
|
42
37
|
rainbow (3.0.0)
|
43
|
-
rake (13.0.
|
38
|
+
rake (13.0.6)
|
44
39
|
rake-compiler (1.1.1)
|
45
40
|
rake
|
46
|
-
|
47
|
-
|
48
|
-
rexml (3.2.4)
|
41
|
+
regexp_parser (2.1.1)
|
42
|
+
rexml (3.2.5)
|
49
43
|
rubocop (0.85.1)
|
50
44
|
parallel (~> 1.10)
|
51
45
|
parser (>= 2.7.0.1)
|
@@ -55,37 +49,29 @@ GEM
|
|
55
49
|
rubocop-ast (>= 0.0.3)
|
56
50
|
ruby-progressbar (~> 1.7)
|
57
51
|
unicode-display_width (>= 1.4.0, < 2.0)
|
58
|
-
rubocop-ast (
|
59
|
-
parser (>=
|
60
|
-
ruby-progressbar (1.
|
61
|
-
sequel (5.34.0)
|
52
|
+
rubocop-ast (1.8.0)
|
53
|
+
parser (>= 3.0.1.1)
|
54
|
+
ruby-progressbar (1.11.0)
|
62
55
|
simplecov (0.17.1)
|
63
56
|
docile (~> 1.1)
|
64
57
|
json (>= 1.8, < 3)
|
65
58
|
simplecov-html (~> 0.10.0)
|
66
59
|
simplecov-html (0.10.2)
|
67
|
-
unicode-display_width (1.
|
60
|
+
unicode-display_width (1.7.0)
|
68
61
|
|
69
62
|
PLATFORMS
|
70
63
|
ruby
|
71
64
|
|
72
65
|
DEPENDENCIES
|
73
|
-
hiredis (= 0.6.3)
|
74
|
-
http_parser.rb (~> 0.6.0)
|
75
66
|
httparty (= 0.17.1)
|
76
67
|
localhost (~> 1.1.4)
|
77
68
|
minitest (= 5.14.4)
|
78
69
|
minitest-reporters (= 1.4.2)
|
79
70
|
msgpack (= 1.4.2)
|
80
|
-
mysql2 (= 0.5.3)
|
81
|
-
pg (= 1.1.4)
|
82
71
|
polyphony!
|
83
72
|
pry (= 0.13.1)
|
84
|
-
rack (>= 2.0.8, < 2.3.0)
|
85
73
|
rake-compiler (= 1.1.1)
|
86
|
-
redis (= 4.1.0)
|
87
74
|
rubocop (= 0.85.1)
|
88
|
-
sequel (= 5.34.0)
|
89
75
|
simplecov (= 0.17.1)
|
90
76
|
|
91
77
|
BUNDLED WITH
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
class Supervisor
|
7
|
+
def initialize(*fibers)
|
8
|
+
@fiber = spin { do_supervise }
|
9
|
+
@fiber.message_on_child_termination = true
|
10
|
+
fibers.each { |f| add(f) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def await
|
14
|
+
@fiber.await
|
15
|
+
end
|
16
|
+
|
17
|
+
def spin(tag = nil, &block)
|
18
|
+
@fiber.spin(tag, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def add(fiber)
|
22
|
+
fiber.attach(@fiber)
|
23
|
+
end
|
24
|
+
|
25
|
+
def do_supervise
|
26
|
+
loop do
|
27
|
+
msg = receive
|
28
|
+
# puts "Supervisor received #{msg.inspect}"
|
29
|
+
f, r = msg
|
30
|
+
puts "Fiber #{f.tag} terminated with #{r.inspect}, restarting..."
|
31
|
+
f.restart
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def supervise(*fibers)
|
37
|
+
supervisor = Supervisor.new(*fibers)
|
38
|
+
supervisor.await
|
39
|
+
end
|
40
|
+
|
41
|
+
def start_worker(id)
|
42
|
+
spin_loop(:"worker#{id}") do
|
43
|
+
duration = rand(0.5..1.0)
|
44
|
+
puts "Worker #{id} sleeping for #{duration} seconds"
|
45
|
+
sleep duration
|
46
|
+
raise 'foo' if rand > 0.7
|
47
|
+
break if rand > 0.6
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
supervise(start_worker(1), start_worker(2))
|
data/examples/io/echo_server.rb
CHANGED
@@ -3,16 +3,25 @@
|
|
3
3
|
require 'bundler/setup'
|
4
4
|
require 'polyphony'
|
5
5
|
|
6
|
+
spin_loop(interval: 5) { p Thread.backend.stats }
|
7
|
+
|
6
8
|
server = TCPServer.open('127.0.0.1', 1234)
|
7
9
|
puts "Pid: #{Process.pid}"
|
8
10
|
puts 'Echoing on port 1234...'
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
begin
|
12
|
+
while (client = server.accept)
|
13
|
+
spin do
|
14
|
+
while (data = client.gets)
|
15
|
+
# client.send("you said: #{data.chomp}!\n", 0)
|
16
|
+
client.write('you said: ', data.chomp, "!\n")
|
17
|
+
end
|
18
|
+
rescue Errno::ECONNRESET
|
19
|
+
'Connection reset...'
|
20
|
+
ensure
|
21
|
+
client.shutdown
|
22
|
+
client.close
|
14
23
|
end
|
15
|
-
rescue Errno::ECONNRESET
|
16
|
-
'Connection reset...'
|
17
24
|
end
|
25
|
+
ensure
|
26
|
+
server.close
|
18
27
|
end
|
@@ -8,6 +8,9 @@
|
|
8
8
|
inline void backend_base_initialize(struct Backend_base *base) {
|
9
9
|
runqueue_initialize(&base->runqueue);
|
10
10
|
base->currently_polling = 0;
|
11
|
+
base->op_count = 0;
|
12
|
+
base->switch_count = 0;
|
13
|
+
base->poll_count = 0;
|
11
14
|
base->pending_count = 0;
|
12
15
|
base->idle_gc_period = 0;
|
13
16
|
base->idle_gc_last_time = 0;
|
@@ -25,33 +28,37 @@ inline void backend_base_mark(struct Backend_base *base) {
|
|
25
28
|
runqueue_mark(&base->runqueue);
|
26
29
|
}
|
27
30
|
|
31
|
+
const unsigned int ANTI_STARVE_SWITCH_COUNT_THRESHOLD = 64;
|
32
|
+
|
33
|
+
inline void conditional_nonblocking_poll(VALUE backend, struct Backend_base *base, VALUE current, VALUE next) {
|
34
|
+
if ((base->switch_count % ANTI_STARVE_SWITCH_COUNT_THRESHOLD) == 0 || next == current)
|
35
|
+
Backend_poll(backend, Qnil);
|
36
|
+
}
|
37
|
+
|
28
38
|
VALUE backend_base_switch_fiber(VALUE backend, struct Backend_base *base) {
|
29
39
|
VALUE current_fiber = rb_fiber_current();
|
30
40
|
runqueue_entry next;
|
31
41
|
unsigned int pending_ops_count = base->pending_count;
|
32
42
|
unsigned int backend_was_polled = 0;
|
33
43
|
unsigned int idle_tasks_run_count = 0;
|
34
|
-
|
35
|
-
|
36
|
-
|
44
|
+
|
45
|
+
base->switch_count++;
|
46
|
+
COND_TRACE(base, 2, SYM_fiber_switchpoint, current_fiber);
|
37
47
|
|
38
48
|
while (1) {
|
39
49
|
next = runqueue_shift(&base->runqueue);
|
40
50
|
if (next.fiber != Qnil) {
|
41
51
|
// Polling for I/O op completion is normally done when the run queue is
|
42
52
|
// empty, but if the runqueue never empties, we'll never get to process
|
43
|
-
// any event completions. In order to prevent this, an anti-
|
53
|
+
// any event completions. In order to prevent this, an anti-starvation
|
44
54
|
// mechanism is employed, under the following conditions:
|
45
55
|
// - a blocking poll was not yet performed
|
46
56
|
// - there are pending blocking operations
|
47
|
-
// - the runqueue has
|
48
|
-
//
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
// this prevents event starvation in case the run queue never empties
|
53
|
-
Backend_poll(backend, Qnil);
|
54
|
-
}
|
57
|
+
// - the runqueue shift count has reached a fixed threshold (currently 64), or
|
58
|
+
// - the next fiber is the same as the current fiber (a single fiber is snoozing)
|
59
|
+
if (!backend_was_polled && pending_ops_count)
|
60
|
+
conditional_nonblocking_poll(backend, base, current_fiber, next.fiber);
|
61
|
+
|
55
62
|
break;
|
56
63
|
}
|
57
64
|
|
@@ -82,7 +89,8 @@ void backend_base_schedule_fiber(VALUE thread, VALUE backend, struct Backend_bas
|
|
82
89
|
if (rb_fiber_alive_p(fiber) != Qtrue) return;
|
83
90
|
already_runnable = rb_ivar_get(fiber, ID_ivar_runnable) != Qnil;
|
84
91
|
|
85
|
-
COND_TRACE(base,
|
92
|
+
COND_TRACE(base, 4, SYM_fiber_schedule, fiber, value, prioritize ? Qtrue : Qfalse);
|
93
|
+
|
86
94
|
(prioritize ? runqueue_unshift : runqueue_push)(&base->runqueue, fiber, value, already_runnable);
|
87
95
|
if (!already_runnable) {
|
88
96
|
rb_ivar_set(fiber, ID_ivar_runnable, Qtrue);
|
@@ -171,7 +179,7 @@ inline VALUE io_enc_str(VALUE str, rb_io_t *fptr) {
|
|
171
179
|
//////////////////////////////////////////////////////////////////////
|
172
180
|
//////////////////////////////////////////////////////////////////////
|
173
181
|
|
174
|
-
VALUE backend_await(struct Backend_base *backend) {
|
182
|
+
inline VALUE backend_await(struct Backend_base *backend) {
|
175
183
|
VALUE ret;
|
176
184
|
backend->pending_count++;
|
177
185
|
ret = Thread_switch_fiber(rb_thread_current());
|
@@ -180,9 +188,10 @@ VALUE backend_await(struct Backend_base *backend) {
|
|
180
188
|
return ret;
|
181
189
|
}
|
182
190
|
|
183
|
-
VALUE backend_snooze() {
|
191
|
+
inline VALUE backend_snooze() {
|
192
|
+
VALUE ret;
|
184
193
|
Fiber_make_runnable(rb_fiber_current(), Qnil);
|
185
|
-
|
194
|
+
ret = Thread_switch_fiber(rb_thread_current());
|
186
195
|
return ret;
|
187
196
|
}
|
188
197
|
|
@@ -286,3 +295,61 @@ inline void backend_run_idle_tasks(struct Backend_base *base) {
|
|
286
295
|
rb_gc_start();
|
287
296
|
rb_gc_disable();
|
288
297
|
}
|
298
|
+
|
299
|
+
inline struct backend_stats backend_base_stats(struct Backend_base *base) {
|
300
|
+
struct backend_stats stats = {
|
301
|
+
.runqueue_size = runqueue_size(&base->runqueue),
|
302
|
+
.runqueue_length = runqueue_len(&base->runqueue),
|
303
|
+
.runqueue_max_length = runqueue_max_len(&base->runqueue),
|
304
|
+
.op_count = base->op_count,
|
305
|
+
.switch_count = base->switch_count,
|
306
|
+
.poll_count = base->poll_count,
|
307
|
+
.pending_ops = base->pending_count
|
308
|
+
};
|
309
|
+
|
310
|
+
base->op_count = 0;
|
311
|
+
base->switch_count = 0;
|
312
|
+
base->poll_count = 0;
|
313
|
+
return stats;
|
314
|
+
}
|
315
|
+
|
316
|
+
VALUE SYM_runqueue_size;
|
317
|
+
VALUE SYM_runqueue_length;
|
318
|
+
VALUE SYM_runqueue_max_length;
|
319
|
+
VALUE SYM_op_count;
|
320
|
+
VALUE SYM_switch_count;
|
321
|
+
VALUE SYM_poll_count;
|
322
|
+
VALUE SYM_pending_ops;
|
323
|
+
|
324
|
+
VALUE Backend_stats(VALUE self) {
|
325
|
+
struct backend_stats backend_stats = backend_get_stats(self);
|
326
|
+
|
327
|
+
VALUE stats = rb_hash_new();
|
328
|
+
rb_hash_aset(stats, SYM_runqueue_size, INT2NUM(backend_stats.runqueue_size));
|
329
|
+
rb_hash_aset(stats, SYM_runqueue_length, INT2NUM(backend_stats.runqueue_length));
|
330
|
+
rb_hash_aset(stats, SYM_runqueue_max_length, INT2NUM(backend_stats.runqueue_max_length));
|
331
|
+
rb_hash_aset(stats, SYM_op_count, INT2NUM(backend_stats.op_count));
|
332
|
+
rb_hash_aset(stats, SYM_switch_count, INT2NUM(backend_stats.switch_count));
|
333
|
+
rb_hash_aset(stats, SYM_poll_count, INT2NUM(backend_stats.poll_count));
|
334
|
+
rb_hash_aset(stats, SYM_pending_ops, INT2NUM(backend_stats.pending_ops));
|
335
|
+
RB_GC_GUARD(stats);
|
336
|
+
return stats;
|
337
|
+
}
|
338
|
+
|
339
|
+
void backend_setup_stats_symbols() {
|
340
|
+
SYM_runqueue_size = ID2SYM(rb_intern("runqueue_size"));
|
341
|
+
SYM_runqueue_length = ID2SYM(rb_intern("runqueue_length"));
|
342
|
+
SYM_runqueue_max_length = ID2SYM(rb_intern("runqueue_max_length"));
|
343
|
+
SYM_op_count = ID2SYM(rb_intern("op_count"));
|
344
|
+
SYM_switch_count = ID2SYM(rb_intern("switch_count"));
|
345
|
+
SYM_poll_count = ID2SYM(rb_intern("poll_count"));
|
346
|
+
SYM_pending_ops = ID2SYM(rb_intern("pending_ops"));
|
347
|
+
|
348
|
+
rb_global_variable(&SYM_runqueue_size);
|
349
|
+
rb_global_variable(&SYM_runqueue_length);
|
350
|
+
rb_global_variable(&SYM_runqueue_max_length);
|
351
|
+
rb_global_variable(&SYM_op_count);
|
352
|
+
rb_global_variable(&SYM_switch_count);
|
353
|
+
rb_global_variable(&SYM_poll_count);
|
354
|
+
rb_global_variable(&SYM_pending_ops);
|
355
|
+
}
|
@@ -6,14 +6,21 @@
|
|
6
6
|
#include "runqueue.h"
|
7
7
|
|
8
8
|
struct backend_stats {
|
9
|
-
int
|
10
|
-
int
|
11
|
-
int
|
9
|
+
unsigned int runqueue_size;
|
10
|
+
unsigned int runqueue_length;
|
11
|
+
unsigned int runqueue_max_length;
|
12
|
+
unsigned int op_count;
|
13
|
+
unsigned int switch_count;
|
14
|
+
unsigned int poll_count;
|
15
|
+
unsigned int pending_ops;
|
12
16
|
};
|
13
17
|
|
14
18
|
struct Backend_base {
|
15
19
|
runqueue_t runqueue;
|
16
20
|
unsigned int currently_polling;
|
21
|
+
unsigned int op_count;
|
22
|
+
unsigned int switch_count;
|
23
|
+
unsigned int poll_count;
|
17
24
|
unsigned int pending_count;
|
18
25
|
double idle_gc_period;
|
19
26
|
double idle_gc_last_time;
|
@@ -27,6 +34,7 @@ void backend_base_mark(struct Backend_base *base);
|
|
27
34
|
VALUE backend_base_switch_fiber(VALUE backend, struct Backend_base *base);
|
28
35
|
void backend_base_schedule_fiber(VALUE thread, VALUE backend, struct Backend_base *base, VALUE fiber, VALUE value, int prioritize);
|
29
36
|
void backend_trace(struct Backend_base *base, int argc, VALUE *argv);
|
37
|
+
struct backend_stats backend_base_stats(struct Backend_base *base);
|
30
38
|
|
31
39
|
// tracing
|
32
40
|
#define SHOULD_TRACE(base) ((base)->trace_proc != Qnil)
|
@@ -60,6 +68,7 @@ VALUE io_enc_str(VALUE str, rb_io_t *fptr);
|
|
60
68
|
//////////////////////////////////////////////////////////////////////
|
61
69
|
//////////////////////////////////////////////////////////////////////
|
62
70
|
|
71
|
+
struct backend_stats backend_get_stats(VALUE self);
|
63
72
|
VALUE backend_await(struct Backend_base *backend);
|
64
73
|
VALUE backend_snooze();
|
65
74
|
|
@@ -92,7 +101,10 @@ VALUE backend_timeout_exception(VALUE exception);
|
|
92
101
|
VALUE Backend_timeout_ensure_safe(VALUE arg);
|
93
102
|
VALUE Backend_timeout_ensure_safe(VALUE arg);
|
94
103
|
VALUE Backend_sendv(VALUE self, VALUE io, VALUE ary, VALUE flags);
|
104
|
+
VALUE Backend_stats(VALUE self);
|
95
105
|
void backend_run_idle_tasks(struct Backend_base *base);
|
96
106
|
void io_verify_blocking_mode(rb_io_t *fptr, VALUE io, VALUE blocking);
|
97
107
|
|
108
|
+
void backend_setup_stats_symbols();
|
109
|
+
|
98
110
|
#endif /* BACKEND_COMMON_H */
|
@@ -191,12 +191,23 @@ inline VALUE Backend_poll(VALUE self, VALUE blocking) {
|
|
191
191
|
Backend_t *backend;
|
192
192
|
GetBackend(self, backend);
|
193
193
|
|
194
|
+
backend->base.poll_count++;
|
195
|
+
|
194
196
|
if (!is_blocking && backend->pending_sqes) {
|
195
197
|
backend->pending_sqes = 0;
|
196
198
|
io_uring_submit(&backend->ring);
|
197
199
|
}
|
198
200
|
|
199
201
|
COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_enter, rb_fiber_current());
|
202
|
+
// if (SHOULD_TRACE(&backend->base))
|
203
|
+
// printf(
|
204
|
+
// "io_uring_poll(blocking_mode: %d, pending: %d, taken: %d, available: %d, runqueue: %d\n",
|
205
|
+
// is_blocking,
|
206
|
+
// backend->base.pending_count,
|
207
|
+
// backend->store.taken_count,
|
208
|
+
// backend->store.available_count,
|
209
|
+
// backend->base.runqueue.entries.count
|
210
|
+
// );
|
200
211
|
if (is_blocking) io_uring_backend_poll(backend);
|
201
212
|
io_uring_backend_handle_ready_cqes(backend);
|
202
213
|
COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_leave, rb_fiber_current());
|
@@ -225,15 +236,11 @@ inline VALUE Backend_switch_fiber(VALUE self) {
|
|
225
236
|
return backend_base_switch_fiber(self, &backend->base);
|
226
237
|
}
|
227
238
|
|
228
|
-
inline struct backend_stats
|
239
|
+
inline struct backend_stats backend_get_stats(VALUE self) {
|
229
240
|
Backend_t *backend;
|
230
241
|
GetBackend(self, backend);
|
231
242
|
|
232
|
-
return (
|
233
|
-
.scheduled_fibers = runqueue_len(&backend->base.runqueue),
|
234
|
-
.waiting_fibers = 0,
|
235
|
-
.pending_ops = backend->base.pending_count
|
236
|
-
};
|
243
|
+
return backend_base_stats(&backend->base);
|
237
244
|
}
|
238
245
|
|
239
246
|
VALUE Backend_wakeup(VALUE self) {
|
@@ -271,6 +278,7 @@ int io_uring_backend_defer_submit_and_await(
|
|
271
278
|
{
|
272
279
|
VALUE switchpoint_result = Qnil;
|
273
280
|
|
281
|
+
backend->base.op_count++;
|
274
282
|
if (sqe) {
|
275
283
|
io_uring_sqe_set_data(sqe, ctx);
|
276
284
|
io_uring_sqe_set_flags(sqe, IOSQE_ASYNC);
|
@@ -302,17 +310,25 @@ VALUE io_uring_backend_wait_fd(Backend_t *backend, int fd, int write) {
|
|
302
310
|
io_uring_prep_poll_add(sqe, fd, write ? POLLOUT : POLLIN);
|
303
311
|
|
304
312
|
io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resumed_value);
|
313
|
+
context_store_release(&backend->store, ctx);
|
314
|
+
|
305
315
|
RB_GC_GUARD(resumed_value);
|
306
316
|
return resumed_value;
|
307
317
|
}
|
308
318
|
|
309
|
-
VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof) {
|
319
|
+
VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof, VALUE pos) {
|
310
320
|
Backend_t *backend;
|
311
321
|
rb_io_t *fptr;
|
312
322
|
long dynamic_len = length == Qnil;
|
313
323
|
long buffer_size = dynamic_len ? 4096 : NUM2INT(length);
|
314
|
-
|
315
|
-
|
324
|
+
long buf_pos = NUM2INT(pos);
|
325
|
+
if (str != Qnil) {
|
326
|
+
int current_len = RSTRING_LEN(str);
|
327
|
+
if (buf_pos < 0 || buf_pos > current_len) buf_pos = current_len;
|
328
|
+
}
|
329
|
+
else buf_pos = 0;
|
330
|
+
int shrinkable = io_setstrbuf(&str, buf_pos + buffer_size);
|
331
|
+
char *buf = RSTRING_PTR(str) + buf_pos;
|
316
332
|
long total = 0;
|
317
333
|
int read_to_eof = RTEST(to_eof);
|
318
334
|
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
|
@@ -349,9 +365,9 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof)
|
|
349
365
|
if (!dynamic_len) break;
|
350
366
|
|
351
367
|
// resize buffer
|
352
|
-
rb_str_resize(str, total);
|
368
|
+
rb_str_resize(str, buf_pos + total);
|
353
369
|
rb_str_modify_expand(str, buffer_size);
|
354
|
-
buf = RSTRING_PTR(str) + total;
|
370
|
+
buf = RSTRING_PTR(str) + buf_pos + total;
|
355
371
|
shrinkable = 0;
|
356
372
|
buffer_size += buffer_size;
|
357
373
|
}
|
@@ -359,7 +375,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof)
|
|
359
375
|
}
|
360
376
|
}
|
361
377
|
|
362
|
-
io_set_read_length(str, total, shrinkable);
|
378
|
+
io_set_read_length(str, buf_pos + total, shrinkable);
|
363
379
|
io_enc_str(str, fptr);
|
364
380
|
|
365
381
|
if (!total) return Qnil;
|
@@ -367,12 +383,12 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof)
|
|
367
383
|
return str;
|
368
384
|
}
|
369
385
|
|
370
|
-
VALUE Backend_read_loop(VALUE self, VALUE io) {
|
386
|
+
VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen) {
|
371
387
|
Backend_t *backend;
|
372
388
|
rb_io_t *fptr;
|
373
389
|
VALUE str;
|
374
390
|
long total;
|
375
|
-
long len =
|
391
|
+
long len = NUM2INT(maxlen);
|
376
392
|
int shrinkable;
|
377
393
|
char *buf;
|
378
394
|
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
|
@@ -580,13 +596,19 @@ VALUE Backend_write_m(int argc, VALUE *argv, VALUE self) {
|
|
580
596
|
Backend_writev(self, argv[0], argc - 1, argv + 1);
|
581
597
|
}
|
582
598
|
|
583
|
-
VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length) {
|
599
|
+
VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos) {
|
584
600
|
Backend_t *backend;
|
585
601
|
rb_io_t *fptr;
|
586
602
|
long dynamic_len = length == Qnil;
|
587
603
|
long len = dynamic_len ? 4096 : NUM2INT(length);
|
588
|
-
|
589
|
-
|
604
|
+
long buf_pos = NUM2INT(pos);
|
605
|
+
if (str != Qnil) {
|
606
|
+
int current_len = RSTRING_LEN(str);
|
607
|
+
if (buf_pos < 0 || buf_pos > current_len) buf_pos = current_len;
|
608
|
+
}
|
609
|
+
else buf_pos = 0;
|
610
|
+
int shrinkable = io_setstrbuf(&str, buf_pos + len);
|
611
|
+
char *buf = RSTRING_PTR(str) + buf_pos;
|
590
612
|
long total = 0;
|
591
613
|
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
|
592
614
|
|
@@ -618,7 +640,7 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length) {
|
|
618
640
|
}
|
619
641
|
}
|
620
642
|
|
621
|
-
io_set_read_length(str, total, shrinkable);
|
643
|
+
io_set_read_length(str, buf_pos + total, shrinkable);
|
622
644
|
io_enc_str(str, fptr);
|
623
645
|
|
624
646
|
if (!total) return Qnil;
|
@@ -626,12 +648,12 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length) {
|
|
626
648
|
return str;
|
627
649
|
}
|
628
650
|
|
629
|
-
VALUE Backend_recv_loop(VALUE self, VALUE io) {
|
651
|
+
VALUE Backend_recv_loop(VALUE self, VALUE io, VALUE maxlen) {
|
630
652
|
Backend_t *backend;
|
631
653
|
rb_io_t *fptr;
|
632
654
|
VALUE str;
|
633
655
|
long total;
|
634
|
-
long len =
|
656
|
+
long len = NUM2INT(maxlen);
|
635
657
|
int shrinkable;
|
636
658
|
char *buf;
|
637
659
|
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
|
@@ -1021,6 +1043,7 @@ VALUE Backend_timeout(int argc, VALUE *argv, VALUE self) {
|
|
1021
1043
|
io_uring_prep_timeout(sqe, &ts, 0, 0);
|
1022
1044
|
io_uring_sqe_set_data(sqe, ctx);
|
1023
1045
|
io_uring_backend_defer_submit(backend);
|
1046
|
+
backend->base.op_count++;
|
1024
1047
|
|
1025
1048
|
struct Backend_timeout_ctx timeout_ctx = {backend, ctx};
|
1026
1049
|
result = rb_ensure(Backend_timeout_ensure_safe, Qnil, Backend_timeout_ensure, (VALUE)&timeout_ctx);
|
@@ -1188,6 +1211,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1188
1211
|
sqe_count++;
|
1189
1212
|
}
|
1190
1213
|
|
1214
|
+
backend->base.op_count += sqe_count;
|
1191
1215
|
ctx->ref_count = sqe_count + 1;
|
1192
1216
|
io_uring_backend_defer_submit(backend);
|
1193
1217
|
resume_value = backend_await((struct Backend_base *)backend);
|
@@ -1324,6 +1348,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1324
1348
|
if (prefix != Qnil) {
|
1325
1349
|
splice_chunks_get_sqe(backend, &ctx, &sqe, OP_WRITE);
|
1326
1350
|
splice_chunks_prep_write(ctx, sqe, dest_fptr->fd, prefix);
|
1351
|
+
backend->base.op_count++;
|
1327
1352
|
}
|
1328
1353
|
|
1329
1354
|
while (1) {
|
@@ -1333,7 +1358,8 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1333
1358
|
|
1334
1359
|
splice_chunks_get_sqe(backend, &ctx, &sqe, OP_SPLICE);
|
1335
1360
|
splice_chunks_prep_splice(ctx, sqe, src_fptr->fd, pipefd[1], maxlen);
|
1336
|
-
|
1361
|
+
backend->base.op_count++;
|
1362
|
+
|
1337
1363
|
SPLICE_CHUNKS_AWAIT_OPS(backend, &ctx, &chunk_len, &switchpoint_result);
|
1338
1364
|
if (chunk_len == 0) break;
|
1339
1365
|
|
@@ -1345,15 +1371,18 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1345
1371
|
chunk_prefix_str = (TYPE(chunk_prefix) == T_STRING) ? chunk_prefix : rb_funcall(chunk_prefix, ID_call, 1, chunk_len_value);
|
1346
1372
|
splice_chunks_get_sqe(backend, &ctx, &sqe, OP_WRITE);
|
1347
1373
|
splice_chunks_prep_write(ctx, sqe, dest_fptr->fd, chunk_prefix_str);
|
1374
|
+
backend->base.op_count++;
|
1348
1375
|
}
|
1349
1376
|
|
1350
1377
|
splice_chunks_get_sqe(backend, &ctx, &sqe, OP_SPLICE);
|
1351
1378
|
splice_chunks_prep_splice(ctx, sqe, pipefd[0], dest_fptr->fd, chunk_len);
|
1379
|
+
backend->base.op_count++;
|
1352
1380
|
|
1353
1381
|
if (chunk_postfix != Qnil) {
|
1354
1382
|
chunk_postfix_str = (TYPE(chunk_postfix) == T_STRING) ? chunk_postfix : rb_funcall(chunk_postfix, ID_call, 1, chunk_len_value);
|
1355
1383
|
splice_chunks_get_sqe(backend, &ctx, &sqe, OP_WRITE);
|
1356
1384
|
splice_chunks_prep_write(ctx, sqe, dest_fptr->fd, chunk_postfix_str);
|
1385
|
+
backend->base.op_count++;
|
1357
1386
|
}
|
1358
1387
|
|
1359
1388
|
RB_GC_GUARD(chunk_prefix_str);
|
@@ -1363,6 +1392,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1363
1392
|
if (postfix != Qnil) {
|
1364
1393
|
splice_chunks_get_sqe(backend, &ctx, &sqe, OP_WRITE);
|
1365
1394
|
splice_chunks_prep_write(ctx, sqe, dest_fptr->fd, postfix);
|
1395
|
+
backend->base.op_count++;
|
1366
1396
|
}
|
1367
1397
|
if (ctx) {
|
1368
1398
|
SPLICE_CHUNKS_AWAIT_OPS(backend, &ctx, 0, &switchpoint_result);
|
@@ -1408,6 +1438,7 @@ void Init_Backend() {
|
|
1408
1438
|
rb_define_method(cBackend, "post_fork", Backend_post_fork, 0);
|
1409
1439
|
rb_define_method(cBackend, "trace", Backend_trace, -1);
|
1410
1440
|
rb_define_method(cBackend, "trace_proc=", Backend_trace_proc_set, 1);
|
1441
|
+
rb_define_method(cBackend, "stats", Backend_stats, 0);
|
1411
1442
|
|
1412
1443
|
rb_define_method(cBackend, "poll", Backend_poll, 1);
|
1413
1444
|
rb_define_method(cBackend, "break", Backend_wakeup, 0);
|
@@ -1421,11 +1452,11 @@ void Init_Backend() {
|
|
1421
1452
|
rb_define_method(cBackend, "accept_loop", Backend_accept_loop, 2);
|
1422
1453
|
rb_define_method(cBackend, "connect", Backend_connect, 3);
|
1423
1454
|
rb_define_method(cBackend, "feed_loop", Backend_feed_loop, 3);
|
1424
|
-
rb_define_method(cBackend, "read", Backend_read,
|
1425
|
-
rb_define_method(cBackend, "read_loop", Backend_read_loop,
|
1426
|
-
rb_define_method(cBackend, "recv", Backend_recv,
|
1455
|
+
rb_define_method(cBackend, "read", Backend_read, 5);
|
1456
|
+
rb_define_method(cBackend, "read_loop", Backend_read_loop, 2);
|
1457
|
+
rb_define_method(cBackend, "recv", Backend_recv, 4);
|
1427
1458
|
rb_define_method(cBackend, "recv_feed_loop", Backend_recv_feed_loop, 3);
|
1428
|
-
rb_define_method(cBackend, "recv_loop", Backend_recv_loop,
|
1459
|
+
rb_define_method(cBackend, "recv_loop", Backend_recv_loop, 2);
|
1429
1460
|
rb_define_method(cBackend, "send", Backend_send, 3);
|
1430
1461
|
rb_define_method(cBackend, "sendv", Backend_sendv, 3);
|
1431
1462
|
rb_define_method(cBackend, "sleep", Backend_sleep, 1);
|
@@ -1447,6 +1478,8 @@ void Init_Backend() {
|
|
1447
1478
|
SYM_send = ID2SYM(rb_intern("send"));
|
1448
1479
|
SYM_splice = ID2SYM(rb_intern("splice"));
|
1449
1480
|
SYM_write = ID2SYM(rb_intern("write"));
|
1481
|
+
|
1482
|
+
backend_setup_stats_symbols();
|
1450
1483
|
}
|
1451
1484
|
|
1452
1485
|
#endif // POLYPHONY_BACKEND_LIBURING
|