polyphony 0.51.0 → 0.52.0

Sign up to get free protection for your applications and to get access to all the features.
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