polyphony 0.53.0 → 0.53.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +1 -1
- data/TODO.md +4 -4
- data/ext/polyphony/backend_io_uring.c +10 -9
- data/ext/polyphony/backend_libev.c +41 -8
- data/ext/polyphony/thread.c +8 -2
- data/lib/polyphony/version.rb +1 -1
- data/test/test_backend.rb +87 -4
- data/test/test_thread.rb +4 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b769b5e71cbfa8679a639d369817abd8e5870efec8ea21feb60bb1e46ee7ca29
|
4
|
+
data.tar.gz: 0b2ded84eb0e120d20dd17c9973e2cab784cdf61c20bd20fcb6a13c2b6e9f58a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e6d3a3d2c130c31483ead4d8f13cc90a87149ac6c461871a43144111cdc37e6e2544c130dc447af26e39e9519b48e3abe1a10197dd4512a7292968e4939e676b
|
7
|
+
data.tar.gz: dc1b53918032fc74578ca528abb5a96e423ea8e7a070047f7936720cb6553d9f247cbb625e9d82c7b9b58795a4a3a74aae566231a7a4bb8443f5352c00d10b2a
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
data/TODO.md
CHANGED
@@ -35,8 +35,8 @@
|
|
35
35
|
|
36
36
|
```ruby
|
37
37
|
Thread.current.backend.submit(
|
38
|
-
[sock,
|
39
|
-
[
|
38
|
+
[:send, sock, chunk_header(len)],
|
39
|
+
[:splice, file, sock, len]
|
40
40
|
)
|
41
41
|
```
|
42
42
|
|
@@ -51,8 +51,8 @@
|
|
51
51
|
break if len == 0
|
52
52
|
|
53
53
|
backend.submit(
|
54
|
-
[sock,
|
55
|
-
[
|
54
|
+
[:write, sock, chunk_header(len)],
|
55
|
+
[:splice, i, sock, len]
|
56
56
|
)
|
57
57
|
end
|
58
58
|
end
|
@@ -150,7 +150,7 @@ static inline bool cq_ring_needs_flush(struct io_uring *ring) {
|
|
150
150
|
return IO_URING_READ_ONCE(*ring->sq.kflags) & IORING_SQ_CQ_OVERFLOW;
|
151
151
|
}
|
152
152
|
|
153
|
-
void io_uring_backend_handle_completion(struct io_uring_cqe *cqe, Backend_t *backend) {
|
153
|
+
static inline void io_uring_backend_handle_completion(struct io_uring_cqe *cqe, Backend_t *backend) {
|
154
154
|
op_context_t *ctx = io_uring_cqe_get_data(cqe);
|
155
155
|
if (!ctx) return;
|
156
156
|
|
@@ -169,7 +169,7 @@ void io_uring_backend_handle_completion(struct io_uring_cqe *cqe, Backend_t *bac
|
|
169
169
|
}
|
170
170
|
|
171
171
|
// adapted from io_uring_peek_batch_cqe in queue.c
|
172
|
-
// this peeks at cqes and
|
172
|
+
// this peeks at cqes and handles each available cqe
|
173
173
|
void io_uring_backend_handle_ready_cqes(Backend_t *backend) {
|
174
174
|
struct io_uring *ring = &backend->ring;
|
175
175
|
bool overflow_checked = false;
|
@@ -315,8 +315,8 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof)
|
|
315
315
|
Backend_t *backend;
|
316
316
|
rb_io_t *fptr;
|
317
317
|
long dynamic_len = length == Qnil;
|
318
|
-
long
|
319
|
-
int shrinkable = io_setstrbuf(&str,
|
318
|
+
long buffer_size = dynamic_len ? 4096 : NUM2INT(length);
|
319
|
+
int shrinkable = io_setstrbuf(&str, buffer_size);
|
320
320
|
char *buf = RSTRING_PTR(str);
|
321
321
|
long total = 0;
|
322
322
|
int read_to_eof = RTEST(to_eof);
|
@@ -334,7 +334,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof)
|
|
334
334
|
VALUE resume_value = Qnil;
|
335
335
|
op_context_t *ctx = OP_CONTEXT_ACQUIRE(&backend->store, OP_READ);
|
336
336
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
337
|
-
io_uring_prep_read(sqe, fptr->fd, buf,
|
337
|
+
io_uring_prep_read(sqe, fptr->fd, buf, buffer_size - total, -1);
|
338
338
|
|
339
339
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
340
340
|
OP_CONTEXT_RELEASE(&backend->store, ctx);
|
@@ -350,14 +350,15 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof)
|
|
350
350
|
total += result;
|
351
351
|
if (!read_to_eof) break;
|
352
352
|
|
353
|
-
if (total ==
|
353
|
+
if (total == buffer_size) {
|
354
354
|
if (!dynamic_len) break;
|
355
355
|
|
356
|
+
// resize buffer
|
356
357
|
rb_str_resize(str, total);
|
357
|
-
rb_str_modify_expand(str,
|
358
|
+
rb_str_modify_expand(str, buffer_size);
|
358
359
|
buf = RSTRING_PTR(str) + total;
|
359
360
|
shrinkable = 0;
|
360
|
-
|
361
|
+
buffer_size += buffer_size;
|
361
362
|
}
|
362
363
|
else buf += result;
|
363
364
|
}
|
@@ -857,8 +858,8 @@ VALUE io_uring_backend_splice(Backend_t *backend, VALUE src, VALUE dest, VALUE m
|
|
857
858
|
if (result < 0)
|
858
859
|
rb_syserr_fail(-result, strerror(-result));
|
859
860
|
|
860
|
-
if (result == 0 || !loop) return INT2NUM(total);
|
861
861
|
total += result;
|
862
|
+
if (result == 0 || !loop) return INT2NUM(total);
|
862
863
|
}
|
863
864
|
|
864
865
|
RB_GC_GUARD(resume_value);
|
@@ -58,6 +58,9 @@ thread.
|
|
58
58
|
#include "ruby/io.h"
|
59
59
|
|
60
60
|
VALUE SYM_libev;
|
61
|
+
VALUE SYM_send;
|
62
|
+
VALUE SYM_splice;
|
63
|
+
VALUE SYM_write;
|
61
64
|
|
62
65
|
ID ID_ivar_is_nonblocking;
|
63
66
|
|
@@ -773,6 +776,7 @@ error:
|
|
773
776
|
return RAISE_EXCEPTION(switchpoint_result);
|
774
777
|
}
|
775
778
|
|
779
|
+
#ifndef POLYPHONY_LINUX
|
776
780
|
VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
777
781
|
Backend_t *backend;
|
778
782
|
struct libev_io watcher;
|
@@ -782,10 +786,6 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
782
786
|
rb_io_t *dest_fptr;
|
783
787
|
int len;
|
784
788
|
|
785
|
-
#ifndef POLYPHONY_LINUX
|
786
|
-
rb_raise(rb_eRuntimeError, "splice not supported");
|
787
|
-
#endif
|
788
|
-
|
789
789
|
GetBackend(self, backend);
|
790
790
|
|
791
791
|
underlying_io = rb_ivar_get(src, ID_ivar_io);
|
@@ -840,10 +840,6 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
840
840
|
int len;
|
841
841
|
int total = 0;
|
842
842
|
|
843
|
-
#ifndef POLYPHONY_LINUX
|
844
|
-
rb_raise(rb_eRuntimeError, "splice not supported");
|
845
|
-
#endif
|
846
|
-
|
847
843
|
GetBackend(self, backend);
|
848
844
|
|
849
845
|
underlying_io = rb_ivar_get(src, ID_ivar_io);
|
@@ -890,6 +886,7 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
890
886
|
error:
|
891
887
|
return RAISE_EXCEPTION(switchpoint_result);
|
892
888
|
}
|
889
|
+
#endif
|
893
890
|
|
894
891
|
VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write) {
|
895
892
|
Backend_t *backend;
|
@@ -1103,6 +1100,31 @@ VALUE Backend_kind(VALUE self) {
|
|
1103
1100
|
return SYM_libev;
|
1104
1101
|
}
|
1105
1102
|
|
1103
|
+
VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
1104
|
+
VALUE result = Qnil;
|
1105
|
+
if (argc == 0) return result;
|
1106
|
+
|
1107
|
+
for (int i = 0; i < argc; i++) {
|
1108
|
+
VALUE op = argv[i];
|
1109
|
+
VALUE op_type = RARRAY_AREF(op, 0);
|
1110
|
+
VALUE op_len = RARRAY_LEN(op);
|
1111
|
+
|
1112
|
+
if (op_type == SYM_write && op_len == 3)
|
1113
|
+
result = Backend_write(self, RARRAY_AREF(op, 1), RARRAY_AREF(op, 2));
|
1114
|
+
else if (op_type == SYM_send && op_len == 4)
|
1115
|
+
result = Backend_send(self, RARRAY_AREF(op, 1), RARRAY_AREF(op, 2), RARRAY_AREF(op, 3));
|
1116
|
+
#ifndef POLYPHONY_LINUX
|
1117
|
+
else if (op_type == SYM_splice && op_len == 4)
|
1118
|
+
result = Backend_splice(self, RARRAY_AREF(op, 1), RARRAY_AREF(op, 2), RARRAY_AREF(op, 3));
|
1119
|
+
#endif
|
1120
|
+
else
|
1121
|
+
rb_raise(rb_eRuntimeError, "Invalid op specified or bad op arity");
|
1122
|
+
}
|
1123
|
+
|
1124
|
+
RB_GC_GUARD(result);
|
1125
|
+
return result;
|
1126
|
+
}
|
1127
|
+
|
1106
1128
|
void Init_Backend() {
|
1107
1129
|
ev_set_allocator(xrealloc);
|
1108
1130
|
|
@@ -1116,6 +1138,7 @@ void Init_Backend() {
|
|
1116
1138
|
rb_define_method(cBackend, "poll", Backend_poll, 3);
|
1117
1139
|
rb_define_method(cBackend, "break", Backend_wakeup, 0);
|
1118
1140
|
rb_define_method(cBackend, "kind", Backend_kind, 0);
|
1141
|
+
rb_define_method(cBackend, "chain", Backend_chain, -1);
|
1119
1142
|
|
1120
1143
|
rb_define_method(cBackend, "accept", Backend_accept, 2);
|
1121
1144
|
rb_define_method(cBackend, "accept_loop", Backend_accept_loop, 2);
|
@@ -1129,6 +1152,12 @@ void Init_Backend() {
|
|
1129
1152
|
rb_define_method(cBackend, "send", Backend_send, 3);
|
1130
1153
|
rb_define_method(cBackend, "sendv", Backend_sendv, 3);
|
1131
1154
|
rb_define_method(cBackend, "sleep", Backend_sleep, 1);
|
1155
|
+
|
1156
|
+
#ifndef POLYPHONY_LINUX
|
1157
|
+
rb_define_method(cBackend, "splice", Backend_splice, 3);
|
1158
|
+
rb_define_method(cBackend, "splice_to_eof", Backend_splice_to_eof, 3);
|
1159
|
+
#endif
|
1160
|
+
|
1132
1161
|
rb_define_method(cBackend, "timeout", Backend_timeout, -1);
|
1133
1162
|
rb_define_method(cBackend, "timer_loop", Backend_timer_loop, 1);
|
1134
1163
|
rb_define_method(cBackend, "wait_event", Backend_wait_event, 1);
|
@@ -1138,6 +1167,10 @@ void Init_Backend() {
|
|
1138
1167
|
|
1139
1168
|
ID_ivar_is_nonblocking = rb_intern("@is_nonblocking");
|
1140
1169
|
SYM_libev = ID2SYM(rb_intern("libev"));
|
1170
|
+
|
1171
|
+
SYM_send = ID2SYM(rb_intern("send"));
|
1172
|
+
SYM_splice = ID2SYM(rb_intern("splice"));
|
1173
|
+
SYM_write = ID2SYM(rb_intern("write"));
|
1141
1174
|
}
|
1142
1175
|
|
1143
1176
|
#endif // POLYPHONY_BACKEND_LIBEV
|
data/ext/polyphony/thread.c
CHANGED
@@ -21,7 +21,7 @@ static VALUE SYM_scheduled_fibers;
|
|
21
21
|
static VALUE SYM_pending_watchers;
|
22
22
|
|
23
23
|
static VALUE Thread_fiber_scheduling_stats(VALUE self) {
|
24
|
-
VALUE backend = rb_ivar_get(self,ID_ivar_backend);
|
24
|
+
VALUE backend = rb_ivar_get(self, ID_ivar_backend);
|
25
25
|
VALUE stats = rb_hash_new();
|
26
26
|
VALUE runqueue = rb_ivar_get(self, ID_ivar_runqueue);
|
27
27
|
long pending_count;
|
@@ -53,7 +53,7 @@ void schedule_fiber(VALUE self, VALUE fiber, VALUE value, int prioritize) {
|
|
53
53
|
// event selector. Otherwise it's gonna be stuck waiting for an event to
|
54
54
|
// happen, not knowing that it there's already a fiber ready to run in its
|
55
55
|
// run queue.
|
56
|
-
VALUE backend = rb_ivar_get(self,ID_ivar_backend);
|
56
|
+
VALUE backend = rb_ivar_get(self, ID_ivar_backend);
|
57
57
|
Backend_wakeup(backend);
|
58
58
|
}
|
59
59
|
}
|
@@ -138,6 +138,10 @@ VALUE Thread_debug(VALUE self) {
|
|
138
138
|
return self;
|
139
139
|
}
|
140
140
|
|
141
|
+
VALUE Thread_class_backend(VALUE _self) {
|
142
|
+
return rb_ivar_get(rb_thread_current(), ID_ivar_backend);
|
143
|
+
}
|
144
|
+
|
141
145
|
void Init_Thread() {
|
142
146
|
rb_define_method(rb_cThread, "setup_fiber_scheduling", Thread_setup_fiber_scheduling, 0);
|
143
147
|
rb_define_method(rb_cThread, "fiber_scheduling_stats", Thread_fiber_scheduling_stats, 0);
|
@@ -150,6 +154,8 @@ void Init_Thread() {
|
|
150
154
|
rb_define_method(rb_cThread, "fiber_scheduling_index", Thread_fiber_scheduling_index, 1);
|
151
155
|
rb_define_method(rb_cThread, "fiber_unschedule", Thread_fiber_unschedule, 1);
|
152
156
|
|
157
|
+
rb_define_singleton_method(rb_cThread, "backend", Thread_class_backend, 0);
|
158
|
+
|
153
159
|
rb_define_method(rb_cThread, "debug!", Thread_debug, 0);
|
154
160
|
|
155
161
|
ID_deactivate_all_watchers_post_fork = rb_intern("deactivate_all_watchers_post_fork");
|
data/lib/polyphony/version.rb
CHANGED
data/test/test_backend.rb
CHANGED
@@ -241,9 +241,10 @@ class BackendTest < MiniTest::Test
|
|
241
241
|
def test_splice
|
242
242
|
i1, o1 = IO.pipe
|
243
243
|
i2, o2 = IO.pipe
|
244
|
+
len = nil
|
244
245
|
|
245
246
|
spin {
|
246
|
-
o2.splice(i1, 1000)
|
247
|
+
len = o2.splice(i1, 1000)
|
247
248
|
o2.close
|
248
249
|
}
|
249
250
|
|
@@ -251,14 +252,16 @@ class BackendTest < MiniTest::Test
|
|
251
252
|
result = i2.read
|
252
253
|
|
253
254
|
assert_equal 'foobar', result
|
255
|
+
assert_equal 6, len
|
254
256
|
end
|
255
257
|
|
256
258
|
def test_splice_to_eof
|
257
259
|
i1, o1 = IO.pipe
|
258
260
|
i2, o2 = IO.pipe
|
261
|
+
len = nil
|
259
262
|
|
260
263
|
f = spin {
|
261
|
-
o2.splice_to_eof(i1, 1000)
|
264
|
+
len = o2.splice_to_eof(i1, 1000)
|
262
265
|
o2.close
|
263
266
|
}
|
264
267
|
|
@@ -269,8 +272,88 @@ class BackendTest < MiniTest::Test
|
|
269
272
|
o1.write('bar')
|
270
273
|
result = i2.readpartial(1000)
|
271
274
|
assert_equal 'bar', result
|
272
|
-
|
273
|
-
f.interrupt
|
275
|
+
o1.close
|
274
276
|
f.await
|
277
|
+
assert_equal 6, len
|
278
|
+
ensure
|
279
|
+
if f.alive?
|
280
|
+
f.interrupt
|
281
|
+
f.await
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
class BackendChainTest < MiniTest::Test
|
287
|
+
def setup
|
288
|
+
super
|
289
|
+
@prev_backend = Thread.current.backend
|
290
|
+
@backend = Polyphony::Backend.new
|
291
|
+
Thread.current.backend = @backend
|
292
|
+
end
|
293
|
+
|
294
|
+
def teardown
|
295
|
+
@backend.finalize
|
296
|
+
Thread.current.backend = @prev_backend
|
297
|
+
end
|
298
|
+
|
299
|
+
def test_simple_write_chain
|
300
|
+
i, o = IO.pipe
|
301
|
+
|
302
|
+
result = Thread.backend.chain(
|
303
|
+
[:write, o, 'hello'],
|
304
|
+
[:write, o, ' world']
|
305
|
+
)
|
306
|
+
|
307
|
+
assert_equal 6, result
|
308
|
+
o.close
|
309
|
+
assert_equal 'hello world', i.read
|
310
|
+
end
|
311
|
+
|
312
|
+
def chunk_header(len)
|
313
|
+
"Content-Length: #{len}\r\n\r\n"
|
314
|
+
end
|
315
|
+
|
316
|
+
def serve_io(from, to)
|
317
|
+
i, o = IO.pipe
|
318
|
+
backend = Thread.current.backend
|
319
|
+
while true
|
320
|
+
len = o.splice(from, 8192)
|
321
|
+
break if len == 0
|
322
|
+
|
323
|
+
backend.chain(
|
324
|
+
[:write, to, chunk_header(len)],
|
325
|
+
[:splice, i, to, len]
|
326
|
+
)
|
327
|
+
end
|
328
|
+
to.close
|
329
|
+
end
|
330
|
+
|
331
|
+
def test_chain_with_splice
|
332
|
+
from_r, from_w = IO.pipe
|
333
|
+
to_r, to_w = IO.pipe
|
334
|
+
|
335
|
+
result = nil
|
336
|
+
f = spin { serve_io(from_r, to_w) }
|
337
|
+
|
338
|
+
from_w << 'Hello world!'
|
339
|
+
from_w.close
|
340
|
+
|
341
|
+
assert_equal "Content-Length: 12\r\n\r\nHello world!", to_r.read
|
342
|
+
end
|
343
|
+
|
344
|
+
def test_invalid_op
|
345
|
+
i, o = IO.pipe
|
346
|
+
|
347
|
+
assert_raises(RuntimeError) {
|
348
|
+
Thread.backend.chain(
|
349
|
+
[:read, o]
|
350
|
+
)
|
351
|
+
}
|
352
|
+
|
353
|
+
assert_raises(TypeError) {
|
354
|
+
Thread.backend.chain(
|
355
|
+
[:write, o]
|
356
|
+
)
|
357
|
+
}
|
275
358
|
end
|
276
359
|
end
|
data/test/test_thread.rb
CHANGED
@@ -124,6 +124,10 @@ class ThreadTest < MiniTest::Test
|
|
124
124
|
t&.join
|
125
125
|
end
|
126
126
|
|
127
|
+
def test_backend_class_method
|
128
|
+
assert_equal Thread.current.backend, Thread.backend
|
129
|
+
end
|
130
|
+
|
127
131
|
def test_that_suspend_returns_immediately_if_no_watchers
|
128
132
|
records = []
|
129
133
|
t = Polyphony::Trace.new(:fiber_all) do |r|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: polyphony
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.53.
|
4
|
+
version: 0.53.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-05-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|