polyphony 0.62 → 0.66
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.yml +1 -1
- data/CHANGELOG.md +18 -0
- data/Gemfile.lock +1 -1
- data/Rakefile +1 -1
- data/ext/polyphony/backend_io_uring.c +69 -23
- data/ext/polyphony/backend_io_uring_context.c +42 -0
- data/ext/polyphony/backend_io_uring_context.h +6 -9
- data/ext/polyphony/backend_libev.c +71 -39
- data/ext/polyphony/queue.c +1 -1
- data/ext/polyphony/runqueue.c +3 -3
- data/ext/polyphony/runqueue.h +3 -3
- data/lib/polyphony/extensions/io.rb +11 -3
- data/lib/polyphony/extensions/openssl.rb +22 -2
- data/lib/polyphony/extensions/socket.rb +66 -10
- data/lib/polyphony/version.rb +1 -1
- data/test/helper.rb +2 -0
- data/test/test_backend.rb +39 -4
- data/test/test_global_api.rb +8 -4
- data/test/test_io.rb +22 -0
- data/test/test_socket.rb +53 -12
- data/test/test_thread.rb +3 -0
- data/test/test_timer.rb +5 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b8e2aa3d011286dda93222164cbf66f1ec4c18b9c212ee7a70dbebd4bc523943
|
4
|
+
data.tar.gz: 99b5fb95c682dfad8df33f07d98bfab7f2109b9d4ec0e24720869c2d331f23fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 27c65b6e340d1aad41d38b4b322b98d282f96fe6d136c897ab8de14651b2da3cfc392650600d63983f76b5fb1dc70e4e49116efb289a790a509bec63caa9b9e4
|
7
|
+
data.tar.gz: 94e62ac7fbcb6d085af7475d987eca45be191aaf7654c3bacb07c4f7793d450281d3da1b08b12636a49398e97c1043c3a2cd628018925bdc082e02a0859743bc
|
data/.github/workflows/test.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
## 0.66 2021-08-01
|
2
|
+
|
3
|
+
- Fix all splicing APIs on non-linux OSes (#63)
|
4
|
+
- Add GC marking of buffers when cancelling read/write ops in io_uring backend
|
5
|
+
|
6
|
+
## 0.65 2021-07-29
|
7
|
+
|
8
|
+
- Add `#__polyphony_read_method__` method for read method detection
|
9
|
+
|
10
|
+
## 0.64 2021-07-26
|
11
|
+
|
12
|
+
- Add optional raise_on_eof argument to `#readpartial`
|
13
|
+
|
14
|
+
## 0.63 2021-07-26
|
15
|
+
|
16
|
+
- Add support for specifying buf and buf_pos in `IO#read`
|
17
|
+
- Fix `Socket#read` to work and conform to `IO#read` interface
|
18
|
+
|
1
19
|
## 0.62 2021-07-21
|
2
20
|
|
3
21
|
- Add `runqueue_size` to backend stats
|
data/Gemfile.lock
CHANGED
data/Rakefile
CHANGED
@@ -25,6 +25,8 @@ VALUE SYM_send;
|
|
25
25
|
VALUE SYM_splice;
|
26
26
|
VALUE SYM_write;
|
27
27
|
|
28
|
+
VALUE eArgumentError;
|
29
|
+
|
28
30
|
#ifdef POLYPHONY_UNSET_NONBLOCK
|
29
31
|
#define io_unset_nonblock(fptr, io) io_verify_blocking_mode(fptr, io, Qtrue)
|
30
32
|
#else
|
@@ -45,6 +47,7 @@ typedef struct Backend_t {
|
|
45
47
|
static void Backend_mark(void *ptr) {
|
46
48
|
Backend_t *backend = ptr;
|
47
49
|
backend_base_mark(&backend->base);
|
50
|
+
context_store_mark_taken_buffers(&backend->store);
|
48
51
|
}
|
49
52
|
|
50
53
|
static void Backend_free(void *ptr) {
|
@@ -349,8 +352,11 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
|
|
349
352
|
|
350
353
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
351
354
|
int completed = context_store_release(&backend->store, ctx);
|
352
|
-
|
353
|
-
|
355
|
+
if (!completed) {
|
356
|
+
context_attach_buffers(ctx, 1, &str);
|
357
|
+
RAISE_IF_EXCEPTION(resume_value);
|
358
|
+
return resume_value;
|
359
|
+
}
|
354
360
|
RB_GC_GUARD(resume_value);
|
355
361
|
|
356
362
|
if (result < 0)
|
@@ -410,8 +416,11 @@ VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen) {
|
|
410
416
|
|
411
417
|
ssize_t result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
412
418
|
int completed = context_store_release(&backend->store, ctx);
|
413
|
-
|
414
|
-
|
419
|
+
if (!completed) {
|
420
|
+
context_attach_buffers(ctx, 1, &str);
|
421
|
+
RAISE_IF_EXCEPTION(resume_value);
|
422
|
+
return resume_value;
|
423
|
+
}
|
415
424
|
RB_GC_GUARD(resume_value);
|
416
425
|
|
417
426
|
if (result < 0)
|
@@ -457,8 +466,11 @@ VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
|
|
457
466
|
|
458
467
|
ssize_t result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
459
468
|
int completed = context_store_release(&backend->store, ctx);
|
460
|
-
|
461
|
-
|
469
|
+
if (!completed) {
|
470
|
+
context_attach_buffers(ctx, 1, &str);
|
471
|
+
RAISE_IF_EXCEPTION(resume_value);
|
472
|
+
return resume_value;
|
473
|
+
}
|
462
474
|
RB_GC_GUARD(resume_value);
|
463
475
|
|
464
476
|
if (result < 0)
|
@@ -500,8 +512,11 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
500
512
|
|
501
513
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
502
514
|
int completed = context_store_release(&backend->store, ctx);
|
503
|
-
|
504
|
-
|
515
|
+
if (!completed) {
|
516
|
+
context_attach_buffers(ctx, 1, &str);
|
517
|
+
RAISE_IF_EXCEPTION(resume_value);
|
518
|
+
return resume_value;
|
519
|
+
}
|
505
520
|
RB_GC_GUARD(resume_value);
|
506
521
|
|
507
522
|
if (result < 0)
|
@@ -549,12 +564,10 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
549
564
|
|
550
565
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
551
566
|
int completed = context_store_release(&backend->store, ctx);
|
552
|
-
if (TEST_EXCEPTION(resume_value)) {
|
553
|
-
free(iov);
|
554
|
-
RAISE_EXCEPTION(resume_value);
|
555
|
-
}
|
556
567
|
if (!completed) {
|
557
568
|
free(iov);
|
569
|
+
context_attach_buffers(ctx, argc, argv);
|
570
|
+
RAISE_IF_EXCEPTION(resume_value);
|
558
571
|
return resume_value;
|
559
572
|
}
|
560
573
|
RB_GC_GUARD(resume_value);
|
@@ -588,8 +601,7 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
588
601
|
|
589
602
|
VALUE Backend_write_m(int argc, VALUE *argv, VALUE self) {
|
590
603
|
if (argc < 2)
|
591
|
-
|
592
|
-
rb_raise(rb_eRuntimeError, "(wrong number of arguments (expected 2 or more))");
|
604
|
+
rb_raise(eArgumentError, "(wrong number of arguments (expected 2 or more))");
|
593
605
|
|
594
606
|
return (argc == 2) ?
|
595
607
|
Backend_write(self, argv[0], argv[1]) :
|
@@ -628,8 +640,11 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos) {
|
|
628
640
|
|
629
641
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
630
642
|
int completed = context_store_release(&backend->store, ctx);
|
631
|
-
|
632
|
-
|
643
|
+
if (!completed) {
|
644
|
+
context_attach_buffers(ctx, 1, &str);
|
645
|
+
RAISE_IF_EXCEPTION(resume_value);
|
646
|
+
return resume_value;
|
647
|
+
}
|
633
648
|
RB_GC_GUARD(resume_value);
|
634
649
|
|
635
650
|
if (result < 0)
|
@@ -675,8 +690,11 @@ VALUE Backend_recv_loop(VALUE self, VALUE io, VALUE maxlen) {
|
|
675
690
|
|
676
691
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
677
692
|
int completed = context_store_release(&backend->store, ctx);
|
678
|
-
|
679
|
-
|
693
|
+
if (!completed) {
|
694
|
+
context_attach_buffers(ctx, 1, &str);
|
695
|
+
RAISE_IF_EXCEPTION(resume_value);
|
696
|
+
return resume_value;
|
697
|
+
}
|
680
698
|
RB_GC_GUARD(resume_value);
|
681
699
|
|
682
700
|
if (result < 0)
|
@@ -721,8 +739,11 @@ VALUE Backend_recv_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method)
|
|
721
739
|
|
722
740
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
723
741
|
int completed = context_store_release(&backend->store, ctx);
|
724
|
-
|
725
|
-
|
742
|
+
if (!completed) {
|
743
|
+
context_attach_buffers(ctx, 1, &str);
|
744
|
+
RAISE_IF_EXCEPTION(resume_value);
|
745
|
+
return resume_value;
|
746
|
+
}
|
726
747
|
RB_GC_GUARD(resume_value);
|
727
748
|
|
728
749
|
if (result < 0)
|
@@ -764,8 +785,11 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
764
785
|
|
765
786
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
766
787
|
int completed = context_store_release(&backend->store, ctx);
|
767
|
-
|
768
|
-
|
788
|
+
if (!completed) {
|
789
|
+
context_attach_buffers(ctx, 1, &str);
|
790
|
+
RAISE_IF_EXCEPTION(resume_value);
|
791
|
+
return resume_value;
|
792
|
+
}
|
769
793
|
RB_GC_GUARD(resume_value);
|
770
794
|
|
771
795
|
if (result < 0)
|
@@ -1165,6 +1189,24 @@ struct io_uring_sqe *Backend_chain_prepare_splice(Backend_t *backend, VALUE src,
|
|
1165
1189
|
return sqe;
|
1166
1190
|
}
|
1167
1191
|
|
1192
|
+
void Backend_chain_ctx_attach_buffers(op_context_t *ctx, int argc, VALUE *argv) {
|
1193
|
+
int count = 0;
|
1194
|
+
if (argc > 1) ctx->buffers = malloc(sizeof(VALUE) * (argc - 1));
|
1195
|
+
|
1196
|
+
for (int i = 0; i < argc; i++) {
|
1197
|
+
VALUE op = argv[i];
|
1198
|
+
VALUE op_type = RARRAY_AREF(op, 0);
|
1199
|
+
|
1200
|
+
if (op_type == SYM_write || op_type == SYM_send) {
|
1201
|
+
if (!count) ctx->buffer0 = RARRAY_AREF(op, 2);
|
1202
|
+
else ctx->buffers[count - 1] = RARRAY_AREF(op, 2);
|
1203
|
+
count++;
|
1204
|
+
}
|
1205
|
+
}
|
1206
|
+
ctx->buffer_count = count;
|
1207
|
+
}
|
1208
|
+
|
1209
|
+
|
1168
1210
|
VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
1169
1211
|
VALUE resume_value = Qnil;
|
1170
1212
|
unsigned int sqe_count = 0;
|
@@ -1218,6 +1260,8 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1218
1260
|
int result = ctx->result;
|
1219
1261
|
int completed = context_store_release(&backend->store, ctx);
|
1220
1262
|
if (!completed) {
|
1263
|
+
Backend_chain_ctx_attach_buffers(ctx, argc, argv);
|
1264
|
+
|
1221
1265
|
// op was not completed (an exception was raised), so we need to cancel it
|
1222
1266
|
ctx->result = -ECANCELED;
|
1223
1267
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
@@ -1409,6 +1453,7 @@ syscallerror:
|
|
1409
1453
|
if (pipefd[1] != -1) close(pipefd[1]);
|
1410
1454
|
rb_syserr_fail(err, strerror(err));
|
1411
1455
|
error:
|
1456
|
+
context_attach_buffers_v(ctx, 4, prefix, postfix, chunk_prefix, chunk_postfix);
|
1412
1457
|
if (pipefd[0] != -1) close(pipefd[0]);
|
1413
1458
|
if (pipefd[1] != -1) close(pipefd[1]);
|
1414
1459
|
return RAISE_EXCEPTION(switchpoint_result);
|
@@ -1469,7 +1514,6 @@ void Init_Backend() {
|
|
1469
1514
|
rb_define_method(cBackend, "waitpid", Backend_waitpid, 1);
|
1470
1515
|
rb_define_method(cBackend, "write", Backend_write_m, -1);
|
1471
1516
|
|
1472
|
-
|
1473
1517
|
#ifdef POLYPHONY_UNSET_NONBLOCK
|
1474
1518
|
ID_ivar_is_nonblocking = rb_intern("@is_nonblocking");
|
1475
1519
|
#endif
|
@@ -1480,6 +1524,8 @@ void Init_Backend() {
|
|
1480
1524
|
SYM_write = ID2SYM(rb_intern("write"));
|
1481
1525
|
|
1482
1526
|
backend_setup_stats_symbols();
|
1527
|
+
|
1528
|
+
eArgumentError = rb_const_get(rb_cObject, rb_intern("ArgumentError"));
|
1483
1529
|
}
|
1484
1530
|
|
1485
1531
|
#endif // POLYPHONY_BACKEND_LIBURING
|
@@ -50,6 +50,7 @@ inline op_context_t *context_store_acquire(op_context_store_t *store, enum op_ty
|
|
50
50
|
ctx->resume_value = Qnil;
|
51
51
|
ctx->ref_count = 2;
|
52
52
|
ctx->result = 0;
|
53
|
+
ctx->buffer_count = 0;
|
53
54
|
|
54
55
|
store->taken_count++;
|
55
56
|
|
@@ -67,6 +68,8 @@ inline int context_store_release(op_context_store_t *store, op_context_t *ctx) {
|
|
67
68
|
ctx->ref_count--;
|
68
69
|
if (ctx->ref_count) return 0;
|
69
70
|
|
71
|
+
if (ctx->buffer_count > 1) free(ctx->buffers);
|
72
|
+
|
70
73
|
store->taken_count--;
|
71
74
|
store->available_count++;
|
72
75
|
|
@@ -93,3 +96,42 @@ void context_store_free(op_context_store_t *store) {
|
|
93
96
|
store->taken = next;
|
94
97
|
}
|
95
98
|
}
|
99
|
+
|
100
|
+
inline void context_store_mark_taken_buffers(op_context_store_t *store) {
|
101
|
+
op_context_t *ctx = store->taken;
|
102
|
+
while (ctx) {
|
103
|
+
for (unsigned int i = 0; i < ctx->buffer_count; i++)
|
104
|
+
rb_gc_mark(i == 0 ? ctx->buffer0 : ctx->buffers[i - 1]);
|
105
|
+
ctx = ctx->next;
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
inline void context_attach_buffers(op_context_t *ctx, unsigned int count, VALUE *buffers) {
|
110
|
+
// attaching buffers to the context is done in order to ensure that any GC
|
111
|
+
// pass done before the context is released will mark those buffers, even if
|
112
|
+
// the fiber has already been resumed and the buffers are not in use anymore.
|
113
|
+
// This is done in order to prevent a possible race condition where on the
|
114
|
+
// kernel side the buffers are still in use, but in userspace they have
|
115
|
+
// effectively been freed after a GC pass.
|
116
|
+
ctx->buffer_count = count;
|
117
|
+
if (count > 1)
|
118
|
+
ctx->buffers = malloc(sizeof(VALUE) * (count - 1));
|
119
|
+
for (unsigned int i = 0; i < count; i++)
|
120
|
+
if (!i) ctx->buffer0 = buffers[0];
|
121
|
+
else ctx->buffers[i - 1] = buffers[i];
|
122
|
+
}
|
123
|
+
|
124
|
+
inline void context_attach_buffers_v(op_context_t *ctx, unsigned int count, ...) {
|
125
|
+
va_list values;
|
126
|
+
|
127
|
+
va_start(values, count);
|
128
|
+
|
129
|
+
ctx->buffer_count = count;
|
130
|
+
if (count > 1)
|
131
|
+
ctx->buffers = malloc(sizeof(VALUE) * (count - 1));
|
132
|
+
for (unsigned int i = 0; i < count; i++)
|
133
|
+
if (!i) ctx->buffer0 = va_arg(values, VALUE);
|
134
|
+
else ctx->buffers[i - 1] = va_arg(values, VALUE);
|
135
|
+
|
136
|
+
va_end(values);
|
137
|
+
}
|
@@ -27,6 +27,9 @@ typedef struct op_context {
|
|
27
27
|
int result;
|
28
28
|
VALUE fiber;
|
29
29
|
VALUE resume_value;
|
30
|
+
unsigned int buffer_count;
|
31
|
+
VALUE buffer0;
|
32
|
+
VALUE *buffers;
|
30
33
|
} op_context_t;
|
31
34
|
|
32
35
|
typedef struct op_context_store {
|
@@ -43,14 +46,8 @@ void context_store_initialize(op_context_store_t *store);
|
|
43
46
|
op_context_t *context_store_acquire(op_context_store_t *store, enum op_type type);
|
44
47
|
int context_store_release(op_context_store_t *store, op_context_t *ctx);
|
45
48
|
void context_store_free(op_context_store_t *store);
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
if (ctx->ref_count)
|
50
|
-
ctx->ref_count -= 1;
|
51
|
-
else
|
52
|
-
context_store_release(store, ctx);
|
53
|
-
return completed;
|
54
|
-
}
|
49
|
+
void context_store_mark_taken_buffers(op_context_store_t *store);
|
50
|
+
void context_attach_buffers(op_context_t *ctx, unsigned int count, VALUE *buffers);
|
51
|
+
void context_attach_buffers_v(op_context_t *ctx, unsigned int count, ...);
|
55
52
|
|
56
53
|
#endif /* BACKEND_IO_URING_CONTEXT_H */
|
@@ -941,9 +941,8 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
941
941
|
error:
|
942
942
|
return RAISE_EXCEPTION(switchpoint_result);
|
943
943
|
}
|
944
|
-
#
|
945
|
-
|
946
|
-
VALUE Backend_fake_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
944
|
+
#else
|
945
|
+
VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
947
946
|
Backend_t *backend;
|
948
947
|
struct libev_io watcher;
|
949
948
|
VALUE switchpoint_result = Qnil;
|
@@ -1018,7 +1017,7 @@ error:
|
|
1018
1017
|
return RAISE_EXCEPTION(switchpoint_result);
|
1019
1018
|
}
|
1020
1019
|
|
1021
|
-
VALUE
|
1020
|
+
VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
1022
1021
|
Backend_t *backend;
|
1023
1022
|
struct libev_io watcher;
|
1024
1023
|
VALUE switchpoint_result = Qnil;
|
@@ -1097,6 +1096,7 @@ done:
|
|
1097
1096
|
error:
|
1098
1097
|
return RAISE_EXCEPTION(switchpoint_result);
|
1099
1098
|
}
|
1099
|
+
#endif
|
1100
1100
|
|
1101
1101
|
VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write) {
|
1102
1102
|
Backend_t *backend;
|
@@ -1384,6 +1384,64 @@ inline int splice_chunks_write(Backend_t *backend, int fd, VALUE str, struct lib
|
|
1384
1384
|
return 0;
|
1385
1385
|
}
|
1386
1386
|
|
1387
|
+
static inline int splice_chunks_splice(Backend_t *backend, int src_fd, int dest_fd, int maxlen,
|
1388
|
+
struct libev_rw_io *watcher, VALUE *result, int *chunk_len) {
|
1389
|
+
#ifdef POLYPHONY_LINUX
|
1390
|
+
backend->base.op_count++;
|
1391
|
+
while (1) {
|
1392
|
+
*chunk_len = splice(src_fd, 0, dest_fd, 0, maxlen, 0);
|
1393
|
+
if (*chunk_len >= 0) return 0;
|
1394
|
+
|
1395
|
+
int err = errno;
|
1396
|
+
if (err != EWOULDBLOCK && err != EAGAIN) return err;
|
1397
|
+
|
1398
|
+
*result = libev_wait_rw_fd_with_watcher(backend, src_fd, dest_fd, watcher);
|
1399
|
+
if (TEST_EXCEPTION(*result)) return -1;
|
1400
|
+
}
|
1401
|
+
#else
|
1402
|
+
char *buf = malloc(maxlen);
|
1403
|
+
int ret;
|
1404
|
+
|
1405
|
+
backend->base.op_count++;
|
1406
|
+
while (1) {
|
1407
|
+
*chunk_len = read(src_fd, buf, maxlen);
|
1408
|
+
if (*chunk_len >= 0) break;
|
1409
|
+
|
1410
|
+
ret = errno;
|
1411
|
+
if ((ret != EWOULDBLOCK && ret != EAGAIN)) goto done;
|
1412
|
+
|
1413
|
+
*result = libev_wait_rw_fd_with_watcher(backend, src_fd, -1, watcher);
|
1414
|
+
if (TEST_EXCEPTION(*result)) goto exception;
|
1415
|
+
}
|
1416
|
+
|
1417
|
+
backend->base.op_count++;
|
1418
|
+
char *ptr = buf;
|
1419
|
+
int left = *chunk_len;
|
1420
|
+
while (left > 0) {
|
1421
|
+
ssize_t n = write(dest_fd, ptr, left);
|
1422
|
+
if (n < 0) {
|
1423
|
+
ret = errno;
|
1424
|
+
if ((ret != EWOULDBLOCK && ret != EAGAIN)) goto done;
|
1425
|
+
|
1426
|
+
*result = libev_wait_rw_fd_with_watcher(backend, -1, dest_fd, watcher);
|
1427
|
+
|
1428
|
+
if (TEST_EXCEPTION(*result)) goto exception;
|
1429
|
+
}
|
1430
|
+
else {
|
1431
|
+
ptr += n;
|
1432
|
+
left -= n;
|
1433
|
+
}
|
1434
|
+
}
|
1435
|
+
ret = 0;
|
1436
|
+
goto done;
|
1437
|
+
exception:
|
1438
|
+
ret = -1;
|
1439
|
+
done:
|
1440
|
+
free(buf);
|
1441
|
+
return ret;
|
1442
|
+
#endif
|
1443
|
+
}
|
1444
|
+
|
1387
1445
|
VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VALUE postfix, VALUE chunk_prefix, VALUE chunk_postfix, VALUE chunk_size) {
|
1388
1446
|
Backend_t *backend;
|
1389
1447
|
GetBackend(self, backend);
|
@@ -1421,26 +1479,13 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1421
1479
|
fcntl(pipefd[1], F_SETFL, O_NONBLOCK);
|
1422
1480
|
|
1423
1481
|
if (prefix != Qnil) {
|
1424
|
-
|
1482
|
+
err = splice_chunks_write(backend, dest_fptr->fd, prefix, &watcher, &result);
|
1425
1483
|
if (err == -1) goto error; else if (err) goto syscallerror;
|
1426
1484
|
}
|
1427
1485
|
while (1) {
|
1428
|
-
int chunk_len;
|
1429
|
-
|
1430
|
-
|
1431
|
-
backend->base.op_count++;
|
1432
|
-
chunk_len = splice(src_fptr->fd, 0, pipefd[1], 0, maxlen, 0);
|
1433
|
-
if (chunk_len < 0) {
|
1434
|
-
err = errno;
|
1435
|
-
if (err != EWOULDBLOCK && err != EAGAIN) goto syscallerror;
|
1436
|
-
|
1437
|
-
result = libev_wait_rw_fd_with_watcher(backend, src_fptr->fd, pipefd[1], &watcher);
|
1438
|
-
if (TEST_EXCEPTION(result)) goto error;
|
1439
|
-
}
|
1440
|
-
else {
|
1441
|
-
break;
|
1442
|
-
}
|
1443
|
-
}
|
1486
|
+
int chunk_len = 0;
|
1487
|
+
err = splice_chunks_splice(backend, src_fptr->fd, pipefd[1], maxlen, &watcher, &result, &chunk_len);
|
1488
|
+
if (err == -1) goto error; else if (err) goto syscallerror;
|
1444
1489
|
if (chunk_len == 0) break;
|
1445
1490
|
|
1446
1491
|
total += chunk_len;
|
@@ -1453,20 +1498,12 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1453
1498
|
}
|
1454
1499
|
|
1455
1500
|
int left = chunk_len;
|
1456
|
-
while (
|
1457
|
-
|
1458
|
-
|
1459
|
-
if (
|
1460
|
-
err = errno;
|
1461
|
-
if (err != EWOULDBLOCK && err != EAGAIN) goto syscallerror;
|
1501
|
+
while (left > 0) {
|
1502
|
+
int len;
|
1503
|
+
err = splice_chunks_splice(backend, pipefd[0], dest_fptr->fd, left, &watcher, &result, &len);
|
1504
|
+
if (err == -1) goto error; else if (err) goto syscallerror;
|
1462
1505
|
|
1463
|
-
|
1464
|
-
if (TEST_EXCEPTION(result)) goto error;
|
1465
|
-
}
|
1466
|
-
else {
|
1467
|
-
left -= n;
|
1468
|
-
if (left == 0) break;
|
1469
|
-
}
|
1506
|
+
left -= len;
|
1470
1507
|
}
|
1471
1508
|
|
1472
1509
|
if (chunk_postfix != Qnil) {
|
@@ -1550,13 +1587,8 @@ void Init_Backend() {
|
|
1550
1587
|
rb_define_method(cBackend, "sendv", Backend_sendv, 3);
|
1551
1588
|
rb_define_method(cBackend, "sleep", Backend_sleep, 1);
|
1552
1589
|
|
1553
|
-
#ifdef POLYPHONY_LINUX
|
1554
1590
|
rb_define_method(cBackend, "splice", Backend_splice, 3);
|
1555
1591
|
rb_define_method(cBackend, "splice_to_eof", Backend_splice_to_eof, 3);
|
1556
|
-
#else
|
1557
|
-
rb_define_method(cBackend, "splice", Backend_fake_splice, 3);
|
1558
|
-
rb_define_method(cBackend, "splice_to_eof", Backend_fake_splice_to_eof, 3);
|
1559
|
-
#endif
|
1560
1592
|
|
1561
1593
|
rb_define_method(cBackend, "timeout", Backend_timeout, -1);
|
1562
1594
|
rb_define_method(cBackend, "timer_loop", Backend_timer_loop, 1);
|
data/ext/polyphony/queue.c
CHANGED
@@ -78,7 +78,7 @@ inline void queue_schedule_blocked_fibers_to_capacity(Queue_t *queue) {
|
|
78
78
|
}
|
79
79
|
}
|
80
80
|
|
81
|
-
inline void capped_queue_block_push(Queue_t *queue) {
|
81
|
+
static inline void capped_queue_block_push(Queue_t *queue) {
|
82
82
|
VALUE fiber = rb_fiber_current();
|
83
83
|
VALUE backend = rb_ivar_get(rb_thread_current(), ID_ivar_backend);
|
84
84
|
VALUE switchpoint_result;
|
data/ext/polyphony/runqueue.c
CHANGED
@@ -44,15 +44,15 @@ inline void runqueue_clear(runqueue_t *runqueue) {
|
|
44
44
|
runqueue_ring_buffer_clear(&runqueue->entries);
|
45
45
|
}
|
46
46
|
|
47
|
-
inline
|
47
|
+
inline unsigned int runqueue_size(runqueue_t *runqueue) {
|
48
48
|
return runqueue->entries.size;
|
49
49
|
}
|
50
50
|
|
51
|
-
inline
|
51
|
+
inline unsigned int runqueue_len(runqueue_t *runqueue) {
|
52
52
|
return runqueue->entries.count;
|
53
53
|
}
|
54
54
|
|
55
|
-
inline
|
55
|
+
inline unsigned int runqueue_max_len(runqueue_t *runqueue) {
|
56
56
|
unsigned int max_len = runqueue->high_watermark;
|
57
57
|
runqueue->high_watermark = 0;
|
58
58
|
return max_len;
|
data/ext/polyphony/runqueue.h
CHANGED
@@ -19,9 +19,9 @@ runqueue_entry runqueue_shift(runqueue_t *runqueue);
|
|
19
19
|
void runqueue_delete(runqueue_t *runqueue, VALUE fiber);
|
20
20
|
int runqueue_index_of(runqueue_t *runqueue, VALUE fiber);
|
21
21
|
void runqueue_clear(runqueue_t *runqueue);
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
unsigned int runqueue_size(runqueue_t *runqueue);
|
23
|
+
unsigned int runqueue_len(runqueue_t *runqueue);
|
24
|
+
unsigned int runqueue_max_len(runqueue_t *runqueue);
|
25
25
|
int runqueue_empty_p(runqueue_t *runqueue);
|
26
26
|
|
27
27
|
#endif /* RUNQUEUE_H */
|
@@ -76,6 +76,10 @@ end
|
|
76
76
|
|
77
77
|
# IO instance method patches
|
78
78
|
class ::IO
|
79
|
+
def __polyphony_read_method__
|
80
|
+
:backend_read
|
81
|
+
end
|
82
|
+
|
79
83
|
# def each(sep = $/, limit = nil, chomp: nil)
|
80
84
|
# sep, limit = $/, sep if sep.is_a?(Integer)
|
81
85
|
# end
|
@@ -108,7 +112,11 @@ class ::IO
|
|
108
112
|
end
|
109
113
|
|
110
114
|
alias_method :orig_read, :read
|
111
|
-
def read(len = nil)
|
115
|
+
def read(len = nil, buf = nil, buf_pos = 0)
|
116
|
+
if buf
|
117
|
+
return Polyphony.backend_read(self, buf, len, true, buf_pos)
|
118
|
+
end
|
119
|
+
|
112
120
|
@read_buffer ||= +''
|
113
121
|
result = Polyphony.backend_read(self, @read_buffer, len, true, -1)
|
114
122
|
return nil unless result
|
@@ -119,9 +127,9 @@ class ::IO
|
|
119
127
|
end
|
120
128
|
|
121
129
|
alias_method :orig_readpartial, :read
|
122
|
-
def readpartial(len, str = +'', buffer_pos = 0)
|
130
|
+
def readpartial(len, str = +'', buffer_pos = 0, raise_on_eof = true)
|
123
131
|
result = Polyphony.backend_read(self, str, len, false, buffer_pos)
|
124
|
-
raise EOFError
|
132
|
+
raise EOFError if !result && raise_on_eof
|
125
133
|
|
126
134
|
result
|
127
135
|
end
|
@@ -5,6 +5,10 @@ require_relative './socket'
|
|
5
5
|
|
6
6
|
# OpenSSL socket helper methods (to make it compatible with Socket API) and overrides
|
7
7
|
class ::OpenSSL::SSL::SSLSocket
|
8
|
+
def __polyphony_read_method__
|
9
|
+
:readpartial
|
10
|
+
end
|
11
|
+
|
8
12
|
alias_method :orig_initialize, :initialize
|
9
13
|
def initialize(socket, context = nil)
|
10
14
|
socket = socket.respond_to?(:io) ? socket.io || socket : socket
|
@@ -64,7 +68,21 @@ class ::OpenSSL::SSL::SSLSocket
|
|
64
68
|
# @sync = osync
|
65
69
|
end
|
66
70
|
|
67
|
-
|
71
|
+
alias_method :orig_read, :read
|
72
|
+
def read(maxlen = nil, buf = nil, buf_pos = 0)
|
73
|
+
return readpartial(maxlen, buf, buf_pos) if buf
|
74
|
+
|
75
|
+
buf = +''
|
76
|
+
return readpartial(maxlen, buf) if maxlen
|
77
|
+
|
78
|
+
while true
|
79
|
+
readpartial(4096, buf, -1)
|
80
|
+
end
|
81
|
+
rescue EOFError
|
82
|
+
buf
|
83
|
+
end
|
84
|
+
|
85
|
+
def readpartial(maxlen, buf = +'', buffer_pos = 0, raise_on_eof = true)
|
68
86
|
if buffer_pos != 0
|
69
87
|
if (result = sysread(maxlen, +''))
|
70
88
|
if buffer_pos == -1
|
@@ -76,7 +94,9 @@ class ::OpenSSL::SSL::SSLSocket
|
|
76
94
|
else
|
77
95
|
result = sysread(maxlen, buf)
|
78
96
|
end
|
79
|
-
|
97
|
+
|
98
|
+
raise EOFError if !result && raise_on_eof
|
99
|
+
result
|
80
100
|
end
|
81
101
|
|
82
102
|
def read_loop(maxlen = 8192)
|
@@ -5,6 +5,12 @@ require 'socket'
|
|
5
5
|
require_relative './io'
|
6
6
|
require_relative '../core/thread_pool'
|
7
7
|
|
8
|
+
class BasicSocket
|
9
|
+
def __polyphony_read_method__
|
10
|
+
:backend_recv
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
8
14
|
# Socket overrides (eventually rewritten in C)
|
9
15
|
class ::Socket
|
10
16
|
def accept
|
@@ -22,6 +28,23 @@ class ::Socket
|
|
22
28
|
Polyphony.backend_connect(self, addr.ip_address, addr.ip_port)
|
23
29
|
end
|
24
30
|
|
31
|
+
alias_method :orig_read, :read
|
32
|
+
def read(maxlen = nil, buf = nil, buf_pos = 0)
|
33
|
+
return Polyphony.backend_recv(self, buf, maxlen, buf_pos) if buf
|
34
|
+
return Polyphony.backend_recv(self, buf || +'', maxlen, 0) if maxlen
|
35
|
+
|
36
|
+
buf = +''
|
37
|
+
len = buf.bytesize
|
38
|
+
while true
|
39
|
+
Polyphony.backend_recv(self, buf, maxlen || 4096, -1)
|
40
|
+
new_len = buf.bytesize
|
41
|
+
break if new_len == len
|
42
|
+
|
43
|
+
len = new_len
|
44
|
+
end
|
45
|
+
buf
|
46
|
+
end
|
47
|
+
|
25
48
|
def recv(maxlen, flags = 0, outbuf = nil)
|
26
49
|
Polyphony.backend_recv(self, outbuf || +'', maxlen, 0)
|
27
50
|
end
|
@@ -60,8 +83,9 @@ class ::Socket
|
|
60
83
|
# Polyphony.backend_send(self, mesg, 0)
|
61
84
|
# end
|
62
85
|
|
63
|
-
def readpartial(maxlen, str = +'', buffer_pos = 0)
|
64
|
-
Polyphony.backend_recv(self, str, maxlen, buffer_pos)
|
86
|
+
def readpartial(maxlen, str = +'', buffer_pos = 0, raise_on_eof = true)
|
87
|
+
result = Polyphony.backend_recv(self, str, maxlen, buffer_pos)
|
88
|
+
raise EOFError if !result && raise_on_eof
|
65
89
|
end
|
66
90
|
|
67
91
|
ZERO_LINGER = [0, 0].pack('ii').freeze
|
@@ -140,6 +164,23 @@ class ::TCPSocket
|
|
140
164
|
setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEPORT, 1)
|
141
165
|
end
|
142
166
|
|
167
|
+
alias_method :orig_read, :read
|
168
|
+
def read(maxlen = nil, buf = nil, buf_pos = 0)
|
169
|
+
return Polyphony.backend_recv(self, buf, maxlen, buf_pos) if buf
|
170
|
+
return Polyphony.backend_recv(self, buf || +'', maxlen, 0) if maxlen
|
171
|
+
|
172
|
+
buf = +''
|
173
|
+
len = buf.bytesize
|
174
|
+
while true
|
175
|
+
Polyphony.backend_recv(self, buf, maxlen || 4096, -1)
|
176
|
+
new_len = buf.bytesize
|
177
|
+
break if new_len == len
|
178
|
+
|
179
|
+
len = new_len
|
180
|
+
end
|
181
|
+
buf
|
182
|
+
end
|
183
|
+
|
143
184
|
def recv(maxlen, flags = 0, outbuf = nil)
|
144
185
|
Polyphony.backend_recv(self, outbuf || +'', maxlen, 0)
|
145
186
|
end
|
@@ -165,11 +206,10 @@ class ::TCPSocket
|
|
165
206
|
# Polyphony.backend_send(self, mesg, 0)
|
166
207
|
# end
|
167
208
|
|
168
|
-
def readpartial(maxlen, str = +'', buffer_pos = 0)
|
209
|
+
def readpartial(maxlen, str = +'', buffer_pos = 0, raise_on_eof)
|
169
210
|
result = Polyphony.backend_recv(self, str, maxlen, buffer_pos)
|
170
|
-
raise EOFError
|
171
|
-
|
172
|
-
str
|
211
|
+
raise EOFError if !result && raise_on_eof
|
212
|
+
result
|
173
213
|
end
|
174
214
|
|
175
215
|
def read_nonblock(len, str = nil, exception: true)
|
@@ -217,6 +257,23 @@ class ::UNIXServer
|
|
217
257
|
end
|
218
258
|
|
219
259
|
class ::UNIXSocket
|
260
|
+
alias_method :orig_read, :read
|
261
|
+
def read(maxlen = nil, buf = nil, buf_pos = 0)
|
262
|
+
return Polyphony.backend_recv(self, buf, maxlen, buf_pos) if buf
|
263
|
+
return Polyphony.backend_recv(self, buf || +'', maxlen, 0) if maxlen
|
264
|
+
|
265
|
+
buf = +''
|
266
|
+
len = buf.bytesize
|
267
|
+
while true
|
268
|
+
Polyphony.backend_recv(self, buf, maxlen || 4096, -1)
|
269
|
+
new_len = buf.bytesize
|
270
|
+
break if new_len == len
|
271
|
+
|
272
|
+
len = new_len
|
273
|
+
end
|
274
|
+
buf
|
275
|
+
end
|
276
|
+
|
220
277
|
def recv(maxlen, flags = 0, outbuf = nil)
|
221
278
|
Polyphony.backend_recv(self, outbuf || +'', maxlen, 0)
|
222
279
|
end
|
@@ -242,11 +299,10 @@ class ::UNIXSocket
|
|
242
299
|
Polyphony.backend_send(self, mesg, 0)
|
243
300
|
end
|
244
301
|
|
245
|
-
def readpartial(maxlen, str = +'', buffer_pos = 0)
|
302
|
+
def readpartial(maxlen, str = +'', buffer_pos = 0, raise_on_eof)
|
246
303
|
result = Polyphony.backend_recv(self, str, maxlen, buffer_pos)
|
247
|
-
raise EOFError
|
248
|
-
|
249
|
-
str
|
304
|
+
raise EOFError if !result && raise_on_eof
|
305
|
+
result
|
250
306
|
end
|
251
307
|
|
252
308
|
def read_nonblock(len, str = nil, exception: true)
|
data/lib/polyphony/version.rb
CHANGED
data/test/helper.rb
CHANGED
data/test/test_backend.rb
CHANGED
@@ -26,7 +26,7 @@ class BackendTest < MiniTest::Test
|
|
26
26
|
@backend.sleep 0.01
|
27
27
|
count += 1
|
28
28
|
}.await
|
29
|
-
assert_in_range 0.02..0.
|
29
|
+
assert_in_range 0.02..0.06, Time.now - t0 if IS_LINUX
|
30
30
|
assert_equal 3, count
|
31
31
|
end
|
32
32
|
|
@@ -98,6 +98,32 @@ class BackendTest < MiniTest::Test
|
|
98
98
|
assert_equal return_value, buf
|
99
99
|
end
|
100
100
|
|
101
|
+
def test_read_concat_big
|
102
|
+
i, o = IO.pipe
|
103
|
+
|
104
|
+
body = " " * 4000
|
105
|
+
|
106
|
+
data = "post /?q=time&blah=blah HTTP/1\r\nHost: dev.realiteq.net\r\n\r\n" +
|
107
|
+
"get /?q=time HTTP/1.1\r\nContent-Length: #{body.bytesize}\r\n\r\n#{body}" +
|
108
|
+
"get /?q=time HTTP/1.1\r\nCookie: foo\r\nCookie: bar\r\n\r\n"
|
109
|
+
|
110
|
+
o << data
|
111
|
+
o.close
|
112
|
+
|
113
|
+
buf = +''
|
114
|
+
|
115
|
+
@backend.read(i, buf, 4096, false, -1)
|
116
|
+
assert_equal 4096, buf.bytesize
|
117
|
+
|
118
|
+
@backend.read(i, buf, 1, false, -1)
|
119
|
+
assert_equal 4097, buf.bytesize
|
120
|
+
|
121
|
+
@backend.read(i, buf, 4096, false, -1)
|
122
|
+
|
123
|
+
assert_equal data.bytesize, buf.bytesize
|
124
|
+
assert_equal data, buf
|
125
|
+
end
|
126
|
+
|
101
127
|
def test_waitpid
|
102
128
|
pid = fork do
|
103
129
|
@backend.post_fork
|
@@ -217,6 +243,8 @@ class BackendTest < MiniTest::Test
|
|
217
243
|
end
|
218
244
|
|
219
245
|
def test_timer_loop
|
246
|
+
skip unless IS_LINUX
|
247
|
+
|
220
248
|
i = 0
|
221
249
|
f = spin do
|
222
250
|
@backend.timer_loop(0.01) { i += 1 }
|
@@ -231,6 +259,8 @@ class BackendTest < MiniTest::Test
|
|
231
259
|
end
|
232
260
|
|
233
261
|
def test_timeout
|
262
|
+
skip unless IS_LINUX
|
263
|
+
|
234
264
|
buffer = []
|
235
265
|
assert_raises(Polyphony::TimeoutException) do
|
236
266
|
@backend.timeout(0.01, Polyphony::TimeoutException) do
|
@@ -262,6 +292,8 @@ class BackendTest < MiniTest::Test
|
|
262
292
|
end
|
263
293
|
|
264
294
|
def test_nested_timeout
|
295
|
+
skip unless IS_LINUX
|
296
|
+
|
265
297
|
buffer = []
|
266
298
|
assert_raises(MyTimeoutException) do
|
267
299
|
@backend.timeout(0.01, MyTimeoutException) do
|
@@ -321,8 +353,8 @@ class BackendTest < MiniTest::Test
|
|
321
353
|
|
322
354
|
|
323
355
|
def test_splice_chunks
|
324
|
-
body = 'abcd' *
|
325
|
-
chunk_size =
|
356
|
+
body = 'abcd' * 4
|
357
|
+
chunk_size = 12
|
326
358
|
|
327
359
|
buf = +''
|
328
360
|
r, w = IO.pipe
|
@@ -347,7 +379,7 @@ class BackendTest < MiniTest::Test
|
|
347
379
|
w.close
|
348
380
|
reader.await
|
349
381
|
|
350
|
-
expected = "Content-Type: foo\r\n\r\n#{
|
382
|
+
expected = "Content-Type: foo\r\n\r\n#{12.to_s(16)}\r\n#{body[0..11]}\r\n#{4.to_s(16)}\r\n#{body[12..15]}\r\n0\r\n\r\n"
|
351
383
|
assert_equal expected, buf
|
352
384
|
ensure
|
353
385
|
o.close
|
@@ -368,6 +400,9 @@ class BackendTest < MiniTest::Test
|
|
368
400
|
assert_equal count, GC.count
|
369
401
|
sleep 0.05
|
370
402
|
assert_equal count, GC.count
|
403
|
+
|
404
|
+
return unless IS_LINUX
|
405
|
+
|
371
406
|
# The idle tasks are ran at most once per fiber switch, before the backend
|
372
407
|
# is polled. Therefore, the second sleep will not have triggered a GC, since
|
373
408
|
# only 0.05s have passed since the gc period was set.
|
data/test/test_global_api.rb
CHANGED
@@ -137,7 +137,7 @@ class MoveOnAfterTest < MiniTest::Test
|
|
137
137
|
t1 = Time.now
|
138
138
|
|
139
139
|
assert_nil v
|
140
|
-
assert_in_range 0.014..0.02, t1 - t0
|
140
|
+
assert_in_range 0.014..0.02, t1 - t0 if IS_LINUX
|
141
141
|
end
|
142
142
|
|
143
143
|
def test_move_on_after_without_block
|
@@ -152,6 +152,8 @@ class MoveOnAfterTest < MiniTest::Test
|
|
152
152
|
end
|
153
153
|
|
154
154
|
def test_nested_move_on_after
|
155
|
+
skip unless IS_LINUX
|
156
|
+
|
155
157
|
t0 = Time.now
|
156
158
|
o = move_on_after(0.01, with_value: 1) do
|
157
159
|
move_on_after(0.02, with_value: 2) do
|
@@ -210,7 +212,7 @@ class CancelAfterTest < MiniTest::Test
|
|
210
212
|
sleep 0.007
|
211
213
|
end
|
212
214
|
t1 = Time.now
|
213
|
-
assert_in_range 0.014..0.024, t1 - t0
|
215
|
+
assert_in_range 0.014..0.024, t1 - t0 if IS_LINUX
|
214
216
|
end
|
215
217
|
|
216
218
|
class CustomException < Exception
|
@@ -399,7 +401,7 @@ class ThrottledLoopTest < MiniTest::Test
|
|
399
401
|
end
|
400
402
|
f.await
|
401
403
|
t1 = Time.now
|
402
|
-
assert_in_range 0.075..0.15, t1 - t0
|
404
|
+
assert_in_range 0.075..0.15, t1 - t0 if IS_LINUX
|
403
405
|
assert_equal [1, 2, 3, 4, 5], buffer
|
404
406
|
end
|
405
407
|
end
|
@@ -415,6 +417,8 @@ class GlobalAPIEtcTest < MiniTest::Test
|
|
415
417
|
end
|
416
418
|
|
417
419
|
def test_every
|
420
|
+
skip unless IS_LINUX
|
421
|
+
|
418
422
|
buffer = []
|
419
423
|
t0 = Time.now
|
420
424
|
f = spin do
|
@@ -429,7 +433,7 @@ class GlobalAPIEtcTest < MiniTest::Test
|
|
429
433
|
t0 = Time.now
|
430
434
|
sleep 0.1
|
431
435
|
elapsed = Time.now - t0
|
432
|
-
assert (0.05..0.15).include? elapsed
|
436
|
+
assert (0.05..0.15).include? elapsed if IS_LINUX
|
433
437
|
|
434
438
|
f = spin { sleep }
|
435
439
|
snooze
|
data/test/test_io.rb
CHANGED
@@ -73,6 +73,26 @@ class IOTest < MiniTest::Test
|
|
73
73
|
assert_equal [:wait_readable, 'foo'], results
|
74
74
|
end
|
75
75
|
|
76
|
+
def test_read
|
77
|
+
i, o = IO.pipe
|
78
|
+
|
79
|
+
o << 'hi'
|
80
|
+
assert_equal 'hi', i.read(2)
|
81
|
+
|
82
|
+
o << 'foobarbaz'
|
83
|
+
assert_equal 'foo', i.read(3)
|
84
|
+
assert_equal 'bar', i.read(3)
|
85
|
+
|
86
|
+
buf = +'abc'
|
87
|
+
assert_equal 'baz', i.read(3, buf)
|
88
|
+
assert_equal 'baz', buf
|
89
|
+
|
90
|
+
buf = +'def'
|
91
|
+
o << 'foobar'
|
92
|
+
assert_equal 'deffoobar', i.read(6, buf, -1)
|
93
|
+
assert_equal 'deffoobar', buf
|
94
|
+
end
|
95
|
+
|
76
96
|
def test_readpartial
|
77
97
|
i, o = IO.pipe
|
78
98
|
|
@@ -331,6 +351,8 @@ class IOClassMethodsTest < MiniTest::Test
|
|
331
351
|
end
|
332
352
|
|
333
353
|
def test_popen
|
354
|
+
skip unless IS_LINUX
|
355
|
+
|
334
356
|
counter = 0
|
335
357
|
timer = spin { throttled_loop(200) { counter += 1 } }
|
336
358
|
|
data/test/test_socket.rb
CHANGED
@@ -12,7 +12,6 @@ class SocketTest < MiniTest::Test
|
|
12
12
|
def test_tcp
|
13
13
|
port = rand(1234..5678)
|
14
14
|
server = TCPServer.new('127.0.0.1', port)
|
15
|
-
|
16
15
|
server_fiber = spin do
|
17
16
|
while (socket = server.accept)
|
18
17
|
spin do
|
@@ -34,6 +33,45 @@ class SocketTest < MiniTest::Test
|
|
34
33
|
server&.close
|
35
34
|
end
|
36
35
|
|
36
|
+
def test_read
|
37
|
+
port = rand(1234..5678)
|
38
|
+
server = TCPServer.new('127.0.0.1', port)
|
39
|
+
server_fiber = spin do
|
40
|
+
while (socket = server.accept)
|
41
|
+
spin do
|
42
|
+
while (data = socket.read(8192))
|
43
|
+
socket << data
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
snooze
|
50
|
+
client = TCPSocket.new('127.0.0.1', port)
|
51
|
+
|
52
|
+
client << 'hi'
|
53
|
+
assert_equal 'hi', client.read(2)
|
54
|
+
|
55
|
+
client << 'foobarbaz'
|
56
|
+
assert_equal 'foo', client.read(3)
|
57
|
+
assert_equal 'bar', client.read(3)
|
58
|
+
|
59
|
+
buf = +'abc'
|
60
|
+
assert_equal 'baz', client.read(3, buf)
|
61
|
+
assert_equal 'baz', buf
|
62
|
+
|
63
|
+
buf = +'def'
|
64
|
+
client << 'foobar'
|
65
|
+
assert_equal 'deffoobar', client.read(6, buf, -1)
|
66
|
+
assert_equal 'deffoobar', buf
|
67
|
+
|
68
|
+
client.close
|
69
|
+
ensure
|
70
|
+
server_fiber&.stop
|
71
|
+
server_fiber&.await
|
72
|
+
server&.close
|
73
|
+
end
|
74
|
+
|
37
75
|
# sending multiple strings at once
|
38
76
|
def test_sendv
|
39
77
|
port = rand(1234..5678)
|
@@ -120,19 +158,22 @@ class SocketTest < MiniTest::Test
|
|
120
158
|
end
|
121
159
|
end
|
122
160
|
|
123
|
-
|
124
|
-
|
161
|
+
if IS_LINUX
|
162
|
+
class HTTPClientTest < MiniTest::Test
|
125
163
|
|
126
|
-
|
127
|
-
res = HTTParty.get('http://ipinfo.io/')
|
164
|
+
require 'json'
|
128
165
|
|
129
|
-
|
130
|
-
|
131
|
-
end
|
166
|
+
def test_http
|
167
|
+
res = HTTParty.get('http://ipinfo.io/')
|
132
168
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
169
|
+
response = JSON.load(res.body)
|
170
|
+
assert_equal 'https://ipinfo.io/missingauth', response['readme']
|
171
|
+
end
|
172
|
+
|
173
|
+
def test_https
|
174
|
+
res = HTTParty.get('https://ipinfo.io/')
|
175
|
+
response = JSON.load(res.body)
|
176
|
+
assert_equal 'https://ipinfo.io/missingauth', response['readme']
|
177
|
+
end
|
137
178
|
end
|
138
179
|
end
|
data/test/test_thread.rb
CHANGED
@@ -180,6 +180,9 @@ class ThreadTest < MiniTest::Test
|
|
180
180
|
assert_equal count, GC.count
|
181
181
|
sleep 0.05
|
182
182
|
assert_equal count, GC.count
|
183
|
+
|
184
|
+
return unless IS_LINUX
|
185
|
+
|
183
186
|
# The idle tasks are ran at most once per fiber switch, before the backend
|
184
187
|
# is polled. Therefore, the second sleep will not have triggered a GC, since
|
185
188
|
# only 0.05s have passed since the gc period was set.
|
data/test/test_timer.rb
CHANGED
@@ -19,7 +19,7 @@ class TimerMoveOnAfterTest < MiniTest::Test
|
|
19
19
|
end
|
20
20
|
t1 = Time.now
|
21
21
|
|
22
|
-
assert_in_range 0.1..0.15, t1 - t0
|
22
|
+
assert_in_range 0.1..0.15, t1 - t0 if IS_LINUX
|
23
23
|
assert_nil v
|
24
24
|
end
|
25
25
|
|
@@ -31,11 +31,13 @@ class TimerMoveOnAfterTest < MiniTest::Test
|
|
31
31
|
end
|
32
32
|
t1 = Time.now
|
33
33
|
|
34
|
-
assert_in_range 0.01..0.05, t1 - t0
|
34
|
+
assert_in_range 0.01..0.05, t1 - t0 if IS_LINUX
|
35
35
|
assert_equal :bar, v
|
36
36
|
end
|
37
37
|
|
38
38
|
def test_timer_move_on_after_with_reset
|
39
|
+
skip unless IS_LINUX
|
40
|
+
|
39
41
|
t0 = Time.now
|
40
42
|
v = @timer.move_on_after(0.01, with_value: :moved_on) do
|
41
43
|
sleep 0.007
|
@@ -71,7 +73,7 @@ class TimerCancelAfterTest < MiniTest::Test
|
|
71
73
|
end
|
72
74
|
end
|
73
75
|
t1 = Time.now
|
74
|
-
assert_in_range 0.01..0.03, t1 - t0
|
76
|
+
assert_in_range 0.01..0.03, t1 - t0 if IS_LINUX
|
75
77
|
end
|
76
78
|
|
77
79
|
def test_timer_cancel_after_with_reset
|
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.66'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-08-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|