polyphony 0.73.1 → 0.77

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +13 -10
  3. data/.github/workflows/test_io_uring.yml +32 -0
  4. data/CHANGELOG.md +22 -0
  5. data/Gemfile.lock +10 -7
  6. data/bin/pdbg +0 -0
  7. data/bin/polyphony-debug +0 -0
  8. data/bin/stress.rb +0 -0
  9. data/bin/test +0 -0
  10. data/examples/core/trap1.rb +21 -0
  11. data/examples/core/trap2.rb +14 -0
  12. data/ext/polyphony/backend_common.c +84 -12
  13. data/ext/polyphony/backend_common.h +8 -0
  14. data/ext/polyphony/backend_io_uring.c +231 -107
  15. data/ext/polyphony/backend_io_uring_context.c +1 -0
  16. data/ext/polyphony/backend_io_uring_context.h +2 -1
  17. data/ext/polyphony/backend_libev.c +12 -9
  18. data/ext/polyphony/event.c +5 -2
  19. data/ext/polyphony/polyphony.c +11 -1
  20. data/ext/polyphony/polyphony.h +4 -1
  21. data/ext/polyphony/queue.c +10 -5
  22. data/ext/polyphony/runqueue_ring_buffer.c +3 -1
  23. data/ext/polyphony/socket_extensions.c +5 -2
  24. data/ext/test_eintr.c +50 -0
  25. data/lib/polyphony/extensions/fiber.rb +85 -5
  26. data/lib/polyphony/extensions/openssl.rb +5 -1
  27. data/lib/polyphony/extensions/socket.rb +12 -6
  28. data/lib/polyphony/extensions/thread.rb +9 -3
  29. data/lib/polyphony/version.rb +1 -1
  30. data/lib/polyphony.rb +4 -1
  31. data/test/helper.rb +2 -6
  32. data/test/stress.rb +1 -1
  33. data/test/test_backend.rb +3 -5
  34. data/test/test_fiber.rb +6 -4
  35. data/test/test_global_api.rb +10 -14
  36. data/test/test_io.rb +2 -2
  37. data/test/test_kernel.rb +2 -2
  38. data/test/test_signal.rb +57 -0
  39. data/test/test_socket.rb +35 -2
  40. data/test/test_thread.rb +1 -1
  41. data/test/test_thread_pool.rb +1 -1
  42. data/test/test_throttler.rb +3 -3
  43. data/test/test_timer.rb +2 -2
  44. data/test/test_trace.rb +7 -1
  45. metadata +11 -7
@@ -42,6 +42,7 @@ typedef struct Backend_t {
42
42
  unsigned int pending_sqes;
43
43
  unsigned int prepared_limit;
44
44
  int event_fd;
45
+ int ring_initialized;
45
46
  } Backend_t;
46
47
 
