polyphony 0.65 → 0.66
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.yml +1 -1
- data/CHANGELOG.md +5 -0
- data/Gemfile.lock +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/version.rb +1 -1
- data/test/helper.rb +2 -0
- data/test/test_backend.rb +13 -4
- data/test/test_global_api.rb +8 -4
- data/test/test_io.rb +2 -0
- data/test/test_socket.rb +14 -11
- 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
data/Gemfile.lock
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 */
|
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
|
|
@@ -243,6 +243,8 @@ class BackendTest < MiniTest::Test
|
|
243
243
|
end
|
244
244
|
|
245
245
|
def test_timer_loop
|
246
|
+
skip unless IS_LINUX
|
247
|
+
|
246
248
|
i = 0
|
247
249
|
f = spin do
|
248
250
|
@backend.timer_loop(0.01) { i += 1 }
|
@@ -257,6 +259,8 @@ class BackendTest < MiniTest::Test
|
|
257
259
|
end
|
258
260
|
|
259
261
|
def test_timeout
|
262
|
+
skip unless IS_LINUX
|
263
|
+
|
260
264
|
buffer = []
|
261
265
|
assert_raises(Polyphony::TimeoutException) do
|
262
266
|
@backend.timeout(0.01, Polyphony::TimeoutException) do
|
@@ -288,6 +292,8 @@ class BackendTest < MiniTest::Test
|
|
288
292
|
end
|
289
293
|
|
290
294
|
def test_nested_timeout
|
295
|
+
skip unless IS_LINUX
|
296
|
+
|
291
297
|
buffer = []
|
292
298
|
assert_raises(MyTimeoutException) do
|
293
299
|
@backend.timeout(0.01, MyTimeoutException) do
|
@@ -347,8 +353,8 @@ class BackendTest < MiniTest::Test
|
|
347
353
|
|
348
354
|
|
349
355
|
def test_splice_chunks
|
350
|
-
body = 'abcd' *
|
351
|
-
chunk_size =
|
356
|
+
body = 'abcd' * 4
|
357
|
+
chunk_size = 12
|
352
358
|
|
353
359
|
buf = +''
|
354
360
|
r, w = IO.pipe
|
@@ -373,7 +379,7 @@ class BackendTest < MiniTest::Test
|
|
373
379
|
w.close
|
374
380
|
reader.await
|
375
381
|
|
376
|
-
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"
|
377
383
|
assert_equal expected, buf
|
378
384
|
ensure
|
379
385
|
o.close
|
@@ -394,6 +400,9 @@ class BackendTest < MiniTest::Test
|
|
394
400
|
assert_equal count, GC.count
|
395
401
|
sleep 0.05
|
396
402
|
assert_equal count, GC.count
|
403
|
+
|
404
|
+
return unless IS_LINUX
|
405
|
+
|
397
406
|
# The idle tasks are ran at most once per fiber switch, before the backend
|
398
407
|
# is polled. Therefore, the second sleep will not have triggered a GC, since
|
399
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
data/test/test_socket.rb
CHANGED
@@ -158,19 +158,22 @@ class SocketTest < MiniTest::Test
|
|
158
158
|
end
|
159
159
|
end
|
160
160
|
|
161
|
-
|
162
|
-
|
161
|
+
if IS_LINUX
|
162
|
+
class HTTPClientTest < MiniTest::Test
|
163
163
|
|
164
|
-
|
165
|
-
res = HTTParty.get('http://ipinfo.io/')
|
164
|
+
require 'json'
|
166
165
|
|
167
|
-
|
168
|
-
|
169
|
-
|
166
|
+
def test_http
|
167
|
+
res = HTTParty.get('http://ipinfo.io/')
|
168
|
+
|
169
|
+
response = JSON.load(res.body)
|
170
|
+
assert_equal 'https://ipinfo.io/missingauth', response['readme']
|
171
|
+
end
|
170
172
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
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
|
175
178
|
end
|
176
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
|