polyphony 0.56.0 → 0.57.0
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 +6 -0
- data/Gemfile.lock +1 -1
- data/examples/io/splice_chunks.rb +29 -0
- data/ext/polyphony/backend_io_uring.c +161 -4
- data/ext/polyphony/backend_libev.c +200 -18
- data/lib/polyphony/version.rb +1 -1
- data/test/test_backend.rb +35 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e350937221c476548465a2881e64689042137eab59571a0940f63236a249563f
|
4
|
+
data.tar.gz: 14870d9e38e7aa9f300d09cdfa0693929edb59756e0d17e7b3e7ae2d4a9dab0d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8087b84c7a583c8f3905c20d06aa4ad119fd2901be2594e66f56b577c1fa141f9e203971aedd27ad7c57b9c184adad1b97d0fbe4024702bfe3ef6bdaa861ac92
|
7
|
+
data.tar.gz: 6943231ef2b29dac3e33cfee865dbc6b3b35549c62e04dd1ed08d40fbd90a5c179417baf3b27b965e80c3ee7e137cbe167be9e8187dff46d89892978beb8a40d
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
## 0.57.0 2021-06-23
|
2
|
+
|
3
|
+
- Implement `Backend#splice_chunks` method for both libev and io_uring backends
|
4
|
+
- Improve waiting for readiness in libev `Backend#splice`, `#splice_to_eof`
|
5
|
+
- Enable splice op in libev `Backend#chain` for non-Linux OS
|
6
|
+
|
1
7
|
## 0.56.0 2021-06-22
|
2
8
|
|
3
9
|
- Implement fake `Backend#splice`, `Backend#splice_to_eof` methods for non-Linux
|
data/Gemfile.lock
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
i, o = IO.pipe
|
7
|
+
|
8
|
+
f = spin do
|
9
|
+
i.read_loop { |data| STDOUT << data }
|
10
|
+
end
|
11
|
+
|
12
|
+
result = nil
|
13
|
+
# File.open(__FILE__, 'r') do |f|
|
14
|
+
File.open('../tipi/log', 'r') do |f|
|
15
|
+
result = Thread.current.backend.splice_chunks(
|
16
|
+
f,
|
17
|
+
o,
|
18
|
+
"Content-Type: ruby\n\n",
|
19
|
+
"0\r\n\r\n",
|
20
|
+
->(len) { "#{len.to_s(16)}\r\n" },
|
21
|
+
"\r\n",
|
22
|
+
16384
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
o.close
|
28
|
+
f.await
|
29
|
+
p result: result
|
@@ -239,8 +239,10 @@ int io_uring_backend_defer_submit_and_await(
|
|
239
239
|
{
|
240
240
|
VALUE switchpoint_result = Qnil;
|
241
241
|
|
242
|
-
|
243
|
-
|
242
|
+
if (sqe) {
|
243
|
+
io_uring_sqe_set_data(sqe, ctx);
|
244
|
+
io_uring_sqe_set_flags(sqe, IOSQE_ASYNC);
|
245
|
+
}
|
244
246
|
io_uring_backend_defer_submit(backend);
|
245
247
|
|
246
248
|
switchpoint_result = backend_await((struct Backend_base *)backend);
|
@@ -446,7 +448,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
446
448
|
VALUE resume_value = Qnil;
|
447
449
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_WRITE);
|
448
450
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
449
|
-
io_uring_prep_write(sqe, fptr->fd, buf, left,
|
451
|
+
io_uring_prep_write(sqe, fptr->fd, buf, left, 0);
|
450
452
|
|
451
453
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
452
454
|
int completed = context_store_release(&backend->store, ctx);
|
@@ -1065,7 +1067,7 @@ struct io_uring_sqe *Backend_chain_prepare_write(Backend_t *backend, VALUE io, V
|
|
1065
1067
|
long len = RSTRING_LEN(str);
|
1066
1068
|
|
1067
1069
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
1068
|
-
io_uring_prep_write(sqe, fptr->fd, buf, len,
|
1070
|
+
io_uring_prep_write(sqe, fptr->fd, buf, len, 0);
|
1069
1071
|
return sqe;
|
1070
1072
|
}
|
1071
1073
|
|
@@ -1190,6 +1192,160 @@ inline VALUE Backend_run_idle_tasks(VALUE self) {
|
|
1190
1192
|
return self;
|
1191
1193
|
}
|
1192
1194
|
|
1195
|
+
static inline void splice_chunks_prep_write(op_context_t *ctx, struct io_uring_sqe *sqe, int fd, VALUE str) {
|
1196
|
+
char *buf = RSTRING_PTR(str);
|
1197
|
+
int len = RSTRING_LEN(str);
|
1198
|
+
io_uring_prep_write(sqe, fd, buf, len, 0);
|
1199
|
+
// io_uring_prep_send(sqe, fd, buf, len, 0);
|
1200
|
+
io_uring_sqe_set_data(sqe, ctx);
|
1201
|
+
}
|
1202
|
+
|
1203
|
+
static inline void splice_chunks_prep_splice(op_context_t *ctx, struct io_uring_sqe *sqe, int src, int dest, int maxlen) {
|
1204
|
+
io_uring_prep_splice(sqe, src, -1, dest, -1, maxlen, 0);
|
1205
|
+
io_uring_sqe_set_data(sqe, ctx);
|
1206
|
+
}
|
1207
|
+
|
1208
|
+
static inline void splice_chunks_get_sqe(
|
1209
|
+
Backend_t *backend,
|
1210
|
+
op_context_t **ctx,
|
1211
|
+
struct io_uring_sqe **sqe,
|
1212
|
+
enum op_type type
|
1213
|
+
)
|
1214
|
+
{
|
1215
|
+
if (*ctx) {
|
1216
|
+
if (*sqe) (*sqe)->flags |= IOSQE_IO_LINK;
|
1217
|
+
(*ctx)->ref_count++;
|
1218
|
+
}
|
1219
|
+
else
|
1220
|
+
*ctx = context_store_acquire(&backend->store, type);
|
1221
|
+
(*sqe) = io_uring_get_sqe(&backend->ring);
|
1222
|
+
}
|
1223
|
+
|
1224
|
+
static inline void splice_chunks_cancel(Backend_t *backend, op_context_t *ctx) {
|
1225
|
+
ctx->result = -ECANCELED;
|
1226
|
+
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
1227
|
+
io_uring_prep_cancel(sqe, ctx, 0);
|
1228
|
+
backend->pending_sqes = 0;
|
1229
|
+
io_uring_submit(&backend->ring);
|
1230
|
+
}
|
1231
|
+
|
1232
|
+
static inline int splice_chunks_await_ops(
|
1233
|
+
Backend_t *backend,
|
1234
|
+
op_context_t **ctx,
|
1235
|
+
int *result,
|
1236
|
+
VALUE *switchpoint_result
|
1237
|
+
)
|
1238
|
+
{
|
1239
|
+
int res = io_uring_backend_defer_submit_and_await(backend, 0, *ctx, switchpoint_result);
|
1240
|
+
if (result) (*result) = res;
|
1241
|
+
int completed = context_store_release(&backend->store, *ctx);
|
1242
|
+
if (!completed) {
|
1243
|
+
splice_chunks_cancel(backend, *ctx);
|
1244
|
+
if (TEST_EXCEPTION(*switchpoint_result)) return 1;
|
1245
|
+
}
|
1246
|
+
*ctx = 0;
|
1247
|
+
return 0;
|
1248
|
+
}
|
1249
|
+
|
1250
|
+
#define SPLICE_CHUNKS_AWAIT_OPS(backend, ctx, result, switchpoint_result) \
|
1251
|
+
if (splice_chunks_await_ops(backend, ctx, result, switchpoint_result)) goto error;
|
1252
|
+
|
1253
|
+
VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VALUE postfix, VALUE chunk_prefix, VALUE chunk_postfix, VALUE chunk_size) {
|
1254
|
+
Backend_t *backend;
|
1255
|
+
GetBackend(self, backend);
|
1256
|
+
int total = 0;
|
1257
|
+
int err = 0;
|
1258
|
+
VALUE switchpoint_result = Qnil;
|
1259
|
+
op_context_t *ctx = 0;
|
1260
|
+
struct io_uring_sqe *sqe = 0;
|
1261
|
+
|
1262
|
+
rb_io_t *src_fptr;
|
1263
|
+
rb_io_t *dest_fptr;
|
1264
|
+
|
1265
|
+
VALUE underlying_io = rb_ivar_get(src, ID_ivar_io);
|
1266
|
+
if (underlying_io != Qnil) src = underlying_io;
|
1267
|
+
GetOpenFile(src, src_fptr);
|
1268
|
+
io_verify_blocking_mode(src_fptr, src, Qtrue);
|
1269
|
+
|
1270
|
+
underlying_io = rb_ivar_get(dest, ID_ivar_io);
|
1271
|
+
if (underlying_io != Qnil) dest = underlying_io;
|
1272
|
+
dest = rb_io_get_write_io(dest);
|
1273
|
+
GetOpenFile(dest, dest_fptr);
|
1274
|
+
io_verify_blocking_mode(dest_fptr, dest, Qtrue);
|
1275
|
+
|
1276
|
+
int maxlen = NUM2INT(chunk_size);
|
1277
|
+
VALUE str = Qnil;
|
1278
|
+
VALUE chunk_len_value = Qnil;
|
1279
|
+
|
1280
|
+
int pipefd[2] = { -1, -1 };
|
1281
|
+
if (pipe(pipefd) == -1) {
|
1282
|
+
err = errno;
|
1283
|
+
goto syscallerror;
|
1284
|
+
}
|
1285
|
+
|
1286
|
+
if (prefix != Qnil) {
|
1287
|
+
splice_chunks_get_sqe(backend, &ctx, &sqe, OP_WRITE);
|
1288
|
+
splice_chunks_prep_write(ctx, sqe, dest_fptr->fd, prefix);
|
1289
|
+
}
|
1290
|
+
|
1291
|
+
while (1) {
|
1292
|
+
int chunk_len;
|
1293
|
+
VALUE chunk_prefix_str = Qnil;
|
1294
|
+
VALUE chunk_postfix_str = Qnil;
|
1295
|
+
|
1296
|
+
splice_chunks_get_sqe(backend, &ctx, &sqe, OP_SPLICE);
|
1297
|
+
splice_chunks_prep_splice(ctx, sqe, src_fptr->fd, pipefd[1], maxlen);
|
1298
|
+
|
1299
|
+
SPLICE_CHUNKS_AWAIT_OPS(backend, &ctx, &chunk_len, &switchpoint_result);
|
1300
|
+
if (chunk_len == 0) break;
|
1301
|
+
|
1302
|
+
total += chunk_len;
|
1303
|
+
chunk_len_value = INT2NUM(chunk_len);
|
1304
|
+
|
1305
|
+
|
1306
|
+
if (chunk_prefix != Qnil) {
|
1307
|
+
chunk_prefix_str = (TYPE(chunk_prefix) == T_STRING) ? chunk_prefix : rb_funcall(chunk_prefix, ID_call, 1, chunk_len_value);
|
1308
|
+
splice_chunks_get_sqe(backend, &ctx, &sqe, OP_WRITE);
|
1309
|
+
splice_chunks_prep_write(ctx, sqe, dest_fptr->fd, chunk_prefix_str);
|
1310
|
+
}
|
1311
|
+
|
1312
|
+
splice_chunks_get_sqe(backend, &ctx, &sqe, OP_SPLICE);
|
1313
|
+
splice_chunks_prep_splice(ctx, sqe, pipefd[0], dest_fptr->fd, chunk_len);
|
1314
|
+
|
1315
|
+
if (chunk_postfix != Qnil) {
|
1316
|
+
chunk_postfix_str = (TYPE(chunk_postfix) == T_STRING) ? chunk_postfix : rb_funcall(chunk_postfix, ID_call, 1, chunk_len_value);
|
1317
|
+
splice_chunks_get_sqe(backend, &ctx, &sqe, OP_WRITE);
|
1318
|
+
splice_chunks_prep_write(ctx, sqe, dest_fptr->fd, chunk_postfix_str);
|
1319
|
+
}
|
1320
|
+
|
1321
|
+
RB_GC_GUARD(chunk_prefix_str);
|
1322
|
+
RB_GC_GUARD(chunk_postfix_str);
|
1323
|
+
}
|
1324
|
+
|
1325
|
+
if (postfix != Qnil) {
|
1326
|
+
splice_chunks_get_sqe(backend, &ctx, &sqe, OP_WRITE);
|
1327
|
+
splice_chunks_prep_write(ctx, sqe, dest_fptr->fd, postfix);
|
1328
|
+
}
|
1329
|
+
if (ctx) {
|
1330
|
+
SPLICE_CHUNKS_AWAIT_OPS(backend, &ctx, 0, &switchpoint_result);
|
1331
|
+
}
|
1332
|
+
|
1333
|
+
RB_GC_GUARD(str);
|
1334
|
+
RB_GC_GUARD(chunk_len_value);
|
1335
|
+
RB_GC_GUARD(switchpoint_result);
|
1336
|
+
if (pipefd[0] != -1) close(pipefd[0]);
|
1337
|
+
if (pipefd[1] != -1) close(pipefd[1]);
|
1338
|
+
return INT2NUM(total);
|
1339
|
+
syscallerror:
|
1340
|
+
if (pipefd[0] != -1) close(pipefd[0]);
|
1341
|
+
if (pipefd[1] != -1) close(pipefd[1]);
|
1342
|
+
rb_syserr_fail(err, strerror(err));
|
1343
|
+
error:
|
1344
|
+
if (pipefd[0] != -1) close(pipefd[0]);
|
1345
|
+
if (pipefd[1] != -1) close(pipefd[1]);
|
1346
|
+
return RAISE_EXCEPTION(switchpoint_result);
|
1347
|
+
}
|
1348
|
+
|
1193
1349
|
void Init_Backend() {
|
1194
1350
|
VALUE cBackend = rb_define_class_under(mPolyphony, "Backend", rb_cObject);
|
1195
1351
|
rb_define_alloc_func(cBackend, Backend_allocate);
|
@@ -1203,6 +1359,7 @@ void Init_Backend() {
|
|
1203
1359
|
rb_define_method(cBackend, "kind", Backend_kind, 0);
|
1204
1360
|
rb_define_method(cBackend, "chain", Backend_chain, -1);
|
1205
1361
|
rb_define_method(cBackend, "idle_gc_period=", Backend_idle_gc_period_set, 1);
|
1362
|
+
rb_define_method(cBackend, "splice_chunks", Backend_splice_chunks, 7);
|
1206
1363
|
|
1207
1364
|
rb_define_method(cBackend, "accept", Backend_accept, 2);
|
1208
1365
|
rb_define_method(cBackend, "accept_loop", Backend_accept_loop, 2);
|
@@ -737,10 +737,63 @@ error:
|
|
737
737
|
return RAISE_EXCEPTION(switchpoint_result);
|
738
738
|
}
|
739
739
|
|
740
|
+
struct libev_rw_ctx {
|
741
|
+
int ref_count;
|
742
|
+
VALUE fiber;
|
743
|
+
};
|
744
|
+
|
745
|
+
struct libev_ref_count_io {
|
746
|
+
struct ev_io io;
|
747
|
+
struct libev_rw_ctx *ctx;
|
748
|
+
};
|
749
|
+
|
750
|
+
struct libev_rw_io {
|
751
|
+
struct libev_ref_count_io r;
|
752
|
+
struct libev_ref_count_io w;
|
753
|
+
struct libev_rw_ctx ctx;
|
754
|
+
};
|
755
|
+
|
756
|
+
void Backend_rw_io_callback(EV_P_ ev_io *w, int revents)
|
757
|
+
{
|
758
|
+
struct libev_ref_count_io *watcher = (struct libev_ref_count_io *)w;
|
759
|
+
int ref_count = watcher->ctx->ref_count--;
|
760
|
+
if (!ref_count)
|
761
|
+
Fiber_make_runnable(watcher->ctx->fiber, Qnil);
|
762
|
+
}
|
763
|
+
|
764
|
+
VALUE libev_wait_rw_fd_with_watcher(Backend_t *backend, int r_fd, int w_fd, struct libev_rw_io *watcher) {
|
765
|
+
VALUE switchpoint_result = Qnil;
|
766
|
+
|
767
|
+
if (watcher->ctx.fiber == Qnil) watcher->ctx.fiber = rb_fiber_current();
|
768
|
+
watcher->ctx.ref_count = 0;
|
769
|
+
if (r_fd != -1) {
|
770
|
+
ev_io_init(&watcher->r.io, Backend_rw_io_callback, r_fd, EV_READ);
|
771
|
+
ev_io_start(backend->ev_loop, &watcher->r.io);
|
772
|
+
watcher->r.ctx = &watcher->ctx;
|
773
|
+
watcher->ctx.ref_count++;
|
774
|
+
}
|
775
|
+
if (w_fd != -1) {
|
776
|
+
ev_io_init(&watcher->w.io, Backend_rw_io_callback, w_fd, EV_WRITE);
|
777
|
+
ev_io_start(backend->ev_loop, &watcher->w.io);
|
778
|
+
watcher->w.ctx = &watcher->ctx;
|
779
|
+
watcher->ctx.ref_count++;
|
780
|
+
}
|
781
|
+
|
782
|
+
switchpoint_result = backend_await((struct Backend_base *)backend);
|
783
|
+
|
784
|
+
if (r_fd != -1) ev_io_stop(backend->ev_loop, &watcher->r.io);
|
785
|
+
if (w_fd != -1) ev_io_stop(backend->ev_loop, &watcher->w.io);
|
786
|
+
RB_GC_GUARD(switchpoint_result);
|
787
|
+
return switchpoint_result;
|
788
|
+
}
|
789
|
+
|
790
|
+
|
791
|
+
|
792
|
+
|
740
793
|
#ifdef POLYPHONY_LINUX
|
741
794
|
VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
742
795
|
Backend_t *backend;
|
743
|
-
struct
|
796
|
+
struct libev_rw_io watcher;
|
744
797
|
VALUE switchpoint_result = Qnil;
|
745
798
|
VALUE underlying_io;
|
746
799
|
rb_io_t *src_fptr;
|
@@ -760,17 +813,14 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
760
813
|
GetOpenFile(dest, dest_fptr);
|
761
814
|
io_verify_blocking_mode(dest_fptr, dest, Qfalse);
|
762
815
|
|
763
|
-
watcher.fiber = Qnil;
|
816
|
+
watcher.ctx.fiber = Qnil;
|
764
817
|
while (1) {
|
765
818
|
len = splice(src_fptr->fd, 0, dest_fptr->fd, 0, NUM2INT(maxlen), 0);
|
766
819
|
if (len < 0) {
|
767
820
|
int e = errno;
|
768
821
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
769
822
|
|
770
|
-
switchpoint_result =
|
771
|
-
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
772
|
-
|
773
|
-
switchpoint_result = libev_wait_fd_with_watcher(backend, dest_fptr->fd, &watcher, EV_WRITE);
|
823
|
+
switchpoint_result = libev_wait_rw_fd_with_watcher(backend, src_fptr->fd, dest_fptr->fd, &watcher);
|
774
824
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
775
825
|
}
|
776
826
|
else {
|
@@ -778,12 +828,12 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
778
828
|
}
|
779
829
|
}
|
780
830
|
|
781
|
-
if (watcher.fiber == Qnil) {
|
831
|
+
if (watcher.ctx.fiber == Qnil) {
|
782
832
|
switchpoint_result = backend_snooze();
|
783
833
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
784
834
|
}
|
785
835
|
|
786
|
-
RB_GC_GUARD(watcher.fiber);
|
836
|
+
RB_GC_GUARD(watcher.ctx.fiber);
|
787
837
|
RB_GC_GUARD(switchpoint_result);
|
788
838
|
|
789
839
|
return INT2NUM(len);
|
@@ -793,7 +843,7 @@ error:
|
|
793
843
|
|
794
844
|
VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
795
845
|
Backend_t *backend;
|
796
|
-
struct
|
846
|
+
struct libev_rw_io watcher;
|
797
847
|
VALUE switchpoint_result = Qnil;
|
798
848
|
VALUE underlying_io;
|
799
849
|
rb_io_t *src_fptr;
|
@@ -814,17 +864,14 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
814
864
|
GetOpenFile(dest, dest_fptr);
|
815
865
|
io_verify_blocking_mode(dest_fptr, dest, Qfalse);
|
816
866
|
|
817
|
-
watcher.fiber = Qnil;
|
867
|
+
watcher.ctx.fiber = Qnil;
|
818
868
|
while (1) {
|
819
869
|
len = splice(src_fptr->fd, 0, dest_fptr->fd, 0, NUM2INT(maxlen), 0);
|
820
870
|
if (len < 0) {
|
821
871
|
int e = errno;
|
822
872
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
823
873
|
|
824
|
-
switchpoint_result =
|
825
|
-
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
826
|
-
|
827
|
-
switchpoint_result = libev_wait_fd_with_watcher(backend, dest_fptr->fd, &watcher, EV_WRITE);
|
874
|
+
switchpoint_result = libev_wait_rw_fd_with_watcher(backend, src_fptr->fd, dest_fptr->fd, &watcher);
|
828
875
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
829
876
|
}
|
830
877
|
else if (len == 0) {
|
@@ -835,12 +882,12 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
835
882
|
}
|
836
883
|
}
|
837
884
|
|
838
|
-
if (watcher.fiber == Qnil) {
|
885
|
+
if (watcher.ctx.fiber == Qnil) {
|
839
886
|
switchpoint_result = backend_snooze();
|
840
887
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
841
888
|
}
|
842
889
|
|
843
|
-
RB_GC_GUARD(watcher.fiber);
|
890
|
+
RB_GC_GUARD(watcher.ctx.fiber);
|
844
891
|
RB_GC_GUARD(switchpoint_result);
|
845
892
|
|
846
893
|
return INT2NUM(total);
|
@@ -1225,10 +1272,8 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1225
1272
|
result = Backend_write(self, RARRAY_AREF(op, 1), RARRAY_AREF(op, 2));
|
1226
1273
|
else if (op_type == SYM_send && op_len == 4)
|
1227
1274
|
result = Backend_send(self, RARRAY_AREF(op, 1), RARRAY_AREF(op, 2), RARRAY_AREF(op, 3));
|
1228
|
-
#ifdef POLYPHONY_LINUX
|
1229
1275
|
else if (op_type == SYM_splice && op_len == 4)
|
1230
1276
|
result = Backend_splice(self, RARRAY_AREF(op, 1), RARRAY_AREF(op, 2), RARRAY_AREF(op, 3));
|
1231
|
-
#endif
|
1232
1277
|
else
|
1233
1278
|
rb_raise(rb_eRuntimeError, "Invalid op specified or bad op arity");
|
1234
1279
|
}
|
@@ -1252,6 +1297,142 @@ inline VALUE Backend_run_idle_tasks(VALUE self) {
|
|
1252
1297
|
return self;
|
1253
1298
|
}
|
1254
1299
|
|
1300
|
+
inline int splice_chunks_write(Backend_t *backend, int fd, VALUE str, struct libev_rw_io *watcher, VALUE *result) {
|
1301
|
+
char *buf = RSTRING_PTR(str);
|
1302
|
+
int len = RSTRING_LEN(str);
|
1303
|
+
int left = len;
|
1304
|
+
while (left > 0) {
|
1305
|
+
ssize_t n = write(fd, buf, left);
|
1306
|
+
if (n < 0) {
|
1307
|
+
int err = errno;
|
1308
|
+
if ((err != EWOULDBLOCK && err != EAGAIN)) return err;
|
1309
|
+
|
1310
|
+
*result = libev_wait_rw_fd_with_watcher(backend, -1, fd, watcher);
|
1311
|
+
if (TEST_EXCEPTION(*result)) return -1;
|
1312
|
+
}
|
1313
|
+
else {
|
1314
|
+
buf += n;
|
1315
|
+
left -= n;
|
1316
|
+
}
|
1317
|
+
}
|
1318
|
+
return 0;
|
1319
|
+
}
|
1320
|
+
|
1321
|
+
VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VALUE postfix, VALUE chunk_prefix, VALUE chunk_postfix, VALUE chunk_size) {
|
1322
|
+
Backend_t *backend;
|
1323
|
+
GetBackend(self, backend);
|
1324
|
+
int total = 0;
|
1325
|
+
int err = 0;
|
1326
|
+
VALUE result = Qnil;
|
1327
|
+
|
1328
|
+
rb_io_t *src_fptr;
|
1329
|
+
rb_io_t *dest_fptr;
|
1330
|
+
|
1331
|
+
VALUE underlying_io = rb_ivar_get(src, ID_ivar_io);
|
1332
|
+
if (underlying_io != Qnil) src = underlying_io;
|
1333
|
+
GetOpenFile(src, src_fptr);
|
1334
|
+
io_verify_blocking_mode(src_fptr, src, Qfalse);
|
1335
|
+
|
1336
|
+
underlying_io = rb_ivar_get(dest, ID_ivar_io);
|
1337
|
+
if (underlying_io != Qnil) dest = underlying_io;
|
1338
|
+
dest = rb_io_get_write_io(dest);
|
1339
|
+
GetOpenFile(dest, dest_fptr);
|
1340
|
+
io_verify_blocking_mode(dest_fptr, dest, Qfalse);
|
1341
|
+
|
1342
|
+
struct libev_rw_io watcher;
|
1343
|
+
watcher.ctx.fiber = Qnil;
|
1344
|
+
int maxlen = NUM2INT(chunk_size);
|
1345
|
+
VALUE str = Qnil;
|
1346
|
+
VALUE chunk_len_value = Qnil;
|
1347
|
+
|
1348
|
+
int pipefd[2] = { -1, -1 };
|
1349
|
+
if (pipe(pipefd) == -1) {
|
1350
|
+
err = errno;
|
1351
|
+
goto syscallerror;
|
1352
|
+
}
|
1353
|
+
|
1354
|
+
fcntl(pipefd[0], F_SETFL, O_NONBLOCK);
|
1355
|
+
fcntl(pipefd[1], F_SETFL, O_NONBLOCK);
|
1356
|
+
|
1357
|
+
if (prefix != Qnil) {
|
1358
|
+
int err = splice_chunks_write(backend, dest_fptr->fd, prefix, &watcher, &result);
|
1359
|
+
if (err == -1) goto error; else if (err) goto syscallerror;
|
1360
|
+
}
|
1361
|
+
while (1) {
|
1362
|
+
int chunk_len;
|
1363
|
+
// splice to pipe
|
1364
|
+
while (1) {
|
1365
|
+
chunk_len = splice(src_fptr->fd, 0, pipefd[1], 0, maxlen, 0);
|
1366
|
+
if (chunk_len < 0) {
|
1367
|
+
err = errno;
|
1368
|
+
if (err != EWOULDBLOCK && err != EAGAIN) goto syscallerror;
|
1369
|
+
|
1370
|
+
result = libev_wait_rw_fd_with_watcher(backend, src_fptr->fd, pipefd[1], &watcher);
|
1371
|
+
if (TEST_EXCEPTION(result)) goto error;
|
1372
|
+
}
|
1373
|
+
else {
|
1374
|
+
break;
|
1375
|
+
}
|
1376
|
+
}
|
1377
|
+
if (chunk_len == 0) break;
|
1378
|
+
|
1379
|
+
total += chunk_len;
|
1380
|
+
chunk_len_value = INT2NUM(chunk_len);
|
1381
|
+
|
1382
|
+
if (chunk_prefix != Qnil) {
|
1383
|
+
VALUE str = (TYPE(chunk_prefix) == T_STRING) ? chunk_prefix : rb_funcall(chunk_prefix, ID_call, 1, chunk_len_value);
|
1384
|
+
int err = splice_chunks_write(backend, dest_fptr->fd, str, &watcher, &result);
|
1385
|
+
if (err == -1) goto error; else if (err) goto syscallerror;
|
1386
|
+
}
|
1387
|
+
|
1388
|
+
int left = chunk_len;
|
1389
|
+
while (1) {
|
1390
|
+
int n = splice(pipefd[0], 0, dest_fptr->fd, 0, left, 0);
|
1391
|
+
if (n < 0) {
|
1392
|
+
err = errno;
|
1393
|
+
if (err != EWOULDBLOCK && err != EAGAIN) goto syscallerror;
|
1394
|
+
|
1395
|
+
result = libev_wait_rw_fd_with_watcher(backend, pipefd[0], dest_fptr->fd, &watcher);
|
1396
|
+
if (TEST_EXCEPTION(result)) goto error;
|
1397
|
+
}
|
1398
|
+
else {
|
1399
|
+
left -= n;
|
1400
|
+
if (left == 0) break;
|
1401
|
+
}
|
1402
|
+
}
|
1403
|
+
|
1404
|
+
if (chunk_postfix != Qnil) {
|
1405
|
+
VALUE str = (TYPE(chunk_postfix) == T_STRING) ? chunk_postfix : rb_funcall(chunk_postfix, ID_call, 1, chunk_len_value);
|
1406
|
+
int err = splice_chunks_write(backend, dest_fptr->fd, str, &watcher, &result);
|
1407
|
+
if (err == -1) goto error; else if (err) goto syscallerror;
|
1408
|
+
}
|
1409
|
+
}
|
1410
|
+
|
1411
|
+
if (postfix != Qnil) {
|
1412
|
+
int err = splice_chunks_write(backend, dest_fptr->fd, postfix, &watcher, &result);
|
1413
|
+
if (err == -1) goto error; else if (err) goto syscallerror;
|
1414
|
+
}
|
1415
|
+
|
1416
|
+
if (watcher.ctx.fiber == Qnil) {
|
1417
|
+
result = backend_snooze();
|
1418
|
+
if (TEST_EXCEPTION(result)) goto error;
|
1419
|
+
}
|
1420
|
+
RB_GC_GUARD(str);
|
1421
|
+
RB_GC_GUARD(chunk_len_value);
|
1422
|
+
RB_GC_GUARD(result);
|
1423
|
+
if (pipefd[0] != -1) close(pipefd[0]);
|
1424
|
+
if (pipefd[1] != -1) close(pipefd[1]);
|
1425
|
+
return INT2NUM(total);
|
1426
|
+
syscallerror:
|
1427
|
+
if (pipefd[0] != -1) close(pipefd[0]);
|
1428
|
+
if (pipefd[1] != -1) close(pipefd[1]);
|
1429
|
+
rb_syserr_fail(err, strerror(err));
|
1430
|
+
error:
|
1431
|
+
if (pipefd[0] != -1) close(pipefd[0]);
|
1432
|
+
if (pipefd[1] != -1) close(pipefd[1]);
|
1433
|
+
return RAISE_EXCEPTION(result);
|
1434
|
+
}
|
1435
|
+
|
1255
1436
|
void Init_Backend() {
|
1256
1437
|
ev_set_allocator(xrealloc);
|
1257
1438
|
|
@@ -1267,6 +1448,7 @@ void Init_Backend() {
|
|
1267
1448
|
rb_define_method(cBackend, "kind", Backend_kind, 0);
|
1268
1449
|
rb_define_method(cBackend, "chain", Backend_chain, -1);
|
1269
1450
|
rb_define_method(cBackend, "idle_gc_period=", Backend_idle_gc_period_set, 1);
|
1451
|
+
rb_define_method(cBackend, "splice_chunks", Backend_splice_chunks, 7);
|
1270
1452
|
|
1271
1453
|
rb_define_method(cBackend, "accept", Backend_accept, 2);
|
1272
1454
|
rb_define_method(cBackend, "accept_loop", Backend_accept_loop, 2);
|
data/lib/polyphony/version.rb
CHANGED
data/test/test_backend.rb
CHANGED
@@ -282,6 +282,41 @@ class BackendTest < MiniTest::Test
|
|
282
282
|
end
|
283
283
|
end
|
284
284
|
|
285
|
+
|
286
|
+
def test_splice_chunks
|
287
|
+
body = 'abcd' * 250
|
288
|
+
chunk_size = 750
|
289
|
+
|
290
|
+
buf = +''
|
291
|
+
r, w = IO.pipe
|
292
|
+
reader = spin do
|
293
|
+
r.read_loop { |data| buf << data }
|
294
|
+
end
|
295
|
+
|
296
|
+
i, o = IO.pipe
|
297
|
+
writer = spin do
|
298
|
+
o << body
|
299
|
+
o.close
|
300
|
+
end
|
301
|
+
Thread.current.backend.splice_chunks(
|
302
|
+
i,
|
303
|
+
w,
|
304
|
+
"Content-Type: foo\r\n\r\n",
|
305
|
+
"0\r\n\r\n",
|
306
|
+
->(len) { "#{len.to_s(16)}\r\n" },
|
307
|
+
"\r\n",
|
308
|
+
chunk_size
|
309
|
+
)
|
310
|
+
w.close
|
311
|
+
reader.await
|
312
|
+
|
313
|
+
expected = "Content-Type: foo\r\n\r\n#{750.to_s(16)}\r\n#{body[0..749]}\r\n#{250.to_s(16)}\r\n#{body[750..999]}\r\n0\r\n\r\n"
|
314
|
+
assert_equal expected, buf
|
315
|
+
ensure
|
316
|
+
o.close
|
317
|
+
w.close
|
318
|
+
end
|
319
|
+
|
285
320
|
def test_idle_gc
|
286
321
|
GC.disable
|
287
322
|
|
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.
|
4
|
+
version: 0.57.0
|
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-06-
|
11
|
+
date: 2021-06-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -361,6 +361,7 @@ files:
|
|
361
361
|
- examples/io/rack_server.rb
|
362
362
|
- examples/io/raw.rb
|
363
363
|
- examples/io/reline.rb
|
364
|
+
- examples/io/splice_chunks.rb
|
364
365
|
- examples/io/stdio.rb
|
365
366
|
- examples/io/system.rb
|
366
367
|
- examples/io/tcp_proxy.rb
|