polyphony 0.87 → 0.89
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/.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: []
|