polyphony 0.49.1 → 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 +4 -4
- data/.github/workflows/test.yml +1 -1
- data/CHANGELOG.md +35 -0
- data/Gemfile.lock +7 -68
- data/TODO.md +6 -0
- data/examples/core/forking.rb +2 -2
- data/examples/core/nested.rb +21 -0
- data/examples/core/suspend.rb +13 -0
- data/examples/core/terminate_main_fiber.rb +12 -0
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +2 -4
- data/ext/polyphony/backend_common.h +58 -8
- data/ext/polyphony/backend_io_uring.c +158 -35
- data/ext/polyphony/backend_libev.c +192 -25
- data/ext/polyphony/event.c +1 -1
- data/ext/polyphony/extconf.rb +7 -2
- data/ext/polyphony/fiber.c +2 -1
- data/ext/polyphony/polyphony.c +94 -0
- data/ext/polyphony/polyphony.h +29 -2
- data/ext/polyphony/queue.c +1 -1
- data/ext/polyphony/runqueue.c +7 -1
- data/ext/polyphony/runqueue_ring_buffer.c +9 -0
- data/ext/polyphony/runqueue_ring_buffer.h +1 -0
- data/ext/polyphony/thread.c +14 -0
- data/lib/polyphony/adapters/irb.rb +1 -1
- data/lib/polyphony/adapters/mysql2.rb +1 -1
- data/lib/polyphony/adapters/postgres.rb +5 -5
- data/lib/polyphony/adapters/process.rb +4 -4
- data/lib/polyphony/core/exceptions.rb +1 -0
- data/lib/polyphony/core/global_api.rb +6 -6
- data/lib/polyphony/core/sync.rb +1 -1
- data/lib/polyphony/core/throttler.rb +1 -1
- data/lib/polyphony/core/timer.rb +63 -20
- data/lib/polyphony/extensions/core.rb +5 -5
- data/lib/polyphony/extensions/fiber.rb +11 -8
- data/lib/polyphony/extensions/io.rb +13 -22
- data/lib/polyphony/extensions/openssl.rb +6 -6
- data/lib/polyphony/extensions/socket.rb +41 -41
- data/lib/polyphony/extensions/thread.rb +1 -2
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +6 -5
- data/test/helper.rb +2 -3
- data/test/stress.rb +2 -0
- data/test/test_backend.rb +58 -5
- data/test/test_fiber.rb +31 -0
- data/test/test_global_api.rb +2 -2
- data/test/test_io.rb +84 -1
- data/test/test_kernel.rb +1 -1
- data/test/test_signal.rb +2 -3
- data/test/test_socket.rb +61 -0
- data/test/test_timer.rb +41 -8
- metadata +21 -60
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2056b02e3b364911ab627ffc49a7251ad2eed68ba6b5b61d380c599127c181f6
|
4
|
+
data.tar.gz: 440f57d240b90a255b470f405980b5fa2f806ba3ff2640f31d78b6403de7ce0e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b5bf34a4ea7addf2b71c2e0acc75041d95f5d76ae425061bd5475e6523111a05cf969b0109ec90874f7f1a1929111182ed193b084b3388be060886145dd20567
|
7
|
+
data.tar.gz: 6165128a0393664c97baa494119e453db177b7d0a12c5a5ade0ab5bb8e77a4143f6156b9cb594ef2edbbe9e0ac3bb85a2c846da8e925c3a6ec1c294120c18bf2
|
data/.github/workflows/test.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,38 @@
|
|
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
|
+
|
11
|
+
## 0.51.0
|
12
|
+
|
13
|
+
- Implement `IO#feed_loop`, `Socket#feed_loop`
|
14
|
+
- Fix error handling in `Process.kill_and_await`
|
15
|
+
|
16
|
+
## 0.50.1
|
17
|
+
|
18
|
+
- Set `IOSQE_ASYNC` flag in io_uring backend
|
19
|
+
- Fix error handling in `Backend#waitpid`
|
20
|
+
- Reimplement libev backend's `#waitpid` by using pidfd_open (in similar manner
|
21
|
+
to the io_uring backend)
|
22
|
+
|
23
|
+
## 0.50.0
|
24
|
+
|
25
|
+
- Use `Process::CLOCK_MONOTONIC` in Timer
|
26
|
+
- Add `Timer#sleep`, `Timer#after`, `Timer#every`
|
27
|
+
- Prevent fiber from being resumed after terminating
|
28
|
+
- Add `Thread#fiber_index_of` method
|
29
|
+
- Use `Backend#wait_event` in `Fiber#await`
|
30
|
+
|
31
|
+
## 0.49.2
|
32
|
+
|
33
|
+
- Fix hang with 100s or more child fibers when terminating
|
34
|
+
- Fix double pending_count increment in io_uring backend
|
35
|
+
|
1
36
|
## 0.49.1
|
2
37
|
|
3
38
|
- Use `TCPSocket` instead of `Socket` in `Net.tcp_connect`
|
data/Gemfile.lock
CHANGED
@@ -1,101 +1,50 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
polyphony (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.
|
24
|
+
minitest (5.14.4)
|
70
25
|
minitest-reporters (1.4.2)
|
71
26
|
ansi
|
72
27
|
builder
|
73
28
|
minitest (>= 5.0)
|
74
29
|
ruby-progressbar
|
30
|
+
msgpack (1.4.2)
|
75
31
|
multi_xml (0.6.0)
|
76
32
|
mysql2 (0.5.3)
|
77
33
|
parallel (1.19.1)
|
78
34
|
parser (2.7.0.2)
|
79
35
|
ast (~> 2.4.0)
|
80
|
-
pathutil (0.16.2)
|
81
|
-
forwardable-extended (~> 2.6)
|
82
36
|
pg (1.1.4)
|
83
37
|
pry (0.13.1)
|
84
38
|
coderay (~> 1.1)
|
85
39
|
method_source (~> 1.0)
|
86
|
-
public_suffix (4.0.3)
|
87
40
|
rack (2.2.3)
|
88
41
|
rainbow (3.0.0)
|
89
|
-
rake (
|
42
|
+
rake (13.0.3)
|
90
43
|
rake-compiler (1.1.1)
|
91
44
|
rake
|
92
|
-
rb-fsevent (0.10.3)
|
93
|
-
rb-inotify (0.10.1)
|
94
|
-
ffi (~> 1.0)
|
95
45
|
redis (4.1.0)
|
96
46
|
regexp_parser (1.7.1)
|
97
47
|
rexml (3.2.4)
|
98
|
-
rouge (3.15.0)
|
99
48
|
rubocop (0.85.1)
|
100
49
|
parallel (~> 1.10)
|
101
50
|
parser (>= 2.7.0.1)
|
@@ -108,13 +57,6 @@ GEM
|
|
108
57
|
rubocop-ast (0.0.3)
|
109
58
|
parser (>= 2.7.0.1)
|
110
59
|
ruby-progressbar (1.10.1)
|
111
|
-
rubyzip (2.0.0)
|
112
|
-
safe_yaml (1.0.5)
|
113
|
-
sass (3.7.4)
|
114
|
-
sass-listen (~> 4.0.0)
|
115
|
-
sass-listen (4.0.0)
|
116
|
-
rb-fsevent (~> 0.9, >= 0.9.4)
|
117
|
-
rb-inotify (~> 0.9, >= 0.9.7)
|
118
60
|
sequel (5.34.0)
|
119
61
|
simplecov (0.17.1)
|
120
62
|
docile (~> 1.1)
|
@@ -130,12 +72,9 @@ DEPENDENCIES
|
|
130
72
|
hiredis (= 0.6.3)
|
131
73
|
http_parser.rb (~> 0.6.0)
|
132
74
|
httparty (= 0.17.1)
|
133
|
-
|
134
|
-
jekyll-remote-theme (~> 0.4.1)
|
135
|
-
jekyll-seo-tag (~> 2.6.1)
|
136
|
-
just-the-docs (~> 0.3.0)
|
137
|
-
minitest (= 5.13.0)
|
75
|
+
minitest (= 5.14.4)
|
138
76
|
minitest-reporters (= 1.4.2)
|
77
|
+
msgpack (= 1.4.2)
|
139
78
|
mysql2 (= 0.5.3)
|
140
79
|
pg (= 1.1.4)
|
141
80
|
polyphony!
|
@@ -148,4 +87,4 @@ DEPENDENCIES
|
|
148
87
|
simplecov (= 0.17.1)
|
149
88
|
|
150
89
|
BUNDLED WITH
|
151
|
-
2.
|
90
|
+
2.2.3
|
data/TODO.md
CHANGED
@@ -1,3 +1,9 @@
|
|
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
|
|
data/examples/core/forking.rb
CHANGED
@@ -5,7 +5,7 @@ require 'polyphony'
|
|
5
5
|
|
6
6
|
puts "parent pid: #{Process.pid}"
|
7
7
|
|
8
|
-
pid =
|
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
|
-
|
23
|
+
Polyphony.backend_waitpid(pid)
|
24
24
|
puts 'parent done waiting'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
def process
|
7
|
+
p :b_start
|
8
|
+
sleep 1
|
9
|
+
p :b_stop
|
10
|
+
end
|
11
|
+
|
12
|
+
spin do
|
13
|
+
p :a_start
|
14
|
+
spin { process }
|
15
|
+
sleep 60
|
16
|
+
p :a_stop
|
17
|
+
end
|
18
|
+
|
19
|
+
p :main_start
|
20
|
+
sleep 120
|
21
|
+
p :main_stop
|
@@ -26,15 +26,13 @@ def write_response(socket)
|
|
26
26
|
socket.write "HTTP/1.1 #{status_code}\r\n#{headers}\r\n#{data}"
|
27
27
|
end
|
28
28
|
|
29
|
-
server = TCPServer.open('0.0.0.0',
|
30
|
-
puts "pid #{Process.pid} Polyphony (#{Thread.current.backend.kind}) listening on port
|
29
|
+
server = TCPServer.open('0.0.0.0', 4411)
|
30
|
+
puts "pid #{Process.pid} Polyphony (#{Thread.current.backend.kind}) listening on port 4411"
|
31
31
|
|
32
32
|
spin_loop(interval: 10) do
|
33
33
|
p Thread.current.fiber_scheduling_stats
|
34
34
|
end
|
35
35
|
|
36
|
-
GC.disable
|
37
|
-
|
38
36
|
server.accept_loop do |c|
|
39
37
|
spin { handle_client(c) }
|
40
38
|
end
|
@@ -3,6 +3,17 @@
|
|
3
3
|
#include "ruby.h"
|
4
4
|
#include "ruby/io.h"
|
5
5
|
|
6
|
+
|
7
|
+
#ifdef POLYPHONY_USE_PIDFD_OPEN
|
8
|
+
#ifndef __NR_pidfd_open
|
9
|
+
#define __NR_pidfd_open 434 /* System call # on most architectures */
|
10
|
+
#endif
|
11
|
+
|
12
|
+
static int pidfd_open(pid_t pid, unsigned int flags) {
|
13
|
+
return syscall(__NR_pidfd_open, pid, flags);
|
14
|
+
}
|
15
|
+
#endif
|
16
|
+
|
6
17
|
//////////////////////////////////////////////////////////////////////
|
7
18
|
//////////////////////////////////////////////////////////////////////
|
8
19
|
// the following is copied verbatim from the Ruby source code (io.c)
|
@@ -15,11 +26,11 @@ struct io_internal_read_struct {
|
|
15
26
|
|
16
27
|
#define StringValue(v) rb_string_value(&(v))
|
17
28
|
|
18
|
-
|
29
|
+
int io_setstrbuf(VALUE *str, long len) {
|
19
30
|
#ifdef _WIN32
|
20
31
|
len = (len + 1) & ~1L; /* round up for wide char */
|
21
32
|
#endif
|
22
|
-
if (
|
33
|
+
if (*str == Qnil) {
|
23
34
|
*str = rb_str_new(0, len);
|
24
35
|
return 1;
|
25
36
|
}
|
@@ -44,7 +55,7 @@ inline void io_shrink_read_string(VALUE str, long n) {
|
|
44
55
|
}
|
45
56
|
}
|
46
57
|
|
47
|
-
|
58
|
+
void io_set_read_length(VALUE str, long n, int shrinkable) {
|
48
59
|
if (RSTRING_LEN(str) != n) {
|
49
60
|
rb_str_modify(str);
|
50
61
|
rb_str_set_len(str, n);
|
@@ -59,7 +70,7 @@ inline rb_encoding* io_read_encoding(rb_io_t *fptr) {
|
|
59
70
|
return rb_default_external_encoding();
|
60
71
|
}
|
61
72
|
|
62
|
-
|
73
|
+
VALUE io_enc_str(VALUE str, rb_io_t *fptr) {
|
63
74
|
OBJ_TAINT(str);
|
64
75
|
rb_enc_associate(str, io_read_encoding(fptr));
|
65
76
|
return str;
|
@@ -99,6 +110,13 @@ inline VALUE backend_snooze() {
|
|
99
110
|
READ_LOOP_PREPARE_STR(); \
|
100
111
|
}
|
101
112
|
|
113
|
+
#define READ_LOOP_PASS_STR_TO_RECEIVER(receiver, method_id) { \
|
114
|
+
io_set_read_length(str, total, shrinkable); \
|
115
|
+
io_enc_str(str, fptr); \
|
116
|
+
rb_funcall_passing_block(receiver, method_id, 1, &str); \
|
117
|
+
READ_LOOP_PREPARE_STR(); \
|
118
|
+
}
|
119
|
+
|
102
120
|
inline void rectify_io_file_pos(rb_io_t *fptr) {
|
103
121
|
// Apparently after reopening a closed file, the file position is not reset,
|
104
122
|
// which causes the read to fail. Fortunately we can use fptr->rbuf.len to
|
@@ -114,16 +132,48 @@ inline double current_time() {
|
|
114
132
|
struct timespec ts;
|
115
133
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
116
134
|
long long ns = ts.tv_sec;
|
117
|
-
ns = ns *
|
135
|
+
ns = ns * 1e9 + ts.tv_nsec;
|
118
136
|
double t = ns;
|
119
137
|
return t / 1e9;
|
120
138
|
}
|
121
139
|
|
122
140
|
inline VALUE backend_timeout_exception(VALUE exception) {
|
123
|
-
if (
|
141
|
+
if (rb_obj_is_kind_of(exception, rb_cArray) == Qtrue)
|
124
142
|
return rb_funcall(rb_ary_entry(exception, 0), ID_new, 1, rb_ary_entry(exception, 1));
|
125
|
-
else if (
|
143
|
+
else if (rb_obj_is_kind_of(exception, rb_cClass) == Qtrue)
|
126
144
|
return rb_funcall(exception, ID_new, 0);
|
127
145
|
else
|
128
146
|
return rb_funcall(rb_eRuntimeError, ID_new, 1, exception);
|
129
|
-
}
|
147
|
+
}
|
148
|
+
|
149
|
+
VALUE Backend_timeout_safe(VALUE arg) {
|
150
|
+
return rb_yield(arg);
|
151
|
+
}
|
152
|
+
|
153
|
+
VALUE Backend_timeout_rescue(VALUE arg, VALUE exception) {
|
154
|
+
return exception;
|
155
|
+
}
|
156
|
+
|
157
|
+
VALUE Backend_timeout_ensure_safe(VALUE arg) {
|
158
|
+
return rb_rescue2(Backend_timeout_safe, Qnil, Backend_timeout_rescue, Qnil, rb_eException, (VALUE)0);
|
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,18 +16,35 @@
|
|
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
|
-
#define __NR_pidfd_open 434 /* System call # on most architectures */
|
24
|
-
#endif
|
23
|
+
VALUE SYM_io_uring;
|
25
24
|
|
26
|
-
|
27
|
-
|
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);
|
28
44
|
}
|
29
|
-
|
30
|
-
|
45
|
+
#else
|
46
|
+
#define io_unset_nonblock(fptr, io)
|
47
|
+
#endif
|
31
48
|
|
32
49
|
typedef struct Backend_t {
|
33
50
|
// common fields
|
@@ -260,12 +277,10 @@ int io_uring_backend_defer_submit_and_await(
|
|
260
277
|
VALUE switchpoint_result = Qnil;
|
261
278
|
|
262
279
|
io_uring_sqe_set_data(sqe, ctx);
|
263
|
-
|
280
|
+
io_uring_sqe_set_flags(sqe, IOSQE_ASYNC);
|
264
281
|
io_uring_backend_defer_submit(backend);
|
265
282
|
|
266
|
-
backend->pending_count++;
|
267
283
|
switchpoint_result = backend_await(backend);
|
268
|
-
backend->pending_count--;
|
269
284
|
|
270
285
|
if (!ctx->completed) {
|
271
286
|
ctx->result = -ECANCELED;
|
@@ -310,6 +325,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof)
|
|
310
325
|
if (underlying_io != Qnil) io = underlying_io;
|
311
326
|
GetOpenFile(io, fptr);
|
312
327
|
rb_io_check_byte_readable(fptr);
|
328
|
+
io_unset_nonblock(fptr, io);
|
313
329
|
rectify_io_file_pos(fptr);
|
314
330
|
OBJ_TAINT(str);
|
315
331
|
|
@@ -370,6 +386,7 @@ VALUE Backend_read_loop(VALUE self, VALUE io) {
|
|
370
386
|
if (underlying_io != Qnil) io = underlying_io;
|
371
387
|
GetOpenFile(io, fptr);
|
372
388
|
rb_io_check_byte_readable(fptr);
|
389
|
+
io_unset_nonblock(fptr, io);
|
373
390
|
rectify_io_file_pos(fptr);
|
374
391
|
|
375
392
|
while (1) {
|
@@ -399,6 +416,53 @@ VALUE Backend_read_loop(VALUE self, VALUE io) {
|
|
399
416
|
return io;
|
400
417
|
}
|
401
418
|
|
419
|
+
VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
|
420
|
+
Backend_t *backend;
|
421
|
+
rb_io_t *fptr;
|
422
|
+
VALUE str;
|
423
|
+
long total;
|
424
|
+
long len = 8192;
|
425
|
+
int shrinkable;
|
426
|
+
char *buf;
|
427
|
+
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
|
428
|
+
ID method_id = SYM2ID(method);
|
429
|
+
|
430
|
+
READ_LOOP_PREPARE_STR();
|
431
|
+
|
432
|
+
GetBackend(self, backend);
|
433
|
+
if (underlying_io != Qnil) io = underlying_io;
|
434
|
+
GetOpenFile(io, fptr);
|
435
|
+
rb_io_check_byte_readable(fptr);
|
436
|
+
io_unset_nonblock(fptr, io);
|
437
|
+
rectify_io_file_pos(fptr);
|
438
|
+
|
439
|
+
while (1) {
|
440
|
+
VALUE resume_value = Qnil;
|
441
|
+
op_context_t *ctx = OP_CONTEXT_ACQUIRE(&backend->store, OP_READ);
|
442
|
+
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
443
|
+
io_uring_prep_read(sqe, fptr->fd, buf, len, -1);
|
444
|
+
|
445
|
+
ssize_t result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
446
|
+
OP_CONTEXT_RELEASE(&backend->store, ctx);
|
447
|
+
RAISE_IF_EXCEPTION(resume_value);
|
448
|
+
if (!ctx->completed) return resume_value;
|
449
|
+
RB_GC_GUARD(resume_value);
|
450
|
+
|
451
|
+
if (result < 0)
|
452
|
+
rb_syserr_fail(-result, strerror(-result));
|
453
|
+
else if (!result)
|
454
|
+
break; // EOF
|
455
|
+
else {
|
456
|
+
total = result;
|
457
|
+
READ_LOOP_PASS_STR_TO_RECEIVER(receiver, method_id);
|
458
|
+
}
|
459
|
+
}
|
460
|
+
|
461
|
+
RB_GC_GUARD(str);
|
462
|
+
|
463
|
+
return io;
|
464
|
+
}
|
465
|
+
|
402
466
|
VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
403
467
|
Backend_t *backend;
|
404
468
|
rb_io_t *fptr;
|
@@ -409,6 +473,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
409
473
|
GetBackend(self, backend);
|
410
474
|
io = rb_io_get_write_io(io);
|
411
475
|
GetOpenFile(io, fptr);
|
476
|
+
io_unset_nonblock(fptr, io);
|
412
477
|
|
413
478
|
char *buf = StringValuePtr(str);
|
414
479
|
long len = RSTRING_LEN(str);
|
@@ -452,6 +517,7 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
452
517
|
GetBackend(self, backend);
|
453
518
|
io = rb_io_get_write_io(io);
|
454
519
|
GetOpenFile(io, fptr);
|
520
|
+
io_unset_nonblock(fptr, io);
|
455
521
|
|
456
522
|
iov = malloc(iov_count * sizeof(struct iovec));
|
457
523
|
for (int i = 0; i < argc; i++) {
|
@@ -531,6 +597,7 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length) {
|
|
531
597
|
if (underlying_io != Qnil) io = underlying_io;
|
532
598
|
GetOpenFile(io, fptr);
|
533
599
|
rb_io_check_byte_readable(fptr);
|
600
|
+
io_unset_nonblock(fptr, io);
|
534
601
|
rectify_io_file_pos(fptr);
|
535
602
|
OBJ_TAINT(str);
|
536
603
|
|
@@ -578,6 +645,7 @@ VALUE Backend_recv_loop(VALUE self, VALUE io) {
|
|
578
645
|
if (underlying_io != Qnil) io = underlying_io;
|
579
646
|
GetOpenFile(io, fptr);
|
580
647
|
rb_io_check_byte_readable(fptr);
|
648
|
+
io_unset_nonblock(fptr, io);
|
581
649
|
rectify_io_file_pos(fptr);
|
582
650
|
|
583
651
|
while (1) {
|
@@ -606,7 +674,53 @@ VALUE Backend_recv_loop(VALUE self, VALUE io) {
|
|
606
674
|
return io;
|
607
675
|
}
|
608
676
|
|
609
|
-
VALUE
|
677
|
+
VALUE Backend_recv_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
|
678
|
+
Backend_t *backend;
|
679
|
+
rb_io_t *fptr;
|
680
|
+
VALUE str;
|
681
|
+
long total;
|
682
|
+
long len = 8192;
|
683
|
+
int shrinkable;
|
684
|
+
char *buf;
|
685
|
+
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
|
686
|
+
ID method_id = SYM2ID(method);
|
687
|
+
|
688
|
+
READ_LOOP_PREPARE_STR();
|
689
|
+
|
690
|
+
GetBackend(self, backend);
|
691
|
+
if (underlying_io != Qnil) io = underlying_io;
|
692
|
+
GetOpenFile(io, fptr);
|
693
|
+
rb_io_check_byte_readable(fptr);
|
694
|
+
io_unset_nonblock(fptr, io);
|
695
|
+
rectify_io_file_pos(fptr);
|
696
|
+
|
697
|
+
while (1) {
|
698
|
+
VALUE resume_value = Qnil;
|
699
|
+
op_context_t *ctx = OP_CONTEXT_ACQUIRE(&backend->store, OP_RECV);
|
700
|
+
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
701
|
+
io_uring_prep_recv(sqe, fptr->fd, buf, len, 0);
|
702
|
+
|
703
|
+
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
704
|
+
OP_CONTEXT_RELEASE(&backend->store, ctx);
|
705
|
+
RAISE_IF_EXCEPTION(resume_value);
|
706
|
+
if (!ctx->completed) return resume_value;
|
707
|
+
RB_GC_GUARD(resume_value);
|
708
|
+
|
709
|
+
if (result < 0)
|
710
|
+
rb_syserr_fail(-result, strerror(-result));
|
711
|
+
else if (!result)
|
712
|
+
break; // EOF
|
713
|
+
else {
|
714
|
+
total = result;
|
715
|
+
READ_LOOP_PASS_STR_TO_RECEIVER(receiver, method_id);
|
716
|
+
}
|
717
|
+
}
|
718
|
+
|
719
|
+
RB_GC_GUARD(str);
|
720
|
+
return io;
|
721
|
+
}
|
722
|
+
|
723
|
+
VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
610
724
|
Backend_t *backend;
|
611
725
|
rb_io_t *fptr;
|
612
726
|
VALUE underlying_io;
|
@@ -616,16 +730,18 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str) {
|
|
616
730
|
GetBackend(self, backend);
|
617
731
|
io = rb_io_get_write_io(io);
|
618
732
|
GetOpenFile(io, fptr);
|
733
|
+
io_unset_nonblock(fptr, io);
|
619
734
|
|
620
735
|
char *buf = StringValuePtr(str);
|
621
736
|
long len = RSTRING_LEN(str);
|
622
737
|
long left = len;
|
738
|
+
int flags_int = NUM2INT(flags);
|
623
739
|
|
624
740
|
while (left > 0) {
|
625
741
|
VALUE resume_value = Qnil;
|
626
742
|
op_context_t *ctx = OP_CONTEXT_ACQUIRE(&backend->store, OP_SEND);
|
627
743
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
628
|
-
io_uring_prep_send(sqe, fptr->fd, buf, left,
|
744
|
+
io_uring_prep_send(sqe, fptr->fd, buf, left, flags_int);
|
629
745
|
|
630
746
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
631
747
|
OP_CONTEXT_RELEASE(&backend->store, ctx);
|
@@ -653,6 +769,8 @@ VALUE io_uring_backend_accept(Backend_t *backend, VALUE server_socket, VALUE soc
|
|
653
769
|
if (underlying_sock != Qnil) server_socket = underlying_sock;
|
654
770
|
|
655
771
|
GetOpenFile(server_socket, fptr);
|
772
|
+
io_unset_nonblock(fptr, server_socket);
|
773
|
+
|
656
774
|
while (1) {
|
657
775
|
VALUE resume_value = Qnil;
|
658
776
|
op_context_t *ctx = OP_CONTEXT_ACQUIRE(&backend->store, OP_ACCEPT);
|
@@ -716,6 +834,7 @@ VALUE Backend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
|
|
716
834
|
|
717
835
|
GetBackend(self, backend);
|
718
836
|
GetOpenFile(sock, fptr);
|
837
|
+
io_unset_nonblock(fptr, sock);
|
719
838
|
|
720
839
|
addr.sin_family = AF_INET;
|
721
840
|
addr.sin_addr.s_addr = inet_addr(host_buf);
|
@@ -742,6 +861,7 @@ VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write) {
|
|
742
861
|
if (underlying_io != Qnil) io = underlying_io;
|
743
862
|
GetBackend(self, backend);
|
744
863
|
GetOpenFile(io, fptr);
|
864
|
+
io_unset_nonblock(fptr, io);
|
745
865
|
|
746
866
|
VALUE resume_value = io_uring_backend_wait_fd(backend, fptr->fd, RTEST(write));
|
747
867
|
RAISE_IF_EXCEPTION(resume_value);
|
@@ -813,18 +933,6 @@ VALUE Backend_timer_loop(VALUE self, VALUE interval) {
|
|
813
933
|
}
|
814
934
|
}
|
815
935
|
|
816
|
-
VALUE Backend_timeout_safe(VALUE arg) {
|
817
|
-
return rb_yield(arg);
|
818
|
-
}
|
819
|
-
|
820
|
-
VALUE Backend_timeout_rescue(VALUE arg, VALUE exception) {
|
821
|
-
return exception;
|
822
|
-
}
|
823
|
-
|
824
|
-
VALUE Backend_timeout_ensure_safe(VALUE arg) {
|
825
|
-
return rb_rescue2(Backend_timeout_safe, Qnil, Backend_timeout_rescue, Qnil, rb_eException, (VALUE)0);
|
826
|
-
}
|
827
|
-
|
828
936
|
struct Backend_timeout_ctx {
|
829
937
|
Backend_t *backend;
|
830
938
|
op_context_t *ctx;
|
@@ -863,7 +971,6 @@ VALUE Backend_timeout(int argc, VALUE *argv, VALUE self) {
|
|
863
971
|
ctx->resume_value = timeout;
|
864
972
|
io_uring_prep_timeout(sqe, &ts, 0, 0);
|
865
973
|
io_uring_sqe_set_data(sqe, ctx);
|
866
|
-
io_uring_sqe_set_flags(sqe, IOSQE_ASYNC);
|
867
974
|
io_uring_backend_defer_submit(backend);
|
868
975
|
|
869
976
|
struct Backend_timeout_ctx timeout_ctx = {backend, ctx};
|
@@ -881,19 +988,28 @@ VALUE Backend_timeout(int argc, VALUE *argv, VALUE self) {
|
|
881
988
|
}
|
882
989
|
|
883
990
|
VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
884
|
-
Backend_t *backend;
|
885
991
|
int pid_int = NUM2INT(pid);
|
886
992
|
int fd = pidfd_open(pid_int, 0);
|
887
|
-
GetBackend(self, backend);
|
888
|
-
|
889
|
-
VALUE resume_value = io_uring_backend_wait_fd(backend, fd, 0);
|
890
|
-
close(fd);
|
891
993
|
|
892
|
-
|
893
|
-
|
994
|
+
if (fd >= 0) {
|
995
|
+
Backend_t *backend;
|
996
|
+
GetBackend(self, backend);
|
894
997
|
|
998
|
+
VALUE resume_value = io_uring_backend_wait_fd(backend, fd, 0);
|
999
|
+
close(fd);
|
1000
|
+
RAISE_IF_EXCEPTION(resume_value);
|
1001
|
+
RB_GC_GUARD(resume_value);
|
1002
|
+
}
|
1003
|
+
|
895
1004
|
int status;
|
896
1005
|
pid_t ret = waitpid(pid_int, &status, WNOHANG);
|
1006
|
+
if (ret < 0) {
|
1007
|
+
int e = errno;
|
1008
|
+
if (e == ECHILD)
|
1009
|
+
ret = pid_int;
|
1010
|
+
else
|
1011
|
+
rb_syserr_fail(e, strerror(e));
|
1012
|
+
}
|
897
1013
|
return rb_ary_new_from_args(2, INT2NUM(ret), INT2NUM(WEXITSTATUS(status)));
|
898
1014
|
}
|
899
1015
|
|
@@ -920,7 +1036,7 @@ VALUE Backend_kind(VALUE self) {
|
|
920
1036
|
}
|
921
1037
|
|
922
1038
|
void Init_Backend() {
|
923
|
-
VALUE cBackend = rb_define_class_under(mPolyphony, "Backend",
|
1039
|
+
VALUE cBackend = rb_define_class_under(mPolyphony, "Backend", rb_cObject);
|
924
1040
|
rb_define_alloc_func(cBackend, Backend_allocate);
|
925
1041
|
|
926
1042
|
rb_define_method(cBackend, "initialize", Backend_initialize, 0);
|
@@ -932,10 +1048,13 @@ void Init_Backend() {
|
|
932
1048
|
|
933
1049
|
rb_define_method(cBackend, "read", Backend_read, 4);
|
934
1050
|
rb_define_method(cBackend, "read_loop", Backend_read_loop, 1);
|
1051
|
+
rb_define_method(cBackend, "feed_loop", Backend_feed_loop, 3);
|
935
1052
|
rb_define_method(cBackend, "write", Backend_write_m, -1);
|
936
1053
|
rb_define_method(cBackend, "recv", Backend_recv, 3);
|
937
1054
|
rb_define_method(cBackend, "recv_loop", Backend_recv_loop, 1);
|
938
|
-
rb_define_method(cBackend, "
|
1055
|
+
rb_define_method(cBackend, "recv_feed_loop", Backend_recv_feed_loop, 3);
|
1056
|
+
rb_define_method(cBackend, "send", Backend_send, 3);
|
1057
|
+
rb_define_method(cBackend, "sendv", Backend_sendv, 3);
|
939
1058
|
rb_define_method(cBackend, "accept", Backend_accept, 2);
|
940
1059
|
rb_define_method(cBackend, "accept_loop", Backend_accept_loop, 2);
|
941
1060
|
rb_define_method(cBackend, "connect", Backend_connect, 3);
|
@@ -948,6 +1067,10 @@ void Init_Backend() {
|
|
948
1067
|
|
949
1068
|
rb_define_method(cBackend, "kind", Backend_kind, 0);
|
950
1069
|
|
1070
|
+
#ifdef POLYPHONY_UNSET_NONBLOCK
|
1071
|
+
ID_ivar_is_nonblocking = rb_intern("@is_nonblocking");
|
1072
|
+
#endif
|
1073
|
+
|
951
1074
|
SYM_io_uring = ID2SYM(rb_intern("io_uring"));
|
952
1075
|
}
|
953
1076
|
|