polyphony 0.68 → 0.72
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/FUNDING.yml +1 -0
- data/CHANGELOG.md +32 -5
- data/Gemfile.lock +2 -2
- data/TODO.md +1 -24
- data/bin/pdbg +1 -1
- data/bin/polyphony-debug +0 -0
- data/bin/stress.rb +0 -0
- data/bin/test +0 -0
- data/docs/_user-guide/all-about-timers.md +1 -1
- data/docs/api-reference/fiber.md +2 -2
- data/docs/faq.md +1 -1
- data/docs/getting-started/overview.md +8 -8
- data/docs/getting-started/tutorial.md +3 -3
- data/docs/main-concepts/concurrency.md +1 -1
- data/docs/main-concepts/extending.md +3 -3
- data/docs/main-concepts/fiber-scheduling.md +1 -1
- data/examples/core/calc.rb +37 -0
- data/examples/core/calc_with_restart.rb +40 -0
- data/examples/core/calc_with_supervise.rb +37 -0
- data/examples/core/message_based_supervision.rb +1 -1
- data/examples/io/rack_server.rb +1 -1
- data/examples/io/tunnel.rb +1 -1
- data/examples/performance/fiber_transfer.rb +1 -1
- data/examples/performance/line_splitting.rb +1 -1
- data/examples/performance/thread-vs-fiber/compare.rb +1 -1
- data/ext/polyphony/backend_common.c +24 -6
- data/ext/polyphony/backend_common.h +1 -0
- data/ext/polyphony/backend_io_uring.c +27 -40
- data/ext/polyphony/backend_io_uring_context.c +1 -1
- data/ext/polyphony/backend_io_uring_context.h +1 -1
- data/ext/polyphony/backend_libev.c +13 -11
- data/ext/polyphony/extconf.rb +24 -13
- data/ext/polyphony/queue.c +2 -2
- data/ext/polyphony/runqueue_ring_buffer.c +3 -2
- data/lib/polyphony/adapters/irb.rb +11 -1
- data/lib/polyphony/core/global_api.rb +3 -3
- data/lib/polyphony/core/timer.rb +2 -2
- data/lib/polyphony/debugger.rb +3 -3
- data/lib/polyphony/extensions/fiber.rb +30 -15
- data/lib/polyphony/extensions/io.rb +3 -3
- data/lib/polyphony/extensions/openssl.rb +21 -6
- data/lib/polyphony/extensions/socket.rb +4 -5
- data/lib/polyphony/net.rb +0 -1
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +1 -1
- data/test/coverage.rb +2 -2
- data/test/stress.rb +1 -1
- data/test/test_backend.rb +12 -12
- data/test/test_event.rb +1 -1
- data/test/test_ext.rb +1 -1
- data/test/test_fiber.rb +52 -12
- data/test/test_global_api.rb +2 -3
- data/test/test_io.rb +3 -3
- data/test/test_process_supervision.rb +38 -9
- data/test/test_queue.rb +6 -6
- data/test/test_socket.rb +12 -10
- data/test/test_supervise.rb +249 -81
- data/test/test_sync.rb +2 -2
- data/test/test_thread.rb +22 -2
- data/test/test_thread_pool.rb +1 -1
- data/test/test_throttler.rb +1 -1
- data/test/test_timer.rb +2 -2
- data/test/test_trace.rb +1 -1
- metadata +7 -3
@@ -106,9 +106,7 @@ VALUE Backend_post_fork(VALUE self) {
|
|
106
106
|
io_uring_queue_exit(&backend->ring);
|
107
107
|
io_uring_queue_init(backend->prepared_limit, &backend->ring, 0);
|
108
108
|
context_store_free(&backend->store);
|
109
|
-
backend->base
|
110
|
-
backend->base.pending_count = 0;
|
111
|
-
backend->pending_sqes = 0;
|
109
|
+
backend_base_reset(&backend->base);
|
112
110
|
|
113
111
|
return self;
|
114
112
|
}
|
@@ -143,7 +141,7 @@ static inline void io_uring_backend_handle_completion(struct io_uring_cqe *cqe,
|
|
143
141
|
context_store_release(&backend->store, ctx);
|
144
142
|
}
|
145
143
|
|
146
|
-
// adapted from io_uring_peek_batch_cqe in queue.c
|
144
|
+
// adapted from io_uring_peek_batch_cqe in queue.c
|
147
145
|
// this peeks at cqes and handles each available cqe
|
148
146
|
void io_uring_backend_handle_ready_cqes(Backend_t *backend) {
|
149
147
|
struct io_uring *ring = &backend->ring;
|
@@ -202,19 +200,12 @@ inline VALUE Backend_poll(VALUE self, VALUE blocking) {
|
|
202
200
|
}
|
203
201
|
|
204
202
|
COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_enter, rb_fiber_current());
|
205
|
-
|
206
|
-
// printf(
|
207
|
-
// "io_uring_poll(blocking_mode: %d, pending: %d, taken: %d, available: %d, runqueue: %d\n",
|
208
|
-
// is_blocking,
|
209
|
-
// backend->base.pending_count,
|
210
|
-
// backend->store.taken_count,
|
211
|
-
// backend->store.available_count,
|
212
|
-
// backend->base.runqueue.entries.count
|
213
|
-
// );
|
203
|
+
|
214
204
|
if (is_blocking) io_uring_backend_poll(backend);
|
215
205
|
io_uring_backend_handle_ready_cqes(backend);
|
216
|
-
COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_leave, rb_fiber_current());
|
217
206
|
|
207
|
+
COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_leave, rb_fiber_current());
|
208
|
+
|
218
209
|
return self;
|
219
210
|
}
|
220
211
|
|
@@ -257,7 +248,7 @@ VALUE Backend_wakeup(VALUE self) {
|
|
257
248
|
io_uring_prep_nop(sqe);
|
258
249
|
backend->pending_sqes = 0;
|
259
250
|
io_uring_submit(&backend->ring);
|
260
|
-
|
251
|
+
|
261
252
|
return Qtrue;
|
262
253
|
}
|
263
254
|
|
@@ -413,7 +404,7 @@ VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen) {
|
|
413
404
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_READ);
|
414
405
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
415
406
|
io_uring_prep_read(sqe, fptr->fd, buf, len, -1);
|
416
|
-
|
407
|
+
|
417
408
|
ssize_t result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
418
409
|
int completed = context_store_release(&backend->store, ctx);
|
419
410
|
if (!completed) {
|
@@ -463,7 +454,7 @@ VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
|
|
463
454
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_READ);
|
464
455
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
465
456
|
io_uring_prep_read(sqe, fptr->fd, buf, len, -1);
|
466
|
-
|
457
|
+
|
467
458
|
ssize_t result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
468
459
|
int completed = context_store_release(&backend->store, ctx);
|
469
460
|
if (!completed) {
|
@@ -509,7 +500,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
509
500
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_WRITE);
|
510
501
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
511
502
|
io_uring_prep_write(sqe, fptr->fd, buf, left, 0);
|
512
|
-
|
503
|
+
|
513
504
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
514
505
|
int completed = context_store_release(&backend->store, ctx);
|
515
506
|
if (!completed) {
|
@@ -518,7 +509,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
518
509
|
return resume_value;
|
519
510
|
}
|
520
511
|
RB_GC_GUARD(resume_value);
|
521
|
-
|
512
|
+
|
522
513
|
if (result < 0)
|
523
514
|
rb_syserr_fail(-result, strerror(-result));
|
524
515
|
else {
|
@@ -561,7 +552,7 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
561
552
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_WRITEV);
|
562
553
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
563
554
|
io_uring_prep_writev(sqe, fptr->fd, iov_ptr, iov_count, -1);
|
564
|
-
|
555
|
+
|
565
556
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
566
557
|
int completed = context_store_release(&backend->store, ctx);
|
567
558
|
if (!completed) {
|
@@ -637,7 +628,7 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos) {
|
|
637
628
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_RECV);
|
638
629
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
639
630
|
io_uring_prep_recv(sqe, fptr->fd, buf, len - total, 0);
|
640
|
-
|
631
|
+
|
641
632
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
642
633
|
int completed = context_store_release(&backend->store, ctx);
|
643
634
|
if (!completed) {
|
@@ -687,7 +678,7 @@ VALUE Backend_recv_loop(VALUE self, VALUE io, VALUE maxlen) {
|
|
687
678
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_RECV);
|
688
679
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
689
680
|
io_uring_prep_recv(sqe, fptr->fd, buf, len, 0);
|
690
|
-
|
681
|
+
|
691
682
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
692
683
|
int completed = context_store_release(&backend->store, ctx);
|
693
684
|
if (!completed) {
|
@@ -736,7 +727,7 @@ VALUE Backend_recv_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method)
|
|
736
727
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_RECV);
|
737
728
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
738
729
|
io_uring_prep_recv(sqe, fptr->fd, buf, len, 0);
|
739
|
-
|
730
|
+
|
740
731
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
741
732
|
int completed = context_store_release(&backend->store, ctx);
|
742
733
|
if (!completed) {
|
@@ -782,7 +773,7 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
782
773
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_SEND);
|
783
774
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
784
775
|
io_uring_prep_send(sqe, fptr->fd, buf, left, flags_int);
|
785
|
-
|
776
|
+
|
786
777
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
787
778
|
int completed = context_store_release(&backend->store, ctx);
|
788
779
|
if (!completed) {
|
@@ -819,7 +810,7 @@ VALUE io_uring_backend_accept(Backend_t *backend, VALUE server_socket, VALUE soc
|
|
819
810
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_ACCEPT);
|
820
811
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
821
812
|
io_uring_prep_accept(sqe, fptr->fd, &addr, &len, 0);
|
822
|
-
|
813
|
+
|
823
814
|
int fd = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
824
815
|
int completed = context_store_release(&backend->store, ctx);
|
825
816
|
RAISE_IF_EXCEPTION(resume_value);
|
@@ -890,7 +881,7 @@ VALUE io_uring_backend_splice(Backend_t *backend, VALUE src, VALUE dest, VALUE m
|
|
890
881
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_SPLICE);
|
891
882
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
892
883
|
io_uring_prep_splice(sqe, src_fptr->fd, -1, dest_fptr->fd, -1, NUM2INT(maxlen), 0);
|
893
|
-
|
884
|
+
|
894
885
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
895
886
|
int completed = context_store_release(&backend->store, ctx);
|
896
887
|
RAISE_IF_EXCEPTION(resume_value);
|
@@ -946,7 +937,7 @@ VALUE Backend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
|
|
946
937
|
RAISE_IF_EXCEPTION(resume_value);
|
947
938
|
if (!completed) return resume_value;
|
948
939
|
RB_GC_GUARD(resume_value);
|
949
|
-
|
940
|
+
|
950
941
|
if (result < 0) rb_syserr_fail(-result, strerror(-result));
|
951
942
|
return sock;
|
952
943
|
}
|
@@ -983,7 +974,7 @@ inline struct __kernel_timespec duration_to_timespec(VALUE duration) {
|
|
983
974
|
int io_uring_backend_submit_timeout_and_await(Backend_t *backend, double duration, VALUE *resume_value) {
|
984
975
|
struct __kernel_timespec ts = double_to_timespec(duration);
|
985
976
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
986
|
-
|
977
|
+
|
987
978
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_TIMEOUT);
|
988
979
|
io_uring_prep_timeout(sqe, &ts, 0, 0);
|
989
980
|
io_uring_backend_defer_submit_and_await(backend, sqe, ctx, resume_value);
|
@@ -1012,7 +1003,7 @@ VALUE Backend_timer_loop(VALUE self, VALUE interval) {
|
|
1012
1003
|
if (next_time == 0.) next_time = current_time() + interval_d;
|
1013
1004
|
double sleep_duration = next_time - now;
|
1014
1005
|
if (sleep_duration < 0) sleep_duration = 0;
|
1015
|
-
|
1006
|
+
|
1016
1007
|
VALUE resume_value = Qnil;
|
1017
1008
|
int completed = io_uring_backend_submit_timeout_and_await(backend, sleep_duration, &resume_value);
|
1018
1009
|
RAISE_IF_EXCEPTION(resume_value);
|
@@ -1053,7 +1044,7 @@ VALUE Backend_timeout(int argc, VALUE *argv, VALUE self) {
|
|
1053
1044
|
VALUE exception;
|
1054
1045
|
VALUE move_on_value = Qnil;
|
1055
1046
|
rb_scan_args(argc, argv, "21", &duration, &exception, &move_on_value);
|
1056
|
-
|
1047
|
+
|
1057
1048
|
struct __kernel_timespec ts = duration_to_timespec(duration);
|
1058
1049
|
Backend_t *backend;
|
1059
1050
|
GetBackend(self, backend);
|
@@ -1061,7 +1052,7 @@ VALUE Backend_timeout(int argc, VALUE *argv, VALUE self) {
|
|
1061
1052
|
VALUE timeout = rb_funcall(cTimeoutException, ID_new, 0);
|
1062
1053
|
|
1063
1054
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
1064
|
-
|
1055
|
+
|
1065
1056
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_TIMEOUT);
|
1066
1057
|
ctx->resume_value = timeout;
|
1067
1058
|
io_uring_prep_timeout(sqe, &ts, 0, 0);
|
@@ -1096,7 +1087,7 @@ VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
|
1096
1087
|
RAISE_IF_EXCEPTION(resume_value);
|
1097
1088
|
RB_GC_GUARD(resume_value);
|
1098
1089
|
}
|
1099
|
-
|
1090
|
+
|
1100
1091
|
int status;
|
1101
1092
|
pid_t ret = waitpid(pid_int, &status, WNOHANG);
|
1102
1093
|
if (ret < 0) {
|
@@ -1246,7 +1237,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1246
1237
|
}
|
1247
1238
|
rb_raise(rb_eRuntimeError, "Invalid op specified or bad op arity");
|
1248
1239
|
}
|
1249
|
-
|
1240
|
+
|
1250
1241
|
io_uring_sqe_set_data(last_sqe, ctx);
|
1251
1242
|
unsigned int flags = (i == (argc - 1)) ? IOSQE_ASYNC : IOSQE_ASYNC | IOSQE_IO_LINK;
|
1252
1243
|
io_uring_sqe_set_flags(last_sqe, flags);
|
@@ -1261,7 +1252,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1261
1252
|
int completed = context_store_release(&backend->store, ctx);
|
1262
1253
|
if (!completed) {
|
1263
1254
|
Backend_chain_ctx_attach_buffers(ctx, argc, argv);
|
1264
|
-
|
1255
|
+
|
1265
1256
|
// op was not completed (an exception was raised), so we need to cancel it
|
1266
1257
|
ctx->result = -ECANCELED;
|
1267
1258
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
@@ -1271,7 +1262,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1271
1262
|
RAISE_IF_EXCEPTION(resume_value);
|
1272
1263
|
return resume_value;
|
1273
1264
|
}
|
1274
|
-
|
1265
|
+
|
1275
1266
|
RB_GC_GUARD(resume_value);
|
1276
1267
|
return INT2NUM(result);
|
1277
1268
|
}
|
@@ -1406,7 +1397,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1406
1397
|
|
1407
1398
|
SPLICE_CHUNKS_AWAIT_OPS(backend, &ctx, &chunk_len, &switchpoint_result);
|
1408
1399
|
if (chunk_len == 0) break;
|
1409
|
-
|
1400
|
+
|
1410
1401
|
total += chunk_len;
|
1411
1402
|
chunk_len_value = INT2NUM(chunk_len);
|
1412
1403
|
|
@@ -1528,10 +1519,6 @@ void Init_Backend() {
|
|
1528
1519
|
rb_define_method(cBackend, "waitpid", Backend_waitpid, 1);
|
1529
1520
|
rb_define_method(cBackend, "write", Backend_write_m, -1);
|
1530
1521
|
|
1531
|
-
#ifdef POLYPHONY_UNSET_NONBLOCK
|
1532
|
-
ID_ivar_is_nonblocking = rb_intern("@is_nonblocking");
|
1533
|
-
#endif
|
1534
|
-
|
1535
1522
|
SYM_io_uring = ID2SYM(rb_intern("io_uring"));
|
1536
1523
|
SYM_send = ID2SYM(rb_intern("send"));
|
1537
1524
|
SYM_splice = ID2SYM(rb_intern("splice"));
|
@@ -64,7 +64,7 @@ inline int context_store_release(op_context_store_t *store, op_context_t *ctx) {
|
|
64
64
|
// printf("release %p %d (%s, ref_count: %d)\n", ctx, ctx->id, op_type_to_str(ctx->type), ctx->ref_count);
|
65
65
|
|
66
66
|
assert(ctx->ref_count);
|
67
|
-
|
67
|
+
|
68
68
|
ctx->ref_count--;
|
69
69
|
if (ctx->ref_count) return 0;
|
70
70
|
|
@@ -118,7 +118,7 @@ inline struct ev_loop *libev_new_loop() {
|
|
118
118
|
|
119
119
|
static VALUE Backend_initialize(VALUE self) {
|
120
120
|
Backend_t *backend;
|
121
|
-
|
121
|
+
|
122
122
|
GetBackend(self, backend);
|
123
123
|
|
124
124
|
backend_base_initialize(&backend->base);
|
@@ -157,6 +157,8 @@ VALUE Backend_post_fork(VALUE self) {
|
|
157
157
|
ev_loop_destroy(backend->ev_loop);
|
158
158
|
backend->ev_loop = EV_DEFAULT;
|
159
159
|
|
160
|
+
backend_base_reset(&backend->base);
|
161
|
+
|
160
162
|
return self;
|
161
163
|
}
|
162
164
|
|
@@ -186,7 +188,7 @@ inline void Backend_unschedule_fiber(VALUE self, VALUE fiber) {
|
|
186
188
|
Backend_t *backend;
|
187
189
|
GetBackend(self, backend);
|
188
190
|
|
189
|
-
runqueue_delete(&backend->base.runqueue, fiber);
|
191
|
+
runqueue_delete(&backend->base.runqueue, fiber);
|
190
192
|
}
|
191
193
|
|
192
194
|
inline VALUE Backend_switch_fiber(VALUE self) {
|
@@ -969,7 +971,7 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
969
971
|
io_verify_blocking_mode(dest_fptr, dest, Qfalse);
|
970
972
|
|
971
973
|
watcher.fiber = Qnil;
|
972
|
-
|
974
|
+
|
973
975
|
while (1) {
|
974
976
|
backend->base.op_count++;
|
975
977
|
ssize_t n = read(src_fptr->fd, buf, len);
|
@@ -1045,7 +1047,7 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
1045
1047
|
|
1046
1048
|
watcher.fiber = Qnil;
|
1047
1049
|
|
1048
|
-
while (1) {
|
1050
|
+
while (1) {
|
1049
1051
|
char *ptr = buf;
|
1050
1052
|
while (1) {
|
1051
1053
|
backend->base.op_count++;
|
@@ -1157,8 +1159,8 @@ noreturn VALUE Backend_timer_loop(VALUE self, VALUE interval) {
|
|
1157
1159
|
if (next_time == 0.) next_time = current_time() + interval_d;
|
1158
1160
|
double sleep_duration = next_time - now;
|
1159
1161
|
if (sleep_duration < 0) sleep_duration = 0;
|
1160
|
-
|
1161
|
-
VALUE switchpoint_result = Qnil;
|
1162
|
+
|
1163
|
+
VALUE switchpoint_result = Qnil;
|
1162
1164
|
ev_timer_init(&watcher.timer, Backend_timer_callback, sleep_duration, 0.);
|
1163
1165
|
ev_timer_start(backend->ev_loop, &watcher.timer);
|
1164
1166
|
backend->base.op_count++;
|
@@ -1217,7 +1219,7 @@ VALUE Backend_timeout(int argc,VALUE *argv, VALUE self) {
|
|
1217
1219
|
|
1218
1220
|
struct Backend_timeout_ctx timeout_ctx = {backend, &watcher};
|
1219
1221
|
result = rb_ensure(Backend_timeout_ensure_safe, Qnil, Backend_timeout_ensure, (VALUE)&timeout_ctx);
|
1220
|
-
|
1222
|
+
|
1221
1223
|
if (result == timeout) {
|
1222
1224
|
if (exception == Qnil) return move_on_value;
|
1223
1225
|
RAISE_EXCEPTION(backend_timeout_exception(exception));
|
@@ -1335,7 +1337,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1335
1337
|
else
|
1336
1338
|
rb_raise(rb_eRuntimeError, "Invalid op specified or bad op arity");
|
1337
1339
|
}
|
1338
|
-
|
1340
|
+
|
1339
1341
|
RB_GC_GUARD(result);
|
1340
1342
|
return result;
|
1341
1343
|
}
|
@@ -1384,14 +1386,14 @@ inline int splice_chunks_write(Backend_t *backend, int fd, VALUE str, struct lib
|
|
1384
1386
|
return 0;
|
1385
1387
|
}
|
1386
1388
|
|
1387
|
-
static inline int splice_chunks_splice(Backend_t *backend, int src_fd, int dest_fd, int maxlen,
|
1389
|
+
static inline int splice_chunks_splice(Backend_t *backend, int src_fd, int dest_fd, int maxlen,
|
1388
1390
|
struct libev_rw_io *watcher, VALUE *result, int *chunk_len) {
|
1389
1391
|
#ifdef POLYPHONY_LINUX
|
1390
1392
|
backend->base.op_count++;
|
1391
1393
|
while (1) {
|
1392
1394
|
*chunk_len = splice(src_fd, 0, dest_fd, 0, maxlen, 0);
|
1393
1395
|
if (*chunk_len >= 0) return 0;
|
1394
|
-
|
1396
|
+
|
1395
1397
|
int err = errno;
|
1396
1398
|
if (err != EWOULDBLOCK && err != EAGAIN) return err;
|
1397
1399
|
|
@@ -1487,7 +1489,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1487
1489
|
err = splice_chunks_splice(backend, src_fptr->fd, pipefd[1], maxlen, &watcher, &result, &chunk_len);
|
1488
1490
|
if (err == -1) goto error; else if (err) goto syscallerror;
|
1489
1491
|
if (chunk_len == 0) break;
|
1490
|
-
|
1492
|
+
|
1491
1493
|
total += chunk_len;
|
1492
1494
|
chunk_len_value = INT2NUM(chunk_len);
|
1493
1495
|
|
data/ext/polyphony/extconf.rb
CHANGED
@@ -3,32 +3,43 @@
|
|
3
3
|
require 'rubygems'
|
4
4
|
require 'mkmf'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
6
|
+
|
7
|
+
KERNEL_INFO_RE = /Linux (\d)\.(\d+)\.(?:\d+)\-(?:\d+\-)?(\w+)/
|
8
|
+
def get_config
|
9
|
+
config = { linux: !!(RUBY_PLATFORM =~ /linux/) }
|
10
|
+
return config if !config[:linux]
|
11
|
+
|
12
|
+
kernel_info = `uname -sr`
|
13
|
+
m = kernel_info.match(KERNEL_INFO_RE)
|
14
|
+
raise "Could not parse Linux kernel information (#{kernel_info.inspect})" if !m
|
15
|
+
|
16
|
+
version, major_revision, distribution = m[1].to_i, m[2].to_i, m[3]
|
17
|
+
config[:pidfd_open] = (version == 5) && (major_revision >= 3)
|
18
|
+
|
19
|
+
force_libev = ENV['POLYPHONY_USE_LIBEV'] != nil
|
20
|
+
config[:io_uring] = !force_libev &&
|
21
|
+
(version == 5) && (major_revision >= 6) && (distribution != 'linuxkit')
|
22
|
+
config
|
15
23
|
end
|
16
24
|
|
17
|
-
|
18
|
-
|
25
|
+
config = get_config
|
26
|
+
puts "Building Polyphony... (#{config.inspect})"
|
27
|
+
|
28
|
+
$defs << '-DPOLYPHONY_USE_PIDFD_OPEN' if config[:pidfd_open]
|
29
|
+
if config[:io_uring]
|
19
30
|
$defs << "-DPOLYPHONY_BACKEND_LIBURING"
|
20
31
|
$defs << "-DPOLYPHONY_UNSET_NONBLOCK" if RUBY_VERSION =~ /^3/
|
21
32
|
$CFLAGS << " -Wno-pointer-arith"
|
22
33
|
else
|
23
34
|
$defs << "-DPOLYPHONY_BACKEND_LIBEV"
|
24
|
-
$defs << "-DPOLYPHONY_LINUX" if linux
|
35
|
+
$defs << "-DPOLYPHONY_LINUX" if config[:linux]
|
25
36
|
$defs << '-DEV_USE_LINUXAIO' if have_header('linux/aio_abi.h')
|
26
37
|
$defs << '-DEV_USE_SELECT' if have_header('sys/select.h')
|
27
38
|
$defs << '-DEV_USE_POLL' if have_type('port_event_t', 'poll.h')
|
28
39
|
$defs << '-DEV_USE_EPOLL' if have_header('sys/epoll.h')
|
29
40
|
$defs << '-DEV_USE_KQUEUE' if have_header('sys/event.h') && have_header('sys/queue.h')
|
30
41
|
$defs << '-DEV_USE_PORT' if have_type('port_event_t', 'port.h')
|
31
|
-
$defs << '-DHAVE_SYS_RESOURCE_H' if have_header('sys/resource.h')
|
42
|
+
$defs << '-DHAVE_SYS_RESOURCE_H' if have_header('sys/resource.h')
|
32
43
|
|
33
44
|
$CFLAGS << " -Wno-comment"
|
34
45
|
$CFLAGS << " -Wno-unused-result"
|
data/ext/polyphony/queue.c
CHANGED
@@ -162,12 +162,12 @@ VALUE Queue_cap(VALUE self, VALUE cap) {
|
|
162
162
|
Queue_t *queue;
|
163
163
|
GetQueue(self, queue);
|
164
164
|
queue->capacity = new_capacity;
|
165
|
-
|
165
|
+
|
166
166
|
if (queue->capacity)
|
167
167
|
queue_schedule_blocked_fibers_to_capacity(queue);
|
168
168
|
else
|
169
169
|
queue_schedule_all_blocked_fibers(&queue->push_queue);
|
170
|
-
|
170
|
+
|
171
171
|
return self;
|
172
172
|
}
|
173
173
|
|
@@ -61,8 +61,9 @@ inline void runqueue_ring_buffer_push(runqueue_ring_buffer *buffer, VALUE fiber,
|
|
61
61
|
|
62
62
|
inline void runqueue_ring_buffer_mark(runqueue_ring_buffer *buffer) {
|
63
63
|
for (unsigned int i = 0; i < buffer->count; i++) {
|
64
|
-
|
65
|
-
rb_gc_mark(
|
64
|
+
runqueue_entry entry = buffer->entries[(buffer->head + i) % buffer->size];
|
65
|
+
rb_gc_mark(entry.fiber);
|
66
|
+
rb_gc_mark(entry.value);
|
66
67
|
}
|
67
68
|
}
|
68
69
|
|
@@ -3,26 +3,36 @@
|
|
3
3
|
require 'polyphony'
|
4
4
|
|
5
5
|
if Object.constants.include?(:Reline)
|
6
|
+
puts "reline"
|
6
7
|
class Reline::ANSI
|
7
8
|
def self.select(read_ios = [], write_ios = [], error_ios = [], timeout = nil)
|
8
|
-
p [:select, read_ios]
|
9
|
+
# p [:select, read_ios, timeout]
|
10
|
+
# puts caller.join("\n")
|
9
11
|
raise if read_ios.size > 1
|
10
12
|
raise if write_ios.size > 0
|
11
13
|
raise if error_ios.size > 0
|
12
14
|
|
15
|
+
# p 1
|
13
16
|
fiber = Fiber.current
|
14
17
|
timer = spin do
|
15
18
|
sleep timeout
|
16
19
|
fiber.cancel
|
17
20
|
end
|
21
|
+
# p 2
|
18
22
|
read_ios.each do |io|
|
23
|
+
# p wait: io
|
19
24
|
Polyphony.backend_wait_io(io, false)
|
25
|
+
# p :done_wait
|
20
26
|
return [io]
|
21
27
|
end
|
28
|
+
# p 3
|
22
29
|
rescue Polyphony::Cancel
|
30
|
+
# p :cancel
|
23
31
|
return nil
|
24
32
|
ensure
|
33
|
+
# p :ensure
|
25
34
|
timer.stop
|
35
|
+
# p :ensure_done
|
26
36
|
end
|
27
37
|
end
|
28
38
|
else
|
@@ -73,7 +73,7 @@ module Polyphony
|
|
73
73
|
|
74
74
|
def spin_scope
|
75
75
|
raise unless block_given?
|
76
|
-
|
76
|
+
|
77
77
|
spin do
|
78
78
|
result = yield
|
79
79
|
Fiber.current.await_all_children
|
@@ -122,8 +122,8 @@ module Polyphony
|
|
122
122
|
Fiber.current.receive_all_pending
|
123
123
|
end
|
124
124
|
|
125
|
-
def supervise(*args, &block)
|
126
|
-
Fiber.current.supervise(*args, &block)
|
125
|
+
def supervise(*args, **opts, &block)
|
126
|
+
Fiber.current.supervise(*args, **opts, &block)
|
127
127
|
end
|
128
128
|
|
129
129
|
def sleep(duration = nil)
|
data/lib/polyphony/core/timer.rb
CHANGED
@@ -44,7 +44,7 @@ module Polyphony
|
|
44
44
|
ensure
|
45
45
|
@timeouts.delete(fiber)
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
def cancel_after(interval, with_exception: Polyphony::Cancel)
|
49
49
|
fiber = Fiber.current
|
50
50
|
@timeouts[fiber] = {
|
@@ -74,7 +74,7 @@ module Polyphony
|
|
74
74
|
def reset
|
75
75
|
record = @timeouts[Fiber.current]
|
76
76
|
return unless record
|
77
|
-
|
77
|
+
|
78
78
|
record[:target_stamp] = now + record[:interval]
|
79
79
|
end
|
80
80
|
|
data/lib/polyphony/debugger.rb
CHANGED
@@ -9,11 +9,11 @@ module Polyphony
|
|
9
9
|
:return,
|
10
10
|
:b_call,
|
11
11
|
:b_return
|
12
|
-
]
|
12
|
+
]
|
13
13
|
|
14
14
|
def self.start_debug_server(socket_path)
|
15
15
|
server = DebugServer.new(socket_path)
|
16
|
-
controller = DebugController.new(server)
|
16
|
+
controller = DebugController.new(server)
|
17
17
|
trace = TracePoint.new(*TP_EVENTS) { |tp| controller.handle_tp(trace, tp) }
|
18
18
|
trace.enable
|
19
19
|
|
@@ -124,7 +124,7 @@ module Polyphony
|
|
124
124
|
h
|
125
125
|
end
|
126
126
|
end
|
127
|
-
|
127
|
+
|
128
128
|
def cmd_step(cmd)
|
129
129
|
tp = nil
|
130
130
|
fiber = nil
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'fiber'
|
4
|
-
|
5
4
|
require_relative '../core/exceptions'
|
6
5
|
|
7
6
|
module Polyphony
|
@@ -19,7 +18,7 @@ module Polyphony
|
|
19
18
|
alias_method :stop, :interrupt
|
20
19
|
|
21
20
|
def restart(value = nil)
|
22
|
-
raise "Can'
|
21
|
+
raise "Can't restart main fiber" if @main
|
23
22
|
|
24
23
|
if @running
|
25
24
|
schedule Polyphony::Restart.new(value)
|
@@ -27,6 +26,7 @@ module Polyphony
|
|
27
26
|
end
|
28
27
|
|
29
28
|
fiber = parent.spin(@tag, @caller, &@block)
|
29
|
+
@monitors&.each_key { |f| fiber.monitor(f) }
|
30
30
|
fiber.schedule(value) unless value.nil?
|
31
31
|
fiber
|
32
32
|
end
|
@@ -80,10 +80,10 @@ module Polyphony
|
|
80
80
|
# Fiber supervision
|
81
81
|
module FiberSupervision
|
82
82
|
def supervise(*fibers, **opts, &block)
|
83
|
-
block ||= opts
|
84
|
-
(opts[:on_error] && supervise_on_error_proc(opts[:on_error]))
|
85
|
-
raise "No block given" unless block
|
83
|
+
block ||= supervise_opts_to_block(opts)
|
86
84
|
|
85
|
+
@supervise_mode = true
|
86
|
+
fibers = children if fibers.empty?
|
87
87
|
fibers.each do |f|
|
88
88
|
f.attach_to(self) unless f.parent == self
|
89
89
|
f.monitor(self)
|
@@ -95,10 +95,24 @@ module Polyphony
|
|
95
95
|
(fiber, result) = mailbox.shift
|
96
96
|
block&.call(fiber, result)
|
97
97
|
end
|
98
|
+
ensure
|
99
|
+
@supervise_mode = false
|
98
100
|
end
|
99
101
|
|
100
|
-
def
|
101
|
-
|
102
|
+
def supervise_opts_to_block(opts)
|
103
|
+
block = opts[:on_done] || opts[:on_error]
|
104
|
+
restart = opts[:restart]
|
105
|
+
return nil unless block || restart
|
106
|
+
|
107
|
+
error_only = !!opts[:on_error]
|
108
|
+
restart_always = (restart == :always) || (restart == true)
|
109
|
+
restart_on_error = restart == :on_error
|
110
|
+
|
111
|
+
->(f, r) do
|
112
|
+
is_error = r.is_a?(Exception)
|
113
|
+
block.(f, r) if block && (!error_only || is_error)
|
114
|
+
f.restart if restart_always || (restart_on_error && is_error)
|
115
|
+
end
|
102
116
|
end
|
103
117
|
end
|
104
118
|
|
@@ -139,7 +153,7 @@ module Polyphony
|
|
139
153
|
|
140
154
|
def select(*fibers)
|
141
155
|
return nil if fibers.empty?
|
142
|
-
|
156
|
+
|
143
157
|
current_fiber = self.current
|
144
158
|
mailbox = current_fiber.monitor_mailbox
|
145
159
|
fibers.each do |f|
|
@@ -153,7 +167,7 @@ module Polyphony
|
|
153
167
|
while true
|
154
168
|
(fiber, result) = mailbox.shift
|
155
169
|
next unless fibers.include?(fiber)
|
156
|
-
|
170
|
+
|
157
171
|
fibers.each { |f| f.unmonitor(current_fiber) }
|
158
172
|
if result.is_a?(Exception)
|
159
173
|
raise result
|
@@ -187,6 +201,7 @@ module Polyphony
|
|
187
201
|
|
188
202
|
def add_child(child_fiber)
|
189
203
|
(@children ||= {})[child_fiber] = true
|
204
|
+
child_fiber.monitor(self) if @supervise_mode
|
190
205
|
end
|
191
206
|
|
192
207
|
def remove_child(child_fiber)
|
@@ -197,6 +212,7 @@ module Polyphony
|
|
197
212
|
f = Fiber.new { |v| f.run(v) }
|
198
213
|
f.prepare(tag, block, orig_caller, self)
|
199
214
|
(@children ||= {})[f] = true
|
215
|
+
f.monitor(self) if @supervise_mode
|
200
216
|
f
|
201
217
|
end
|
202
218
|
|
@@ -225,19 +241,17 @@ module Polyphony
|
|
225
241
|
c.terminate(graceful)
|
226
242
|
c.await
|
227
243
|
end
|
228
|
-
reap_dead_children
|
229
244
|
end
|
230
245
|
|
231
|
-
def
|
232
|
-
|
233
|
-
|
234
|
-
@children.reject! { |f| f.dead? }
|
246
|
+
def attach_all_children_to(fiber)
|
247
|
+
@children&.keys.each { |c| c.attach_to(fiber) }
|
235
248
|
end
|
236
249
|
|
237
250
|
def detach
|
238
251
|
@parent.remove_child(self)
|
239
252
|
@parent = @thread.main_fiber
|
240
253
|
@parent.add_child(self)
|
254
|
+
self
|
241
255
|
end
|
242
256
|
|
243
257
|
def attach_to(fiber)
|
@@ -315,6 +329,7 @@ module Polyphony
|
|
315
329
|
inform_monitors(result, uncaught_exception)
|
316
330
|
@running = false
|
317
331
|
ensure
|
332
|
+
@parent&.remove_child(self)
|
318
333
|
# Prevent fiber from being resumed after terminating
|
319
334
|
@thread.fiber_unschedule(self)
|
320
335
|
Thread.current.switch_fiber
|
@@ -324,7 +339,7 @@ module Polyphony
|
|
324
339
|
# the children are shut down, it is returned along with the uncaught_exception
|
325
340
|
# flag set. Otherwise, it returns the given arguments.
|
326
341
|
def finalize_children(result, uncaught_exception)
|
327
|
-
shutdown_all_children
|
342
|
+
shutdown_all_children(graceful_shutdown?)
|
328
343
|
[result, uncaught_exception]
|
329
344
|
rescue Exception => e
|
330
345
|
[e, true]
|