polyphony 0.51.0 → 0.52.0

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: 72f11d867863c51f1fc1ab3ec85fe575cca9ee53a5047f4d3f7b76cea3b650b7
4
- data.tar.gz: c29354b2de2f207185fc06fd86421b53d328aaf67d611109a6f95e9130ac5967
3
+ metadata.gz: 2056b02e3b364911ab627ffc49a7251ad2eed68ba6b5b61d380c599127c181f6
4
+ data.tar.gz: 440f57d240b90a255b470f405980b5fa2f806ba3ff2640f31d78b6403de7ce0e
5
5
  SHA512:
6
- metadata.gz: 93351a3c4007145ff317257f82b764708b445e94b848d31f783f4d72071b097a8309322c4bedfdb7f321b0613ef436a314ad4e650928d0855143d3a5b98d9c13
7
- data.tar.gz: 9119039548264867fa012bcbb90999f4ad82170c28539d43b0145687a761d508630da538ac87b75f9bf32f6b33cb0e13c22f50143248b85cc90289d5d3451d3f
6
+ metadata.gz: b5bf34a4ea7addf2b71c2e0acc75041d95f5d76ae425061bd5475e6523111a05cf969b0109ec90874f7f1a1929111182ed193b084b3388be060886145dd20567
7
+ data.tar.gz: 6165128a0393664c97baa494119e453db177b7d0a12c5a5ade0ab5bb8e77a4143f6156b9cb594ef2edbbe9e0ac3bb85a2c846da8e925c3a6ec1c294120c18bf2
@@ -8,7 +8,7 @@ jobs:
8
8
  fail-fast: false
9
9
  matrix:
10
10
  os: [ubuntu-latest]
11
- ruby: [2.6, 2.7]
11
+ ruby: [2.6, 2.7, 3.0]
12
12
 
13
13
  name: >-
