polyphony 0.90 → 0.91

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d9f125403a124d0374ebef23adfd4fe7f553767797003d63513ef780a248370b
4
- data.tar.gz: 682134740af1614ac5e31d49c7d6a8ac8b881bbc26e5911e2f12a81f5ea52b27
3
+ metadata.gz: d1b4a68e893c4cdca8e308cf3297fbf2549f70c0a7038f7c492f5c7c0a6ca6b4
4
+ data.tar.gz: 65a1cd1b10fa1a29c37c24972c0a47c324f744ff0ddba6e67464000da2a2707e
5
5
  SHA512:
6
- metadata.gz: d6292c9f2ddd6faf3d8df9565f8e6dce3be9ecd64fff95201bd2907cfacdb46eac5ef87a9281a3e88324471951493b6ebaa150dad40afb6a19958dd1e5992c0c
7
- data.tar.gz: 10f8e607a0bd403664318e03abd4bbb4ab16704a69d1c0858ce5c9269c5c883e081dd95c51488dce7732ae471bf04cd139c0cbfb9623d6751a857551304e60f5
6
+ metadata.gz: 316969779f3e2ce5a055c886ee89448b1908e57dcfb06775f5aa01491e895b450cfdaa3ec3d1f72f3a59017326dd7c3478b21e85cb7914a8bf2c17544bd47de7
7
+ data.tar.gz: 0a5badc5927cac1b111a13dd65eac242e2c2a7436dbf9a42e2376c4b321d042e27012e7d6b3906bf1d434d62a85bbfa8651700f2d4585475cbf89bc52de64569
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 0.91 2022-03-23
2
+
3
+ - Add pipe examples
4
+ - Implement `Backend#double_splice_to_eof` (io_ring only)
5
+ - Improve safety of tracing
6
+
1
7
  ## 0.90 2022-03-21
2
8
 
3
9
  - Fix possible compilation error on Ruby 2.7.5 (#79)
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.90)
4
+ polyphony (0.91)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ def handle_client(conn)
7
+ spin do
8
+ buffer = Polyphony.pipe
9
+ spin { IO.splice_to_eof(conn, buffer) }
10
+ IO.splice_to_eof(buffer, conn)
11
+ end
12
+ rescue SystemCallError
13
+ # ignore
14
+ end
15
+
16
+ puts "Serving echo on port 1234..."
17
+ TCPServer.new('127.0.0.1', 1234).accept_loop { |c| handle_client(c) }
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ IO.gunzip(STDIN, STDOUT)
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ IO.gzip(STDIN, STDOUT)
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/inline'
4
+
5
+ gemfile do
6
+ gem 'h1p'
7
+ gem 'polyphony', path: '.'
8
+ end
9
+
10
+ require 'polyphony'
11
+ require 'h1p'
12
+
13
+ def handle_client(conn)
14
+ spin do
15
+ parser = H1P::Parser.new(conn, :server)
16
+
17
+ while true # assuming persistent connection
18
+ headers = parser.parse_headers
19
+ break unless headers
20
+
21
+ raw_buffer = Polyphony.pipe
22
+ gzip_buffer = Polyphony.pipe
23
+
24
+ # splice request body to buffer
25
+ spin do
26
+ parser.splice_body_to(raw_buffer)
27
+ raw_buffer.close
28
+ end
29
+
30
+ # zip data from buffer into gzip buffer
31
+ spin do
32
+ IO.gzip(raw_buffer, gzip_buffer)
33
+ gzip_buffer.close
34
+ end
35
+
36
+ # send headers and splice response from gzip buffer
37
+ conn << "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"
38
+ IO.http1_splice_chunked(gzip_buffer, conn, 65535)
39
+ end
40
+ rescue H1P::Error
41
+ puts 'Got invalid request, closing connection...'
42
+ ensure
43
+ conn.close
44
+ end
45
+ end
46
+
47
+ puts "Serving echo on port 1234..."
48
+ TCPServer.new('127.0.0.1', 1234).accept_loop { |c| handle_client(c) }
49
+
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ DESTINATION = ['127.0.0.1', 1234]
7
+
8
+ def handle_client(conn)
9
+ spin do
10
+ dest = TCPSocket.new(*DESTINATION)
11
+ w_buffer = Polyphony.pipe
12
+ r_buffer = Polyphony.pipe
13
+
14
+ spin { IO.splice_to_eof(conn, w_buffer) }
15
+ spin { IO.splice_to_eof(w_buffer, dest) }
16
+
17
+ spin { IO.splice_to_eof(dest, r_buffer) }
18
+ spin { IO.splice_to_eof(r_buffer, conn) }
19
+
20
+ Fiber.current.await_all_children
21
+ end
22
+ rescue SystemCallError
23
+ dest.close rescue nil
24
+ # ignore
25
+ end
26
+
27
+ puts "Serving TCP proxy on port 4321..."
28
+ TCPServer.new('127.0.0.1', 4321).accept_loop { |c| handle_client(c) }
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ chunk_size = 1 << 16
7
+ file_path = ARGV[0]
8
+
9
+ File.open(file_path, 'w+') do |f|
10
+ loop do
11
+ len = IO.tee(STDIN, STDOUT, chunk_size)
12
+ break if len == 0
13
+ IO.splice(STDIN, f, len)
14
+ end
15
+ end
@@ -140,7 +140,9 @@ inline void backend_base_unpark_fiber(struct Backend_base *base, VALUE fiber) {
140
140
  inline void backend_trace(struct Backend_base *base, int argc, VALUE *argv) {
141
141
  if (base->trace_proc == Qnil || base->in_trace_proc) return;
142
142
 
143
+ base->in_trace_proc = 1;
143
144
  rb_funcallv(base->trace_proc, ID_call, argc, argv);
145
+ base->in_trace_proc = 0;
144
146
  }
145
147
 
146
148
  #ifdef POLYPHONY_USE_PIDFD_OPEN
@@ -416,13 +418,13 @@ VALUE Backend_stats(VALUE self) {
416
418
  struct backend_stats backend_stats = backend_get_stats(self);
417
419
 
418
420
  VALUE stats = rb_hash_new();
419
- rb_hash_aset(stats, SYM_runqueue_size, INT2NUM(backend_stats.runqueue_size));
420
- rb_hash_aset(stats, SYM_runqueue_length, INT2NUM(backend_stats.runqueue_length));
421
- rb_hash_aset(stats, SYM_runqueue_max_length, INT2NUM(backend_stats.runqueue_max_length));
422
- rb_hash_aset(stats, SYM_op_count, INT2NUM(backend_stats.op_count));
423
- rb_hash_aset(stats, SYM_switch_count, INT2NUM(backend_stats.switch_count));
424
- rb_hash_aset(stats, SYM_poll_count, INT2NUM(backend_stats.poll_count));
425
- rb_hash_aset(stats, SYM_pending_ops, INT2NUM(backend_stats.pending_ops));
421
+ rb_hash_aset(stats, SYM_runqueue_size, INT2FIX(backend_stats.runqueue_size));
422
+ rb_hash_aset(stats, SYM_runqueue_length, INT2FIX(backend_stats.runqueue_length));
423
+ rb_hash_aset(stats, SYM_runqueue_max_length, INT2FIX(backend_stats.runqueue_max_length));
424
+ rb_hash_aset(stats, SYM_op_count, INT2FIX(backend_stats.op_count));
425
+ rb_hash_aset(stats, SYM_switch_count, INT2FIX(backend_stats.switch_count));
426
+ rb_hash_aset(stats, SYM_poll_count, INT2FIX(backend_stats.poll_count));
427
+ rb_hash_aset(stats, SYM_pending_ops, INT2FIX(backend_stats.pending_ops));
426
428
  RB_GC_GUARD(stats);
427
429
  return stats;
428
430
  }
@@ -364,7 +364,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
364
364
  int fd;
365
365
  rb_io_t *fptr;
366
366
  struct io_buffer buffer = get_io_buffer(str);
367
- long buf_pos = NUM2INT(pos);
367
+ long buf_pos = FIX2INT(pos);
368
368
  int shrinkable_string = 0;
369
369
  int expandable_buffer = 0;
370
370
  long total = 0;
@@ -456,7 +456,7 @@ VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen) {
456
456
  rb_io_t *fptr;
457
457
  VALUE str;
458
458
  long total;
459
- long len = NUM2INT(maxlen);
459
+ long len = FIX2INT(maxlen);
460
460
  int shrinkable;
461
461
  char *buf;
462
462
 
@@ -584,7 +584,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
584
584
  }
