polyphony 0.71 → 0.72
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +1 -0
- data/CHANGELOG.md +18 -4
- data/Gemfile.lock +1 -1
- data/TODO.md +1 -1
- 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 +8 -8
- data/ext/polyphony/backend_io_uring.c +26 -33
- 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 +11 -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 +19 -8
- data/lib/polyphony/extensions/io.rb +2 -2
- data/lib/polyphony/extensions/openssl.rb +20 -5
- data/lib/polyphony/extensions/socket.rb +3 -4
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +1 -1
- data/test/coverage.rb +2 -2
- 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 +31 -7
- data/test/test_global_api.rb +2 -2
- data/test/test_io.rb +3 -3
- data/test/test_queue.rb +6 -6
- data/test/test_socket.rb +12 -10
- data/test/test_supervise.rb +85 -0
- 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
@@ -141,7 +141,7 @@ static inline void io_uring_backend_handle_completion(struct io_uring_cqe *cqe,
|
|
141
141
|
context_store_release(&backend->store, ctx);
|
142
142
|
}
|
143
143
|
|
144
|
-
// adapted from io_uring_peek_batch_cqe in queue.c
|
144
|
+
// adapted from io_uring_peek_batch_cqe in queue.c
|
145
145
|
// this peeks at cqes and handles each available cqe
|
146
146
|
void io_uring_backend_handle_ready_cqes(Backend_t *backend) {
|
147
147
|
struct io_uring *ring = &backend->ring;
|
@@ -200,19 +200,12 @@ inline VALUE Backend_poll(VALUE self, VALUE blocking) {
|
|
200
200
|
}
|
201
201
|
|
202
202
|
COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_enter, rb_fiber_current());
|
203
|
-
|
204
|
-
// printf(
|
205
|
-
// "io_uring_poll(blocking_mode: %d, pending: %d, taken: %d, available: %d, runqueue: %d\n",
|
206
|
-
// is_blocking,
|
207
|
-
// backend->base.pending_count,
|
208
|
-
// backend->store.taken_count,
|
209
|
-
// backend->store.available_count,
|
210
|
-
// backend->base.runqueue.entries.count
|
211
|
-
// );
|
203
|
+
|
212
204
|
if (is_blocking) io_uring_backend_poll(backend);
|
213
205
|
io_uring_backend_handle_ready_cqes(backend);
|
214
|
-
COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_leave, rb_fiber_current());
|
215
206
|
|
207
|
+
COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_leave, rb_fiber_current());
|
208
|
+
|
216
209
|
return self;
|
217
210
|
}
|
218
211
|
|
@@ -255,7 +248,7 @@ VALUE Backend_wakeup(VALUE self) {
|
|
255
248
|
io_uring_prep_nop(sqe);
|
256
249
|
backend->pending_sqes = 0;
|
257
250
|
io_uring_submit(&backend->ring);
|
258
|
-
|
251
|
+
|
259
252
|
return Qtrue;
|
260
253
|
}
|
261
254
|
|
@@ -411,7 +404,7 @@ VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen) {
|
|
411
404
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_READ);
|
412
405
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
413
406
|
io_uring_prep_read(sqe, fptr->fd, buf, len, -1);
|
414
|
-
|
407
|
+
|
415
408
|
ssize_t result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
416
409
|
int completed = context_store_release(&backend->store, ctx);
|
417
410
|
if (!completed) {
|
@@ -461,7 +454,7 @@ VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
|
|
461
454
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_READ);
|
462
455
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
463
456
|
io_uring_prep_read(sqe, fptr->fd, buf, len, -1);
|
464
|
-
|
457
|
+
|
465
458
|
ssize_t result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
466
459
|
int completed = context_store_release(&backend->store, ctx);
|
467
460
|
if (!completed) {
|
@@ -507,7 +500,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
507
500
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_WRITE);
|
508
501
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
509
502
|
io_uring_prep_write(sqe, fptr->fd, buf, left, 0);
|
510
|
-
|
503
|
+
|
511
504
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
512
505
|
int completed = context_store_release(&backend->store, ctx);
|
513
506
|
if (!completed) {
|
@@ -516,7 +509,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
516
509
|
return resume_value;
|
517
510
|
}
|
518
511
|
RB_GC_GUARD(resume_value);
|
519
|
-
|
512
|
+
|
520
513
|
if (result < 0)
|
521
514
|
rb_syserr_fail(-result, strerror(-result));
|
522
515
|
else {
|
@@ -559,7 +552,7 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
559
552
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_WRITEV);
|
560
553
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
561
554
|
io_uring_prep_writev(sqe, fptr->fd, iov_ptr, iov_count, -1);
|
562
|
-
|
555
|
+
|
563
556
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
564
557
|
int completed = context_store_release(&backend->store, ctx);
|
565
558
|
if (!completed) {
|
@@ -635,7 +628,7 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos) {
|
|
635
628
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_RECV);
|
636
629
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
637
630
|
io_uring_prep_recv(sqe, fptr->fd, buf, len - total, 0);
|
638
|
-
|
631
|
+
|
639
632
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
640
633
|
int completed = context_store_release(&backend->store, ctx);
|
641
634
|
if (!completed) {
|
@@ -685,7 +678,7 @@ VALUE Backend_recv_loop(VALUE self, VALUE io, VALUE maxlen) {
|
|
685
678
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_RECV);
|
686
679
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
687
680
|
io_uring_prep_recv(sqe, fptr->fd, buf, len, 0);
|
688
|
-
|
681
|
+
|
689
682
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
690
683
|
int completed = context_store_release(&backend->store, ctx);
|
691
684
|
if (!completed) {
|
@@ -734,7 +727,7 @@ VALUE Backend_recv_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method)
|
|
734
727
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_RECV);
|
735
728
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
736
729
|
io_uring_prep_recv(sqe, fptr->fd, buf, len, 0);
|
737
|
-
|
730
|
+
|
738
731
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
739
732
|
int completed = context_store_release(&backend->store, ctx);
|
740
733
|
if (!completed) {
|
@@ -780,7 +773,7 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
780
773
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_SEND);
|
781
774
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
782
775
|
io_uring_prep_send(sqe, fptr->fd, buf, left, flags_int);
|
783
|
-
|
776
|
+
|
784
777
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
785
778
|
int completed = context_store_release(&backend->store, ctx);
|
786
779
|
if (!completed) {
|
@@ -817,7 +810,7 @@ VALUE io_uring_backend_accept(Backend_t *backend, VALUE server_socket, VALUE soc
|
|
817
810
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_ACCEPT);
|
818
811
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
819
812
|
io_uring_prep_accept(sqe, fptr->fd, &addr, &len, 0);
|
820
|
-
|
813
|
+
|
821
814
|
int fd = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
822
815
|
int completed = context_store_release(&backend->store, ctx);
|
823
816
|
RAISE_IF_EXCEPTION(resume_value);
|
@@ -888,7 +881,7 @@ VALUE io_uring_backend_splice(Backend_t *backend, VALUE src, VALUE dest, VALUE m
|
|
888
881
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_SPLICE);
|
889
882
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
890
883
|
io_uring_prep_splice(sqe, src_fptr->fd, -1, dest_fptr->fd, -1, NUM2INT(maxlen), 0);
|
891
|
-
|
884
|
+
|
892
885
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
893
886
|
int completed = context_store_release(&backend->store, ctx);
|
894
887
|
RAISE_IF_EXCEPTION(resume_value);
|
@@ -944,7 +937,7 @@ VALUE Backend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
|
|
944
937
|
RAISE_IF_EXCEPTION(resume_value);
|
945
938
|
if (!completed) return resume_value;
|
946
939
|
RB_GC_GUARD(resume_value);
|
947
|
-
|
940
|
+
|
948
941
|
if (result < 0) rb_syserr_fail(-result, strerror(-result));
|
949
942
|
return sock;
|
950
943
|
}
|
@@ -981,7 +974,7 @@ inline struct __kernel_timespec duration_to_timespec(VALUE duration) {
|
|
981
974
|
int io_uring_backend_submit_timeout_and_await(Backend_t *backend, double duration, VALUE *resume_value) {
|
982
975
|
struct __kernel_timespec ts = double_to_timespec(duration);
|
983
976
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
984
|
-
|
977
|
+
|
985
978
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_TIMEOUT);
|
986
979
|
io_uring_prep_timeout(sqe, &ts, 0, 0);
|
987
980
|
io_uring_backend_defer_submit_and_await(backend, sqe, ctx, resume_value);
|
@@ -1010,7 +1003,7 @@ VALUE Backend_timer_loop(VALUE self, VALUE interval) {
|
|
1010
1003
|
if (next_time == 0.) next_time = current_time() + interval_d;
|
1011
1004
|
double sleep_duration = next_time - now;
|
1012
1005
|
if (sleep_duration < 0) sleep_duration = 0;
|
1013
|
-
|
1006
|
+
|
1014
1007
|
VALUE resume_value = Qnil;
|
1015
1008
|
int completed = io_uring_backend_submit_timeout_and_await(backend, sleep_duration, &resume_value);
|
1016
1009
|
RAISE_IF_EXCEPTION(resume_value);
|
@@ -1051,7 +1044,7 @@ VALUE Backend_timeout(int argc, VALUE *argv, VALUE self) {
|
|
1051
1044
|
VALUE exception;
|
1052
1045
|
VALUE move_on_value = Qnil;
|
1053
1046
|
rb_scan_args(argc, argv, "21", &duration, &exception, &move_on_value);
|
1054
|
-
|
1047
|
+
|
1055
1048
|
struct __kernel_timespec ts = duration_to_timespec(duration);
|
1056
1049
|
Backend_t *backend;
|
1057
1050
|
GetBackend(self, backend);
|
@@ -1059,7 +1052,7 @@ VALUE Backend_timeout(int argc, VALUE *argv, VALUE self) {
|
|
1059
1052
|
VALUE timeout = rb_funcall(cTimeoutException, ID_new, 0);
|
1060
1053
|
|
1061
1054
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
1062
|
-
|
1055
|
+
|
1063
1056
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_TIMEOUT);
|
1064
1057
|
ctx->resume_value = timeout;
|
1065
1058
|
io_uring_prep_timeout(sqe, &ts, 0, 0);
|
@@ -1094,7 +1087,7 @@ VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
|
1094
1087
|
RAISE_IF_EXCEPTION(resume_value);
|
1095
1088
|
RB_GC_GUARD(resume_value);
|
1096
1089
|
}
|
1097
|
-
|
1090
|
+
|
1098
1091
|
int status;
|
1099
1092
|
pid_t ret = waitpid(pid_int, &status, WNOHANG);
|
1100
1093
|
if (ret < 0) {
|
@@ -1244,7 +1237,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1244
1237
|
}
|
1245
1238
|
rb_raise(rb_eRuntimeError, "Invalid op specified or bad op arity");
|
1246
1239
|
}
|
1247
|
-
|
1240
|
+
|
1248
1241
|
io_uring_sqe_set_data(last_sqe, ctx);
|
1249
1242
|
unsigned int flags = (i == (argc - 1)) ? IOSQE_ASYNC : IOSQE_ASYNC | IOSQE_IO_LINK;
|
1250
1243
|
io_uring_sqe_set_flags(last_sqe, flags);
|
@@ -1259,7 +1252,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1259
1252
|
int completed = context_store_release(&backend->store, ctx);
|
1260
1253
|
if (!completed) {
|
1261
1254
|
Backend_chain_ctx_attach_buffers(ctx, argc, argv);
|
1262
|
-
|
1255
|
+
|
1263
1256
|
// op was not completed (an exception was raised), so we need to cancel it
|
1264
1257
|
ctx->result = -ECANCELED;
|
1265
1258
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
@@ -1269,7 +1262,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1269
1262
|
RAISE_IF_EXCEPTION(resume_value);
|
1270
1263
|
return resume_value;
|
1271
1264
|
}
|
1272
|
-
|
1265
|
+
|
1273
1266
|
RB_GC_GUARD(resume_value);
|
1274
1267
|
return INT2NUM(result);
|
1275
1268
|
}
|
@@ -1404,7 +1397,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1404
1397
|
|
1405
1398
|
SPLICE_CHUNKS_AWAIT_OPS(backend, &ctx, &chunk_len, &switchpoint_result);
|
1406
1399
|
if (chunk_len == 0) break;
|
1407
|
-
|
1400
|
+
|
1408
1401
|
total += chunk_len;
|
1409
1402
|
chunk_len_value = INT2NUM(chunk_len);
|
1410
1403
|
|
@@ -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);
|
@@ -188,7 +188,7 @@ inline void Backend_unschedule_fiber(VALUE self, VALUE fiber) {
|
|
188
188
|
Backend_t *backend;
|
189
189
|
GetBackend(self, backend);
|
190
190
|
|
191
|
-
runqueue_delete(&backend->base.runqueue, fiber);
|
191
|
+
runqueue_delete(&backend->base.runqueue, fiber);
|
192
192
|
}
|
193
193
|
|
194
194
|
inline VALUE Backend_switch_fiber(VALUE self) {
|
@@ -971,7 +971,7 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
971
971
|
io_verify_blocking_mode(dest_fptr, dest, Qfalse);
|
972
972
|
|
973
973
|
watcher.fiber = Qnil;
|
974
|
-
|
974
|
+
|
975
975
|
while (1) {
|
976
976
|
backend->base.op_count++;
|
977
977
|
ssize_t n = read(src_fptr->fd, buf, len);
|
@@ -1047,7 +1047,7 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
1047
1047
|
|
1048
1048
|
watcher.fiber = Qnil;
|
1049
1049
|
|
1050
|
-
while (1) {
|
1050
|
+
while (1) {
|
1051
1051
|
char *ptr = buf;
|
1052
1052
|
while (1) {
|
1053
1053
|
backend->base.op_count++;
|
@@ -1159,8 +1159,8 @@ noreturn VALUE Backend_timer_loop(VALUE self, VALUE interval) {
|
|
1159
1159
|
if (next_time == 0.) next_time = current_time() + interval_d;
|
1160
1160
|
double sleep_duration = next_time - now;
|
1161
1161
|
if (sleep_duration < 0) sleep_duration = 0;
|
1162
|
-
|
1163
|
-
VALUE switchpoint_result = Qnil;
|
1162
|
+
|
1163
|
+
VALUE switchpoint_result = Qnil;
|
1164
1164
|
ev_timer_init(&watcher.timer, Backend_timer_callback, sleep_duration, 0.);
|
1165
1165
|
ev_timer_start(backend->ev_loop, &watcher.timer);
|
1166
1166
|
backend->base.op_count++;
|
@@ -1219,7 +1219,7 @@ VALUE Backend_timeout(int argc,VALUE *argv, VALUE self) {
|
|
1219
1219
|
|
1220
1220
|
struct Backend_timeout_ctx timeout_ctx = {backend, &watcher};
|
1221
1221
|
result = rb_ensure(Backend_timeout_ensure_safe, Qnil, Backend_timeout_ensure, (VALUE)&timeout_ctx);
|
1222
|
-
|
1222
|
+
|
1223
1223
|
if (result == timeout) {
|
1224
1224
|
if (exception == Qnil) return move_on_value;
|
1225
1225
|
RAISE_EXCEPTION(backend_timeout_exception(exception));
|
@@ -1337,7 +1337,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1337
1337
|
else
|
1338
1338
|
rb_raise(rb_eRuntimeError, "Invalid op specified or bad op arity");
|
1339
1339
|
}
|
1340
|
-
|
1340
|
+
|
1341
1341
|
RB_GC_GUARD(result);
|
1342
1342
|
return result;
|
1343
1343
|
}
|
@@ -1386,14 +1386,14 @@ inline int splice_chunks_write(Backend_t *backend, int fd, VALUE str, struct lib
|
|
1386
1386
|
return 0;
|
1387
1387
|
}
|
1388
1388
|
|
1389
|
-
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,
|
1390
1390
|
struct libev_rw_io *watcher, VALUE *result, int *chunk_len) {
|
1391
1391
|
#ifdef POLYPHONY_LINUX
|
1392
1392
|
backend->base.op_count++;
|
1393
1393
|
while (1) {
|
1394
1394
|
*chunk_len = splice(src_fd, 0, dest_fd, 0, maxlen, 0);
|
1395
1395
|
if (*chunk_len >= 0) return 0;
|
1396
|
-
|
1396
|
+
|
1397
1397
|
int err = errno;
|
1398
1398
|
if (err != EWOULDBLOCK && err != EAGAIN) return err;
|
1399
1399
|
|
@@ -1489,7 +1489,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1489
1489
|
err = splice_chunks_splice(backend, src_fptr->fd, pipefd[1], maxlen, &watcher, &result, &chunk_len);
|
1490
1490
|
if (err == -1) goto error; else if (err) goto syscallerror;
|
1491
1491
|
if (chunk_len == 0) break;
|
1492
|
-
|
1492
|
+
|
1493
1493
|
total += chunk_len;
|
1494
1494
|
chunk_len_value = INT2NUM(chunk_len);
|
1495
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)
|
@@ -83,6 +82,8 @@ module Polyphony
|
|
83
82
|
def supervise(*fibers, **opts, &block)
|
84
83
|
block ||= supervise_opts_to_block(opts)
|
85
84
|
|
85
|
+
@supervise_mode = true
|
86
|
+
fibers = children if fibers.empty?
|
86
87
|
fibers.each do |f|
|
87
88
|
f.attach_to(self) unless f.parent == self
|
88
89
|
f.monitor(self)
|
@@ -94,15 +95,18 @@ module Polyphony
|
|
94
95
|
(fiber, result) = mailbox.shift
|
95
96
|
block&.call(fiber, result)
|
96
97
|
end
|
98
|
+
ensure
|
99
|
+
@supervise_mode = false
|
97
100
|
end
|
98
101
|
|
99
102
|
def supervise_opts_to_block(opts)
|
100
103
|
block = opts[:on_done] || opts[:on_error]
|
101
|
-
|
104
|
+
restart = opts[:restart]
|
105
|
+
return nil unless block || restart
|
102
106
|
|
103
107
|
error_only = !!opts[:on_error]
|
104
|
-
restart_always =
|
105
|
-
restart_on_error =
|
108
|
+
restart_always = (restart == :always) || (restart == true)
|
109
|
+
restart_on_error = restart == :on_error
|
106
110
|
|
107
111
|
->(f, r) do
|
108
112
|
is_error = r.is_a?(Exception)
|
@@ -149,7 +153,7 @@ module Polyphony
|
|
149
153
|
|
150
154
|
def select(*fibers)
|
151
155
|
return nil if fibers.empty?
|
152
|
-
|
156
|
+
|
153
157
|
current_fiber = self.current
|
154
158
|
mailbox = current_fiber.monitor_mailbox
|
155
159
|
fibers.each do |f|
|
@@ -163,7 +167,7 @@ module Polyphony
|
|
163
167
|
while true
|
164
168
|
(fiber, result) = mailbox.shift
|
165
169
|
next unless fibers.include?(fiber)
|
166
|
-
|
170
|
+
|
167
171
|
fibers.each { |f| f.unmonitor(current_fiber) }
|
168
172
|
if result.is_a?(Exception)
|
169
173
|
raise result
|
@@ -197,6 +201,7 @@ module Polyphony
|
|
197
201
|
|
198
202
|
def add_child(child_fiber)
|
199
203
|
(@children ||= {})[child_fiber] = true
|
204
|
+
child_fiber.monitor(self) if @supervise_mode
|
200
205
|
end
|
201
206
|
|
202
207
|
def remove_child(child_fiber)
|
@@ -207,6 +212,7 @@ module Polyphony
|
|
207
212
|
f = Fiber.new { |v| f.run(v) }
|
208
213
|
f.prepare(tag, block, orig_caller, self)
|
209
214
|
(@children ||= {})[f] = true
|
215
|
+
f.monitor(self) if @supervise_mode
|
210
216
|
f
|
211
217
|
end
|
212
218
|
|
@@ -237,10 +243,15 @@ module Polyphony
|
|
237
243
|
end
|
238
244
|
end
|
239
245
|
|
246
|
+
def attach_all_children_to(fiber)
|
247
|
+
@children&.keys.each { |c| c.attach_to(fiber) }
|
248
|
+
end
|
249
|
+
|
240
250
|
def detach
|
241
251
|
@parent.remove_child(self)
|
242
252
|
@parent = @thread.main_fiber
|
243
253
|
@parent.add_child(self)
|
254
|
+
self
|
244
255
|
end
|
245
256
|
|
246
257
|
def attach_to(fiber)
|
@@ -328,7 +339,7 @@ module Polyphony
|
|
328
339
|
# the children are shut down, it is returned along with the uncaught_exception
|
329
340
|
# flag set. Otherwise, it returns the given arguments.
|
330
341
|
def finalize_children(result, uncaught_exception)
|
331
|
-
shutdown_all_children
|
342
|
+
shutdown_all_children(graceful_shutdown?)
|
332
343
|
[result, uncaught_exception]
|
333
344
|
rescue Exception => e
|
334
345
|
[e, true]
|
@@ -103,7 +103,7 @@ class ::IO
|
|
103
103
|
alias_method :orig_getc, :getc
|
104
104
|
def getc
|
105
105
|
return @read_buffer.slice!(0) if @read_buffer && !@read_buffer.empty?
|
106
|
-
|
106
|
+
|
107
107
|
@read_buffer ||= +''
|
108
108
|
Polyphony.backend_read(self, @read_buffer, 8192, false, -1)
|
109
109
|
return @read_buffer.slice!(0) if !@read_buffer.empty?
|
@@ -116,7 +116,7 @@ class ::IO
|
|
116
116
|
if buf
|
117
117
|
return Polyphony.backend_read(self, buf, len, true, buf_pos)
|
118
118
|
end
|
119
|
-
|
119
|
+
|
120
120
|
@read_buffer ||= +''
|
121
121
|
result = Polyphony.backend_read(self, @read_buffer, len, true, -1)
|
122
122
|
return nil unless result
|