14
14
  ${{matrix.os}}, ${{matrix.ruby}}
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## 0.52.0
2
+
3
+ - Polyphony is now compatible with Ruby 3.0
4
+ - Add `Backend#sendv` method for sending multiple strings
5
+ - Accept flags argument in `Backend#send` (#48)
6
+ - Fix io_uring backend on Ruby 3.0 (#47)
7
+ - Implement C-based public backend API: `Polyphony.backend_XXXX` methods
8
+ - libev backend: Use` pidfd_open` for Linux 5.3+, otherwise use a libev child watcher
9
+ - Use `:call` as default method in `#feed_loop`
10
+
1
11
  ## 0.51.0
2
12
 
3
13
  - Implement `IO#feed_loop`, `Socket#feed_loop`
data/Gemfile.lock CHANGED
@@ -1,72 +1,27 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.51.0)
4
+ polyphony (0.52.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- addressable (2.7.0)
10
- public_suffix (>= 2.0.2, < 5.0)
11
9
  ansi (1.5.0)
12
10
  ast (2.4.0)
13
11
  builder (3.2.4)
14
12
  coderay (1.1.3)
15
- colorator (1.1.0)
16
- concurrent-ruby (1.1.6)
17
13
  docile (1.3.2)
18
- em-websocket (0.5.1)
19
- eventmachine (>= 0.12.9)
20
- http_parser.rb (~> 0.6.0)
21
- eventmachine (1.2.7)
22
- ffi (1.12.1)
23
- forwardable-extended (2.6.0)
24
14
  hiredis (0.6.3)
25
15
  http_parser.rb (0.6.0)
26
16
  httparty (0.17.1)
27
17
  mime-types (~> 3.0)
28
18
  multi_xml (>= 0.5.2)
29
- i18n (0.9.5)
30
- concurrent-ruby (~> 1.0)
31
- jekyll (3.8.6)
32
- addressable (~> 2.4)
33
- colorator (~> 1.0)
34
- em-websocket (~> 0.5)
35
- i18n (~> 0.7)
36
- jekyll-sass-converter (~> 1.0)
37
- jekyll-watch (~> 2.0)
38
- kramdown (~> 1.14)
39
- liquid (~> 4.0)
40
- mercenary (~> 0.3.3)
41
- pathutil (~> 0.9)
42
- rouge (>= 1.7, < 4)
43
- safe_yaml (~> 1.0)
44
- jekyll-remote-theme (0.4.1)
45
- addressable (~> 2.0)
46
- jekyll (>= 3.5, < 5.0)
47
- rubyzip (>= 1.3.0)
48
- jekyll-sass-converter (1.5.2)
49
- sass (~> 3.4)
50
- jekyll-seo-tag (2.6.1)
51
- jekyll (>= 3.3, < 5.0)
52
- jekyll-watch (2.2.1)
53
- listen (~> 3.0)
54
19
  json (2.3.0)
55
- just-the-docs (0.3.0)
56
- jekyll (>= 3.8.5)
57
- jekyll-seo-tag (~> 2.0)
58
- rake (>= 12.3.1, < 13.1.0)
59
- kramdown (1.17.0)
60
- liquid (4.0.3)
61
- listen (3.2.1)
62
- rb-fsevent (~> 0.10, >= 0.10.3)
63
- rb-inotify (~> 0.9, >= 0.9.10)
64
- mercenary (0.3.6)
65
20
  method_source (1.0.0)
66
21
  mime-types (3.3.1)
67
22
  mime-types-data (~> 3.2015)
68
23
  mime-types-data (3.2020.0512)
69
- minitest (5.13.0)
24
+ minitest (5.14.4)
70
25
  minitest-reporters (1.4.2)
71
26
  ansi
72
27
  builder
@@ -78,25 +33,18 @@ GEM
78
33
  parallel (1.19.1)
79
34
  parser (2.7.0.2)
80
35
  ast (~> 2.4.0)
81
- pathutil (0.16.2)
82
- forwardable-extended (~> 2.6)
83
36
  pg (1.1.4)
84
37
  pry (0.13.1)
85
38
  coderay (~> 1.1)
86
39
  method_source (~> 1.0)
87
- public_suffix (4.0.3)
88
40
  rack (2.2.3)
89
41
  rainbow (3.0.0)
90
- rake (12.3.3)
42
+ rake (13.0.3)
91
43
  rake-compiler (1.1.1)
92
44
  rake
93
- rb-fsevent (0.10.3)
94
- rb-inotify (0.10.1)
95
- ffi (~> 1.0)
96
45
  redis (4.1.0)
97
46
  regexp_parser (1.7.1)
98
47
  rexml (3.2.4)
99
- rouge (3.15.0)
100
48
  rubocop (0.85.1)
101
49
  parallel (~> 1.10)
102
50
  parser (>= 2.7.0.1)
@@ -109,13 +57,6 @@ GEM
109
57
  rubocop-ast (0.0.3)
110
58
  parser (>= 2.7.0.1)
111
59
  ruby-progressbar (1.10.1)
112
- rubyzip (2.0.0)
113
- safe_yaml (1.0.5)
114
- sass (3.7.4)
115
- sass-listen (~> 4.0.0)
116
- sass-listen (4.0.0)
117
- rb-fsevent (~> 0.9, >= 0.9.4)
118
- rb-inotify (~> 0.9, >= 0.9.7)
119
60
  sequel (5.34.0)
120
61
  simplecov (0.17.1)
121
62
  docile (~> 1.1)
@@ -131,11 +72,7 @@ DEPENDENCIES
131
72
  hiredis (= 0.6.3)
132
73
  http_parser.rb (~> 0.6.0)
133
74
  httparty (= 0.17.1)
134
- jekyll (~> 3.8.6)
135
- jekyll-remote-theme (~> 0.4.1)
136
- jekyll-seo-tag (~> 2.6.1)
137
- just-the-docs (~> 0.3.0)
138
- minitest (= 5.13.0)
75
+ minitest (= 5.14.4)
139
76
  minitest-reporters (= 1.4.2)
140
77
  msgpack (= 1.4.2)
141
78
  mysql2 (= 0.5.3)
@@ -150,4 +87,4 @@ DEPENDENCIES
150
87
  simplecov (= 0.17.1)
151
88
 
152
89
  BUNDLED WITH
153
- 2.1.4
90
+ 2.2.3
data/TODO.md CHANGED
@@ -1,9 +1,12 @@
1
+ - Implement io_uring Backend_send with variable arity.
2
+ - Implement a buffer store for use in:
3
+ - io_uring Backend_send_m
4
+ - io_uring Backend_writev (for iov)
5
+ - libvev Backend_writev (for iov)
6
+
1
7
  - Check segfault when resetting a `cancel_after` timeout lots of times at very high rate
2
8
  - Check why `throttled_loop` inside of `move_on_after` fails to stop
3
9
 
4
- - Commented out `io_uring_sqe_set_flags(sqe, IOSQE_ASYNC);` in `io_uring_backend_defer_submit_and_await`:
5
- - This flag should be set for I/O ops, not for other stuff
6
-
7
10
  - Override stock `::SizedQueue` impl with Queue with capacity
8
11
 
9
12
  - Add support for `break` and `StopIteration` in all loops (with tests)
@@ -5,7 +5,7 @@ require 'polyphony'
5
5
 
6
6
  puts "parent pid: #{Process.pid}"
7
7
 
8
- pid = Polyphony.fork do
8
+ pid = fork do
9
9
  puts "child pid: #{Process.pid}"
10
10
 
11
11
  spin do
@@ -20,5 +20,5 @@ end
20
20
  puts "got child pid #{pid}"
21
21
 
22
22
  puts 'parent waiting for child'
23
- Thread.current.backend.waitpid(pid)
23
+ Polyphony.backend_waitpid(pid)
24
24
  puts 'parent done waiting'
@@ -3,6 +3,8 @@
3
3
  #include "ruby.h"
4
4
  #include "ruby/io.h"
5
5
 
6
+
7
+ #ifdef POLYPHONY_USE_PIDFD_OPEN
6
8
  #ifndef __NR_pidfd_open
7
9
  #define __NR_pidfd_open 434 /* System call # on most architectures */
8
10
  #endif
@@ -10,6 +12,7 @@
10
12
  static int pidfd_open(pid_t pid, unsigned int flags) {
11
13
  return syscall(__NR_pidfd_open, pid, flags);
12
14
  }
15
+ #endif
13
16
 
14
17
  //////////////////////////////////////////////////////////////////////
15
18
  //////////////////////////////////////////////////////////////////////
@@ -23,11 +26,11 @@ struct io_internal_read_struct {
23
26
 
24
27
  #define StringValue(v) rb_string_value(&(v))
25
28
 
26
- inline int io_setstrbuf(VALUE *str, long len) {
29
+ int io_setstrbuf(VALUE *str, long len) {
27
30
  #ifdef _WIN32
28
31
  len = (len + 1) & ~1L; /* round up for wide char */
29
32
  #endif
30
- if (NIL_P(*str)) {
33
+ if (*str == Qnil) {
31
34
  *str = rb_str_new(0, len);
32
35
  return 1;
33
36
  }
@@ -52,7 +55,7 @@ inline void io_shrink_read_string(VALUE str, long n) {
52
55
  }
53
56
  }
54
57
 
55
- inline void io_set_read_length(VALUE str, long n, int shrinkable) {
58
+ void io_set_read_length(VALUE str, long n, int shrinkable) {
56
59
  if (RSTRING_LEN(str) != n) {
57
60
  rb_str_modify(str);
58
61
  rb_str_set_len(str, n);
@@ -67,7 +70,7 @@ inline rb_encoding* io_read_encoding(rb_io_t *fptr) {
67
70
  return rb_default_external_encoding();
68
71
  }
69
72
 
70
- inline VALUE io_enc_str(VALUE str, rb_io_t *fptr) {
73
+ VALUE io_enc_str(VALUE str, rb_io_t *fptr) {
71
74
  OBJ_TAINT(str);
72
75
  rb_enc_associate(str, io_read_encoding(fptr));
73
76
  return str;
@@ -135,9 +138,9 @@ inline double current_time() {
135
138
  }
136
139
 
137
140
  inline VALUE backend_timeout_exception(VALUE exception) {
138
- if (RTEST(rb_obj_is_kind_of(exception, rb_cArray)))
141
+ if (rb_obj_is_kind_of(exception, rb_cArray) == Qtrue)
139
142
  return rb_funcall(rb_ary_entry(exception, 0), ID_new, 1, rb_ary_entry(exception, 1));
140
- else if (RTEST(rb_obj_is_kind_of(exception, rb_cClass)))
143
+ else if (rb_obj_is_kind_of(exception, rb_cClass) == Qtrue)
141
144
  return rb_funcall(exception, ID_new, 0);
142
145
  else
143
146
  return rb_funcall(rb_eRuntimeError, ID_new, 1, exception);
@@ -154,3 +157,23 @@ VALUE Backend_timeout_rescue(VALUE arg, VALUE exception) {
154
157
  VALUE Backend_timeout_ensure_safe(VALUE arg) {
155
158
  return rb_rescue2(Backend_timeout_safe, Qnil, Backend_timeout_rescue, Qnil, rb_eException, (VALUE)0);
156
159
  }
160
+
161
+ static VALUE empty_string = Qnil;
162
+
163
+ VALUE Backend_sendv(VALUE self, VALUE io, VALUE ary, VALUE flags) {
164
+ switch (RARRAY_LEN(ary)) {
165
+ case 0:
166
+ return Qnil;
167
+ case 1:
168
+ return Backend_send(self, io, RARRAY_AREF(ary, 0), flags);
169
+ default:
170
+ if (empty_string == Qnil) {
171
+ empty_string = rb_str_new_literal("");
172
+ rb_global_variable(&empty_string);
173
+ }
174
+ VALUE joined = rb_ary_join(ary, empty_string);
175
+ VALUE result = Backend_send(self, io, joined, flags);
176
+ RB_GC_GUARD(joined);
177
+ return result;
178
+ }
179
+ }
@@ -16,11 +16,36 @@
16
16
 
17
17
  #include "polyphony.h"
18
18
  #include "../liburing/liburing.h"
19
- #include "ruby/thread.h"
20
19
  #include "backend_io_uring_context.h"
20
+ #include "ruby/thread.h"
21
+ #include "ruby/io.h"
21
22
 
22
23
  VALUE SYM_io_uring;
23
24
 
25
+ #ifdef POLYPHONY_UNSET_NONBLOCK
26
+ ID ID_ivar_is_nonblocking;
27
+
28
+ // One of the changes introduced in Ruby 3.0 as part of the work on the
29
+ // FiberScheduler interface is that all created sockets are marked as
30
+ // non-blocking. This prevents the io_uring backend from working correctly,
31
+ // since it will return an EAGAIN error just like a normal syscall. So here
32
+ // instead of setting O_NONBLOCK (which is required for the libev backend), we
33
+ // unset it.
34
+ inline void io_unset_nonblock(rb_io_t *fptr, VALUE io) {
35
+ VALUE is_nonblocking = rb_ivar_get(io, ID_ivar_is_nonblocking);
36
+ if (is_nonblocking == Qfalse) return;
37
+
38
+ rb_ivar_set(io, ID_ivar_is_nonblocking, Qfalse);
39
+
40
+ int oflags = fcntl(fptr->fd, F_GETFL);
41
+ if ((oflags == -1) && (oflags & O_NONBLOCK)) return;
42
+ oflags &= !O_NONBLOCK;
43
+ fcntl(fptr->fd, F_SETFL, oflags);
44
+ }
45
+ #else
46
+ #define io_unset_nonblock(fptr, io)
47
+ #endif
48
+
24
49
  typedef struct Backend_t {
25
50
  // common fields
26
51
  unsigned int currently_polling;
@@ -300,6 +325,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof)
300
325
  if (underlying_io != Qnil) io = underlying_io;
301
326
  GetOpenFile(io, fptr);
302
327
  rb_io_check_byte_readable(fptr);
328
+ io_unset_nonblock(fptr, io);
303
329
  rectify_io_file_pos(fptr);
304
330
  OBJ_TAINT(str);
305
331
 
@@ -360,6 +386,7 @@ VALUE Backend_read_loop(VALUE self, VALUE io) {
360
386
  if (underlying_io != Qnil) io = underlying_io;
361
387
  GetOpenFile(io, fptr);
362
388
  rb_io_check_byte_readable(fptr);
389
+ io_unset_nonblock(fptr, io);
363
390
  rectify_io_file_pos(fptr);
364
391
 
365
392
  while (1) {
@@ -406,6 +433,7 @@ VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
406
433
  if (underlying_io != Qnil) io = underlying_io;
407
434
  GetOpenFile(io, fptr);
408
435
  rb_io_check_byte_readable(fptr);
436
+ io_unset_nonblock(fptr, io);
409
437
  rectify_io_file_pos(fptr);
410
438
 
411
439
  while (1) {
@@ -445,6 +473,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
445
473
  GetBackend(self, backend);
446
474
  io = rb_io_get_write_io(io);
447
475
  GetOpenFile(io, fptr);
476
+ io_unset_nonblock(fptr, io);
448
477
 
449
478
  char *buf = StringValuePtr(str);
450
479
  long len = RSTRING_LEN(str);
@@ -488,6 +517,7 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
488
517
  GetBackend(self, backend);
489
518
  io = rb_io_get_write_io(io);
490
519
  GetOpenFile(io, fptr);
520
+ io_unset_nonblock(fptr, io);
491
521
 
492
522
  iov = malloc(iov_count * sizeof(struct iovec));
493
523
  for (int i = 0; i < argc; i++) {
@@ -567,6 +597,7 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length) {
567
597
  if (underlying_io != Qnil) io = underlying_io;
568
598
  GetOpenFile(io, fptr);
569
599
  rb_io_check_byte_readable(fptr);
600
+ io_unset_nonblock(fptr, io);
570
601
  rectify_io_file_pos(fptr);
571
602
  OBJ_TAINT(str);
572
603
 
@@ -614,6 +645,7 @@ VALUE Backend_recv_loop(VALUE self, VALUE io) {
614
645
  if (underlying_io != Qnil) io = underlying_io;
615
646
  GetOpenFile(io, fptr);
616
647
  rb_io_check_byte_readable(fptr);
648
+ io_unset_nonblock(fptr, io);
617
649
  rectify_io_file_pos(fptr);
618
650
 
619
651
  while (1) {
@@ -659,6 +691,7 @@ VALUE Backend_recv_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method)
659
691
  if (underlying_io != Qnil) io = underlying_io;
660
692
  GetOpenFile(io, fptr);
661
693
  rb_io_check_byte_readable(fptr);
694
+ io_unset_nonblock(fptr, io);
662
695
  rectify_io_file_pos(fptr);
663
696
 
664
697
  while (1) {
@@ -687,7 +720,7 @@ VALUE Backend_recv_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method)
687
720
  return io;
688
721
  }
689
722
 
690
- VALUE Backend_send(VALUE self, VALUE io, VALUE str) {
723
+ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
691
724
  Backend_t *backend;
692
725
  rb_io_t *fptr;
693
726
  VALUE underlying_io;
@@ -697,16 +730,18 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str) {
697
730
  GetBackend(self, backend);
698
731
  io = rb_io_get_write_io(io);
699
732
  GetOpenFile(io, fptr);
733
+ io_unset_nonblock(fptr, io);
700
734
 
701
735
  char *buf = StringValuePtr(str);
702
736
  long len = RSTRING_LEN(str);
703
737
  long left = len;
738
+ int flags_int = NUM2INT(flags);
704
739
 
705
740
  while (left > 0) {
706
741
  VALUE resume_value = Qnil;
707
742
  op_context_t *ctx = OP_CONTEXT_ACQUIRE(&backend->store, OP_SEND);
708
743
  struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
709
- io_uring_prep_send(sqe, fptr->fd, buf, left, 0);
744
+ io_uring_prep_send(sqe, fptr->fd, buf, left, flags_int);
710
745
 
711
746
  int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
712
747
  OP_CONTEXT_RELEASE(&backend->store, ctx);
@@ -734,6 +769,8 @@ VALUE io_uring_backend_accept(Backend_t *backend, VALUE server_socket, VALUE soc
734
769
  if (underlying_sock != Qnil) server_socket = underlying_sock;
735
770
 
736
771
  GetOpenFile(server_socket, fptr);
772
+ io_unset_nonblock(fptr, server_socket);
773
+
737
774
  while (1) {
738
775
  VALUE resume_value = Qnil;
739
776
  op_context_t *ctx = OP_CONTEXT_ACQUIRE(&backend->store, OP_ACCEPT);
@@ -797,6 +834,7 @@ VALUE Backend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
797
834
 
798
835
  GetBackend(self, backend);
799
836
  GetOpenFile(sock, fptr);
837
+ io_unset_nonblock(fptr, sock);
800
838
 
801
839
  addr.sin_family = AF_INET;
802
840
  addr.sin_addr.s_addr = inet_addr(host_buf);
@@ -823,6 +861,7 @@ VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write) {
823
861
  if (underlying_io != Qnil) io = underlying_io;
824
862
  GetBackend(self, backend);
825
863
  GetOpenFile(io, fptr);
864
+ io_unset_nonblock(fptr, io);
826
865
 
827
866
  VALUE resume_value = io_uring_backend_wait_fd(backend, fptr->fd, RTEST(write));
828
867
  RAISE_IF_EXCEPTION(resume_value);
@@ -997,7 +1036,7 @@ VALUE Backend_kind(VALUE self) {
997
1036
  }
998
1037
 
999
1038
  void Init_Backend() {
1000
- VALUE cBackend = rb_define_class_under(mPolyphony, "Backend", rb_cData);
1039
+ VALUE cBackend = rb_define_class_under(mPolyphony, "Backend", rb_cObject);
1001
1040
  rb_define_alloc_func(cBackend, Backend_allocate);
1002
1041
 
1003
1042
  rb_define_method(cBackend, "initialize", Backend_initialize, 0);
@@ -1014,7 +1053,8 @@ void Init_Backend() {
1014
1053
  rb_define_method(cBackend, "recv", Backend_recv, 3);
1015
1054
  rb_define_method(cBackend, "recv_loop", Backend_recv_loop, 1);
1016
1055
  rb_define_method(cBackend, "recv_feed_loop", Backend_recv_feed_loop, 3);
1017
- rb_define_method(cBackend, "send", Backend_send, 2);
1056
+ rb_define_method(cBackend, "send", Backend_send, 3);
1057
+ rb_define_method(cBackend, "sendv", Backend_sendv, 3);
1018
1058
  rb_define_method(cBackend, "accept", Backend_accept, 2);
1019
1059
  rb_define_method(cBackend, "accept_loop", Backend_accept_loop, 2);
1020
1060
  rb_define_method(cBackend, "connect", Backend_connect, 3);
@@ -1027,6 +1067,10 @@ void Init_Backend() {
1027
1067
 
1028
1068
  rb_define_method(cBackend, "kind", Backend_kind, 0);
1029
1069
 
1070
+ #ifdef POLYPHONY_UNSET_NONBLOCK
1071
+ ID_ivar_is_nonblocking = rb_intern("@is_nonblocking");
1072
+ #endif
1073
+
1030
1074
  SYM_io_uring = ID2SYM(rb_intern("io_uring"));
1031
1075
  }
1032
1076