polyphony 0.47.5.1 → 0.50.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/CHANGELOG.md +29 -0
- data/Gemfile.lock +1 -1
- data/LICENSE +1 -1
- data/TODO.md +37 -17
- 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/io/tcp_proxy.rb +32 -0
- data/examples/performance/line_splitting.rb +34 -0
- data/examples/performance/loop.rb +32 -0
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +6 -2
- data/ext/polyphony/backend_common.h +3 -3
- data/ext/polyphony/backend_io_uring.c +29 -68
- data/ext/polyphony/backend_libev.c +18 -59
- data/ext/polyphony/event.c +1 -1
- data/ext/polyphony/fiber.c +2 -1
- data/ext/polyphony/polyphony.c +0 -2
- data/ext/polyphony/polyphony.h +6 -4
- data/ext/polyphony/queue.c +2 -2
- data/ext/polyphony/runqueue.c +6 -0
- data/ext/polyphony/runqueue_ring_buffer.c +9 -0
- data/ext/polyphony/runqueue_ring_buffer.h +1 -0
- data/ext/polyphony/thread.c +23 -28
- data/lib/polyphony.rb +2 -1
- data/lib/polyphony/adapters/postgres.rb +3 -3
- data/lib/polyphony/adapters/process.rb +2 -0
- data/lib/polyphony/core/exceptions.rb +1 -0
- data/lib/polyphony/core/global_api.rb +15 -3
- data/lib/polyphony/core/thread_pool.rb +3 -1
- data/lib/polyphony/core/throttler.rb +1 -1
- data/lib/polyphony/core/timer.rb +115 -0
- data/lib/polyphony/extensions/core.rb +4 -4
- data/lib/polyphony/extensions/fiber.rb +30 -13
- data/lib/polyphony/extensions/io.rb +8 -14
- data/lib/polyphony/extensions/openssl.rb +4 -4
- data/lib/polyphony/extensions/socket.rb +1 -1
- data/lib/polyphony/extensions/thread.rb +1 -2
- data/lib/polyphony/net.rb +3 -6
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +1 -1
- data/test/helper.rb +2 -2
- data/test/test_backend.rb +26 -1
- data/test/test_fiber.rb +95 -1
- data/test/test_global_api.rb +30 -0
- data/test/test_io.rb +26 -0
- data/test/test_signal.rb +1 -2
- data/test/test_socket.rb +5 -5
- data/test/test_supervise.rb +1 -1
- data/test/test_timer.rb +157 -0
- metadata +11 -4
- data/ext/polyphony/backend.h +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2aac80a08ca16498c3ee0044b0ba6de039b179425051cbcee67af4c9b948c349
|
4
|
+
data.tar.gz: bbe016d6b2ad3c5c89129089f9ebb8457a37159e03be2ff84f2572454880b0c2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2f91d0b40bceb4600e4bbd22f39cdbd6bfd4ac5b5fc038f77deb7d26a464ce3cad177884f9aadde60c78bc48df170ab6909c44d133283af3abf77a090ac58332
|
7
|
+
data.tar.gz: 37dfa412a25f41dd704a203a865817bf273a23db0ccbe1bbec1a3f6017b9cd953301d67077e3b58601485f4dd96db94bef77da3d46cabd57fb563d3652173175
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,32 @@
|
|
1
|
+
## 0.50.0
|
2
|
+
|
3
|
+
- Use `Process::CLOCK_MONOTONIC` in Timer
|
4
|
+
- Add `Timer#sleep`, `Timer#after`, `Timer#every`
|
5
|
+
- Prevent fiber from being resumed after terminating
|
6
|
+
- Add `Thread#fiber_index_of` method
|
7
|
+
- Use `Backend#wait_event` in `Fiber#await`
|
8
|
+
|
9
|
+
## 0.49.2
|
10
|
+
|
11
|
+
- Fix hang with 100s or more child fibers when terminating
|
12
|
+
- Fix double pending_count increment in io_uring backend
|
13
|
+
|
14
|
+
## 0.49.1
|
15
|
+
|
16
|
+
- Use `TCPSocket` instead of `Socket` in `Net.tcp_connect`
|
17
|
+
- Catch `Errno::ERSCH` in `Process.kill_and_await`
|
18
|
+
- Set io_uring queue size to 2048
|
19
|
+
|
20
|
+
## 0.49.0
|
21
|
+
|
22
|
+
- Implement `Polyphony::Timer` for performant timeouts
|
23
|
+
|
24
|
+
## 0.48.0
|
25
|
+
|
26
|
+
- Implement graceful shutdown
|
27
|
+
- Add support for `break` / `StopIteration` in `spin_loop`
|
28
|
+
- Fix `IO#gets`, `IO#readpartial`
|
29
|
+
|
1
30
|
## 0.47.5.1
|
2
31
|
|
3
32
|
- Add missing `Socket#accept_loop` method
|
data/Gemfile.lock
CHANGED
data/LICENSE
CHANGED
data/TODO.md
CHANGED
@@ -1,29 +1,49 @@
|
|
1
|
-
-
|
1
|
+
- Check segfault when resetting a `cancel_after` timeout lots of times at very high rate
|
2
|
+
- Check why `throttled_loop` inside of `move_on_after` fails to stop
|
3
|
+
|
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
|
+
- Override stock `::SizedQueue` impl with Queue with capacity
|
2
8
|
|
3
|
-
|
4
|
-
- `Fiber#terminate(graceul)` - with a graceful flag
|
5
|
-
- `Fiber#terminate_all_children(graceful)` - with a graceful flag
|
6
|
-
- `Fiber#shutdown_all_children(graceful)` - with a graceful flag
|
9
|
+
- Add support for `break` and `StopIteration` in all loops (with tests)
|
7
10
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
+
- Change `IO#gets` to use `String#split` to cut into lines, much faster (see
|
12
|
+
examples/performance/line_splitting.rb)
|
13
|
+
|
14
|
+
- More tight loops
|
15
|
+
- `IO#gets_loop`, `Socket#gets_loop`, `OpenSSL::Socket#gets_loop` (medium effort)
|
16
|
+
- `Fiber#receive_loop` (very little effort, should be implemented in C)
|
11
17
|
|
12
|
-
|
18
|
+
|
19
|
+
- Add `Backend#splice`, `Backend#splice_loop` for implementing stuff like proxying:
|
13
20
|
|
14
21
|
```ruby
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
22
|
+
def two_way_proxy(socket1, socket2)
|
23
|
+
backend = Thread.current.backend
|
24
|
+
f1 = spin { backend.splice_loop(socket1, socket2) }
|
25
|
+
f2 = spin { backend.splice_loop(socket2, socket1) }
|
26
|
+
Fiber.await(f1, f2)
|
19
27
|
end
|
20
28
|
```
|
21
29
|
|
30
|
+
- Graceful shutdown again:
|
31
|
+
- What happens to children when doing a graceful shutdown?
|
32
|
+
- What are the implications of passing graceful shutdown flag to children?
|
33
|
+
- What about errors while doing a graceful shutdown?
|
34
|
+
- What about graceful restarts?
|
35
|
+
- Some interesting discussions:
|
36
|
+
- https://trio.discourse.group/search?q=graceful%20shutdown
|
37
|
+
- https://github.com/python-trio/trio/issues/147
|
38
|
+
- https://github.com/python-trio/trio/issues/143
|
39
|
+
- https://trio.discourse.group/t/graceful-shutdown/93/2
|
40
|
+
- https://250bpm.com/blog:146/
|
41
|
+
- https://www.rodrigoaraujo.me/posts/golang-pattern-graceful-shutdown-of-concurrent-events/
|
42
|
+
- https://github.com/tj/go-gracefully
|
22
43
|
- `Fiber#finalize_children` should pass graceful shutdown flag to children
|
23
|
-
|
24
|
-
-
|
25
|
-
|
26
|
-
- Fiber#receive_loop (very little effort, should be implemented in C)
|
44
|
+
- A good use case is an HTTP server that on graceful shutdown:
|
45
|
+
- stops listening
|
46
|
+
- waits for all ongoing requests to finish, optionally with a timeout
|
27
47
|
|
28
48
|
## Roadmap for Polyphony 1.0
|
29
49
|
|
@@ -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
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
server1 = TCPServer.open('127.0.0.1', 1234)
|
7
|
+
server2 = TCPServer.open('127.0.0.1', 1235)
|
8
|
+
|
9
|
+
puts "Pid: #{Process.pid}"
|
10
|
+
puts 'Proxying port 1234 => port 1235'
|
11
|
+
|
12
|
+
client1 = client2 = nil
|
13
|
+
|
14
|
+
f1 = spin {
|
15
|
+
client1 = server1.accept
|
16
|
+
loop do
|
17
|
+
if client2
|
18
|
+
Thread.current.backend.splice_loop(client1, client2)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
}
|
22
|
+
|
23
|
+
f2 = spin {
|
24
|
+
client2 = server2.accept
|
25
|
+
loop do
|
26
|
+
if client1
|
27
|
+
Thread.current.backend.splice_loop(client2, client1)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
}
|
31
|
+
|
32
|
+
Fiber.await(f1, f2)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "benchmark/ips"
|
4
|
+
|
5
|
+
def slice
|
6
|
+
str = ('*' * 40) + "\n" + ('*' * 40) + "\n" + ('*' * 40) + "\n" + ('*' * 40) + "\n" + ('*' * 40)
|
7
|
+
lines = []
|
8
|
+
while true
|
9
|
+
idx = str.index("\n")
|
10
|
+
break unless idx
|
11
|
+
|
12
|
+
lines << str.slice!(0, idx + 1)
|
13
|
+
end
|
14
|
+
raise unless lines.size == 4
|
15
|
+
raise unless str == ('*' * 40)
|
16
|
+
end
|
17
|
+
|
18
|
+
def split
|
19
|
+
str = ('*' * 40) + "\n" + ('*' * 40) + "\n" + ('*' * 40) + "\n" + ('*' * 40) + "\n" + ('*' * 40)
|
20
|
+
lines = str.split("\n")
|
21
|
+
if str[-1] == "\n"
|
22
|
+
str = ''
|
23
|
+
else
|
24
|
+
str = lines.pop
|
25
|
+
end
|
26
|
+
raise unless lines.size == 4
|
27
|
+
raise unless str == ('*' * 40)
|
28
|
+
end
|
29
|
+
|
30
|
+
Benchmark.ips do |x|
|
31
|
+
x.report("slice") { slice }
|
32
|
+
x.report("split") { split }
|
33
|
+
x.compare!
|
34
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'benchmark'
|
4
|
+
|
5
|
+
LIMIT = 1_000_0
|
6
|
+
|
7
|
+
def do_while
|
8
|
+
i = 0
|
9
|
+
while true
|
10
|
+
i += 1
|
11
|
+
break if i == LIMIT
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def do_loop
|
16
|
+
i = 0
|
17
|
+
loop do
|
18
|
+
i += 1
|
19
|
+
break if i == LIMIT
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
GC.disable
|
24
|
+
Benchmark.bm do |x|
|
25
|
+
x.report('while') do
|
26
|
+
LIMIT.times { do_while }
|
27
|
+
end
|
28
|
+
x.report('loop') do
|
29
|
+
LIMIT.times { do_loop }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
@@ -26,8 +26,12 @@ 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
|
+
|
32
|
+
spin_loop(interval: 10) do
|
33
|
+
p Thread.current.fiber_scheduling_stats
|
34
|
+
end
|
31
35
|
|
32
36
|
server.accept_loop do |c|
|
33
37
|
spin { handle_client(c) }
|
@@ -70,9 +70,9 @@ inline VALUE io_enc_str(VALUE str, rb_io_t *fptr) {
|
|
70
70
|
|
71
71
|
inline VALUE backend_await(Backend_t *backend) {
|
72
72
|
VALUE ret;
|
73
|
-
backend->
|
73
|
+
backend->pending_count++;
|
74
74
|
ret = Thread_switch_fiber(rb_thread_current());
|
75
|
-
backend->
|
75
|
+
backend->pending_count--;
|
76
76
|
RB_GC_GUARD(ret);
|
77
77
|
return ret;
|
78
78
|
}
|
@@ -114,7 +114,7 @@ inline double current_time() {
|
|
114
114
|
struct timespec ts;
|
115
115
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
116
116
|
long long ns = ts.tv_sec;
|
117
|
-
ns = ns *
|
117
|
+
ns = ns * 1e9 + ts.tv_nsec;
|
118
118
|
double t = ns;
|
119
119
|
return t / 1e9;
|
120
120
|
}
|
@@ -30,11 +30,14 @@ static int pidfd_open(pid_t pid, unsigned int flags) {
|
|
30
30
|
VALUE SYM_io_uring;
|
31
31
|
|
32
32
|
typedef struct Backend_t {
|
33
|
+
// common fields
|
34
|
+
unsigned int currently_polling;
|
35
|
+
unsigned int pending_count;
|
36
|
+
unsigned int poll_no_wait_count;
|
37
|
+
|
38
|
+
// implementation-specific fields
|
33
39
|
struct io_uring ring;
|
34
40
|
op_context_store_t store;
|
35
|
-
int waiting_for_cqe;
|
36
|
-
unsigned int ref_count;
|
37
|
-
unsigned int run_no_wait_count;
|
38
41
|
unsigned int pending_sqes;
|
39
42
|
unsigned int prepared_limit;
|
40
43
|
int event_fd;
|
@@ -65,11 +68,11 @@ static VALUE Backend_initialize(VALUE self) {
|
|
65
68
|
Backend_t *backend;
|
66
69
|
GetBackend(self, backend);
|
67
70
|
|
68
|
-
backend->
|
69
|
-
backend->
|
70
|
-
backend->
|
71
|
+
backend->currently_polling = 0;
|
72
|
+
backend->pending_count = 0;
|
73
|
+
backend->poll_no_wait_count = 0;
|
71
74
|
backend->pending_sqes = 0;
|
72
|
-
backend->prepared_limit =
|
75
|
+
backend->prepared_limit = 2048;
|
73
76
|
|
74
77
|
context_store_initialize(&backend->store);
|
75
78
|
io_uring_queue_init(backend->prepared_limit, &backend->ring, 0);
|
@@ -95,46 +98,19 @@ VALUE Backend_post_fork(VALUE self) {
|
|
95
98
|
io_uring_queue_exit(&backend->ring);
|
96
99
|
io_uring_queue_init(backend->prepared_limit, &backend->ring, 0);
|
97
100
|
context_store_free(&backend->store);
|
98
|
-
backend->
|
99
|
-
backend->
|
100
|
-
backend->
|
101
|
+
backend->currently_polling = 0;
|
102
|
+
backend->pending_count = 0;
|
103
|
+
backend->poll_no_wait_count = 0;
|
101
104
|
backend->pending_sqes = 0;
|
102
105
|
|
103
106
|
return self;
|
104
107
|
}
|
105
108
|
|
106
|
-
|
107
|
-
Backend_t *backend;
|
108
|
-
GetBackend(self, backend);
|
109
|
-
|
110
|
-
backend->ref_count++;
|
111
|
-
return self;
|
112
|
-
}
|
113
|
-
|
114
|
-
VALUE Backend_unref(VALUE self) {
|
109
|
+
unsigned int Backend_pending_count(VALUE self) {
|
115
110
|
Backend_t *backend;
|
116
111
|
GetBackend(self, backend);
|
117
112
|
|
118
|
-
backend->
|
119
|
-
return self;
|
120
|
-
}
|
121
|
-
|
122
|
-
int Backend_ref_count(VALUE self) {
|
123
|
-
Backend_t *backend;
|
124
|
-
GetBackend(self, backend);
|
125
|
-
|
126
|
-
return backend->ref_count;
|
127
|
-
}
|
128
|
-
|
129
|
-
void Backend_reset_ref_count(VALUE self) {
|
130
|
-
Backend_t *backend;
|
131
|
-
GetBackend(self, backend);
|
132
|
-
|
133
|
-
backend->ref_count = 0;
|
134
|
-
}
|
135
|
-
|
136
|
-
VALUE Backend_pending_count(VALUE self) {
|
137
|
-
return INT2NUM(0);
|
113
|
+
return backend->pending_count;
|
138
114
|
}
|
139
115
|
|
140
116
|
typedef struct poll_context {
|
@@ -158,7 +134,7 @@ static inline bool cq_ring_needs_flush(struct io_uring *ring) {
|
|
158
134
|
|
159
135
|
void io_uring_backend_handle_completion(struct io_uring_cqe *cqe, Backend_t *backend) {
|
160
136
|
op_context_t *ctx = io_uring_cqe_get_data(cqe);
|
161
|
-
if (ctx
|
137
|
+
if (!ctx) return;
|
162
138
|
|
163
139
|
ctx->result = cqe->res;
|
164
140
|
|
@@ -211,9 +187,9 @@ void io_uring_backend_poll(Backend_t *backend) {
|
|
211
187
|
io_uring_submit(&backend->ring);
|
212
188
|
}
|
213
189
|
|
214
|
-
backend->
|
190
|
+
backend->currently_polling = 1;
|
215
191
|
rb_thread_call_without_gvl(io_uring_backend_poll_without_gvl, (void *)&poll_ctx, RUBY_UBF_IO, 0);
|
216
|
-
backend->
|
192
|
+
backend->currently_polling = 0;
|
217
193
|
if (poll_ctx.result < 0) return;
|
218
194
|
|
219
195
|
io_uring_backend_handle_completion(poll_ctx.cqe, backend);
|
@@ -226,14 +202,14 @@ VALUE Backend_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE runqueue
|
|
226
202
|
GetBackend(self, backend);
|
227
203
|
|
228
204
|
if (is_nowait) {
|
229
|
-
backend->
|
230
|
-
if (backend->
|
205
|
+
backend->poll_no_wait_count++;
|
206
|
+
if (backend->poll_no_wait_count < 10) return self;
|
231
207
|
|
232
208
|
long runnable_count = Runqueue_len(runqueue);
|
233
|
-
if (backend->
|
209
|
+
if (backend->poll_no_wait_count < runnable_count) return self;
|
234
210
|
}
|
235
211
|
|
236
|
-
backend->
|
212
|
+
backend->poll_no_wait_count = 0;
|
237
213
|
|
238
214
|
if (is_nowait && backend->pending_sqes) {
|
239
215
|
backend->pending_sqes = 0;
|
@@ -252,7 +228,7 @@ VALUE Backend_wakeup(VALUE self) {
|
|
252
228
|
Backend_t *backend;
|
253
229
|
GetBackend(self, backend);
|
254
230
|
|
255
|
-
if (backend->
|
231
|
+
if (backend->currently_polling) {
|
256
232
|
// Since we're currently blocking while waiting for a completion, we add a
|
257
233
|
// NOP which would cause the io_uring_enter syscall to return
|
258
234
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
@@ -284,12 +260,10 @@ int io_uring_backend_defer_submit_and_await(
|
|
284
260
|
VALUE switchpoint_result = Qnil;
|
285
261
|
|
286
262
|
io_uring_sqe_set_data(sqe, ctx);
|
287
|
-
io_uring_sqe_set_flags(sqe, IOSQE_ASYNC);
|
263
|
+
// io_uring_sqe_set_flags(sqe, IOSQE_ASYNC);
|
288
264
|
io_uring_backend_defer_submit(backend);
|
289
265
|
|
290
|
-
backend->ref_count++;
|
291
266
|
switchpoint_result = backend_await(backend);
|
292
|
-
backend->ref_count--;
|
293
267
|
|
294
268
|
if (!ctx->completed) {
|
295
269
|
ctx->result = -ECANCELED;
|
@@ -351,7 +325,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof)
|
|
351
325
|
|
352
326
|
if (result < 0)
|
353
327
|
rb_syserr_fail(-result, strerror(-result));
|
354
|
-
else if (result
|
328
|
+
else if (!result)
|
355
329
|
break; // EOF
|
356
330
|
else {
|
357
331
|
total += result;
|
@@ -373,7 +347,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof)
|
|
373
347
|
io_set_read_length(str, total, shrinkable);
|
374
348
|
io_enc_str(str, fptr);
|
375
349
|
|
376
|
-
if (total
|
350
|
+
if (!total) return Qnil;
|
377
351
|
|
378
352
|
return str;
|
379
353
|
}
|
@@ -410,7 +384,7 @@ VALUE Backend_read_loop(VALUE self, VALUE io) {
|
|
410
384
|
|
411
385
|
if (result < 0)
|
412
386
|
rb_syserr_fail(-result, strerror(-result));
|
413
|
-
else if (result
|
387
|
+
else if (!result)
|
414
388
|
break; // EOF
|
415
389
|
else {
|
416
390
|
total = result;
|
@@ -581,7 +555,7 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length) {
|
|
581
555
|
io_set_read_length(str, total, shrinkable);
|
582
556
|
io_enc_str(str, fptr);
|
583
557
|
|
584
|
-
if (total
|
558
|
+
if (!total) return Qnil;
|
585
559
|
|
586
560
|
return str;
|
587
561
|
}
|
@@ -618,7 +592,7 @@ VALUE Backend_recv_loop(VALUE self, VALUE io) {
|
|
618
592
|
|
619
593
|
if (result < 0)
|
620
594
|
rb_syserr_fail(-result, strerror(-result));
|
621
|
-
else if (result
|
595
|
+
else if (!result)
|
622
596
|
break; // EOF
|
623
597
|
else {
|
624
598
|
total = result;
|
@@ -950,10 +924,6 @@ void Init_Backend() {
|
|
950
924
|
rb_define_method(cBackend, "initialize", Backend_initialize, 0);
|
951
925
|
rb_define_method(cBackend, "finalize", Backend_finalize, 0);
|
952
926
|
rb_define_method(cBackend, "post_fork", Backend_post_fork, 0);
|
953
|
-
rb_define_method(cBackend, "pending_count", Backend_pending_count, 0);
|
954
|
-
|
955
|
-
rb_define_method(cBackend, "ref", Backend_ref, 0);
|
956
|
-
rb_define_method(cBackend, "unref", Backend_unref, 0);
|
957
927
|
|
958
928
|
rb_define_method(cBackend, "poll", Backend_poll, 3);
|
959
929
|
rb_define_method(cBackend, "break", Backend_wakeup, 0);
|
@@ -977,15 +947,6 @@ void Init_Backend() {
|
|
977
947
|
rb_define_method(cBackend, "kind", Backend_kind, 0);
|
978
948
|
|
979
949
|
SYM_io_uring = ID2SYM(rb_intern("io_uring"));
|
980
|
-
|
981
|
-
__BACKEND__.pending_count = Backend_pending_count;
|
982
|
-
__BACKEND__.poll = Backend_poll;
|
983
|
-
__BACKEND__.ref = Backend_ref;
|
984
|
-
__BACKEND__.ref_count = Backend_ref_count;
|
985
|
-
__BACKEND__.reset_ref_count = Backend_reset_ref_count;
|
986
|
-
__BACKEND__.unref = Backend_unref;
|
987
|
-
__BACKEND__.wait_event = Backend_wait_event;
|
988
|
-
__BACKEND__.wakeup = Backend_wakeup;
|
989
950
|
}
|
990
951
|
|
991
952
|
#endif // POLYPHONY_BACKEND_LIBURING
|