polyphony 0.87 → 0.89
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test_io_uring.yml +8 -4
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +1 -1
- data/ext/polyphony/backend_common.c +1 -3
- data/ext/polyphony/backend_io_uring.c +44 -28
- data/ext/polyphony/extconf.rb +1 -0
- data/ext/polyphony/io_extensions.c +133 -57
- data/ext/polyphony/polyphony.c +1 -8
- data/lib/polyphony/version.rb +1 -1
- data/test/test_io.rb +204 -9
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b79252b4e1c8617c398d6804b93063b8d155d1b5d813b65cb2c9a2a1ce4e5e0
|
4
|
+
data.tar.gz: 619e0c77d6ed5bc3d4d0c33e143d5f18eaf83e34d5fc8fe576524a554843faeb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 137e6a8387305c160af5a59c7d7df91c18e09cd5ba954da3fcd78f339d877aa7d91430ae212852dc8bba5771e12cce4e6fa5b51350ebfb75cc3c61e979babf8c
|
7
|
+
data.tar.gz: 8f0bfeb1b9d05fd7b6494a17f23d79ecb28b825b0e37ace7be913a42eee589859320ebd904313f28e691eef0e5951109acca4be95dfe53156edc108c3dab060f
|
@@ -8,15 +8,19 @@ jobs:
|
|
8
8
|
fail-fast: false
|
9
9
|
matrix:
|
10
10
|
os: [ubuntu-latest]
|
11
|
-
ruby: [2.
|
11
|
+
ruby: ['2.7', '3.0', '3.1', 'head']
|
12
12
|
|
13
13
|
name: >-
|
14
14
|
${{matrix.os}}, ${{matrix.ruby}}
|
15
15
|
|
16
16
|
runs-on: ${{matrix.os}}
|
17
17
|
steps:
|
18
|
-
-
|
19
|
-
|
18
|
+
- name: Checkout repository and submodules
|
19
|
+
uses: actions/checkout@v2
|
20
|
+
with:
|
21
|
+
submodules: recursive
|
22
|
+
- name: Setup Ruby
|
23
|
+
uses: ruby/setup-ruby@v1
|
20
24
|
with:
|
21
25
|
ruby-version: ${{matrix.ruby}}
|
22
26
|
bundler-cache: true # 'bundle install' and cache
|
@@ -29,4 +33,4 @@ jobs:
|
|
29
33
|
- name: Compile C-extension
|
30
34
|
run: bundle exec rake compile
|
31
35
|
- name: Run tests
|
32
|
-
run: bundle exec
|
36
|
+
run: bundle exec ruby test/run.rb --verbose --name test_sleep
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -363,8 +363,6 @@ inline void set_fd_blocking_mode(int fd, int blocking) {
|
|
363
363
|
}
|
364
364
|
|
365
365
|
inline void io_verify_blocking_mode(rb_io_t *fptr, VALUE io, VALUE blocking) {
|
366
|
-
int flags;
|
367
|
-
int is_nonblocking;
|
368
366
|
VALUE blocking_mode = rb_ivar_get(io, ID_ivar_blocking_mode);
|
369
367
|
if (blocking == blocking_mode) return;
|
370
368
|
|
@@ -481,7 +479,7 @@ struct io_buffer get_io_buffer(VALUE in) {
|
|
481
479
|
struct raw_buffer *raw = FIX2PTR(in);
|
482
480
|
return (struct io_buffer){ raw->ptr, raw->len, 1 };
|
483
481
|
}
|
484
|
-
return (struct io_buffer){ RSTRING_PTR(in), RSTRING_LEN(in), 0 };
|
482
|
+
return (struct io_buffer){ (unsigned char *)RSTRING_PTR(in), RSTRING_LEN(in), 0 };
|
485
483
|
}
|
486
484
|
|
487
485
|
VALUE coerce_io_string_or_buffer(VALUE buf) {
|
@@ -262,6 +262,22 @@ inline struct backend_stats backend_get_stats(VALUE self) {
|
|
262
262
|
return backend_base_stats(&backend->base);
|
263
263
|
}
|
264
264
|
|
265
|
+
static inline struct io_uring_sqe *io_uring_backend_get_sqe(Backend_t *backend) {
|
266
|
+
struct io_uring_sqe *sqe;
|
267
|
+
try:
|
268
|
+
sqe = io_uring_get_sqe(&backend->ring);
|
269
|
+
if (sqe) goto done;
|
270
|
+
|
271
|
+
if (backend->pending_sqes)
|
272
|
+
io_uring_backend_immediate_submit(backend);
|
273
|
+
else {
|
274
|
+
VALUE resume_value = backend_snooze(&backend->base);
|
275
|
+
RAISE_IF_EXCEPTION(resume_value);
|
276
|
+
}
|
277
|
+
done:
|
278
|
+
return sqe;
|
279
|
+
}
|
280
|
+
|
265
281
|
VALUE Backend_wakeup(VALUE self) {
|
266
282
|
Backend_t *backend;
|
267
283
|
GetBackend(self, backend);
|
@@ -269,7 +285,7 @@ VALUE Backend_wakeup(VALUE self) {
|
|
269
285
|
if (backend->base.currently_polling) {
|
270
286
|
// Since we're currently blocking while waiting for a completion, we add a
|
271
287
|
// NOP which would cause the io_uring_enter syscall to return
|
272
|
-
struct io_uring_sqe *sqe =
|
288
|
+
struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
|
273
289
|
io_uring_prep_nop(sqe);
|
274
290
|
io_uring_backend_immediate_submit(backend);
|
275
291
|
|
@@ -302,7 +318,7 @@ int io_uring_backend_defer_submit_and_await(
|
|
302
318
|
|
303
319
|
// op was not completed (an exception was raised), so we need to cancel it
|
304
320
|
ctx->result = -ECANCELED;
|
305
|
-
sqe =
|
321
|
+
sqe = io_uring_backend_get_sqe(backend);
|
306
322
|
io_uring_prep_cancel(sqe, (__u64)ctx, 0);
|
307
323
|
io_uring_backend_immediate_submit(backend);
|
308
324
|
}
|
@@ -317,7 +333,7 @@ VALUE io_uring_backend_wait_fd(Backend_t *backend, int fd, int write) {
|
|
317
333
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_POLL);
|
318
334
|
VALUE resumed_value = Qnil;
|
319
335
|
|
320
|
-
struct io_uring_sqe *sqe =
|
336
|
+
struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
|
321
337
|
io_uring_prep_poll_add(sqe, fd, write ? POLLOUT : POLLIN);
|
322
338
|
|
323
339
|
io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resumed_value);
|
@@ -385,7 +401,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
|
|
385
401
|
while (1) {
|
386
402
|
VALUE resume_value = Qnil;
|
387
403
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_READ);
|
388
|
-
struct io_uring_sqe *sqe =
|
404
|
+
struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
|
389
405
|
int result;
|
390
406
|
int completed;
|
391
407
|
|
@@ -453,7 +469,7 @@ VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen) {
|
|
453
469
|
while (1) {
|
454
470
|
VALUE resume_value = Qnil;
|
455
471
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_READ);
|
456
|
-
struct io_uring_sqe *sqe =
|
472
|
+
struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
|
457
473
|
ssize_t result;
|
458
474
|
int completed;
|
459
475
|
|
@@ -502,7 +518,7 @@ VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
|
|
502
518
|
while (1) {
|
503
519
|
VALUE resume_value = Qnil;
|
504
520
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_READ);
|
505
|
-
struct io_uring_sqe *sqe =
|
521
|
+
struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
|
506
522
|
ssize_t result;
|
507
523
|
int completed;
|
508
524
|
|
@@ -546,7 +562,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
546
562
|
while (left > 0) {
|
547
563
|
VALUE resume_value = Qnil;
|
548
564
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_WRITE);
|
549
|
-
struct io_uring_sqe *sqe =
|
565
|
+
struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
|
550
566
|
int result;
|
551
567
|
int completed;
|
552
568
|
|
@@ -597,7 +613,7 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
597
613
|
while (1) {
|
598
614
|
VALUE resume_value = Qnil;
|
599
615
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_WRITEV);
|
600
|
-
struct io_uring_sqe *sqe =
|
616
|
+
struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
|
601
617
|
int result;
|
602
618
|
int completed;
|
603
619
|
|
@@ -689,7 +705,7 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos) {
|
|
689
705
|
while (1) {
|
690
706
|
VALUE resume_value = Qnil;
|
691
707
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_RECV);
|
692
|
-
struct io_uring_sqe *sqe =
|
708
|
+
struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
|
693
709
|
int result;
|
694
710
|
int completed;
|
695
711
|
|
@@ -739,7 +755,7 @@ VALUE Backend_recv_loop(VALUE self, VALUE io, VALUE maxlen) {
|
|
739
755
|
while (1) {
|
740
756
|
VALUE resume_value = Qnil;
|
741
757
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_RECV);
|
742
|
-
struct io_uring_sqe *sqe =
|
758
|
+
struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
|
743
759
|
int result;
|
744
760
|
int completed;
|
745
761
|
|
@@ -787,7 +803,7 @@ VALUE Backend_recv_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method)
|
|
787
803
|
while (1) {
|
788
804
|
VALUE resume_value = Qnil;
|
789
805
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_RECV);
|
790
|
-
struct io_uring_sqe *sqe =
|
806
|
+
struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
|
791
807
|
int result;
|
792
808
|
int completed;
|
793
809
|
|
@@ -831,7 +847,7 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
831
847
|
while (left > 0) {
|
832
848
|
VALUE resume_value = Qnil;
|
833
849
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_SEND);
|
834
|
-
struct io_uring_sqe *sqe =
|
850
|
+
struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
|
835
851
|
int result;
|
836
852
|
int completed;
|
837
853
|
|
@@ -869,7 +885,7 @@ VALUE io_uring_backend_accept(Backend_t *backend, VALUE server_socket, VALUE soc
|
|
869
885
|
while (1) {
|
870
886
|
VALUE resume_value = Qnil;
|
871
887
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_ACCEPT);
|
872
|
-
struct io_uring_sqe *sqe =
|
888
|
+
struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
|
873
889
|
int fd;
|
874
890
|
int completed;
|
875
891
|
|
@@ -935,7 +951,7 @@ VALUE io_uring_backend_splice(Backend_t *backend, VALUE src, VALUE dest, VALUE m
|
|
935
951
|
|
936
952
|
while (1) {
|
937
953
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_SPLICE);
|
938
|
-
struct io_uring_sqe *sqe =
|
954
|
+
struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
|
939
955
|
int result;
|
940
956
|
int completed;
|
941
957
|
|
@@ -984,7 +1000,7 @@ VALUE Backend_tee(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
984
1000
|
|
985
1001
|
while (1) {
|
986
1002
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_SPLICE);
|
987
|
-
struct io_uring_sqe *sqe =
|
1003
|
+
struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
|
988
1004
|
int result;
|
989
1005
|
int completed;
|
990
1006
|
|
@@ -1021,7 +1037,7 @@ VALUE Backend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
|
|
1021
1037
|
GetBackend(self, backend);
|
1022
1038
|
fd = fd_from_io(sock, &fptr, 1, 0);
|
1023
1039
|
ctx = context_store_acquire(&backend->store, OP_CONNECT);
|
1024
|
-
sqe =
|
1040
|
+
sqe = io_uring_backend_get_sqe(backend);
|
1025
1041
|
io_uring_prep_connect(sqe, fd, ai_addr, ai_addrlen);
|
1026
1042
|
result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
1027
1043
|
completed = context_store_release(&backend->store, ctx);
|
@@ -1063,7 +1079,7 @@ VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write) {
|
|
1063
1079
|
// io_unset_nonblock(fptr, io);
|
1064
1080
|
|
1065
1081
|
// ctx = context_store_acquire(&backend->store, OP_CLOSE);
|
1066
|
-
// sqe =
|
1082
|
+
// sqe = io_uring_backend_get_sqe(backend);
|
1067
1083
|
// io_uring_prep_close(sqe, fd);
|
1068
1084
|
// result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
1069
1085
|
// completed = context_store_release(&backend->store, ctx);
|
@@ -1094,7 +1110,7 @@ inline struct __kernel_timespec duration_to_timespec(VALUE duration) {
|
|
1094
1110
|
// returns true if completed, 0 otherwise
|
1095
1111
|
int io_uring_backend_submit_timeout_and_await(Backend_t *backend, double duration, VALUE *resume_value) {
|
1096
1112
|
struct __kernel_timespec ts = double_to_timespec(duration);
|
1097
|
-
struct io_uring_sqe *sqe =
|
1113
|
+
struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
|
1098
1114
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_TIMEOUT);
|
1099
1115
|
|
1100
1116
|
io_uring_prep_timeout(sqe, &ts, 0, 0);
|
@@ -1183,7 +1199,7 @@ VALUE Backend_timeout(int argc, VALUE *argv, VALUE self) {
|
|
1183
1199
|
GetBackend(self, backend);
|
1184
1200
|
timeout = rb_funcall(cTimeoutException, ID_new, 0);
|
1185
1201
|
|
1186
|
-
sqe =
|
1202
|
+
sqe = io_uring_backend_get_sqe(backend);
|
1187
1203
|
ctx = context_store_acquire(&backend->store, OP_TIMEOUT);
|
1188
1204
|
ctx->resume_value = timeout;
|
1189
1205
|
io_uring_prep_timeout(sqe, &ts, 0, 0);
|
@@ -1259,7 +1275,7 @@ VALUE Backend_wait_event(VALUE self, VALUE raise) {
|
|
1259
1275
|
struct io_uring_sqe *sqe;
|
1260
1276
|
|
1261
1277
|
backend->event_fd_ctx = context_store_acquire(&backend->store, OP_POLL);
|
1262
|
-
sqe =
|
1278
|
+
sqe = io_uring_backend_get_sqe(backend);
|
1263
1279
|
io_uring_prep_poll_add(sqe, backend->event_fd, POLLIN);
|
1264
1280
|
backend->base.op_count++;
|
1265
1281
|
io_uring_sqe_set_data(sqe, backend->event_fd_ctx);
|
@@ -1275,7 +1291,7 @@ VALUE Backend_wait_event(VALUE self, VALUE raise) {
|
|
1275
1291
|
|
1276
1292
|
// last fiber to use the eventfd, so we cancel the ongoing poll
|
1277
1293
|
struct io_uring_sqe *sqe;
|
1278
|
-
sqe =
|
1294
|
+
sqe = io_uring_backend_get_sqe(backend);
|
1279
1295
|
io_uring_prep_cancel(sqe, (__u64)backend->event_fd_ctx, 0);
|
1280
1296
|
io_uring_backend_immediate_submit(backend);
|
1281
1297
|
backend->event_fd_ctx = NULL;
|
@@ -1296,7 +1312,7 @@ struct io_uring_sqe *Backend_chain_prepare_write(Backend_t *backend, VALUE io, V
|
|
1296
1312
|
struct io_uring_sqe *sqe;
|
1297
1313
|
|
1298
1314
|
fd = fd_from_io(io, &fptr, 1, 0);
|
1299
|
-
sqe =
|
1315
|
+
sqe = io_uring_backend_get_sqe(backend);
|
1300
1316
|
io_uring_prep_write(sqe, fd, StringValuePtr(str), RSTRING_LEN(str), 0);
|
1301
1317
|
return sqe;
|
1302
1318
|
}
|
@@ -1308,7 +1324,7 @@ struct io_uring_sqe *Backend_chain_prepare_send(Backend_t *backend, VALUE io, VA
|
|
1308
1324
|
|
1309
1325
|
fd = fd_from_io(io, &fptr, 1, 0);
|
1310
1326
|
|
1311
|
-
sqe =
|
1327
|
+
sqe = io_uring_backend_get_sqe(backend);
|
1312
1328
|
io_uring_prep_send(sqe, fd, StringValuePtr(str), RSTRING_LEN(str), NUM2INT(flags));
|
1313
1329
|
return sqe;
|
1314
1330
|
}
|
@@ -1322,7 +1338,7 @@ struct io_uring_sqe *Backend_chain_prepare_splice(Backend_t *backend, VALUE src,
|
|
1322
1338
|
|
1323
1339
|
src_fd = fd_from_io(src, &src_fptr, 0, 0);
|
1324
1340
|
dest_fd = fd_from_io(dest, &dest_fptr, 1, 0);
|
1325
|
-
sqe =
|
1341
|
+
sqe = io_uring_backend_get_sqe(backend);
|
1326
1342
|
io_uring_prep_splice(sqe, src_fd, -1, dest_fd, -1, NUM2INT(maxlen), 0);
|
1327
1343
|
return sqe;
|
1328
1344
|
}
|
@@ -1381,7 +1397,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1381
1397
|
|
1382
1398
|
ctx->ref_count = sqe_count;
|
1383
1399
|
ctx->result = -ECANCELED;
|
1384
|
-
sqe =
|
1400
|
+
sqe = io_uring_backend_get_sqe(backend);
|
1385
1401
|
io_uring_prep_cancel(sqe, (__u64)ctx, 0);
|
1386
1402
|
io_uring_backend_immediate_submit(backend);
|
1387
1403
|
}
|
@@ -1411,7 +1427,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1411
1427
|
|
1412
1428
|
// op was not completed (an exception was raised), so we need to cancel it
|
1413
1429
|
ctx->result = -ECANCELED;
|
1414
|
-
sqe =
|
1430
|
+
sqe = io_uring_backend_get_sqe(backend);
|
1415
1431
|
io_uring_prep_cancel(sqe, (__u64)ctx, 0);
|
1416
1432
|
io_uring_backend_immediate_submit(backend);
|
1417
1433
|
RAISE_IF_EXCEPTION(resume_value);
|
@@ -1470,14 +1486,14 @@ static inline void splice_chunks_get_sqe(
|
|
1470
1486
|
}
|
1471
1487
|
else
|
1472
1488
|
*ctx = context_store_acquire(&backend->store, type);
|
1473
|
-
(*sqe) =
|
1489
|
+
(*sqe) = io_uring_backend_get_sqe(backend);
|
1474
1490
|
}
|
1475
1491
|
|
1476
1492
|
static inline void splice_chunks_cancel(Backend_t *backend, op_context_t *ctx) {
|
1477
1493
|
struct io_uring_sqe *sqe;
|
1478
1494
|
|
1479
1495
|
ctx->result = -ECANCELED;
|
1480
|
-
sqe =
|
1496
|
+
sqe = io_uring_backend_get_sqe(backend);
|
1481
1497
|
io_uring_prep_cancel(sqe, (__u64)ctx, 0);
|
1482
1498
|
io_uring_backend_immediate_submit(backend);
|
1483
1499
|
}
|
data/ext/polyphony/extconf.rb
CHANGED
@@ -47,6 +47,7 @@ end
|
|
47
47
|
$defs << '-DPOLYPHONY_USE_PIDFD_OPEN' if config[:pidfd_open]
|
48
48
|
if config[:io_uring]
|
49
49
|
$defs << "-DPOLYPHONY_BACKEND_LIBURING"
|
50
|
+
$defs << "-DPOLYPHONY_LINUX"
|
50
51
|
$defs << "-DPOLYPHONY_UNSET_NONBLOCK" if RUBY_VERSION =~ /^3/
|
51
52
|
$CFLAGS << " -Wno-pointer-arith"
|
52
53
|
else
|
@@ -10,6 +10,7 @@
|
|
10
10
|
#include "polyphony.h"
|
11
11
|
#include "zlib.h"
|
12
12
|
#include "assert.h"
|
13
|
+
#include "ruby/thread.h"
|
13
14
|
|
14
15
|
ID ID_at;
|
15
16
|
ID ID_read_method;
|
@@ -29,6 +30,7 @@ VALUE SYM_orig_name;
|
|
29
30
|
VALUE SYM_readpartial;
|
30
31
|
|
31
32
|
enum read_method {
|
33
|
+
RM_STRING,
|
32
34
|
RM_BACKEND_READ,
|
33
35
|
RM_BACKEND_RECV,
|
34
36
|
RM_READPARTIAL,
|
@@ -36,13 +38,15 @@ enum read_method {
|
|
36
38
|
};
|
37
39
|
|
38
40
|
enum write_method {
|
41
|
+
WM_STRING,
|
39
42
|
WM_BACKEND_WRITE,
|
40
43
|
WM_BACKEND_SEND,
|
41
44
|
WM_WRITE,
|
42
45
|
WM_CALL
|
43
46
|
};
|
44
47
|
|
45
|
-
static enum read_method detect_read_method(VALUE io) {
|
48
|
+
static inline enum read_method detect_read_method(VALUE io) {
|
49
|
+
if (TYPE(io) == T_STRING) return RM_STRING;
|
46
50
|
if (rb_respond_to(io, ID_read_method)) {
|
47
51
|
VALUE method = rb_funcall(io, ID_read_method, 0);
|
48
52
|
if (method == SYM_readpartial) return RM_READPARTIAL;
|
@@ -58,7 +62,8 @@ static enum read_method detect_read_method(VALUE io) {
|
|
58
62
|
rb_raise(rb_eRuntimeError, "Given io instance should be a callable or respond to #__read_method__");
|
59
63
|
}
|
60
64
|
|
61
|
-
static enum write_method detect_write_method(VALUE io) {
|
65
|
+
static inline enum write_method detect_write_method(VALUE io) {
|
66
|
+
if (TYPE(io) == T_STRING) return WM_STRING;
|
62
67
|
if (rb_respond_to(io, ID_write_method)) {
|
63
68
|
VALUE method = rb_funcall(io, ID_write_method, 0);
|
64
69
|
if (method == SYM_readpartial) return WM_WRITE;
|
@@ -136,11 +141,18 @@ static inline int read_to_raw_buffer(VALUE backend, VALUE io, enum read_method m
|
|
136
141
|
RB_GC_GUARD(str);
|
137
142
|
return len;
|
138
143
|
}
|
144
|
+
default: {
|
145
|
+
rb_raise(rb_eRuntimeError, "Invalid read method");
|
146
|
+
}
|
139
147
|
}
|
140
148
|
}
|
141
149
|
|
142
150
|
static inline int write_from_raw_buffer(VALUE backend, VALUE io, enum write_method method, struct raw_buffer *buffer) {
|
143
151
|
switch (method) {
|
152
|
+
case WM_STRING: {
|
153
|
+
rb_str_buf_cat(io, (char *)buffer->ptr, buffer->len);
|
154
|
+
return buffer->len;
|
155
|
+
}
|
144
156
|
case WM_BACKEND_WRITE: {
|
145
157
|
VALUE len = Backend_write(backend, io, PTR2FIX(buffer));
|
146
158
|
return FIX2INT(len);
|
@@ -165,6 +177,9 @@ static inline int write_from_raw_buffer(VALUE backend, VALUE io, enum write_meth
|
|
165
177
|
RB_GC_GUARD(str);
|
166
178
|
return buffer->len;
|
167
179
|
}
|
180
|
+
default: {
|
181
|
+
rb_raise(rb_eRuntimeError, "Invalid write method");
|
182
|
+
}
|
168
183
|
}
|
169
184
|
}
|
170
185
|
|
@@ -228,7 +243,7 @@ static inline time_t time_from_object(VALUE o) {
|
|
228
243
|
return FIX2INT(rb_funcall(o, rb_intern("to_i"), 0));
|
229
244
|
}
|
230
245
|
|
231
|
-
int gzip_prepare_header(struct gzip_header_ctx *ctx, char *buffer, int maxlen) {
|
246
|
+
int gzip_prepare_header(struct gzip_header_ctx *ctx, unsigned char *buffer, int maxlen) {
|
232
247
|
int len = 0;
|
233
248
|
unsigned char flags = 0, extraflags = 0;
|
234
249
|
|
@@ -259,7 +274,7 @@ int gzip_prepare_header(struct gzip_header_ctx *ctx, char *buffer, int maxlen) {
|
|
259
274
|
return len;
|
260
275
|
}
|
261
276
|
|
262
|
-
int gzip_prepare_footer(unsigned long crc32, unsigned long total_in, char *buffer, int maxlen) {
|
277
|
+
static inline int gzip_prepare_footer(unsigned long crc32, unsigned long total_in, unsigned char *buffer, int maxlen) {
|
263
278
|
assert(maxlen >= GZIP_FOOTER_LEN);
|
264
279
|
|
265
280
|
gzfile_set32(crc32, buffer);
|
@@ -287,8 +302,8 @@ struct z_stream_ctx {
|
|
287
302
|
|
288
303
|
unsigned char in[CHUNK];
|
289
304
|
unsigned char out[CHUNK];
|
290
|
-
int in_pos;
|
291
|
-
int out_pos;
|
305
|
+
unsigned int in_pos;
|
306
|
+
unsigned int out_pos;
|
292
307
|
unsigned long in_total;
|
293
308
|
unsigned long out_total;
|
294
309
|
|
@@ -297,8 +312,8 @@ struct z_stream_ctx {
|
|
297
312
|
|
298
313
|
typedef int (*zlib_func)(z_streamp, int);
|
299
314
|
|
300
|
-
void read_gzip_header_str(struct raw_buffer *buffer, VALUE *str, int *in_pos, unsigned long *total_read) {
|
301
|
-
|
315
|
+
void read_gzip_header_str(struct raw_buffer *buffer, VALUE *str, unsigned int *in_pos, unsigned long *total_read) {
|
316
|
+
unsigned long null_pos;
|
302
317
|
// find null terminator
|
303
318
|
for (null_pos = *in_pos; null_pos < *total_read; null_pos++) {
|
304
319
|
if (!buffer->ptr[null_pos]) break;
|
@@ -306,28 +321,37 @@ void read_gzip_header_str(struct raw_buffer *buffer, VALUE *str, int *in_pos, un
|
|
306
321
|
if (null_pos == *total_read)
|
307
322
|
rb_raise(rb_eRuntimeError, "Invalid gzip header");
|
308
323
|
|
309
|
-
*str = rb_str_new_cstr(buffer->ptr + *in_pos);
|
324
|
+
*str = rb_str_new_cstr((char *)buffer->ptr + *in_pos);
|
310
325
|
*in_pos = null_pos + 1;
|
311
326
|
}
|
312
327
|
|
313
328
|
void gzip_read_header(struct z_stream_ctx *ctx, struct gzip_header_ctx *header_ctx) {
|
314
|
-
struct raw_buffer in_buffer
|
329
|
+
struct raw_buffer in_buffer;
|
315
330
|
int flags;
|
316
331
|
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
ctx->in_total
|
332
|
+
if (ctx->src_read_method == RM_STRING) {
|
333
|
+
in_buffer.ptr = (unsigned char *)RSTRING_PTR(ctx->src);
|
334
|
+
in_buffer.len = RSTRING_LEN(ctx->src);
|
335
|
+
ctx->in_total = in_buffer.len;
|
336
|
+
}
|
337
|
+
else {
|
338
|
+
in_buffer.ptr = ctx->in;
|
339
|
+
in_buffer.len = CHUNK;
|
340
|
+
while (ctx->in_total < 10) {
|
341
|
+
int read = read_to_raw_buffer(ctx->backend, ctx->src, ctx->src_read_method, &in_buffer);
|
342
|
+
if (read == 0) goto error;
|
343
|
+
ctx->in_total += read;
|
344
|
+
}
|
321
345
|
}
|
346
|
+
|
322
347
|
// PRINT_BUFFER("read gzip header", ctx->in, ctx->in_total);
|
323
|
-
if (
|
324
|
-
if (
|
325
|
-
if (
|
326
|
-
flags =
|
348
|
+
if (in_buffer.ptr[0] != GZ_MAGIC1) goto error;
|
349
|
+
if (in_buffer.ptr[1] != GZ_MAGIC2) goto error;
|
350
|
+
if (in_buffer.ptr[2] != GZ_METHOD_DEFLATE) goto error;
|
351
|
+
flags = in_buffer.ptr[3];
|
327
352
|
|
328
|
-
unsigned long mtime = gzfile_get32(
|
353
|
+
unsigned long mtime = gzfile_get32(in_buffer.ptr + 4);
|
329
354
|
header_ctx->mtime = INT2FIX(mtime);
|
330
|
-
|
331
355
|
ctx->in_pos = 10;
|
332
356
|
|
333
357
|
if (flags & GZ_FLAG_ORIG_NAME)
|
@@ -344,6 +368,26 @@ error:
|
|
344
368
|
rb_raise(rb_eRuntimeError, "Invalid gzip header");
|
345
369
|
}
|
346
370
|
|
371
|
+
struct process_z_stream_ctx {
|
372
|
+
z_stream *strm;
|
373
|
+
int flags;
|
374
|
+
zlib_func fun;
|
375
|
+
int ret;
|
376
|
+
};
|
377
|
+
|
378
|
+
void *do_process_z_stream_without_gvl(void *ptr) {
|
379
|
+
struct process_z_stream_ctx *ctx = (struct process_z_stream_ctx *)ptr;
|
380
|
+
|
381
|
+
ctx->ret = (ctx->fun)(ctx->strm, ctx->flags);
|
382
|
+
return NULL;
|
383
|
+
}
|
384
|
+
|
385
|
+
static inline int process_without_gvl(zlib_func fun, z_stream *strm, int flags) {
|
386
|
+
struct process_z_stream_ctx ctx = { strm, flags, fun, 0 };
|
387
|
+
rb_thread_call_without_gvl2(do_process_z_stream_without_gvl, (void *)&ctx, RUBY_UBF_IO, 0);
|
388
|
+
return ctx.ret;
|
389
|
+
}
|
390
|
+
|
347
391
|
static inline int z_stream_write_out(struct z_stream_ctx *ctx, zlib_func fun, int eof) {
|
348
392
|
int ret;
|
349
393
|
int written;
|
@@ -351,7 +395,7 @@ static inline int z_stream_write_out(struct z_stream_ctx *ctx, zlib_func fun, in
|
|
351
395
|
|
352
396
|
int avail_out_pre = ctx->strm.avail_out = CHUNK - ctx->out_pos;
|
353
397
|
ctx->strm.next_out = ctx->out + ctx->out_pos;
|
354
|
-
ret = fun
|
398
|
+
ret = process_without_gvl(fun, &ctx->strm, eof ? Z_FINISH : Z_NO_FLUSH);
|
355
399
|
assert(ret != Z_STREAM_ERROR);
|
356
400
|
written = avail_out_pre - ctx->strm.avail_out;
|
357
401
|
out_buffer.ptr = ctx->out;
|
@@ -372,12 +416,13 @@ static inline int z_stream_write_out(struct z_stream_ctx *ctx, zlib_func fun, in
|
|
372
416
|
return ctx->strm.avail_out;
|
373
417
|
}
|
374
418
|
|
375
|
-
|
419
|
+
VALUE z_stream_io_loop(struct z_stream_ctx *ctx) {
|
376
420
|
zlib_func fun = (ctx->mode == SM_DEFLATE) ? deflate : inflate;
|
377
421
|
|
378
|
-
if (ctx->in_total > ctx->in_pos) {
|
422
|
+
if ((ctx->src_read_method != RM_STRING) && (ctx->in_total > ctx->in_pos)) {
|
379
423
|
// In bytes already read for parsing gzip header, so we need to process the
|
380
424
|
// rest.
|
425
|
+
|
381
426
|
ctx->strm.next_in = ctx->in + ctx->in_pos;
|
382
427
|
ctx->strm.avail_in = ctx->in_total -= ctx->in_pos;
|
383
428
|
|
@@ -389,14 +434,27 @@ void z_stream_io_loop(struct z_stream_ctx *ctx) {
|
|
389
434
|
}
|
390
435
|
|
391
436
|
while (1) {
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
ctx->
|
437
|
+
int eof;
|
438
|
+
int read_len;
|
439
|
+
if (ctx->src_read_method == RM_STRING) {
|
440
|
+
struct raw_buffer in_buffer = {
|
441
|
+
(unsigned char *)RSTRING_PTR(ctx->src) + ctx->in_pos,
|
442
|
+
RSTRING_LEN(ctx->src) - ctx->in_pos
|
443
|
+
};
|
444
|
+
ctx->strm.next_in = in_buffer.ptr;
|
445
|
+
read_len = ctx->strm.avail_in = in_buffer.len;
|
446
|
+
eof = 1;
|
447
|
+
if (ctx->mode == SM_DEFLATE) ctx->crc32 = crc32(ctx->crc32, in_buffer.ptr, read_len);
|
448
|
+
}
|
449
|
+
else {
|
450
|
+
struct raw_buffer in_buffer = {ctx->in, CHUNK};
|
451
|
+
ctx->strm.next_in = ctx->in;
|
452
|
+
read_len = ctx->strm.avail_in = read_to_raw_buffer(ctx->backend, ctx->src, ctx->src_read_method, &in_buffer);
|
453
|
+
if (!read_len) break;
|
454
|
+
eof = read_len < CHUNK;
|
455
|
+
if (ctx->mode == SM_DEFLATE) ctx->crc32 = crc32(ctx->crc32, ctx->in, read_len);
|
456
|
+
}
|
457
|
+
|
400
458
|
ctx->in_total += read_len;
|
401
459
|
|
402
460
|
// PRINT_BUFFER("read stream", ctx->in, read_len);
|
@@ -407,13 +465,15 @@ void z_stream_io_loop(struct z_stream_ctx *ctx) {
|
|
407
465
|
if (z_stream_write_out(ctx, fun, eof)) break;
|
408
466
|
}
|
409
467
|
|
410
|
-
if (eof)
|
468
|
+
if (eof) goto done;
|
411
469
|
}
|
412
470
|
|
413
471
|
//flush
|
414
472
|
ctx->strm.avail_in = 0;
|
415
473
|
ctx->strm.next_in = ctx->in;
|
416
474
|
z_stream_write_out(ctx, fun, 1);
|
475
|
+
done:
|
476
|
+
return Qnil;
|
417
477
|
}
|
418
478
|
|
419
479
|
static inline void setup_ctx(struct z_stream_ctx *ctx, enum stream_mode mode, VALUE src, VALUE dest) {
|
@@ -434,6 +494,18 @@ static inline void setup_ctx(struct z_stream_ctx *ctx, enum stream_mode mode, VA
|
|
434
494
|
ctx->crc32 = 0;
|
435
495
|
}
|
436
496
|
|
497
|
+
static inline VALUE z_stream_cleanup(struct z_stream_ctx *ctx) {
|
498
|
+
if (ctx->mode == SM_DEFLATE)
|
499
|
+
deflateEnd(&ctx->strm);
|
500
|
+
else
|
501
|
+
inflateEnd(&ctx->strm);
|
502
|
+
return Qnil;
|
503
|
+
}
|
504
|
+
|
505
|
+
#define SAFE(f) (VALUE (*)(VALUE))(f)
|
506
|
+
#define Z_STREAM_SAFE_IO_LOOP_WITH_CLEANUP(ctx) \
|
507
|
+
rb_ensure(SAFE(z_stream_io_loop), (VALUE)&ctx, SAFE(z_stream_cleanup), (VALUE)&ctx)
|
508
|
+
|
437
509
|
VALUE IO_gzip(int argc, VALUE *argv, VALUE self) {
|
438
510
|
VALUE src;
|
439
511
|
VALUE dest;
|
@@ -450,18 +522,16 @@ VALUE IO_gzip(int argc, VALUE *argv, VALUE self) {
|
|
450
522
|
};
|
451
523
|
|
452
524
|
struct z_stream_ctx ctx;
|
453
|
-
int level = DEFAULT_LEVEL;
|
454
525
|
int ret;
|
455
526
|
|
456
527
|
setup_ctx(&ctx, SM_DEFLATE, src, dest);
|
457
528
|
ctx.f_gzip_footer = 1; // write gzip footer
|
458
|
-
ctx.out_pos = gzip_prepare_header(&header_ctx, ctx.out, sizeof(ctx.out));
|
529
|
+
ctx.out_total = ctx.out_pos = gzip_prepare_header(&header_ctx, ctx.out, sizeof(ctx.out));
|
459
530
|
|
460
|
-
ret = deflateInit2(&ctx.strm,
|
461
|
-
if (ret != Z_OK)
|
462
|
-
|
463
|
-
|
464
|
-
|
531
|
+
ret = deflateInit2(&ctx.strm, DEFAULT_LEVEL, Z_DEFLATED, -MAX_WBITS, DEFAULT_MEM_LEVEL, Z_DEFAULT_STRATEGY);
|
532
|
+
if (ret != Z_OK)
|
533
|
+
rb_raise(rb_eRuntimeError, "zlib error: %s\n", ctx.strm.msg);
|
534
|
+
Z_STREAM_SAFE_IO_LOOP_WITH_CLEANUP(ctx);
|
465
535
|
return INT2FIX(ctx.out_total);
|
466
536
|
}
|
467
537
|
|
@@ -482,21 +552,25 @@ VALUE IO_gunzip(int argc, VALUE *argv, VALUE self) {
|
|
482
552
|
setup_ctx(&ctx, SM_INFLATE, src, dest);
|
483
553
|
gzip_read_header(&ctx, &header_ctx);
|
484
554
|
|
555
|
+
ret = inflateInit2(&ctx.strm, -MAX_WBITS);
|
556
|
+
if (ret != Z_OK)
|
557
|
+
rb_raise(rb_eRuntimeError, "zlib error: %s\n", ctx.strm.msg);
|
558
|
+
|
559
|
+
Z_STREAM_SAFE_IO_LOOP_WITH_CLEANUP(ctx);
|
560
|
+
|
561
|
+
// gzip_read_footer(&ctx, &footer_ctx);
|
562
|
+
// TODO: verify crc32
|
563
|
+
// TODO: verify total length
|
564
|
+
|
485
565
|
if (info != Qnil) {
|
486
566
|
rb_hash_aset(info, SYM_mtime, FIX2TIME(header_ctx.mtime));
|
487
567
|
rb_hash_aset(info, SYM_orig_name, header_ctx.orig_name);
|
488
568
|
rb_hash_aset(info, SYM_comment, header_ctx.comment);
|
489
569
|
}
|
570
|
+
RB_GC_GUARD(header_ctx.orig_name);
|
571
|
+
RB_GC_GUARD(header_ctx.comment);
|
490
572
|
|
491
|
-
|
492
|
-
if (ret != Z_OK) return INT2FIX(ret);
|
493
|
-
z_stream_io_loop(&ctx);
|
494
|
-
inflateEnd(&ctx.strm);
|
495
|
-
|
496
|
-
// gzip_read_footer(&ctx, &footer_ctx);
|
497
|
-
// TODO: verify crc32
|
498
|
-
// TODO: verify total length
|
499
|
-
return self;
|
573
|
+
return INT2FIX(ctx.out_total);
|
500
574
|
}
|
501
575
|
|
502
576
|
VALUE IO_deflate(VALUE self, VALUE src, VALUE dest) {
|
@@ -506,9 +580,10 @@ VALUE IO_deflate(VALUE self, VALUE src, VALUE dest) {
|
|
506
580
|
|
507
581
|
setup_ctx(&ctx, SM_DEFLATE, src, dest);
|
508
582
|
ret = deflateInit(&ctx.strm, level);
|
509
|
-
if (ret != Z_OK)
|
510
|
-
|
511
|
-
|
583
|
+
if (ret != Z_OK)
|
584
|
+
rb_raise(rb_eRuntimeError, "zlib error: %s\n", ctx.strm.msg);
|
585
|
+
|
586
|
+
Z_STREAM_SAFE_IO_LOOP_WITH_CLEANUP(ctx);
|
512
587
|
|
513
588
|
return INT2FIX(ctx.out_total);
|
514
589
|
}
|
@@ -519,9 +594,10 @@ VALUE IO_inflate(VALUE self, VALUE src, VALUE dest) {
|
|
519
594
|
|
520
595
|
setup_ctx(&ctx, SM_INFLATE, src, dest);
|
521
596
|
ret = inflateInit(&ctx.strm);
|
522
|
-
if (ret != Z_OK)
|
523
|
-
|
524
|
-
|
597
|
+
if (ret != Z_OK)
|
598
|
+
rb_raise(rb_eRuntimeError, "zlib error: %s\n", ctx.strm.msg);
|
599
|
+
|
600
|
+
Z_STREAM_SAFE_IO_LOOP_WITH_CLEANUP(ctx);
|
525
601
|
|
526
602
|
return INT2FIX(ctx.out_total);
|
527
603
|
}
|
@@ -538,16 +614,16 @@ VALUE IO_http1_splice_chunked(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
538
614
|
if (!len) break;
|
539
615
|
|
540
616
|
// write chunk header
|
541
|
-
buffer.len += sprintf(buffer.ptr + buffer.len, "%x\r\n", len);
|
617
|
+
buffer.len += sprintf((char *)buffer.ptr + buffer.len, "%x\r\n", len);
|
542
618
|
write_from_raw_buffer(backend, dest, method, &buffer);
|
543
619
|
buffer.len = 0;
|
544
620
|
while (len) {
|
545
621
|
int spliced = FIX2INT(Backend_splice(backend, pipe, dest, INT2FIX(len)));
|
546
622
|
len -= spliced;
|
547
623
|
}
|
548
|
-
buffer.len += sprintf(buffer.ptr + buffer.len, "\r\n");
|
624
|
+
buffer.len += sprintf((char *)buffer.ptr + buffer.len, "\r\n");
|
549
625
|
}
|
550
|
-
buffer.len += sprintf(buffer.ptr + buffer.len, "0\r\n\r\n");
|
626
|
+
buffer.len += sprintf((char *)buffer.ptr + buffer.len, "0\r\n\r\n");
|
551
627
|
write_from_raw_buffer(backend, dest, method, &buffer);
|
552
628
|
|
553
629
|
Pipe_close(pipe);
|
data/ext/polyphony/polyphony.c
CHANGED
@@ -145,7 +145,7 @@ VALUE Polyphony_raw_buffer_get(int argc, VALUE *argv, VALUE self) {
|
|
145
145
|
int length = (len == Qnil) ? buffer->len : FIX2INT(len);
|
146
146
|
|
147
147
|
if (length > buffer->len) length = buffer->len;
|
148
|
-
return rb_utf8_str_new(buffer->ptr, length);
|
148
|
+
return rb_utf8_str_new((char *)buffer->ptr, length);
|
149
149
|
}
|
150
150
|
|
151
151
|
VALUE Polyphony_raw_buffer_set(VALUE self, VALUE buf, VALUE str) {
|
@@ -164,12 +164,6 @@ VALUE Polyphony_raw_buffer_size(VALUE self, VALUE buf) {
|
|
164
164
|
return INT2FIX(buffer->len);
|
165
165
|
}
|
166
166
|
|
167
|
-
VALUE Polyphony_backend_test(VALUE self, VALUE io, VALUE str) {
|
168
|
-
struct raw_buffer buffer = { RSTRING_PTR(str), RSTRING_LEN(str) };
|
169
|
-
VALUE args[2] = { io, PTR2FIX(&buffer) };
|
170
|
-
return Polyphony_backend_write(2, args, self);
|
171
|
-
}
|
172
|
-
|
173
167
|
// VALUE Polyphony_backend_close(VALUE self, VALUE io) {
|
174
168
|
// return Backend_close(BACKEND(), io);
|
175
169
|
// }
|
@@ -210,7 +204,6 @@ void Init_Polyphony() {
|
|
210
204
|
rb_define_singleton_method(mPolyphony, "__raw_buffer_get__", Polyphony_raw_buffer_get, -1);
|
211
205
|
rb_define_singleton_method(mPolyphony, "__raw_buffer_set__", Polyphony_raw_buffer_set, 2);
|
212
206
|
rb_define_singleton_method(mPolyphony, "__raw_buffer_size__", Polyphony_raw_buffer_size, 1);
|
213
|
-
rb_define_singleton_method(mPolyphony, "backend_test", Polyphony_backend_test, 2);
|
214
207
|
|
215
208
|
rb_define_global_function("snooze", Polyphony_snooze, 0);
|
216
209
|
rb_define_global_function("suspend", Polyphony_suspend, 0);
|
data/lib/polyphony/version.rb
CHANGED
data/test/test_io.rb
CHANGED
@@ -656,19 +656,75 @@ class IOExtensionsTest < MiniTest::Test
|
|
656
656
|
i, o = IO.pipe
|
657
657
|
r, w = IO.pipe
|
658
658
|
|
659
|
-
|
660
|
-
|
659
|
+
ret = nil
|
660
|
+
f = spin {
|
661
|
+
ret = IO.deflate(i, w)
|
661
662
|
w.close
|
662
663
|
}
|
663
664
|
|
664
665
|
o << 'foobar' * 20
|
665
666
|
o.close
|
666
667
|
|
668
|
+
f.await
|
669
|
+
assert_equal 17, ret
|
670
|
+
|
667
671
|
data = r.read
|
668
672
|
msg = Zlib::Inflate.inflate(data)
|
669
673
|
assert_equal 'foobar' * 20, msg
|
670
674
|
end
|
671
675
|
|
676
|
+
def test_deflate_to_string
|
677
|
+
i, o = IO.pipe
|
678
|
+
r, w = IO.pipe
|
679
|
+
str = +''
|
680
|
+
|
681
|
+
ret = nil
|
682
|
+
f = spin {
|
683
|
+
ret = IO.deflate(i, str)
|
684
|
+
w << str
|
685
|
+
w.close
|
686
|
+
}
|
687
|
+
|
688
|
+
o << 'foobar' * 20
|
689
|
+
o.close
|
690
|
+
|
691
|
+
f.await
|
692
|
+
assert_equal 17, ret
|
693
|
+
|
694
|
+
data = r.read
|
695
|
+
msg = Zlib::Inflate.inflate(data)
|
696
|
+
assert_equal 'foobar' * 20, msg
|
697
|
+
end
|
698
|
+
|
699
|
+
def test_deflate_to_frozen_string
|
700
|
+
i, o = IO.pipe
|
701
|
+
str = '' # frozen
|
702
|
+
|
703
|
+
f = spin {
|
704
|
+
o << 'foobar' * 20
|
705
|
+
o.close
|
706
|
+
}
|
707
|
+
|
708
|
+
assert_raises(FrozenError) { IO.deflate(i, str) }
|
709
|
+
end
|
710
|
+
|
711
|
+
def test_deflate_from_string
|
712
|
+
r, w = IO.pipe
|
713
|
+
str = 'foobar' * 10000
|
714
|
+
ret = nil
|
715
|
+
|
716
|
+
f = spin {
|
717
|
+
ret = IO.deflate(str, w)
|
718
|
+
w.close
|
719
|
+
}
|
720
|
+
f.await
|
721
|
+
assert_equal 118, ret
|
722
|
+
|
723
|
+
data = r.read
|
724
|
+
msg = Zlib::Inflate.inflate(data)
|
725
|
+
assert_equal str, msg
|
726
|
+
end
|
727
|
+
|
672
728
|
def test_inflate
|
673
729
|
i, o = IO.pipe
|
674
730
|
r, w = IO.pipe
|
@@ -679,7 +735,35 @@ class IOExtensionsTest < MiniTest::Test
|
|
679
735
|
o.close
|
680
736
|
}
|
681
737
|
|
682
|
-
IO.inflate(i, w)
|
738
|
+
ret = IO.inflate(i, w)
|
739
|
+
assert_equal 6, ret
|
740
|
+
w.close
|
741
|
+
msg = r.read
|
742
|
+
assert_equal 'foobar', msg
|
743
|
+
end
|
744
|
+
|
745
|
+
def test_inflate_to_string
|
746
|
+
i, o = IO.pipe
|
747
|
+
str = +''
|
748
|
+
|
749
|
+
spin {
|
750
|
+
data = Zlib::Deflate.deflate('foobar', 9)
|
751
|
+
o << data
|
752
|
+
o.close
|
753
|
+
}
|
754
|
+
|
755
|
+
ret = IO.inflate(i, str)
|
756
|
+
assert_equal 6, ret
|
757
|
+
assert_equal 6, str.bytesize
|
758
|
+
assert_equal 'foobar', str
|
759
|
+
end
|
760
|
+
|
761
|
+
def test_inflate_from_string
|
762
|
+
r, w = IO.pipe
|
763
|
+
str = Zlib::Deflate.deflate('foobar', 9)
|
764
|
+
|
765
|
+
ret = IO.inflate(str, w)
|
766
|
+
assert_equal 6, ret
|
683
767
|
w.close
|
684
768
|
msg = r.read
|
685
769
|
assert_equal 'foobar', msg
|
@@ -690,7 +774,7 @@ class IOExtensionsTest < MiniTest::Test
|
|
690
774
|
dest = Polyphony.pipe
|
691
775
|
now = nil
|
692
776
|
|
693
|
-
spin {
|
777
|
+
f = spin {
|
694
778
|
now = Time.now
|
695
779
|
IO.gzip(src, dest)
|
696
780
|
dest.close
|
@@ -698,6 +782,32 @@ class IOExtensionsTest < MiniTest::Test
|
|
698
782
|
|
699
783
|
src << IO.read(__FILE__)
|
700
784
|
src.close
|
785
|
+
f.await
|
786
|
+
|
787
|
+
gz = Zlib::GzipReader.new(dest)
|
788
|
+
data = gz.read
|
789
|
+
assert_equal IO.read(__FILE__), data
|
790
|
+
assert_in_range (now-2)..(now+1), gz.mtime
|
791
|
+
assert_nil gz.orig_name
|
792
|
+
assert_nil gz.comment
|
793
|
+
end
|
794
|
+
|
795
|
+
def test_gzip_to_string
|
796
|
+
src = Polyphony.pipe
|
797
|
+
dest = Polyphony.pipe
|
798
|
+
str = +''
|
799
|
+
now = nil
|
800
|
+
|
801
|
+
f = spin {
|
802
|
+
now = Time.now
|
803
|
+
IO.gzip(src, str)
|
804
|
+
dest << str
|
805
|
+
dest.close
|
806
|
+
}
|
807
|
+
|
808
|
+
src << IO.read(__FILE__)
|
809
|
+
src.close
|
810
|
+
f.await
|
701
811
|
|
702
812
|
gz = Zlib::GzipReader.new(dest)
|
703
813
|
data = gz.read
|
@@ -707,6 +817,39 @@ class IOExtensionsTest < MiniTest::Test
|
|
707
817
|
assert_nil gz.comment
|
708
818
|
end
|
709
819
|
|
820
|
+
def test_gzip_from_string
|
821
|
+
str = IO.read(__FILE__)
|
822
|
+
dest = Polyphony.pipe
|
823
|
+
now = nil
|
824
|
+
|
825
|
+
IO.gzip(str, dest)
|
826
|
+
dest.close
|
827
|
+
|
828
|
+
gz = Zlib::GzipReader.new(dest)
|
829
|
+
data = gz.read
|
830
|
+
assert_equal IO.read(__FILE__), data
|
831
|
+
end
|
832
|
+
|
833
|
+
def test_gzip_return_value
|
834
|
+
src = Polyphony.pipe
|
835
|
+
dest = Polyphony.pipe
|
836
|
+
now = nil
|
837
|
+
ret = nil
|
838
|
+
|
839
|
+
f = spin {
|
840
|
+
now = Time.now
|
841
|
+
ret = IO.gzip(src, dest)
|
842
|
+
dest.close
|
843
|
+
}
|
844
|
+
|
845
|
+
src << IO.read(__FILE__)
|
846
|
+
src.close
|
847
|
+
f.await
|
848
|
+
|
849
|
+
gzipped = dest.read
|
850
|
+
assert_equal gzipped.bytesize, ret
|
851
|
+
end
|
852
|
+
|
710
853
|
def test_gzip_with_mtime_int
|
711
854
|
src = Polyphony.pipe
|
712
855
|
dest = Polyphony.pipe
|
@@ -801,19 +944,51 @@ class IOExtensionsTest < MiniTest::Test
|
|
801
944
|
def test_gunzip
|
802
945
|
src = Polyphony.pipe
|
803
946
|
dest = Polyphony.pipe
|
947
|
+
ret = nil
|
804
948
|
|
805
|
-
spin {
|
806
|
-
IO.gunzip(src, dest)
|
949
|
+
f = spin {
|
950
|
+
ret = IO.gunzip(src, dest)
|
807
951
|
dest.close
|
808
952
|
}
|
809
953
|
|
810
954
|
gz = Zlib::GzipWriter.new(src, 9)
|
811
|
-
gz <<
|
955
|
+
gz << IO.read(__FILE__)
|
812
956
|
gz.close
|
957
|
+
f.await
|
813
958
|
|
814
959
|
data = dest.read
|
815
|
-
|
816
|
-
assert_equal
|
960
|
+
assert_equal IO.read(__FILE__).bytesize, ret
|
961
|
+
assert_equal IO.read(__FILE__), data
|
962
|
+
end
|
963
|
+
|
964
|
+
def test_gunzip_to_string
|
965
|
+
src = Polyphony.pipe
|
966
|
+
str = +''
|
967
|
+
ret = nil
|
968
|
+
|
969
|
+
f = spin {
|
970
|
+
ret = IO.gunzip(src, str)
|
971
|
+
}
|
972
|
+
|
973
|
+
gz = Zlib::GzipWriter.new(src, 9)
|
974
|
+
gz << IO.read(__FILE__)
|
975
|
+
gz.close
|
976
|
+
f.await
|
977
|
+
|
978
|
+
assert_equal IO.read(__FILE__).bytesize, ret
|
979
|
+
assert_equal IO.read(__FILE__), str
|
980
|
+
end
|
981
|
+
|
982
|
+
def test_gunzip_from_string
|
983
|
+
src_data = 'foobar' * 1000
|
984
|
+
str = Zlib.gzip(src_data, level: 9)
|
985
|
+
dest = Polyphony.pipe
|
986
|
+
ret = IO.gunzip(str, dest)
|
987
|
+
dest.close
|
988
|
+
|
989
|
+
dest_data = dest.read
|
990
|
+
assert_equal src_data.bytesize, ret
|
991
|
+
assert_equal src_data, dest_data
|
817
992
|
end
|
818
993
|
|
819
994
|
def test_gunzip_multi
|
@@ -893,4 +1068,24 @@ class IOExtensionsTest < MiniTest::Test
|
|
893
1068
|
assert_equal 'foo.bar', dest_info[:orig_name]
|
894
1069
|
assert_equal 'hello!', dest_info[:comment]
|
895
1070
|
end
|
1071
|
+
|
1072
|
+
def test_deflate_inflate_strings
|
1073
|
+
src_data = IO.read(__FILE__)
|
1074
|
+
deflated = +''
|
1075
|
+
IO.deflate(src_data, deflated)
|
1076
|
+
inflated = +''
|
1077
|
+
IO.inflate(deflated, inflated)
|
1078
|
+
|
1079
|
+
assert_equal src_data, inflated
|
1080
|
+
end
|
1081
|
+
|
1082
|
+
def test_gzip_gunzip_strings
|
1083
|
+
src_data = IO.read(__FILE__)
|
1084
|
+
gzipped = +''
|
1085
|
+
IO.gzip(src_data, gzipped)
|
1086
|
+
gunzipped = +''
|
1087
|
+
IO.gunzip(gzipped, gunzipped)
|
1088
|
+
|
1089
|
+
assert_equal src_data, gunzipped
|
1090
|
+
end
|
896
1091
|
end
|
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.89'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-03-
|
11
|
+
date: 2022-03-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -136,7 +136,7 @@ dependencies:
|
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: 1.1.4
|
139
|
-
description:
|
139
|
+
description:
|
140
140
|
email: sharon@noteflakes.com
|
141
141
|
executables: []
|
142
142
|
extensions:
|
@@ -639,7 +639,7 @@ metadata:
|
|
639
639
|
documentation_uri: https://digital-fabric.github.io/polyphony/
|
640
640
|
homepage_uri: https://digital-fabric.github.io/polyphony/
|
641
641
|
changelog_uri: https://github.com/digital-fabric/polyphony/blob/master/CHANGELOG.md
|
642
|
-
post_install_message:
|
642
|
+
post_install_message:
|
643
643
|
rdoc_options:
|
644
644
|
- "--title"
|
645
645
|
- polyphony
|
@@ -658,8 +658,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
658
658
|
- !ruby/object:Gem::Version
|
659
659
|
version: '0'
|
660
660
|
requirements: []
|
661
|
-
rubygems_version: 3.
|
662
|
-
signing_key:
|
661
|
+
rubygems_version: 3.3.3
|
662
|
+
signing_key:
|
663
663
|
specification_version: 4
|
664
664
|
summary: Fine grained concurrency for Ruby
|
665
665
|
test_files: []
|