585
585
  }
586
586
 
587
- return INT2NUM(buffer.len);
587
+ return INT2FIX(buffer.len);
588
588
  }
589
589
 
590
590
  VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
@@ -652,7 +652,7 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
652
652
  }
653
653
 
654
654
  free(iov);
655
- return INT2NUM(total_written);
655
+ return INT2FIX(total_written);
656
656
  }
657
657
 
658
658
  VALUE Backend_write_m(int argc, VALUE *argv, VALUE self) {
@@ -669,7 +669,7 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos) {
669
669
  int fd;
670
670
  rb_io_t *fptr;
671
671
  struct io_buffer buffer = get_io_buffer(str);
672
- long buf_pos = NUM2INT(pos);
672
+ long buf_pos = FIX2INT(pos);
673
673
  int shrinkable_string = 0;
674
674
  int expandable_buffer = 0;
675
675
  long total = 0;
@@ -742,7 +742,7 @@ VALUE Backend_recv_loop(VALUE self, VALUE io, VALUE maxlen) {
742
742
  rb_io_t *fptr;
743
743
  VALUE str;
744
744
  long total;
745
- long len = NUM2INT(maxlen);
745
+ long len = FIX2INT(maxlen);
746
746
  int shrinkable;
747
747
  char *buf;
748
748
 
@@ -838,7 +838,7 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
838
838
 
839
839
  struct io_buffer buffer = get_io_buffer(str);
840
840
  long left = buffer.len;
841
- int flags_int = NUM2INT(flags);
841
+ int flags_int = FIX2INT(flags);
842
842
 
843
843
  GetBackend(self, backend);
844
844
  fd = fd_from_io(io, &fptr, 1, 0);
@@ -869,7 +869,7 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
869
869
  }
870
870
  }
871
871
 
872
- return INT2NUM(buffer.len);
872
+ return INT2FIX(buffer.len);
873
873
  }
874
874
 
