polyphony 0.64 → 0.68
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 +22 -0
- data/Gemfile.lock +1 -1
- data/TODO.md +10 -40
- data/bin/pdbg +112 -0
- data/examples/core/await.rb +9 -1
- data/ext/polyphony/backend_common.c +14 -1
- data/ext/polyphony/backend_common.h +3 -1
- data/ext/polyphony/backend_io_uring.c +85 -25
- data/ext/polyphony/backend_io_uring_context.c +42 -0
- data/ext/polyphony/backend_io_uring_context.h +6 -9
- data/ext/polyphony/backend_libev.c +85 -39
- data/ext/polyphony/fiber.c +20 -0
- data/ext/polyphony/polyphony.c +2 -0
- data/ext/polyphony/polyphony.h +5 -2
- data/ext/polyphony/queue.c +1 -1
- data/ext/polyphony/runqueue.c +7 -3
- data/ext/polyphony/runqueue.h +4 -3
- data/ext/polyphony/runqueue_ring_buffer.c +25 -14
- data/ext/polyphony/runqueue_ring_buffer.h +2 -0
- data/ext/polyphony/thread.c +2 -8
- data/lib/polyphony.rb +6 -0
- data/lib/polyphony/debugger.rb +225 -0
- data/lib/polyphony/extensions/debug.rb +1 -1
- data/lib/polyphony/extensions/fiber.rb +64 -71
- data/lib/polyphony/extensions/io.rb +4 -2
- data/lib/polyphony/extensions/openssl.rb +66 -0
- data/lib/polyphony/extensions/socket.rb +8 -2
- data/lib/polyphony/net.rb +1 -0
- data/lib/polyphony/version.rb +1 -1
- data/test/helper.rb +6 -5
- data/test/stress.rb +6 -2
- data/test/test_backend.rb +13 -4
- data/test/test_fiber.rb +35 -11
- data/test/test_global_api.rb +9 -4
- data/test/test_io.rb +2 -0
- data/test/test_socket.rb +14 -11
- data/test/test_supervise.rb +24 -24
- data/test/test_thread.rb +3 -0
- data/test/test_thread_pool.rb +1 -1
- data/test/test_throttler.rb +2 -2
- data/test/test_timer.rb +5 -3
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d23a9c0f60530fdee1d367f34359e4f694bd4a42ba3c0112e61433df05c29a81
|
4
|
+
data.tar.gz: bf75e3f1a633f5c94a43fd45a2de2545d87b1e751753980abb8e1d3eddd4eade
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b810c7ddbd383039e5f34fe76dbea089807417d4415e79a952f6d6a46538cf99c55ae7a34f3eadf61d22af23ac29a0910c62ea5c97dff6e86b94083d98444edf
|
7
|
+
data.tar.gz: '063459edd8f669a024e0b7b8f1daa47983db4cf9ac7f3ca81a69359de92eace4831d843e9b74645db08a50c26d83a2878a5fdb6b125adc260afd13a3135e710c'
|
data/.github/workflows/test.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
## 0.68 2021-08-13
|
2
|
+
|
3
|
+
- Fix missing default value in socket classes' `#readpartial`
|
4
|
+
- Fix linking of operations in `Backend#chain` (io_uring version)
|
5
|
+
- Rename `Fiber#attach` to `Fiber#attach_to`
|
6
|
+
- Expose original `SSLServer#accept`
|
7
|
+
|
8
|
+
## 0.67 2021-08-06
|
9
|
+
|
10
|
+
- Improve fiber monitoring
|
11
|
+
- Add fiber parking (a parked fiber is prevented from running). This is in
|
12
|
+
preparation for the upcoming work on an integrated debugger.
|
13
|
+
|
14
|
+
## 0.66 2021-08-01
|
15
|
+
|
16
|
+
- Fix all splicing APIs on non-linux OSes (#63)
|
17
|
+
- Add GC marking of buffers when cancelling read/write ops in io_uring backend
|
18
|
+
|
19
|
+
## 0.65 2021-07-29
|
20
|
+
|
21
|
+
- Add `#__polyphony_read_method__` method for read method detection
|
22
|
+
|
1
23
|
## 0.64 2021-07-26
|
2
24
|
|
3
25
|
- Add optional raise_on_eof argument to `#readpartial`
|
data/Gemfile.lock
CHANGED
data/TODO.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
- io_uring backend:
|
2
|
+
- if `io_uring_get_sqe` returns null, call `io_uring_submit`, (snooze fiber)?
|
3
|
+
and try again
|
4
|
+
|
5
|
+
- Tracing:
|
6
|
+
- Emit events on I/O ops, e.g.:
|
7
|
+
- [:op_read_submit, id, io, len]
|
8
|
+
- [:op_read_complete, id, io, len, buffer]
|
9
|
+
- Prevent tracing while an event is being emitted (to allow the trace proc to perform I/O)
|
10
|
+
|
1
11
|
- Add support for IPv6:
|
2
12
|
https://www.reddit.com/r/ruby/comments/lyen23/understanding_ipv6_and_why_its_important_to_you/
|
3
13
|
|
@@ -14,47 +24,8 @@
|
|
14
24
|
- `IO#gets_loop`, `Socket#gets_loop`, `OpenSSL::Socket#gets_loop` (medium effort)
|
15
25
|
- `Fiber#receive_loop` (very little effort, should be implemented in C)
|
16
26
|
|
17
|
-
|
18
|
-
- Add `Backend#splice`, `Backend#splice_to_eof` for implementing stuff like proxying:
|
19
|
-
|
20
|
-
```ruby
|
21
|
-
def two_way_proxy(socket1, socket2)
|
22
|
-
backend = Thread.current.backend
|
23
|
-
f1 = spin { backend.splice_to_eof(socket1, socket2) }
|
24
|
-
f2 = spin { backend.splice_to_eof(socket2, socket1) }
|
25
|
-
Fiber.await(f1, f2)
|
26
|
-
end
|
27
|
-
```
|
28
|
-
|
29
27
|
- Add support for `close` to io_uring backend
|
30
28
|
|
31
|
-
- Add support for submission of multiple requests to io_uring backend:
|
32
|
-
|
33
|
-
```ruby
|
34
|
-
Thread.current.backend.submit(
|
35
|
-
[:send, sock, chunk_header(len)],
|
36
|
-
[:splice, file, sock, len]
|
37
|
-
)
|
38
|
-
```
|
39
|
-
|
40
|
-
Full example (for writing chunks from a file to an HTTP response):
|
41
|
-
|
42
|
-
```ruby
|
43
|
-
def serve_io(io)
|
44
|
-
i, o = IO.pipe
|
45
|
-
backend = Thread.current.backend
|
46
|
-
while true
|
47
|
-
len = o.splice(io, 8192)
|
48
|
-
break if len == 0
|
49
|
-
|
50
|
-
backend.submit(
|
51
|
-
[:write, sock, chunk_header(len)],
|
52
|
-
[:splice, i, sock, len]
|
53
|
-
)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
```
|
57
|
-
|
58
29
|
- Graceful shutdown again:
|
59
30
|
- What happens to children when doing a graceful shutdown?
|
60
31
|
- What are the implications of passing graceful shutdown flag to children?
|
@@ -92,7 +63,6 @@
|
|
92
63
|
|
93
64
|
-----------------------------------------------------
|
94
65
|
|
95
|
-
- Add `Backend#splice(in, out, nbytes)` API
|
96
66
|
- Adapter for io/console (what does `IO#raw` do?)
|
97
67
|
- Adapter for Pry and IRB (Which fixes #5 and #6)
|
98
68
|
- allow backend selection at runtime
|
data/bin/pdbg
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'polyphony'
|
6
|
+
|
7
|
+
UNIX_SOCKET_PATH = '/tmp/pdbg.sock'
|
8
|
+
|
9
|
+
cmd = ARGV.join(' ')
|
10
|
+
injected_lib_path = File.expand_path('../lib/polyphony/debugger/server_inject.rb', __dir__)
|
11
|
+
pid = fork { exec("env POLYPHONY_DEBUG_SOCKET_PATH=#{UNIX_SOCKET_PATH} ruby #{cmd}") }
|
12
|
+
puts "Started debugged process (#{pid})"
|
13
|
+
|
14
|
+
socket = nil
|
15
|
+
while !socket
|
16
|
+
socket = UNIXSocket.new(UNIX_SOCKET_PATH) rescue nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse_command(cmd)
|
20
|
+
case cmd
|
21
|
+
when /^(step|s)$/
|
22
|
+
{ cmd: :step }
|
23
|
+
when /^(state|st)$/
|
24
|
+
{ cmd: :state }
|
25
|
+
when /^(help|h)$/
|
26
|
+
{ cmd: :help }
|
27
|
+
when /^(list|l)$/
|
28
|
+
{ cmd: :list }
|
29
|
+
else
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def display_info(info)
|
35
|
+
info = eval(info)
|
36
|
+
case (info && info[:kind])
|
37
|
+
when :listing
|
38
|
+
print_listing(info)
|
39
|
+
when :state
|
40
|
+
print_state(info)
|
41
|
+
else
|
42
|
+
p info
|
43
|
+
end
|
44
|
+
rescue SyntaxError
|
45
|
+
puts "Failed to eval:"
|
46
|
+
p info
|
47
|
+
end
|
48
|
+
|
49
|
+
FILE_LINES_CACHE = {}
|
50
|
+
|
51
|
+
def self.get_snippet(path, lineno)
|
52
|
+
lines = FILE_LINES_CACHE[path] ||= IO.read(path).lines
|
53
|
+
start_idx = lineno - 5
|
54
|
+
stop_idx = lineno + 3
|
55
|
+
stop_idx = lines.size - 1 if stop_idx >= lines.size
|
56
|
+
start_idx = 0 if start_idx < 0
|
57
|
+
(start_idx..stop_idx).map { |idx| [idx + 1, lines[idx]]}
|
58
|
+
end
|
59
|
+
|
60
|
+
def print_snippet(info, snippet, cur_line)
|
61
|
+
places = FILE_LINES_CACHE[info[:path]].size.to_s.size
|
62
|
+
snippet.each do |(lineno, line)|
|
63
|
+
is_cur = lineno == cur_line
|
64
|
+
formatted = format("%s% #{places}d %s", is_cur ? '=> ' : ' ', lineno, line)
|
65
|
+
puts formatted
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def print_listing(info)
|
70
|
+
snippet = get_snippet(info[:path], info[:lineno])
|
71
|
+
puts "Fiber: #{info[:fiber]} Location: #{info[:path]}:#{info[:lineno]}"
|
72
|
+
puts
|
73
|
+
print_snippet(info, snippet, info[:lineno])
|
74
|
+
puts
|
75
|
+
end
|
76
|
+
|
77
|
+
def print_help
|
78
|
+
puts
|
79
|
+
puts "Here's some help..."
|
80
|
+
puts
|
81
|
+
end
|
82
|
+
|
83
|
+
def print_state(info)
|
84
|
+
p info
|
85
|
+
end
|
86
|
+
|
87
|
+
def get_user_cmd
|
88
|
+
while true
|
89
|
+
STDOUT << "(pdbg) "
|
90
|
+
cmd = parse_command(STDIN.gets)
|
91
|
+
next unless cmd
|
92
|
+
|
93
|
+
if cmd[:cmd] == :help
|
94
|
+
print_help
|
95
|
+
else
|
96
|
+
return cmd if cmd
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
socket.puts 'pdbg'
|
102
|
+
response = socket.gets
|
103
|
+
if response.chomp == 'pdbg'
|
104
|
+
puts 'Connected to process'
|
105
|
+
end
|
106
|
+
loop do
|
107
|
+
info = socket.gets.chomp
|
108
|
+
display_info(info)
|
109
|
+
|
110
|
+
cmd = get_user_cmd
|
111
|
+
socket.puts cmd.inspect
|
112
|
+
end
|
data/examples/core/await.rb
CHANGED
@@ -2,7 +2,11 @@
|
|
2
2
|
|
3
3
|
require 'bundler/setup'
|
4
4
|
require 'polyphony'
|
5
|
+
require 'polyphony/extensions/debug'
|
5
6
|
|
7
|
+
Exception.__disable_sanitized_backtrace__ = true
|
8
|
+
|
9
|
+
puts '----- start await example ------'
|
6
10
|
sleeper = spin do
|
7
11
|
puts 'going to sleep'
|
8
12
|
sleep 1
|
@@ -17,4 +21,8 @@ waiter = spin do
|
|
17
21
|
puts 'done waiting'
|
18
22
|
end
|
19
23
|
|
20
|
-
|
24
|
+
trace :before_await
|
25
|
+
|
26
|
+
sleep 2
|
27
|
+
waiter.await
|
28
|
+
trace :after_await
|
@@ -7,6 +7,7 @@
|
|
7
7
|
|
8
8
|
inline void backend_base_initialize(struct Backend_base *base) {
|
9
9
|
runqueue_initialize(&base->runqueue);
|
10
|
+
runqueue_initialize(&base->parked_runqueue);
|
10
11
|
base->currently_polling = 0;
|
11
12
|
base->op_count = 0;
|
12
13
|
base->switch_count = 0;
|
@@ -20,12 +21,14 @@ inline void backend_base_initialize(struct Backend_base *base) {
|
|
20
21
|
|
21
22
|
inline void backend_base_finalize(struct Backend_base *base) {
|
22
23
|
runqueue_finalize(&base->runqueue);
|
24
|
+
runqueue_finalize(&base->parked_runqueue);
|
23
25
|
}
|
24
26
|
|
25
27
|
inline void backend_base_mark(struct Backend_base *base) {
|
26
28
|
if (base->idle_proc != Qnil) rb_gc_mark(base->idle_proc);
|
27
29
|
if (base->trace_proc != Qnil) rb_gc_mark(base->trace_proc);
|
28
30
|
runqueue_mark(&base->runqueue);
|
31
|
+
runqueue_mark(&base->parked_runqueue);
|
29
32
|
}
|
30
33
|
|
31
34
|
const unsigned int ANTI_STARVE_SWITCH_COUNT_THRESHOLD = 64;
|
@@ -91,7 +94,10 @@ void backend_base_schedule_fiber(VALUE thread, VALUE backend, struct Backend_bas
|
|
91
94
|
|
92
95
|
COND_TRACE(base, 4, SYM_fiber_schedule, fiber, value, prioritize ? Qtrue : Qfalse);
|
93
96
|
|
94
|
-
|
97
|
+
runqueue_t *runqueue = rb_ivar_get(fiber, ID_ivar_parked) == Qtrue ?
|
98
|
+
&base->parked_runqueue : &base->runqueue;
|
99
|
+
|
100
|
+
(prioritize ? runqueue_unshift : runqueue_push)(runqueue, fiber, value, already_runnable);
|
95
101
|
if (!already_runnable) {
|
96
102
|
rb_ivar_set(fiber, ID_ivar_runnable, Qtrue);
|
97
103
|
if (rb_thread_current() != thread) {
|
@@ -105,6 +111,13 @@ void backend_base_schedule_fiber(VALUE thread, VALUE backend, struct Backend_bas
|
|
105
111
|
}
|
106
112
|
}
|
107
113
|
|
114
|
+
inline void backend_base_park_fiber(struct Backend_base *base, VALUE fiber) {
|
115
|
+
runqueue_migrate(&base->runqueue, &base->parked_runqueue, fiber);
|
116
|
+
}
|
117
|
+
|
118
|
+
inline void backend_base_unpark_fiber(struct Backend_base *base, VALUE fiber) {
|
119
|
+
runqueue_migrate(&base->parked_runqueue, &base->runqueue, fiber);
|
120
|
+
}
|
108
121
|
|
109
122
|
inline void backend_trace(struct Backend_base *base, int argc, VALUE *argv) {
|
110
123
|
if (base->trace_proc == Qnil) return;
|
@@ -17,6 +17,7 @@ struct backend_stats {
|
|
17
17
|
|
18
18
|
struct Backend_base {
|
19
19
|
runqueue_t runqueue;
|
20
|
+
runqueue_t parked_runqueue;
|
20
21
|
unsigned int currently_polling;
|
21
22
|
unsigned int op_count;
|
22
23
|
unsigned int switch_count;
|
@@ -33,6 +34,8 @@ void backend_base_finalize(struct Backend_base *base);
|
|
33
34
|
void backend_base_mark(struct Backend_base *base);
|
34
35
|
VALUE backend_base_switch_fiber(VALUE backend, struct Backend_base *base);
|
35
36
|
void backend_base_schedule_fiber(VALUE thread, VALUE backend, struct Backend_base *base, VALUE fiber, VALUE value, int prioritize);
|
37
|
+
void backend_base_park_fiber(struct Backend_base *base, VALUE fiber);
|
38
|
+
void backend_base_unpark_fiber(struct Backend_base *base, VALUE fiber);
|
36
39
|
void backend_trace(struct Backend_base *base, int argc, VALUE *argv);
|
37
40
|
struct backend_stats backend_base_stats(struct Backend_base *base);
|
38
41
|
|
@@ -104,7 +107,6 @@ VALUE Backend_sendv(VALUE self, VALUE io, VALUE ary, VALUE flags);
|
|
104
107
|
VALUE Backend_stats(VALUE self);
|
105
108
|
void backend_run_idle_tasks(struct Backend_base *base);
|
106
109
|
void io_verify_blocking_mode(rb_io_t *fptr, VALUE io, VALUE blocking);
|
107
|
-
|
108
110
|
void backend_setup_stats_symbols();
|
109
111
|
|
110
112
|
#endif /* BACKEND_COMMON_H */
|
@@ -25,6 +25,8 @@ VALUE SYM_send;
|
|
25
25
|
VALUE SYM_splice;
|
26
26
|
VALUE SYM_write;
|
27
27
|
|
28
|
+
VALUE eArgumentError;
|
29
|
+
|
28
30
|
#ifdef POLYPHONY_UNSET_NONBLOCK
|
29
31
|
#define io_unset_nonblock(fptr, io) io_verify_blocking_mode(fptr, io, Qtrue)
|
30
32
|
#else
|
@@ -45,6 +47,7 @@ typedef struct Backend_t {
|
|
45
47
|
static void Backend_mark(void *ptr) {
|
46
48
|
Backend_t *backend = ptr;
|
47
49
|
backend_base_mark(&backend->base);
|
50
|
+
context_store_mark_taken_buffers(&backend->store);
|
48
51
|
}
|
49
52
|
|
50
53
|
static void Backend_free(void *ptr) {
|
@@ -226,7 +229,7 @@ inline void Backend_unschedule_fiber(VALUE self, VALUE fiber) {
|
|
226
229
|
Backend_t *backend;
|
227
230
|
GetBackend(self, backend);
|
228
231
|
|
229
|
-
runqueue_delete(&backend->base.runqueue, fiber);
|
232
|
+
runqueue_delete(&backend->base.runqueue, fiber);
|
230
233
|
}
|
231
234
|
|
232
235
|
inline VALUE Backend_switch_fiber(VALUE self) {
|
@@ -349,8 +352,11 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
|
|
349
352
|
|
350
353
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
351
354
|
int completed = context_store_release(&backend->store, ctx);
|
352
|
-
|
353
|
-
|
355
|
+
if (!completed) {
|
356
|
+
context_attach_buffers(ctx, 1, &str);
|
357
|
+
RAISE_IF_EXCEPTION(resume_value);
|
358
|
+
return resume_value;
|
359
|
+
}
|
354
360
|
RB_GC_GUARD(resume_value);
|
355
361
|
|
356
362
|
if (result < 0)
|
@@ -410,8 +416,11 @@ VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen) {
|
|
410
416
|
|
411
417
|
ssize_t result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
412
418
|
int completed = context_store_release(&backend->store, ctx);
|
413
|
-
|
414
|
-
|
419
|
+
if (!completed) {
|
420
|
+
context_attach_buffers(ctx, 1, &str);
|
421
|
+
RAISE_IF_EXCEPTION(resume_value);
|
422
|
+
return resume_value;
|
423
|
+
}
|
415
424
|
RB_GC_GUARD(resume_value);
|
416
425
|
|
417
426
|
if (result < 0)
|
@@ -457,8 +466,11 @@ VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
|
|
457
466
|
|
458
467
|
ssize_t result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
459
468
|
int completed = context_store_release(&backend->store, ctx);
|
460
|
-
|
461
|
-
|
469
|
+
if (!completed) {
|
470
|
+
context_attach_buffers(ctx, 1, &str);
|
471
|
+
RAISE_IF_EXCEPTION(resume_value);
|
472
|
+
return resume_value;
|
473
|
+
}
|
462
474
|
RB_GC_GUARD(resume_value);
|
463
475
|
|
464
476
|
if (result < 0)
|
@@ -500,8 +512,11 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
500
512
|
|
501
513
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
502
514
|
int completed = context_store_release(&backend->store, ctx);
|
503
|
-
|
504
|
-
|
515
|
+
if (!completed) {
|
516
|
+
context_attach_buffers(ctx, 1, &str);
|
517
|
+
RAISE_IF_EXCEPTION(resume_value);
|
518
|
+
return resume_value;
|
519
|
+
}
|
505
520
|
RB_GC_GUARD(resume_value);
|
506
521
|
|
507
522
|
if (result < 0)
|
@@ -549,12 +564,10 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
549
564
|
|
550
565
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
551
566
|
int completed = context_store_release(&backend->store, ctx);
|
552
|
-
if (TEST_EXCEPTION(resume_value)) {
|
553
|
-
free(iov);
|
554
|
-
RAISE_EXCEPTION(resume_value);
|
555
|
-
}
|
556
567
|
if (!completed) {
|
557
568
|
free(iov);
|
569
|
+
context_attach_buffers(ctx, argc, argv);
|
570
|
+
RAISE_IF_EXCEPTION(resume_value);
|
558
571
|
return resume_value;
|
559
572
|
}
|
560
573
|
RB_GC_GUARD(resume_value);
|
@@ -588,8 +601,7 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
588
601
|
|
589
602
|
VALUE Backend_write_m(int argc, VALUE *argv, VALUE self) {
|
590
603
|
if (argc < 2)
|
591
|
-
|
592
|
-
rb_raise(rb_eRuntimeError, "(wrong number of arguments (expected 2 or more))");
|
604
|
+
rb_raise(eArgumentError, "(wrong number of arguments (expected 2 or more))");
|
593
605
|
|
594
606
|
return (argc == 2) ?
|
595
607
|
Backend_write(self, argv[0], argv[1]) :
|
@@ -628,8 +640,11 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos) {
|
|
628
640
|
|
629
641
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
630
642
|
int completed = context_store_release(&backend->store, ctx);
|
631
|
-
|
632
|
-
|
643
|
+
if (!completed) {
|
644
|
+
context_attach_buffers(ctx, 1, &str);
|
645
|
+
RAISE_IF_EXCEPTION(resume_value);
|
646
|
+
return resume_value;
|
647
|
+
}
|
633
648
|
RB_GC_GUARD(resume_value);
|
634
649
|
|
635
650
|
if (result < 0)
|
@@ -675,8 +690,11 @@ VALUE Backend_recv_loop(VALUE self, VALUE io, VALUE maxlen) {
|
|
675
690
|
|
676
691
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
677
692
|
int completed = context_store_release(&backend->store, ctx);
|
678
|
-
|
679
|
-
|
693
|
+
if (!completed) {
|
694
|
+
context_attach_buffers(ctx, 1, &str);
|
695
|
+
RAISE_IF_EXCEPTION(resume_value);
|
696
|
+
return resume_value;
|
697
|
+
}
|
680
698
|
RB_GC_GUARD(resume_value);
|
681
699
|
|
682
700
|
if (result < 0)
|
@@ -721,8 +739,11 @@ VALUE Backend_recv_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method)
|
|
721
739
|
|
722
740
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
723
741
|
int completed = context_store_release(&backend->store, ctx);
|
724
|
-
|
725
|
-
|
742
|
+
if (!completed) {
|
743
|
+
context_attach_buffers(ctx, 1, &str);
|
744
|
+
RAISE_IF_EXCEPTION(resume_value);
|
745
|
+
return resume_value;
|
746
|
+
}
|
726
747
|
RB_GC_GUARD(resume_value);
|
727
748
|
|
728
749
|
if (result < 0)
|
@@ -764,8 +785,11 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
764
785
|
|
765
786
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
766
787
|
int completed = context_store_release(&backend->store, ctx);
|
767
|
-
|
768
|
-
|
788
|
+
if (!completed) {
|
789
|
+
context_attach_buffers(ctx, 1, &str);
|
790
|
+
RAISE_IF_EXCEPTION(resume_value);
|
791
|
+
return resume_value;
|
792
|
+
}
|
769
793
|
RB_GC_GUARD(resume_value);
|
770
794
|
|
771
795
|
if (result < 0)
|
@@ -1165,6 +1189,24 @@ struct io_uring_sqe *Backend_chain_prepare_splice(Backend_t *backend, VALUE src,
|
|
1165
1189
|
return sqe;
|
1166
1190
|
}
|
1167
1191
|
|
1192
|
+
void Backend_chain_ctx_attach_buffers(op_context_t *ctx, int argc, VALUE *argv) {
|
1193
|
+
int count = 0;
|
1194
|
+
if (argc > 1) ctx->buffers = malloc(sizeof(VALUE) * (argc - 1));
|
1195
|
+
|
1196
|
+
for (int i = 0; i < argc; i++) {
|
1197
|
+
VALUE op = argv[i];
|
1198
|
+
VALUE op_type = RARRAY_AREF(op, 0);
|
1199
|
+
|
1200
|
+
if (op_type == SYM_write || op_type == SYM_send) {
|
1201
|
+
if (!count) ctx->buffer0 = RARRAY_AREF(op, 2);
|
1202
|
+
else ctx->buffers[count - 1] = RARRAY_AREF(op, 2);
|
1203
|
+
count++;
|
1204
|
+
}
|
1205
|
+
}
|
1206
|
+
ctx->buffer_count = count;
|
1207
|
+
}
|
1208
|
+
|
1209
|
+
|
1168
1210
|
VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
1169
1211
|
VALUE resume_value = Qnil;
|
1170
1212
|
unsigned int sqe_count = 0;
|
@@ -1206,7 +1248,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1206
1248
|
}
|
1207
1249
|
|
1208
1250
|
io_uring_sqe_set_data(last_sqe, ctx);
|
1209
|
-
unsigned int flags = (i == argc - 1) ? IOSQE_ASYNC : IOSQE_ASYNC
|
1251
|
+
unsigned int flags = (i == (argc - 1)) ? IOSQE_ASYNC : IOSQE_ASYNC | IOSQE_IO_LINK;
|
1210
1252
|
io_uring_sqe_set_flags(last_sqe, flags);
|
1211
1253
|
sqe_count++;
|
1212
1254
|
}
|
@@ -1218,6 +1260,8 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1218
1260
|
int result = ctx->result;
|
1219
1261
|
int completed = context_store_release(&backend->store, ctx);
|
1220
1262
|
if (!completed) {
|
1263
|
+
Backend_chain_ctx_attach_buffers(ctx, argc, argv);
|
1264
|
+
|
1221
1265
|
// op was not completed (an exception was raised), so we need to cancel it
|
1222
1266
|
ctx->result = -ECANCELED;
|
1223
1267
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
@@ -1409,6 +1453,7 @@ syscallerror:
|
|
1409
1453
|
if (pipefd[1] != -1) close(pipefd[1]);
|
1410
1454
|
rb_syserr_fail(err, strerror(err));
|
1411
1455
|
error:
|
1456
|
+
context_attach_buffers_v(ctx, 4, prefix, postfix, chunk_prefix, chunk_postfix);
|
1412
1457
|
if (pipefd[0] != -1) close(pipefd[0]);
|
1413
1458
|
if (pipefd[1] != -1) close(pipefd[1]);
|
1414
1459
|
return RAISE_EXCEPTION(switchpoint_result);
|
@@ -1429,6 +1474,20 @@ VALUE Backend_trace_proc_set(VALUE self, VALUE block) {
|
|
1429
1474
|
return self;
|
1430
1475
|
}
|
1431
1476
|
|
1477
|
+
void Backend_park_fiber(VALUE self, VALUE fiber) {
|
1478
|
+
Backend_t *backend;
|
1479
|
+
GetBackend(self, backend);
|
1480
|
+
|
1481
|
+
backend_base_park_fiber(&backend->base, fiber);
|
1482
|
+
}
|
1483
|
+
|
1484
|
+
void Backend_unpark_fiber(VALUE self, VALUE fiber) {
|
1485
|
+
Backend_t *backend;
|
1486
|
+
GetBackend(self, backend);
|
1487
|
+
|
1488
|
+
backend_base_unpark_fiber(&backend->base, fiber);
|
1489
|
+
}
|
1490
|
+
|
1432
1491
|
void Init_Backend() {
|
1433
1492
|
VALUE cBackend = rb_define_class_under(mPolyphony, "Backend", rb_cObject);
|
1434
1493
|
rb_define_alloc_func(cBackend, Backend_allocate);
|
@@ -1469,7 +1528,6 @@ void Init_Backend() {
|
|
1469
1528
|
rb_define_method(cBackend, "waitpid", Backend_waitpid, 1);
|
1470
1529
|
rb_define_method(cBackend, "write", Backend_write_m, -1);
|
1471
1530
|
|
1472
|
-
|
1473
1531
|
#ifdef POLYPHONY_UNSET_NONBLOCK
|
1474
1532
|
ID_ivar_is_nonblocking = rb_intern("@is_nonblocking");
|
1475
1533
|
#endif
|
@@ -1480,6 +1538,8 @@ void Init_Backend() {
|
|
1480
1538
|
SYM_write = ID2SYM(rb_intern("write"));
|
1481
1539
|
|
1482
1540
|
backend_setup_stats_symbols();
|
1541
|
+
|
1542
|
+
eArgumentError = rb_const_get(rb_cObject, rb_intern("ArgumentError"));
|
1483
1543
|
}
|
1484
1544
|
|
1485
1545
|
#endif // POLYPHONY_BACKEND_LIBURING
|