polyphony 0.71 → 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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +1 -0
  3. data/CHANGELOG.md +18 -4
  4. data/Gemfile.lock +1 -1
  5. data/TODO.md +1 -1
  6. data/bin/pdbg +1 -1
  7. data/bin/polyphony-debug +0 -0
  8. data/bin/stress.rb +0 -0
  9. data/bin/test +0 -0
  10. data/docs/_user-guide/all-about-timers.md +1 -1
  11. data/docs/api-reference/fiber.md +2 -2
  12. data/docs/faq.md +1 -1
  13. data/docs/getting-started/overview.md +8 -8
  14. data/docs/getting-started/tutorial.md +3 -3
  15. data/docs/main-concepts/concurrency.md +1 -1
  16. data/docs/main-concepts/extending.md +3 -3
  17. data/docs/main-concepts/fiber-scheduling.md +1 -1
  18. data/examples/core/calc.rb +37 -0
  19. data/examples/core/calc_with_restart.rb +40 -0
  20. data/examples/core/calc_with_supervise.rb +37 -0
  21. data/examples/core/message_based_supervision.rb +1 -1
  22. data/examples/io/rack_server.rb +1 -1
  23. data/examples/io/tunnel.rb +1 -1
  24. data/examples/performance/fiber_transfer.rb +1 -1
  25. data/examples/performance/line_splitting.rb +1 -1
  26. data/examples/performance/thread-vs-fiber/compare.rb +1 -1
  27. data/ext/polyphony/backend_common.c +8 -8
  28. data/ext/polyphony/backend_io_uring.c +26 -33
  29. data/ext/polyphony/backend_io_uring_context.c +1 -1
  30. data/ext/polyphony/backend_io_uring_context.h +1 -1
  31. data/ext/polyphony/backend_libev.c +11 -11
  32. data/ext/polyphony/extconf.rb +24 -13
  33. data/ext/polyphony/queue.c +2 -2
  34. data/ext/polyphony/runqueue_ring_buffer.c +3 -2
  35. data/lib/polyphony/adapters/irb.rb +11 -1
  36. data/lib/polyphony/core/global_api.rb +3 -3
  37. data/lib/polyphony/core/timer.rb +2 -2
  38. data/lib/polyphony/debugger.rb +3 -3
  39. data/lib/polyphony/extensions/fiber.rb +19 -8
  40. data/lib/polyphony/extensions/io.rb +2 -2
  41. data/lib/polyphony/extensions/openssl.rb +20 -5
  42. data/lib/polyphony/extensions/socket.rb +3 -4
  43. data/lib/polyphony/version.rb +1 -1
  44. data/polyphony.gemspec +1 -1
  45. data/test/coverage.rb +2 -2
  46. data/test/test_backend.rb +12 -12
  47. data/test/test_event.rb +1 -1
  48. data/test/test_ext.rb +1 -1
  49. data/test/test_fiber.rb +31 -7
  50. data/test/test_global_api.rb +2 -2
  51. data/test/test_io.rb +3 -3
  52. data/test/test_queue.rb +6 -6
  53. data/test/test_socket.rb +12 -10
  54. data/test/test_supervise.rb +85 -0
  55. data/test/test_sync.rb +2 -2
  56. data/test/test_thread.rb +22 -2
  57. data/test/test_thread_pool.rb +1 -1
  58. data/test/test_throttler.rb +1 -1
  59. data/test/test_timer.rb +2 -2
  60. data/test/test_trace.rb +1 -1
  61. 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
- // if (SHOULD_TRACE(&backend->base))
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
 
@@ -22,7 +22,7 @@ typedef struct op_context {
22
22
  struct op_context *prev;
23
23
  struct op_context *next;
24
24
  enum op_type type: 16;
25
- unsigned int ref_count : 16;
25
+ unsigned int ref_count : 16;
26
26
  int id;
27
27
  int result;
28
28
  VALUE fiber;
@@ -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
 
@@ -3,32 +3,43 @@
3
3
  require 'rubygems'
4
4
  require 'mkmf'
5
5
 
6
- use_liburing = false
7
- use_pidfd_open = false
8
- force_use_libev = ENV['POLYPHONY_USE_LIBEV'] != nil
9
- linux = RUBY_PLATFORM =~ /linux/
10
-
11
- if linux && `uname -sr` =~ /Linux 5\.(\d+)/
12
- kernel_minor_version = $1.to_i
13
- use_liburing = !force_use_libev && kernel_minor_version >= 6
14
- use_pidfd_open = kernel_minor_version >= 3
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
- $defs << '-DPOLYPHONY_USE_PIDFD_OPEN' if use_pidfd_open
18
- if use_liburing
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"
@@ -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
- rb_gc_mark(buffer->entries[(buffer->head + i) % buffer->size].fiber);
65
- rb_gc_mark(buffer->entries[(buffer->head + i) % buffer->size].value);
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)
@@ -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
 
@@ -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''t restart main fiber" if @main
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
- return nil unless block || opts[:restart]
104
+ restart = opts[:restart]
105
+ return nil unless block || restart
102
106
 
103
107
  error_only = !!opts[:on_error]
104
- restart_always = opts[:restart] == :always
105
- restart_on_error = opts[: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