875
875
  VALUE io_uring_backend_accept(Backend_t *backend, VALUE server_socket, VALUE socket_class, int loop) {
@@ -954,7 +954,7 @@ VALUE io_uring_backend_splice(Backend_t *backend, VALUE src, VALUE dest, VALUE m
954
954
  int result;
955
955
  int completed;
956
956
 
957
- io_uring_prep_splice(sqe, src_fd, -1, dest_fd, -1, NUM2INT(maxlen), 0);
957
+ io_uring_prep_splice(sqe, src_fd, -1, dest_fd, -1, FIX2INT(maxlen), 0);
958
958
 
959
959
  result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
960
960
  completed = context_store_release(&backend->store, ctx);
@@ -965,7 +965,7 @@ VALUE io_uring_backend_splice(Backend_t *backend, VALUE src, VALUE dest, VALUE m
965
965
  rb_syserr_fail(-result, strerror(-result));
966
966
 
967
967
  total += result;
968
- if (result == 0 || !loop) return INT2NUM(total);
968
+ if (result == 0 || !loop) return INT2FIX(total);
969
969
  }
970
970
 
971
971
  RB_GC_GUARD(resume_value);
@@ -984,6 +984,112 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE chunksize)
984
984
  return io_uring_backend_splice(backend, src, dest, chunksize, 1);
985
985
  }
986
986
 
