polyphony 0.59.1 → 0.63
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/Gemfile.lock +15 -29
- data/Rakefile +1 -1
- 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/extensions/fiber.rb +100 -80
- data/lib/polyphony/extensions/io.rb +15 -10
- data/lib/polyphony/extensions/openssl.rb +28 -4
- data/lib/polyphony/extensions/socket.rb +66 -15
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +0 -7
- data/test/test_backend.rb +69 -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 +49 -0
- data/test/test_socket.rb +39 -1
- 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: b2c69a05b391ebc688550a3894e56362de6603d04e807cad3072dfdffe966787
|
4
|
+
data.tar.gz: c09da8e0cb9e04eb4ea964e81cdd75a735f9e2f08f882ddaec8f2bee4be5661b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cbd89d448e06cc80a105ab763b21b62054eb7ee4a21b8b115954765e80170d55a99b4a314695554493d81cbd73f87941846521a4b0dcac9d1653bcb8a51497f6
|
7
|
+
data.tar.gz: 6fc94352edc156fb963a4f74180208353ecd8cae82ffef1c6ac02b6413870ba028a5cea547dcdebb5bb3998b73a5529de209c035ae32ec7d4500678b3a7f7b65
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,28 @@
|
|
1
|
+
## 0.63 2021-07-26
|
2
|
+
|
3
|
+
- Add support for specifying buf and buf_pos in `IO#read`
|
4
|
+
- Fix `Socket#read` to work and conform to `IO#read` interface
|
5
|
+
|
6
|
+
## 0.62 2021-07-21
|
7
|
+
|
8
|
+
- Add `runqueue_size` to backend stats
|
9
|
+
|
10
|
+
## 0.61 2021-07-20
|
11
|
+
|
12
|
+
- Add more statistics, move stats to `Backend#stats`
|
13
|
+
|
14
|
+
## 0.60 2021-07-15
|
15
|
+
|
16
|
+
|
17
|
+
- Fix linux version detection (for kernel version > 5.9)
|
18
|
+
- Fix op ctx leak in io_uring backend (when polling for I/O readiness)
|
19
|
+
- Add support for appending to buffer in `Backend#read`, `Backend#recv` methods
|
20
|
+
- Improve anti-event starvation mechanism
|
21
|
+
- Redesign fiber monitoring mechanism
|
22
|
+
- Implement `Fiber#attach`
|
23
|
+
- Add optional maxlen argument to `IO#read_loop`, `Socket#recv_loop` (#60)
|
24
|
+
- Implement `Fiber#detach` (#52)
|
25
|
+
|
1
26
|
## 0.59.1 2021-06-28
|
2
27
|
|
3
28
|
- Accept fiber tag in `Polyphony::Timer.new`
|
data/Gemfile.lock
CHANGED
@@ -1,27 +1,25 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
polyphony (0.
|
4
|
+
polyphony (0.63)
|
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
|
data/Rakefile
CHANGED
@@ -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
|