47
48
  static void Backend_mark(void *ptr) {
@@ -80,20 +81,32 @@ static VALUE Backend_initialize(VALUE self) {
80
81
 
81
82
  backend_base_initialize(&backend->base);
82
83
  backend->pending_sqes = 0;
83
- backend->prepared_limit = 2048;
84
+ backend->ring_initialized = 0;
85
+ backend->event_fd = -1;
84
86
 
85
87
  context_store_initialize(&backend->store);
86
- io_uring_queue_init(backend->prepared_limit, &backend->ring, 0);
87
- backend->event_fd = -1;
88
88
 
89
- return Qnil;
89
+ backend->prepared_limit = 1024;
90
+ while (1) {
91
+ int ret = io_uring_queue_init(backend->prepared_limit, &backend->ring, 0);
92
+ if (!ret) break;
93
+
94
+ // if ENOMEM is returned, use a smaller limit
95
+ if (ret == -ENOMEM && backend->prepared_limit > 64)
96
+ backend->prepared_limit = backend->prepared_limit / 2;
97
+ else
98
+ rb_syserr_fail(-ret, strerror(-ret));
99
+ }
100
+ backend->ring_initialized = 1;
101
+
102
+ return self;
90
103
  }
91
104
 
92
105
  VALUE Backend_finalize(VALUE self) {
93
106
  Backend_t *backend;
94
107
  GetBackend(self, backend);
95
108
 
96
- io_uring_queue_exit(&backend->ring);
109
+ if (backend->ring_initialized) io_uring_queue_exit(&backend->ring);
97
110
  if (backend->event_fd != -1) close(backend->event_fd);
98
111
  context_store_free(&backend->store);
99
112
  return self;
@@ -178,10 +191,14 @@ void io_uring_backend_poll(Backend_t *backend) {
178
191
  io_uring_submit(&backend->ring);
179
192
  }
180
193
 
194
+ wait_cqe:
181
195
  backend->base.currently_polling = 1;
182
196
  rb_thread_call_without_gvl(io_uring_backend_poll_without_gvl, (void *)&poll_ctx, RUBY_UBF_IO, 0);
183
197
  backend->base.currently_polling = 0;
184
- if (poll_ctx.result < 0) return;
198
+ if (poll_ctx.result < 0) {
199
+ if (poll_ctx.result == -EINTR && runqueue_empty_p(&backend->base.runqueue)) goto wait_cqe;
200
+ return;
201
+ }
185
202
 
186
203
  io_uring_backend_handle_completion(poll_ctx.cqe, backend);
187
204
  io_uring_cqe_seen(&backend->ring, poll_ctx.cqe);
@@ -282,9 +299,11 @@ int io_uring_backend_defer_submit_and_await(
282
299
  switchpoint_result = backend_await((struct Backend_base *)backend);
283
300
 
284
301
  if (ctx->ref_count > 1) {
302
+ struct io_uring_sqe *sqe;
303
+
285
304
  // op was not completed (an exception was raised), so we need to cancel it
286
305
  ctx->result = -ECANCELED;
287
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
306
+ sqe = io_uring_get_sqe(&backend->ring);
288
307
  io_uring_prep_cancel(sqe, ctx, 0);
289
308
  backend->pending_sqes = 0;
290
309
  io_uring_submit(&backend->ring);
@@ -316,16 +335,20 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
316
335
  long dynamic_len = length == Qnil;
317
336
  long buffer_size = dynamic_len ? 4096 : NUM2INT(length);
318
337
  long buf_pos = NUM2INT(pos);
338
+ int shrinkable;
339
+ char *buf;
340
+ long total = 0;
341
+ int read_to_eof = RTEST(to_eof);
342
+ VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
343
+
344
+
319
345
  if (str != Qnil) {
320
346
  int current_len = RSTRING_LEN(str);
321
347
  if (buf_pos < 0 || buf_pos > current_len) buf_pos = current_len;
322
348
  }
323
349
  else buf_pos = 0;
324
- int shrinkable = io_setstrbuf(&str, buf_pos + buffer_size);
325
- char *buf = RSTRING_PTR(str) + buf_pos;
326
- long total = 0;
327
- int read_to_eof = RTEST(to_eof);
328
- VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
350
+ shrinkable = io_setstrbuf(&str, buf_pos + buffer_size);
351
+ buf = RSTRING_PTR(str) + buf_pos;
329
352
 
330
353
  GetBackend(self, backend);
331
354
  if (underlying_io != Qnil) io = underlying_io;
@@ -338,10 +361,13 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
338
361
  VALUE resume_value = Qnil;
339
362
  op_context_t *ctx = context_store_acquire(&backend->store, OP_READ);
340
363
  struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
364
+ int result;
365
+ int completed;
366
+
341
367
  io_uring_prep_read(sqe, fptr->fd, buf, buffer_size - total, -1);
342
368
 
343
- int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
344
- int completed = context_store_release(&backend->store, ctx);
369
+ result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
370
+ completed = context_store_release(&backend->store, ctx);
345
371
  if (!completed) {
346
372
  context_attach_buffers(ctx, 1, &str);
347
373
  RAISE_IF_EXCEPTION(resume_value);
@@ -402,10 +428,13 @@ VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen) {
402
428
  VALUE resume_value = Qnil;
403
429
  op_context_t *ctx = context_store_acquire(&backend->store, OP_READ);
404
430
  struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
431
+ ssize_t result;
432
+ int completed;
433
+
405
434
  io_uring_prep_read(sqe, fptr->fd, buf, len, -1);
406
435
 
407
- ssize_t result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
408
- int completed = context_store_release(&backend->store, ctx);
436
+ result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
437
+ completed = context_store_release(&backend->store, ctx);
409
438
  if (!completed) {
410
439
  context_attach_buffers(ctx, 1, &str);
411
440
  RAISE_IF_EXCEPTION(resume_value);
@@ -452,10 +481,13 @@ VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
452
481
  VALUE resume_value = Qnil;
453
482
  op_context_t *ctx = context_store_acquire(&backend->store, OP_READ);
454
483
  struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
484
+ ssize_t result;
485
+ int completed;
486
+
455
487
  io_uring_prep_read(sqe, fptr->fd, buf, len, -1);
456
488
 
457
- ssize_t result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
458
- int completed = context_store_release(&backend->store, ctx);
489
+ result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
490
+ completed = context_store_release(&backend->store, ctx);
459
491
  if (!completed) {
460
492
  context_attach_buffers(ctx, 1, &str);
461
493
  RAISE_IF_EXCEPTION(resume_value);
@@ -482,6 +514,9 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
482
514
  Backend_t *backend;
483
515
  rb_io_t *fptr;
484
516
  VALUE underlying_io;
517
+ char *buf = StringValuePtr(str);
518
+ long len = RSTRING_LEN(str);
519
+ long left = len;
485
520
 
486
521
  underlying_io = rb_ivar_get(io, ID_ivar_io);
487
522
  if (underlying_io != Qnil) io = underlying_io;
@@ -490,18 +525,17 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
490
525
  GetOpenFile(io, fptr);
491
526
  io_unset_nonblock(fptr, io);
492
527
 
493
- char *buf = StringValuePtr(str);
494
- long len = RSTRING_LEN(str);
495
- long left = len;
496
-
497
528
  while (left > 0) {
498
529
  VALUE resume_value = Qnil;
499
530
  op_context_t *ctx = context_store_acquire(&backend->store, OP_WRITE);
500
531
  struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
532
+ int result;
533
+ int completed;
534
+
501
535
  io_uring_prep_write(sqe, fptr->fd, buf, left, 0);
502
536
 
503
- int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
504
- int completed = context_store_release(&backend->store, ctx);
537
+ result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
538
+ completed = context_store_release(&backend->store, ctx);
505
539
  if (!completed) {
506
540
  context_attach_buffers(ctx, 1, &str);
507
541
  RAISE_IF_EXCEPTION(resume_value);
@@ -550,10 +584,13 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
550
584
  VALUE resume_value = Qnil;
551
585
  op_context_t *ctx = context_store_acquire(&backend->store, OP_WRITEV);
552
586
  struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
587
+ int result;
588
+ int completed;
589
+
553
590
  io_uring_prep_writev(sqe, fptr->fd, iov_ptr, iov_count, -1);
554
591
 
555
- int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
556
- int completed = context_store_release(&backend->store, ctx);
592
+ result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
593
+ completed = context_store_release(&backend->store, ctx);
557
594
  if (!completed) {
558
595
  free(iov);
559
596
  context_attach_buffers(ctx, argc, argv);
@@ -604,15 +641,18 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos) {
604
641
  long dynamic_len = length == Qnil;
605
642
  long len = dynamic_len ? 4096 : NUM2INT(length);
606
643
  long buf_pos = NUM2INT(pos);
644
+ int shrinkable;
645
+ char *buf;
646
+ long total = 0;
647
+ VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);;
648
+
607
649
  if (str != Qnil) {
608
650
  int current_len = RSTRING_LEN(str);
609
651
  if (buf_pos < 0 || buf_pos > current_len) buf_pos = current_len;
610
652
  }
611
653
  else buf_pos = 0;
612
- int shrinkable = io_setstrbuf(&str, buf_pos + len);
613
- char *buf = RSTRING_PTR(str) + buf_pos;
614
- long total = 0;
615
- VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
654
+ shrinkable = io_setstrbuf(&str, buf_pos + len);
655
+ buf = RSTRING_PTR(str) + buf_pos;
616
656
 
617
657
  GetBackend(self, backend);
618
658
  if (underlying_io != Qnil) io = underlying_io;
@@ -625,10 +665,13 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos) {
625
665
  VALUE resume_value = Qnil;
626
666
  op_context_t *ctx = context_store_acquire(&backend->store, OP_RECV);
627
667
  struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
668
+ int result;
669
+ int completed;
670
+
628
671
  io_uring_prep_recv(sqe, fptr->fd, buf, len - total, 0);
629
672
 
630
- int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
631
- int completed = context_store_release(&backend->store, ctx);
673
+ result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
674
+ completed = context_store_release(&backend->store, ctx);
632
675
  if (!completed) {
633
676
  context_attach_buffers(ctx, 1, &str);
634
677
  RAISE_IF_EXCEPTION(resume_value);
@@ -675,10 +718,13 @@ VALUE Backend_recv_loop(VALUE self, VALUE io, VALUE maxlen) {
675
718
  VALUE resume_value = Qnil;
676
719
  op_context_t *ctx = context_store_acquire(&backend->store, OP_RECV);
677
720
  struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
721
+ int result;
722
+ int completed;
723
+
678
724
  io_uring_prep_recv(sqe, fptr->fd, buf, len, 0);
679
725
 
680
- int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
681
- int completed = context_store_release(&backend->store, ctx);
726
+ result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
727
+ completed = context_store_release(&backend->store, ctx);
682
728
  if (!completed) {
683
729
  context_attach_buffers(ctx, 1, &str);
684
730
  RAISE_IF_EXCEPTION(resume_value);
@@ -724,10 +770,13 @@ VALUE Backend_recv_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method)
724
770
  VALUE resume_value = Qnil;
725
771
  op_context_t *ctx = context_store_acquire(&backend->store, OP_RECV);
726
772
  struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
773
+ int result;
774
+ int completed;
775
+
727
776
  io_uring_prep_recv(sqe, fptr->fd, buf, len, 0);
728
777
 
729
- int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
730
- int completed = context_store_release(&backend->store, ctx);
778
+ result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
779
+ completed = context_store_release(&backend->store, ctx);
731
780
  if (!completed) {
732
781
  context_attach_buffers(ctx, 1, &str);
733
782
  RAISE_IF_EXCEPTION(resume_value);
@@ -753,6 +802,10 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
753
802
  Backend_t *backend;
754
803
  rb_io_t *fptr;
755
804
  VALUE underlying_io;
805
+ char *buf;
806
+ long len;
807
+ long left;
808
+ int flags_int;
756
809
 
757
810
  underlying_io = rb_ivar_get(io, ID_ivar_io);
758
811
  if (underlying_io != Qnil) io = underlying_io;
@@ -761,19 +814,22 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
761
814
  GetOpenFile(io, fptr);
762
815
  io_unset_nonblock(fptr, io);
763
816
 
764
- char *buf = StringValuePtr(str);
765
- long len = RSTRING_LEN(str);
766
- long left = len;
767
- int flags_int = NUM2INT(flags);
817
+ buf = StringValuePtr(str);
818
+ len = RSTRING_LEN(str);
819
+ left = len;
820
+ flags_int = NUM2INT(flags);
768
821
 
769
822
  while (left > 0) {
770
823
  VALUE resume_value = Qnil;
771
824
  op_context_t *ctx = context_store_acquire(&backend->store, OP_SEND);
772
825
  struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
826
+ int result;
827
+ int completed;
828
+
773
829
  io_uring_prep_send(sqe, fptr->fd, buf, left, flags_int);
774
830
 
775
- int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
776
- int completed = context_store_release(&backend->store, ctx);
831
+ result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
832
+ completed = context_store_release(&backend->store, ctx);
777
833
  if (!completed) {
778
834
  context_attach_buffers(ctx, 1, &str);
779
835
  RAISE_IF_EXCEPTION(resume_value);
@@ -807,10 +863,13 @@ VALUE io_uring_backend_accept(Backend_t *backend, VALUE server_socket, VALUE soc
807
863
  VALUE resume_value = Qnil;
808
864
  op_context_t *ctx = context_store_acquire(&backend->store, OP_ACCEPT);
809
865
  struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
866
+ int fd;
867
+ int completed;
868
+
810
869
  io_uring_prep_accept(sqe, fptr->fd, &addr, &len, 0);
811
870
 
812
- int fd = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
813
- int completed = context_store_release(&backend->store, ctx);
871
+ fd = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
872
+ completed = context_store_release(&backend->store, ctx);
814
873
  RAISE_IF_EXCEPTION(resume_value);
815
874
  if (!completed) return resume_value;
816
875
  RB_GC_GUARD(resume_value);
@@ -861,6 +920,7 @@ VALUE io_uring_backend_splice(Backend_t *backend, VALUE src, VALUE dest, VALUE m
861
920
  rb_io_t *dest_fptr;
862
921
  VALUE underlying_io;
863
922
  int total = 0;
923
+ VALUE resume_value = Qnil;
864
924
 
865
925
  underlying_io = rb_ivar_get(src, ID_ivar_io);
866
926
  if (underlying_io != Qnil) src = underlying_io;
@@ -873,15 +933,16 @@ VALUE io_uring_backend_splice(Backend_t *backend, VALUE src, VALUE dest, VALUE m
873
933
  GetOpenFile(dest, dest_fptr);
874
934
  io_unset_nonblock(dest_fptr, dest);
875
935
 
876
- VALUE resume_value = Qnil;
877
-
878
936
  while (1) {
879
937
  op_context_t *ctx = context_store_acquire(&backend->store, OP_SPLICE);
880
938
  struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
939
+ int result;
940
+ int completed;
941
+
881
942
  io_uring_prep_splice(sqe, src_fptr->fd, -1, dest_fptr->fd, -1, NUM2INT(maxlen), 0);
882
943
 
883
- int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
884
- int completed = context_store_release(&backend->store, ctx);
944
+ result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
945
+ completed = context_store_release(&backend->store, ctx);
885
946
  RAISE_IF_EXCEPTION(resume_value);
886
947
  if (!completed) return resume_value;
887
948
 
@@ -909,29 +970,31 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE chunksize)
909
970
  return io_uring_backend_splice(backend, src, dest, chunksize, 1);
910
971
  }
911
972
 
912
-
913
973
  VALUE Backend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
914
974
  Backend_t *backend;
915
975
  rb_io_t *fptr;
916
- struct sockaddr_in addr;
917
- char *host_buf = StringValueCStr(host);
976
+ struct sockaddr *ai_addr;
977
+ int ai_addrlen;
918
978
  VALUE underlying_sock = rb_ivar_get(sock, ID_ivar_io);
979
+ VALUE resume_value = Qnil;
980
+ op_context_t *ctx;
981
+ struct io_uring_sqe *sqe;
982
+ int result;
983
+ int completed;
984
+
985
+ ai_addrlen = backend_getaddrinfo(host, port, &ai_addr);
986
+
919
987
  if (underlying_sock != Qnil) sock = underlying_sock;
920
988
 
921
989
  GetBackend(self, backend);
922
990
  GetOpenFile(sock, fptr);
923
991
  io_unset_nonblock(fptr, sock);
924
992
 
925
- addr.sin_family = AF_INET;
926
- addr.sin_addr.s_addr = inet_addr(host_buf);
927
- addr.sin_port = htons(NUM2INT(port));
928
-
929
- VALUE resume_value = Qnil;
930
- op_context_t *ctx = context_store_acquire(&backend->store, OP_CONNECT);
931
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
932
- io_uring_prep_connect(sqe, fptr->fd, (struct sockaddr *)&addr, sizeof(addr));
933
- int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
934
- int completed = context_store_release(&backend->store, ctx);
993
+ ctx = context_store_acquire(&backend->store, OP_CONNECT);
994
+ sqe = io_uring_get_sqe(&backend->ring);
995
+ io_uring_prep_connect(sqe, fptr->fd, ai_addr, ai_addrlen);
996
+ result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
997
+ completed = context_store_release(&backend->store, ctx);
935
998
  RAISE_IF_EXCEPTION(resume_value);
936
999
  if (!completed) return resume_value;
937
1000
  RB_GC_GUARD(resume_value);
@@ -944,17 +1007,54 @@ VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write) {
944
1007
  Backend_t *backend;
945
1008
  rb_io_t *fptr;
946
1009
  VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
1010
+ VALUE resume_value;
1011
+
947
1012
  if (underlying_io != Qnil) io = underlying_io;
948
1013
  GetBackend(self, backend);
949
1014
  GetOpenFile(io, fptr);
950
1015
  io_unset_nonblock(fptr, io);
951
1016
 
952
- VALUE resume_value = io_uring_backend_wait_fd(backend, fptr->fd, RTEST(write));
1017
+ resume_value = io_uring_backend_wait_fd(backend, fptr->fd, RTEST(write));
1018
+
953
1019
  RAISE_IF_EXCEPTION(resume_value);
954
1020
  RB_GC_GUARD(resume_value);
955
1021
  return self;
956
1022
  }
957
1023
 
1024
+ // VALUE Backend_close(VALUE self, VALUE io) {
1025
+ // Backend_t *backend;
1026
+ // rb_io_t *fptr;
1027
+ // VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
1028
+ // VALUE resume_value = Qnil;
1029
+ // op_context_t *ctx;
1030
+ // struct io_uring_sqe *sqe;
1031
+ // int result;
1032
+ // int completed;
1033
+
1034
+ // if (underlying_io != Qnil) io = underlying_io;
1035
+ // GetBackend(self, backend);
1036
+ // GetOpenFile(io, fptr);
1037
+
1038
+ // if (fptr->fd < 0) return Qnil;
1039
+
1040
+ // io_unset_nonblock(fptr, io);
1041
+
1042
+ // ctx = context_store_acquire(&backend->store, OP_CLOSE);
1043
+ // sqe = io_uring_get_sqe(&backend->ring);
1044
+ // io_uring_prep_close(sqe, fptr->fd);
1045
+ // result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
1046
+ // completed = context_store_release(&backend->store, ctx);
1047
+ // RAISE_IF_EXCEPTION(resume_value);
1048
+ // if (!completed) return resume_value;
1049
+ // RB_GC_GUARD(resume_value);
1050
+
1051
+ // if (result < 0) rb_syserr_fail(-result, strerror(-result));
1052
+
1053
+ // fptr_finalize(fptr);
1054
+ // // fptr->fd = -1;
1055
+ // return io;
1056
+ // }
1057
+
958
1058
  inline struct __kernel_timespec double_to_timespec(double duration) {
959
1059
  double duration_integral;
960
1060
  double duration_fraction = modf(duration, &duration_integral);
@@ -972,18 +1072,18 @@ inline struct __kernel_timespec duration_to_timespec(VALUE duration) {
972
1072
  int io_uring_backend_submit_timeout_and_await(Backend_t *backend, double duration, VALUE *resume_value) {
973
1073
  struct __kernel_timespec ts = double_to_timespec(duration);
974
1074
  struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
975
-
976
1075
  op_context_t *ctx = context_store_acquire(&backend->store, OP_TIMEOUT);
1076
+
977
1077
  io_uring_prep_timeout(sqe, &ts, 0, 0);
978
1078
  io_uring_backend_defer_submit_and_await(backend, sqe, ctx, resume_value);
979
1079
  return context_store_release(&backend->store, ctx);
980
1080
  }
981
1081
 
982
1082
  VALUE Backend_sleep(VALUE self, VALUE duration) {
1083
+ VALUE resume_value = Qnil;
983
1084
  Backend_t *backend;
984
1085
  GetBackend(self, backend);
985
1086
 
986
- VALUE resume_value = Qnil;
987
1087
  io_uring_backend_submit_timeout_and_await(backend, NUM2DBL(duration), &resume_value);
988
1088
  RAISE_IF_EXCEPTION(resume_value);
989
1089
  RB_GC_GUARD(resume_value);
@@ -1028,12 +1128,13 @@ struct Backend_timeout_ctx {
1028
1128
  };
1029
1129
 
1030
1130
  VALUE Backend_timeout_ensure(VALUE arg) {
1031
- struct Backend_timeout_ctx *timeout_ctx = (struct Backend_timeout_ctx *)arg;
1032
- if (timeout_ctx->ctx->ref_count) {
1033
- timeout_ctx->ctx->result = -ECANCELED;
1131
+ struct Backend_timeout_ctx *timeout_ctx = (struct Backend_timeout_ctx *)arg;
1132
+ if (timeout_ctx->ctx->ref_count) {
1133
+ struct io_uring_sqe *sqe;
1034
1134
 
1135
+ timeout_ctx->ctx->result = -ECANCELED;
1035
1136
  // op was not completed, so we need to cancel it
1036
- struct io_uring_sqe *sqe = io_uring_get_sqe(&timeout_ctx->backend->ring);
1137
+ sqe = io_uring_get_sqe(&timeout_ctx->backend->ring);
1037
1138
  io_uring_prep_cancel(sqe, timeout_ctx->ctx, 0);
1038
1139
  timeout_ctx->backend->pending_sqes = 0;
1039
1140
  io_uring_submit(&timeout_ctx->backend->ring);
@@ -1046,24 +1147,30 @@ VALUE Backend_timeout(int argc, VALUE *argv, VALUE self) {
1046
1147
  VALUE duration;
1047
1148
  VALUE exception;
1048
1149
  VALUE move_on_value = Qnil;
1049
- rb_scan_args(argc, argv, "21", &duration, &exception, &move_on_value);
1050
-
1051
- struct __kernel_timespec ts = duration_to_timespec(duration);
1150
+ struct Backend_timeout_ctx timeout_ctx;
1151
+ op_context_t *ctx;
1152
+ struct io_uring_sqe *sqe;
1052
1153
  Backend_t *backend;
1053
- GetBackend(self, backend);
1154
+ struct __kernel_timespec ts;
1054
1155
  VALUE result = Qnil;
1055
- VALUE timeout = rb_funcall(cTimeoutException, ID_new, 0);
1156
+ VALUE timeout;
1056
1157
 
1057
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
1158
+ rb_scan_args(argc, argv, "21", &duration, &exception, &move_on_value);
1058
1159
 
1059
- op_context_t *ctx = context_store_acquire(&backend->store, OP_TIMEOUT);
1160
+ ts = duration_to_timespec(duration);
1161
+ GetBackend(self, backend);
1162
+ timeout = rb_funcall(cTimeoutException, ID_new, 0);
1163
+
1164
+ sqe = io_uring_get_sqe(&backend->ring);
1165
+ ctx = context_store_acquire(&backend->store, OP_TIMEOUT);
1060
1166
  ctx->resume_value = timeout;
1061
1167
  io_uring_prep_timeout(sqe, &ts, 0, 0);
1062
1168
  io_uring_sqe_set_data(sqe, ctx);
1063
1169
  io_uring_backend_defer_submit(backend);
1064
1170
  backend->base.op_count++;
1065
1171
 
1066
- struct Backend_timeout_ctx timeout_ctx = {backend, ctx};
1172
+ timeout_ctx.backend = backend;
1173
+ timeout_ctx.ctx = ctx;
1067
1174
  result = rb_ensure(Backend_timeout_ensure_safe, Qnil, Backend_timeout_ensure, (VALUE)&timeout_ctx);
1068
1175
 
1069
1176
  if (result == timeout) {
@@ -1080,19 +1187,21 @@ VALUE Backend_timeout(int argc, VALUE *argv, VALUE self) {
1080
1187
  VALUE Backend_waitpid(VALUE self, VALUE pid) {
1081
1188
  int pid_int = NUM2INT(pid);
1082
1189
  int fd = pidfd_open(pid_int, 0);
1190
+ int status;
1191
+ pid_t ret;
1083
1192
 
1084
1193
  if (fd >= 0) {
1194
+ VALUE resume_value;
1085
1195
  Backend_t *backend;
1086
1196
  GetBackend(self, backend);
1087
1197
 
1088
- VALUE resume_value = io_uring_backend_wait_fd(backend, fd, 0);
1198
+ resume_value = io_uring_backend_wait_fd(backend, fd, 0);
1089
1199
  close(fd);
1090
1200
  RAISE_IF_EXCEPTION(resume_value);
1091
1201
  RB_GC_GUARD(resume_value);
1092
1202
  }
1093
1203
 
1094
- int status;
1095
- pid_t ret = waitpid(pid_int, &status, WNOHANG);
1204
+ ret = waitpid(pid_int, &status, WNOHANG);
1096
1205
  if (ret < 0) {
1097
1206
  int e = errno;
1098
1207
  if (e == ECHILD)
@@ -1105,6 +1214,8 @@ VALUE Backend_waitpid(VALUE self, VALUE pid) {
1105
1214
 
1106
1215
  VALUE Backend_wait_event(VALUE self, VALUE raise) {
1107
1216
  Backend_t *backend;
1217
+ VALUE resume_value;
1218
+
1108
1219
  GetBackend(self, backend);
1109
1220
 
1110
1221
  if (backend->event_fd == -1) {
@@ -1115,7 +1226,7 @@ VALUE Backend_wait_event(VALUE self, VALUE raise) {
1115
1226
  }
1116
1227
  }
1117
1228
 
1118
- VALUE resume_value = io_uring_backend_wait_fd(backend, backend->event_fd, 0);
1229
+ resume_value = io_uring_backend_wait_fd(backend, backend->event_fd, 0);
1119
1230
  if (RTEST(raise)) RAISE_IF_EXCEPTION(resume_value);
1120
1231
  RB_GC_GUARD(resume_value);
1121
1232
  return resume_value;
@@ -1128,6 +1239,7 @@ VALUE Backend_kind(VALUE self) {
1128
1239
  struct io_uring_sqe *Backend_chain_prepare_write(Backend_t *backend, VALUE io, VALUE str) {
1129
1240
  rb_io_t *fptr;
1130
1241
  VALUE underlying_io;
1242
+ struct io_uring_sqe *sqe;
1131
1243
 
1132
1244
  underlying_io = rb_ivar_get(io, ID_ivar_io);
1133
1245
  if (underlying_io != Qnil) io = underlying_io;
@@ -1135,17 +1247,15 @@ struct io_uring_sqe *Backend_chain_prepare_write(Backend_t *backend, VALUE io, V
1135
1247
  GetOpenFile(io, fptr);
1136
1248
  io_unset_nonblock(fptr, io);
1137
1249
 
1138
- char *buf = StringValuePtr(str);
1139
- long len = RSTRING_LEN(str);
1140
-
1141
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
1142
- io_uring_prep_write(sqe, fptr->fd, buf, len, 0);
1250
+ sqe = io_uring_get_sqe(&backend->ring);
1251
+ io_uring_prep_write(sqe, fptr->fd, StringValuePtr(str), RSTRING_LEN(str), 0);
1143
1252
  return sqe;
1144
1253
  }
1145
1254
 
1146
1255
  struct io_uring_sqe *Backend_chain_prepare_send(Backend_t *backend, VALUE io, VALUE str, VALUE flags) {
1147
1256
  rb_io_t *fptr;
1148
1257
  VALUE underlying_io;
1258
+ struct io_uring_sqe *sqe;
1149
1259
 
1150
1260
  underlying_io = rb_ivar_get(io, ID_ivar_io);
1151
1261
  if (underlying_io != Qnil) io = underlying_io;
@@ -1153,12 +1263,8 @@ struct io_uring_sqe *Backend_chain_prepare_send(Backend_t *backend, VALUE io, VA
1153
1263
  GetOpenFile(io, fptr);
1154
1264
  io_unset_nonblock(fptr, io);
1155
1265
 
1156
- char *buf = StringValuePtr(str);
1157
- long len = RSTRING_LEN(str);
1158
- int flags_int = NUM2INT(flags);
1159
-
1160
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
1161
- io_uring_prep_send(sqe, fptr->fd, buf, len, flags_int);
1266
+ sqe = io_uring_get_sqe(&backend->ring);
1267
+ io_uring_prep_send(sqe, fptr->fd, StringValuePtr(str), RSTRING_LEN(str), NUM2INT(flags));
1162
1268
  return sqe;
1163
1269
  }
1164
1270
 
@@ -1166,6 +1272,7 @@ struct io_uring_sqe *Backend_chain_prepare_splice(Backend_t *backend, VALUE src,
1166
1272
  rb_io_t *src_fptr;
1167
1273
  rb_io_t *dest_fptr;
1168
1274
  VALUE underlying_io;
1275
+ struct io_uring_sqe *sqe;
1169
1276
 
1170
1277
  underlying_io = rb_ivar_get(src, ID_ivar_io);
1171
1278
  if (underlying_io != Qnil) src = underlying_io;
@@ -1178,7 +1285,7 @@ struct io_uring_sqe *Backend_chain_prepare_splice(Backend_t *backend, VALUE src,
1178
1285
  GetOpenFile(dest, dest_fptr);
1179
1286
  io_unset_nonblock(dest_fptr, dest);
1180
1287
 
1181
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
1288
+ sqe = io_uring_get_sqe(&backend->ring);
1182
1289
  io_uring_prep_splice(sqe, src_fptr->fd, -1, dest_fptr->fd, -1, NUM2INT(maxlen), 0);
1183
1290
  return sqe;
1184
1291
  }
@@ -1206,14 +1313,19 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
1206
1313
  unsigned int sqe_count = 0;
1207
1314
  struct io_uring_sqe *last_sqe = 0;
1208
1315
  Backend_t *backend;
1316
+ int result;
1317
+ int completed;
1318
+ op_context_t *ctx;
1319
+
1209
1320
  GetBackend(self, backend);
1210
1321
  if (argc == 0) return resume_value;
1211
1322
 
1212
- op_context_t *ctx = context_store_acquire(&backend->store, OP_CHAIN);
1323
+ ctx = context_store_acquire(&backend->store, OP_CHAIN);
1213
1324
  for (int i = 0; i < argc; i++) {
1214
1325
  VALUE op = argv[i];
1215
1326
  VALUE op_type = RARRAY_AREF(op, 0);
1216
1327
  VALUE op_len = RARRAY_LEN(op);
1328
+ unsigned int flags;
1217
1329
 
1218
1330
  if (op_type == SYM_write && op_len == 3) {
1219
1331
  last_sqe = Backend_chain_prepare_write(backend, RARRAY_AREF(op, 1), RARRAY_AREF(op, 2));
@@ -1223,13 +1335,16 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
1223
1335
  else if (op_type == SYM_splice && op_len == 4)
1224
1336
  last_sqe = Backend_chain_prepare_splice(backend, RARRAY_AREF(op, 1), RARRAY_AREF(op, 2), RARRAY_AREF(op, 3));
1225
1337
  else {
1338
+
1226
1339
  if (sqe_count) {
1340
+ struct io_uring_sqe *sqe;
1341
+
1227
1342
  io_uring_sqe_set_data(last_sqe, ctx);
1228
1343
  io_uring_sqe_set_flags(last_sqe, IOSQE_ASYNC);
1229
1344
 
1230
1345
  ctx->ref_count = sqe_count;
1231
1346
  ctx->result = -ECANCELED;
1232
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
1347
+ sqe = io_uring_get_sqe(&backend->ring);
1233
1348
  io_uring_prep_cancel(sqe, ctx, 0);
1234
1349
  backend->pending_sqes = 0;
1235
1350
  io_uring_submit(&backend->ring);
@@ -1242,7 +1357,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
1242
1357
  }
1243
1358
 
1244
1359
  io_uring_sqe_set_data(last_sqe, ctx);
1245
- unsigned int flags = (i == (argc - 1)) ? IOSQE_ASYNC : IOSQE_ASYNC | IOSQE_IO_LINK;
1360
+ flags = (i == (argc - 1)) ? IOSQE_ASYNC : IOSQE_ASYNC | IOSQE_IO_LINK;
1246
1361
  io_uring_sqe_set_flags(last_sqe, flags);
1247
1362
  sqe_count++;
1248
1363
  }
@@ -1251,14 +1366,16 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
1251
1366
  ctx->ref_count = sqe_count + 1;
1252
1367
  io_uring_backend_defer_submit(backend);
1253
1368
  resume_value = backend_await((struct Backend_base *)backend);
1254
- int result = ctx->result;
1255
- int completed = context_store_release(&backend->store, ctx);
1369
+ result = ctx->result;
1370
+ completed = context_store_release(&backend->store, ctx);
1256
1371
  if (!completed) {
1372
+ struct io_uring_sqe *sqe;
1373
+
1257
1374
  Backend_chain_ctx_attach_buffers(ctx, argc, argv);
1258
1375
 
1259
1376
  // op was not completed (an exception was raised), so we need to cancel it
1260
1377
  ctx->result = -ECANCELED;
1261
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
1378
+ sqe = io_uring_get_sqe(&backend->ring);
1262
1379
  io_uring_prep_cancel(sqe, ctx, 0);
1263
1380
  backend->pending_sqes = 0;
1264
1381
  io_uring_submit(&backend->ring);
@@ -1322,8 +1439,10 @@ static inline void splice_chunks_get_sqe(
1322
1439
  }
1323
1440
 
1324
1441
  static inline void splice_chunks_cancel(Backend_t *backend, op_context_t *ctx) {
1442
+ struct io_uring_sqe *sqe;
1443
+
1325
1444
  ctx->result = -ECANCELED;
1326
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
1445
+ sqe = io_uring_get_sqe(&backend->ring);
1327
1446
  io_uring_prep_cancel(sqe, ctx, 0);
1328
1447
  backend->pending_sqes = 0;
1329
1448
  io_uring_submit(&backend->ring);
@@ -1336,9 +1455,11 @@ static inline int splice_chunks_await_ops(
1336
1455
  VALUE *switchpoint_result
1337
1456
  )
1338
1457
  {
1458
+ int completed;
1339
1459
  int res = io_uring_backend_defer_submit_and_await(backend, 0, *ctx, switchpoint_result);
1460
+
1340
1461
  if (result) (*result) = res;
1341
- int completed = context_store_release(&backend->store, *ctx);
1462
+ completed = context_store_release(&backend->store, *ctx);
1342
1463
  if (!completed) {
1343
1464
  splice_chunks_cancel(backend, *ctx);
1344
1465
  if (TEST_EXCEPTION(*switchpoint_result)) return 1;
@@ -1352,17 +1473,22 @@ static inline int splice_chunks_await_ops(
1352
1473
 
1353
1474
  VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VALUE postfix, VALUE chunk_prefix, VALUE chunk_postfix, VALUE chunk_size) {
1354
1475
  Backend_t *backend;
1355
- GetBackend(self, backend);
1356
1476
  int total = 0;
1357
1477
  int err = 0;
1358
1478
  VALUE switchpoint_result = Qnil;
1359
1479
  op_context_t *ctx = 0;
1360
1480
  struct io_uring_sqe *sqe = 0;
1361
-
1481
+ int maxlen;
1482
+ VALUE underlying_io;
1483
+ VALUE str = Qnil;
1484
+ VALUE chunk_len_value = Qnil;
1362
1485
  rb_io_t *src_fptr;
1363
1486
  rb_io_t *dest_fptr;
1487
+ int pipefd[2] = { -1, -1 };
1488
+
1489
+ GetBackend(self, backend);
1364
1490
 
1365
- VALUE underlying_io = rb_ivar_get(src, ID_ivar_io);
1491
+ underlying_io = rb_ivar_get(src, ID_ivar_io);
1366
1492
  if (underlying_io != Qnil) src = underlying_io;
1367
1493
  GetOpenFile(src, src_fptr);
1368
1494
  io_verify_blocking_mode(src_fptr, src, Qtrue);
@@ -1373,11 +1499,8 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
1373
1499
  GetOpenFile(dest, dest_fptr);
1374
1500
  io_verify_blocking_mode(dest_fptr, dest, Qtrue);
1375
1501
 
1376
- int maxlen = NUM2INT(chunk_size);
1377
- VALUE str = Qnil;
1378
- VALUE chunk_len_value = Qnil;
1502
+ maxlen = NUM2INT(chunk_size);
1379
1503
 
1380
- int pipefd[2] = { -1, -1 };
1381
1504
  if (pipe(pipefd) == -1) {
1382
1505
  err = errno;
1383
1506
  goto syscallerror;
@@ -1521,6 +1644,7 @@ void Init_Backend() {
1521
1644
  rb_define_method(cBackend, "wait_io", Backend_wait_io, 2);
1522
1645
  rb_define_method(cBackend, "waitpid", Backend_waitpid, 1);
1523
1646
  rb_define_method(cBackend, "write", Backend_write_m, -1);
1647
+ // rb_define_method(cBackend, "close", Backend_close, 1);
1524
1648
 
1525
1649
  SYM_io_uring = ID2SYM(rb_intern("io_uring"));
1526
1650
  SYM_send = ID2SYM(rb_intern("send"));