987
+ struct double_splice_ctx {
988
+ Backend_t *backend;
989
+ VALUE src;
990
+ VALUE dest;
991
+ int pipefd[2];
992
+ };
993
+
994
+ #define DOUBLE_SPLICE_MAXLEN (1 << 16)
995
+
996
+ static inline op_context_t *prepare_double_splice_ctx(Backend_t *backend, int src_fd, int dest_fd) {
997
+ op_context_t *ctx = context_store_acquire(&backend->store, OP_SPLICE);
998
+ struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
999
+ io_uring_prep_splice(sqe, src_fd, -1, dest_fd, -1, DOUBLE_SPLICE_MAXLEN, 0);
1000
+ io_uring_sqe_set_data(sqe, ctx);
1001
+ io_uring_sqe_set_flags(sqe, IOSQE_ASYNC);
1002
+ backend->base.op_count += 1;
1003
+ backend->pending_sqes += 1;
1004
+
1005
+ return ctx;
1006
+ }
1007
+
1008
+ static inline void io_uring_backend_cancel(Backend_t *backend, op_context_t *ctx) {
1009
+ struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
1010
+ ctx->result = -ECANCELED;
1011
+ io_uring_prep_cancel(sqe, (__u64)ctx, 0);
1012
+ }
1013
+
1014
+ VALUE double_splice_to_eof_safe(struct double_splice_ctx *ctx) {
1015
+ int src_fd;
1016
+ int dest_fd;
1017
+ rb_io_t *src_fptr;
1018
+ rb_io_t *dest_fptr;
1019
+ int total = 0;
1020
+ VALUE resume_value = Qnil;
1021
+
1022
+ src_fd = fd_from_io(ctx->src, &src_fptr, 0, 0);
1023
+ dest_fd = fd_from_io(ctx->dest, &dest_fptr, 1, 0);
1024
+
1025
+ op_context_t *ctx_src = prepare_double_splice_ctx(ctx->backend, src_fd, ctx->pipefd[1]);
1026
+ op_context_t *ctx_dest = prepare_double_splice_ctx(ctx->backend, ctx->pipefd[0], dest_fd);
1027
+
1028
+ if (ctx->backend->pending_sqes >= ctx->backend->prepared_limit)
1029
+ io_uring_backend_immediate_submit(ctx->backend);
1030
+
1031
+ while (1) {
1032
+ resume_value = backend_await((struct Backend_base *)ctx->backend);
1033
+
1034
+ if ((ctx_src && ctx_src->ref_count == 2 && ctx_dest && ctx_dest->ref_count == 2) || TEST_EXCEPTION(resume_value)) {
1035
+ if (ctx_src) {
1036
+ context_store_release(&ctx->backend->store, ctx_src);
1037
+ io_uring_backend_cancel(ctx->backend, ctx_src);
1038
+ }
1039
+ if (ctx_dest) {
1040
+ context_store_release(&ctx->backend->store, ctx_dest);
1041
+ io_uring_backend_cancel(ctx->backend, ctx_dest);
1042
+ }
1043
+ io_uring_backend_immediate_submit(ctx->backend);
1044
+ RAISE_IF_EXCEPTION(resume_value);
1045
+ return resume_value;
1046
+ }
1047
+
1048
+ if (ctx_src && ctx_src->ref_count == 1) {
1049
+ context_store_release(&ctx->backend->store, ctx_src);
1050
+ if (ctx_src->result == 0) {
1051
+ // close write end of pipe
1052
+ close(ctx->pipefd[1]);
1053
+ ctx_src = NULL;
1054
+ }
1055
+ else {
1056
+ ctx_src = prepare_double_splice_ctx(ctx->backend, src_fd, ctx->pipefd[1]);
1057
+ }
1058
+ }
1059
+ if (ctx_dest && ctx_dest->ref_count == 1) {
1060
+ context_store_release(&ctx->backend->store, ctx_dest);
1061
+ if (ctx_dest->result == 0)
1062
+ break;
1063
+ else {
1064
+ total += ctx_dest->result;
1065
+ ctx_dest = prepare_double_splice_ctx(ctx->backend, ctx->pipefd[0], dest_fd);
1066
+ }
1067
+ }
1068
+
1069
+ if (ctx->backend->pending_sqes >= ctx->backend->prepared_limit)
1070
+ io_uring_backend_immediate_submit(ctx->backend);
1071
+ }
1072
+ RB_GC_GUARD(resume_value);
1073
+ return INT2FIX(total);
1074
+ }
1075
+
1076
+ VALUE double_splice_to_eof_cleanup(struct double_splice_ctx *ctx) {
1077
+ if (ctx->pipefd[0]) close(ctx->pipefd[0]);
1078
+ if (ctx->pipefd[1]) close(ctx->pipefd[1]);
1079
+ return Qnil;
1080
+ }
1081
+
1082
+ VALUE Backend_double_splice_to_eof(VALUE self, VALUE src, VALUE dest) {
1083
+ struct double_splice_ctx ctx = { NULL, src, dest, 0, 0 };
1084
+ GetBackend(self, ctx.backend);
1085
+ if (pipe(ctx.pipefd) == -1) rb_syserr_fail(errno, strerror(errno));
1086
+
1087
+ return rb_ensure(
1088
+ SAFE(double_splice_to_eof_safe), (VALUE)&ctx,
1089
+ SAFE(double_splice_to_eof_cleanup), (VALUE)&ctx
1090
+ );
1091
+ }
1092
+
987
1093
  VALUE Backend_tee(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
988
1094
  Backend_t *backend;
989
1095
  GetBackend(self, backend);
@@ -1003,7 +1109,7 @@ VALUE Backend_tee(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
1003
1109
  int result;
1004
1110
  int completed;
1005
1111
 
1006
- io_uring_prep_tee(sqe, src_fd, dest_fd, NUM2INT(maxlen), 0);
1112
+ io_uring_prep_tee(sqe, src_fd, dest_fd, FIX2INT(maxlen), 0);
1007
1113
 
1008
1114
  result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
1009
1115
  completed = context_store_release(&backend->store, ctx);
@@ -1013,7 +1119,7 @@ VALUE Backend_tee(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
1013
1119
  if (result < 0)
1014
1120
  rb_syserr_fail(-result, strerror(-result));
1015
1121
 
1016
- return INT2NUM(result);
1122
+ return INT2FIX(result);
1017
1123
  }
1018
1124
 
1019
1125
  RB_GC_GUARD(resume_value);
@@ -1222,7 +1328,7 @@ VALUE Backend_timeout(int argc, VALUE *argv, VALUE self) {
1222
1328
  }
1223
1329
 
1224
1330
  VALUE Backend_waitpid(VALUE self, VALUE pid) {
1225
- int pid_int = NUM2INT(pid);
1331
+ int pid_int = FIX2INT(pid);
1226
1332
  int fd = pidfd_open(pid_int, 0);
1227
1333
  int status;
1228
1334
  pid_t ret;
@@ -1246,7 +1352,7 @@ VALUE Backend_waitpid(VALUE self, VALUE pid) {
1246
1352
  else
1247
1353
  rb_syserr_fail(e, strerror(e));
1248
1354
  }
1249
- return rb_ary_new_from_args(2, INT2NUM(ret), INT2NUM(WEXITSTATUS(status)));
1355
+ return rb_ary_new_from_args(2, INT2FIX(ret), INT2FIX(WEXITSTATUS(status)));
1250
1356
  }
1251
1357
 
1252
1358
  /*
@@ -1324,7 +1430,7 @@ struct io_uring_sqe *Backend_chain_prepare_send(Backend_t *backend, VALUE io, VA
1324
1430
  fd = fd_from_io(io, &fptr, 1, 0);
1325
1431
 
1326
1432
  sqe = io_uring_backend_get_sqe(backend);
1327
- io_uring_prep_send(sqe, fd, StringValuePtr(str), RSTRING_LEN(str), NUM2INT(flags));
1433
+ io_uring_prep_send(sqe, fd, StringValuePtr(str), RSTRING_LEN(str), FIX2INT(flags));
1328
1434
  return sqe;
1329
1435
  }
1330
1436
 
@@ -1338,7 +1444,7 @@ struct io_uring_sqe *Backend_chain_prepare_splice(Backend_t *backend, VALUE src,
1338
1444
  src_fd = fd_from_io(src, &src_fptr, 0, 0);
1339
1445
  dest_fd = fd_from_io(dest, &dest_fptr, 1, 0);
1340
1446
  sqe = io_uring_backend_get_sqe(backend);
1341
- io_uring_prep_splice(sqe, src_fd, -1, dest_fd, -1, NUM2INT(maxlen), 0);
1447
+ io_uring_prep_splice(sqe, src_fd, -1, dest_fd, -1, FIX2INT(maxlen), 0);
1342
1448
  return sqe;
1343
1449
  }
1344
1450
 
@@ -1434,7 +1540,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
1434
1540
  }
1435
1541
 
1436
1542
  RB_GC_GUARD(resume_value);
1437
- return INT2NUM(result);
1543
+ return INT2FIX(result);
1438
1544
  }
1439
1545
 
1440
1546
  VALUE Backend_idle_gc_period_set(VALUE self, VALUE period) {
@@ -1540,7 +1646,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
1540
1646
  src_fd = fd_from_io(src, &src_fptr, 0, 0);
1541
1647
  dest_fd = fd_from_io(dest, &dest_fptr, 1, 0);
1542
1648
 
1543
- maxlen = NUM2INT(chunk_size);
1649
+ maxlen = FIX2INT(chunk_size);
1544
1650
 
1545
1651
  if (pipe(pipefd) == -1) {
1546
1652
  err = errno;
@@ -1566,7 +1672,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
1566
1672
  if (chunk_len == 0) break;
1567
1673
 
1568
1674
  total += chunk_len;
1569
- chunk_len_value = INT2NUM(chunk_len);
1675
+ chunk_len_value = INT2FIX(chunk_len);
1570
1676
 
1571
1677
 
1572
1678
  if (chunk_prefix != Qnil) {
@@ -1605,7 +1711,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
1605
1711
  RB_GC_GUARD(switchpoint_result);
1606
1712
  if (pipefd[0] != -1) close(pipefd[0]);
1607
1713
  if (pipefd[1] != -1) close(pipefd[1]);
1608
- return INT2NUM(total);
1714
+ return INT2FIX(total);
1609
1715
  syscallerror:
1610
1716
  if (pipefd[0] != -1) close(pipefd[0]);
1611
1717
  if (pipefd[1] != -1) close(pipefd[1]);
@@ -1693,9 +1799,12 @@ void Init_Backend() {
1693
1799
  rb_define_method(cBackend, "send", Backend_send, 3);
1694
1800
  rb_define_method(cBackend, "sendv", Backend_sendv, 3);
1695
1801
  rb_define_method(cBackend, "sleep", Backend_sleep, 1);
1802
+
1696
1803
  rb_define_method(cBackend, "splice", Backend_splice, 3);
1697
1804
  rb_define_method(cBackend, "splice_to_eof", Backend_splice_to_eof, 3);
1805
+ rb_define_method(cBackend, "double_splice_to_eof", Backend_double_splice_to_eof, 2);
1698
1806
  rb_define_method(cBackend, "tee", Backend_tee, 3);
1807
+
1699
1808
  rb_define_method(cBackend, "timeout", Backend_timeout, -1);
1700
1809
  rb_define_method(cBackend, "timer_loop", Backend_timer_loop, 1);
1701
1810
  rb_define_method(cBackend, "wait_event", Backend_wait_event, 1);
@@ -291,7 +291,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
291
291
  rb_io_t *fptr;
292
292
 
293
293
  struct io_buffer buffer = get_io_buffer(str);
294
- long buf_pos = NUM2INT(pos);
294
+ long buf_pos = FIX2INT(pos);
295
295
  int shrinkable_string = 0;
296
296
  int expandable_buffer = 0;
297
297
  long total = 0;
@@ -389,7 +389,7 @@ VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen) {
389
389
  rb_io_t *fptr;
390
390
  VALUE str;
391
391
  long total;
392
- long len = NUM2INT(maxlen);
392
+ long len = FIX2INT(maxlen);
393
393
  int shrinkable;
394
394
  char *buf;
395
395
  VALUE switchpoint_result = Qnil;
@@ -519,7 +519,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
519
519
  RB_GC_GUARD(watcher.fiber);
520
520
  RB_GC_GUARD(switchpoint_result);
521
521
 
522
- return INT2NUM(buffer.len);
522
+ return INT2FIX(buffer.len);
523
523
  error:
524
524
  return RAISE_EXCEPTION(switchpoint_result);
525
525
  }
@@ -590,7 +590,7 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
590
590
  RB_GC_GUARD(switchpoint_result);
591
591
 
592
592
  free(iov);
593
- return INT2NUM(total_written);
593
+ return INT2FIX(total_written);
594
594
  error:
595
595
  free(iov);
596
596
  return RAISE_EXCEPTION(switchpoint_result);
@@ -763,7 +763,7 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
763
763
 
764
764
  struct io_buffer buffer = get_io_buffer(str);
765
765
  long left = buffer.len;
766
- int flags_int = NUM2INT(flags);
766
+ int flags_int = FIX2INT(flags);
767
767
 
768
768
  GetBackend(self, backend);
769
769
  fd = fd_from_io(io, &fptr, 1, 0);
@@ -795,7 +795,7 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
795
795
  RB_GC_GUARD(watcher.fiber);
796
796
  RB_GC_GUARD(switchpoint_result);
797
797
 
798
- return INT2NUM(buffer.len);
798
+ return INT2FIX(buffer.len);
799
799
  error:
800
800
  return RAISE_EXCEPTION(switchpoint_result);
801
801
  }
@@ -868,7 +868,7 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
868
868
 
869
869
  while (1) {
870
870
  backend->base.op_count++;
871
- len = splice(src_fd, 0, dest_fd, 0, NUM2INT(maxlen), 0);
871
+ len = splice(src_fd, 0, dest_fd, 0, FIX2INT(maxlen), 0);
872
872
  if (len < 0) {
873
873
  int e = errno;
874
874
  if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
@@ -889,7 +889,7 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
889
889
  RB_GC_GUARD(watcher.ctx.fiber);
890
890
  RB_GC_GUARD(switchpoint_result);
891
891
 
892
- return INT2NUM(len);
892
+ return INT2FIX(len);
893
893
  error:
894
894
  return RAISE_EXCEPTION(switchpoint_result);
895
895
  }
@@ -912,7 +912,7 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
912
912
 
913
913
  while (1) {
914
914
  backend->base.op_count++;
915
- len = splice(src_fd, 0, dest_fd, 0, NUM2INT(maxlen), 0);
915
+ len = splice(src_fd, 0, dest_fd, 0, FIX2INT(maxlen), 0);
916
916
  if (len < 0) {
917
917
  int e = errno;
918
918
  if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
@@ -936,7 +936,7 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
936
936
  RB_GC_GUARD(watcher.ctx.fiber);
937
937
  RB_GC_GUARD(switchpoint_result);
938
938
 
939
- return INT2NUM(total);
939
+ return INT2FIX(total);
940
940
  error:
941
941
  return RAISE_EXCEPTION(switchpoint_result);
942
942
  }
@@ -958,7 +958,7 @@ VALUE Backend_tee(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
958
958
 
959
959
  while (1) {
960
960
  backend->base.op_count++;
961
- len = tee(src_fd, dest_fd, NUM2INT(maxlen), 0);
961
+ len = tee(src_fd, dest_fd, FIX2INT(maxlen), 0);
962
962
  if (len < 0) {
963
963
  int e = errno;
964
964
  if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
@@ -979,7 +979,7 @@ VALUE Backend_tee(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
979
979
  RB_GC_GUARD(watcher.ctx.fiber);
980
980
  RB_GC_GUARD(switchpoint_result);
981
981
 
982
- return INT2NUM(len);
982
+ return INT2FIX(len);
983
983
  error:
984
984
  return RAISE_EXCEPTION(switchpoint_result);
985
985
  }
@@ -994,7 +994,7 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
994
994
  int dest_fd;
995
995
  rb_io_t *src_fptr;
996
996
  rb_io_t *dest_fptr;
997
- int len = NUM2INT(maxlen);
997
+ int len = FIX2INT(maxlen);
998
998
  VALUE str = rb_str_new(0, len);
999
999
  char *buf = RSTRING_PTR(str);
1000
1000
  int left = 0;
@@ -1047,7 +1047,7 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
1047
1047
  RB_GC_GUARD(switchpoint_result);
1048
1048
  RB_GC_GUARD(str);
1049
1049
 
1050
- return INT2NUM(total);
1050
+ return INT2FIX(total);
1051
1051
  error:
1052
1052
  return RAISE_EXCEPTION(switchpoint_result);
1053
1053
  }
@@ -1060,7 +1060,7 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
1060
1060
  int dest_fd;
1061
1061
  rb_io_t *src_fptr;
1062
1062
  rb_io_t *dest_fptr;
1063
- int len = NUM2INT(maxlen);
1063
+ int len = FIX2INT(maxlen);
1064
1064
  VALUE str = rb_str_new(0, len);
1065
1065
  char *buf = RSTRING_PTR(str);
1066
1066
  int left = 0;
@@ -1118,7 +1118,7 @@ done:
1118
1118
  RB_GC_GUARD(switchpoint_result);
1119
1119
  RB_GC_GUARD(str);
1120
1120
 
1121
- return INT2NUM(total);
1121
+ return INT2FIX(total);
1122
1122
  error:
1123
1123
  return RAISE_EXCEPTION(switchpoint_result);
1124
1124
  }
@@ -1263,7 +1263,7 @@ VALUE Backend_timeout(int argc,VALUE *argv, VALUE self) {
1263
1263
 
1264
1264
  #ifdef POLYPHONY_USE_PIDFD_OPEN
1265
1265
  VALUE Backend_waitpid(VALUE self, VALUE pid) {
1266
- int pid_int = NUM2INT(pid);
1266
+ int pid_int = FIX2INT(pid);
1267
1267
  int fd = pidfd_open(pid_int, 0);
1268
1268
  if (fd >= 0) {
1269
1269
  Backend_t *backend;
@@ -1286,7 +1286,7 @@ VALUE Backend_waitpid(VALUE self, VALUE pid) {
1286
1286
  int e = errno;
1287
1287
  rb_syserr_fail(e, strerror(e));
1288
1288
  }
1289
- return rb_ary_new_from_args(2, INT2NUM(ret), INT2NUM(WEXITSTATUS(status)));
1289
+ return rb_ary_new_from_args(2, INT2FIX(ret), INT2FIX(WEXITSTATUS(status)));
1290
1290
  }
1291
1291
  #else
1292
1292
  struct libev_child {
@@ -1299,7 +1299,7 @@ void Backend_child_callback(EV_P_ ev_child *w, int revents) {
1299
1299
  int exit_status = WEXITSTATUS(w->rstatus);
1300
1300
  VALUE status;
1301
1301
 
1302
- status = rb_ary_new_from_args(2, INT2NUM(w->rpid), INT2NUM(exit_status));
1302
+ status = rb_ary_new_from_args(2, INT2FIX(w->rpid), INT2FIX(exit_status));
1303
1303
  Fiber_make_runnable(watcher->fiber, status);
1304
1304
  }
1305
1305
 
@@ -1310,7 +1310,7 @@ VALUE Backend_waitpid(VALUE self, VALUE pid) {
1310
1310
  GetBackend(self, backend);
1311
1311
 
1312
1312
  watcher.fiber = rb_fiber_current();
1313
- ev_child_init(&watcher.child, Backend_child_callback, NUM2INT(pid), 0);
1313
+ ev_child_init(&watcher.child, Backend_child_callback, FIX2INT(pid), 0);
1314
1314
  ev_child_start(backend->ev_loop, &watcher.child);
1315
1315
  backend->base.op_count++;
1316
1316
 
@@ -1491,7 +1491,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
1491
1491
 
1492
1492
  struct libev_rw_io watcher;
1493
1493
  watcher.ctx.fiber = Qnil;
1494
- int maxlen = NUM2INT(chunk_size);
1494
+ int maxlen = FIX2INT(chunk_size);
1495
1495
  VALUE str = Qnil;
1496
1496
  VALUE chunk_len_value = Qnil;
1497
1497
 
@@ -1515,7 +1515,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
1515
1515
  if (chunk_len == 0) break;
1516
1516
 
1517
1517
  total += chunk_len;
1518
- chunk_len_value = INT2NUM(chunk_len);
1518
+ chunk_len_value = INT2FIX(chunk_len);
1519
1519
 
1520
1520
  if (chunk_prefix != Qnil) {
1521
1521
  VALUE str = (TYPE(chunk_prefix) == T_STRING) ? chunk_prefix : rb_funcall(chunk_prefix, ID_call, 1, chunk_len_value);
@@ -1553,7 +1553,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
1553
1553
  RB_GC_GUARD(result);
1554
1554
  if (pipefd[0] != -1) close(pipefd[0]);
1555
1555
  if (pipefd[1] != -1) close(pipefd[1]);
1556
- return INT2NUM(total);
1556
+ return INT2FIX(total);
1557
1557
  syscallerror:
1558
1558
  if (pipefd[0] != -1) close(pipefd[0]);
1559
1559
  if (pipefd[1] != -1) close(pipefd[1]);
@@ -502,7 +502,6 @@ static inline VALUE z_stream_cleanup(struct z_stream_ctx *ctx) {
502
502
  return Qnil;
503
503
  }
504
504
 
505
- #define SAFE(f) (VALUE (*)(VALUE))(f)
506
505
  #define Z_STREAM_SAFE_IO_LOOP_WITH_CLEANUP(ctx) \
507
506
  rb_ensure(SAFE(z_stream_io_loop), (VALUE)&ctx, SAFE(z_stream_cleanup), (VALUE)&ctx)
508
507
 
@@ -94,6 +94,12 @@ VALUE Polyphony_backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE c
94
94
  return Backend_splice_to_eof(BACKEND(), src, dest, chunksize);
95
95
  }
96
96
 
97
+ #ifdef POLYPHONY_BACKEND_LIBURING
98
+ VALUE Polyphony_backend_double_splice_to_eof(VALUE self, VALUE src, VALUE dest) {
99
+ return Backend_double_splice_to_eof(BACKEND(), src, dest);
100
+ }
101
+ #endif
102
+
97
103
  #ifdef POLYPHONY_LINUX
98
104
  VALUE Polyphony_backend_tee(VALUE self, VALUE src, VALUE dest, VALUE chunksize) {
99
105
  return Backend_tee(BACKEND(), src, dest, chunksize);
@@ -126,7 +132,7 @@ VALUE Polyphony_backend_write(int argc, VALUE *argv, VALUE self) {
126
132
 
127
133
  VALUE Polyphony_with_raw_buffer(VALUE self, VALUE size) {
128
134
  struct raw_buffer buffer;
129
- buffer.len = NUM2INT(size);
135
+ buffer.len = FIX2INT(size);
130
136
  buffer.ptr = malloc(buffer.len);
131
137
  if (!buffer.ptr)
132
138
  rb_raise(rb_eRuntimeError, "Failed to allocate buffer");
@@ -187,6 +193,10 @@ void Init_Polyphony() {
187
193
  rb_define_singleton_method(mPolyphony, "backend_splice", Polyphony_backend_splice, 3);
188
194
  rb_define_singleton_method(mPolyphony, "backend_splice_to_eof", Polyphony_backend_splice_to_eof, 3);
189
195
 
196
+ #ifdef POLYPHONY_BACKEND_LIBURING
197
+ rb_define_singleton_method(mPolyphony, "backend_double_splice_to_eof", Polyphony_backend_double_splice_to_eof, 2);
198
+ #endif
199
+
190
200
  #ifdef POLYPHONY_LINUX
191
201
  rb_define_singleton_method(mPolyphony, "backend_tee", Polyphony_backend_tee, 3);
192
202
  #endif
@@ -35,6 +35,9 @@
35
35
 
36
36
  #define BACKEND() (rb_ivar_get(rb_thread_current(), ID_ivar_backend))
37
37
 
38
+ // SAFE is used to cast functions used in rb_ensure
39
+ #define SAFE(f) (VALUE (*)(VALUE))(f)
40
+
38
41
  extern VALUE mPolyphony;
39
42
  extern VALUE cPipe;
40
43
  extern VALUE cQueue;
@@ -114,6 +117,10 @@ VALUE Backend_sleep(VALUE self, VALUE duration);
114
117
  VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen);
115
118
  VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE chunksize);
116
119
 
120
+ #ifdef POLYPHONY_BACKEND_LIBURING
121
+ VALUE Backend_double_splice_to_eof(VALUE self, VALUE src, VALUE dest);
122
+ #endif
123
+
117
124
  #ifdef POLYPHONY_LINUX
118
125
  VALUE Backend_tee(VALUE self, VALUE src, VALUE dest, VALUE maxlen);
119
126
  #endif
@@ -210,7 +210,7 @@ VALUE Queue_capped_p(VALUE self) {
210
210
  Queue_t *queue;
211
211
  GetQueue(self, queue);
212
212
 
213
- return queue->capacity ? UINT2NUM(queue->capacity) : Qnil;
213
+ return queue->capacity ? INT2FIX(queue->capacity) : Qnil;
214
214
  }
215
215
 
216
216
  VALUE Queue_clear(VALUE self) {
@@ -280,14 +280,14 @@ VALUE Queue_num_waiting(VALUE self) {
280
280
  Queue_t *queue;
281
281
  GetQueue(self, queue);
282
282
 
283
- return INT2NUM(queue->shift_queue.count);
283
+ return INT2FIX(queue->shift_queue.count);
284
284
  }
285
285
 
286
286
  VALUE Queue_size_m(VALUE self) {
287
287
  Queue_t *queue;
288
288
  GetQueue(self, queue);
289
289
 
290
- return INT2NUM(queue->values.count);
290
+ return INT2FIX(queue->values.count);
291
291
  }
292
292
 
293
293
  VALUE Queue_closed_p(VALUE self) {
@@ -6,13 +6,13 @@ VALUE Socket_send(VALUE self, VALUE msg, VALUE flags) {
6
6
 
7
7
  VALUE Socket_write(int argc, VALUE *argv, VALUE self) {
8
8
  VALUE ary = rb_ary_new_from_values(argc, argv);
9
- VALUE result = Backend_sendv(BACKEND(), self, ary, INT2NUM(0));
9
+ VALUE result = Backend_sendv(BACKEND(), self, ary, INT2FIX(0));
10
10
  RB_GC_GUARD(ary);
11
11
  return result;
12
12
  }
13
13
 
14
14
  VALUE Socket_double_chevron(VALUE self, VALUE msg) {
15
- Backend_send(BACKEND(), self, msg, INT2NUM(0));
15
+ Backend_send(BACKEND(), self, msg, INT2FIX(0));
16
16
  return self;
17
17
  }
18
18
 
@@ -83,6 +83,10 @@ class ::IO
83
83
  end
84
84
 
85
85
  if RUBY_PLATFORM =~ /linux/
86
+ def double_splice_to_eof(src, dest)
87
+ Polyphony.backend_double_splice_to_eof(src, dest)
88
+ end
89
+
86
90
  def tee(src, dest, maxlen)
87
91
  Polyphony.backend_tee(src, dest, maxlen)
88
92
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.90'
4
+ VERSION = '0.91'
5
5
  end
data/test/stress.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  count = ARGV[0] ? ARGV[0].to_i : 100
4
4
  test_name = ARGV[1]
5
5
 
6
- $test_cmd = +'ruby test/run.rb --name test_cross_thread_send_receive'
6
+ $test_cmd = +'ruby test/run.rb --name test_signal_handler_trace'
7
7
  if test_name
8
8
  $test_cmd << " --name #{test_name}"
9
9
  end
data/test/test_io.rb CHANGED
@@ -368,6 +368,31 @@ class IOTest < MiniTest::Test
368
368
  end
369
369
  end
370
370
 
371
+ def test_double_splice_to_eof
372
+ if Thread.current.backend.kind == :io_uring
373
+ skip "IO.double_splice_to_eof available only with io_uring"
374
+ end
375
+
376
+ src = Polyphony.pipe
377
+ dest = Polyphony.pipe
378
+ ret = nil
379
+ data = 'foobar' * 10
380
+
381
+ f1 = spin {
382
+ ret = IO.double_splice_to_eof(src, dest)
383
+ dest.close
384
+ }
385
+
386
+ src << data
387
+ src.close
388
+
389
+ f1.await
390
+
391
+ spliced = dest.read
392
+ assert_equal data, spliced
393
+ assert_equal data.bytesize, ret
394
+ end
395
+
371
396
  def test_tee_from
372
397
  skip "tested only on Linux" unless RUBY_PLATFORM =~ /linux/
373
398
 
data/test/test_signal.rb CHANGED
@@ -32,11 +32,15 @@ class SignalTrapTest < Minitest::Test
32
32
  trap ('SIGINT') { raise Interrupt }
33
33
  end
34
34
 
35
+ # remove [:spin, :oob], [:schedule, :oob], since they are generated inside
36
+ # the signal handler, which occur while the trace proc is running.
37
+ events = events.reject do |e|
38
+ e == [:spin, :oob] || e == [:schedule, :oob]
39
+ end
40
+
35
41
  expected = [
36
42
  [:block, :main],
37
43
  [:enter_poll, :main],
38
- [:spin, :oob],
39
- [:schedule, :oob],
40
44
  [:leave_poll, :main],
41
45
  [:unblock, :oob],
42
46
  [:terminate, :oob],
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: polyphony
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.90'
4
+ version: '0.91'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-21 00:00:00.000000000 Z
11
+ date: 2022-03-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -305,6 +305,12 @@ files:
305
305
  - examples/performance/thread-vs-fiber/threaded_server.rb
306
306
  - examples/performance/thread_pool_perf.rb
307
307
  - examples/performance/thread_switch.rb
308
+ - examples/pipes/echo_server.rb
309
+ - examples/pipes/gunzip.rb
310
+ - examples/pipes/gzip.rb
311
+ - examples/pipes/gzip_http_server.rb
312
+ - examples/pipes/tcp_proxy.rb
313
+ - examples/pipes/tee.rb
308
314
  - ext/libev/Changes
309
315
  - ext/libev/LICENSE
310
316
  - ext/libev/README