polyphony 0.66 → 0.70
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 +23 -1
- data/Gemfile.lock +1 -1
- data/TODO.md +10 -63
- data/bin/pdbg +112 -0
- data/examples/core/await.rb +9 -1
- data/ext/polyphony/backend_common.c +32 -1
- data/ext/polyphony/backend_common.h +4 -1
- data/ext/polyphony/backend_io_uring.c +17 -5
- data/ext/polyphony/backend_libev.c +16 -0
- data/ext/polyphony/fiber.c +20 -0
- data/ext/polyphony/polyphony.c +2 -0
- data/ext/polyphony/polyphony.h +5 -2
- data/ext/polyphony/runqueue.c +4 -0
- data/ext/polyphony/runqueue.h +1 -0
- 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 +66 -69
- data/lib/polyphony/extensions/io.rb +1 -3
- data/lib/polyphony/extensions/openssl.rb +63 -1
- data/lib/polyphony/extensions/socket.rb +3 -3
- data/lib/polyphony/version.rb +1 -1
- data/test/helper.rb +4 -5
- data/test/stress.rb +6 -2
- data/test/test_fiber.rb +30 -11
- data/test/test_process_supervision.rb +38 -9
- data/test/test_supervise.rb +183 -100
- data/test/test_thread_pool.rb +1 -1
- data/test/test_throttler.rb +2 -2
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 65be64df5933c24a4afb38b24c139213dcc71a7fbde7689c46c862d7bb04eef3
|
4
|
+
data.tar.gz: 3feec6f48ea17b15468790c91a790438d163b1d905d5ef6c7a2ffd6d3e47bac8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3417d863dcd7e99c3123fbc81923627a77c6a5b45ed20d6e84148eabb945ecb38f429873be01fc53d5c35f36a225045c42e51b2c36f543fb3539ebc7d91f8bcf
|
7
|
+
data.tar.gz: be39ff1ec9616998fc2a5df0bd9af368687e3424cf4b97776466e803624953440bbf75fc166cd273f8f3d4502eefee4a13283c4129c3ed02113cc2015d314428
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
## 0.70 2021-08-19
|
2
|
+
|
3
|
+
- New implementation for `#supervise`
|
4
|
+
- Reset backend state and runqueue on fork
|
5
|
+
|
6
|
+
## 0.69 2021-08-16
|
7
|
+
|
8
|
+
- Rename `#__polyphony_read_method__` to `#__parser_read_method__`
|
9
|
+
|
10
|
+
## 0.68 2021-08-13
|
11
|
+
|
12
|
+
- Fix missing default value in socket classes' `#readpartial`
|
13
|
+
- Fix linking of operations in `Backend#chain` (io_uring version)
|
14
|
+
- Rename `Fiber#attach` to `Fiber#attach_to`
|
15
|
+
- Expose original `SSLServer#accept`
|
16
|
+
|
17
|
+
## 0.67 2021-08-06
|
18
|
+
|
19
|
+
- Improve fiber monitoring
|
20
|
+
- Add fiber parking (a parked fiber is prevented from running). This is in
|
21
|
+
preparation for the upcoming work on an integrated debugger.
|
22
|
+
|
1
23
|
## 0.66 2021-08-01
|
2
24
|
|
3
25
|
- Fix all splicing APIs on non-linux OSes (#63)
|
@@ -5,7 +27,7 @@
|
|
5
27
|
|
6
28
|
## 0.65 2021-07-29
|
7
29
|
|
8
|
-
- Add `#
|
30
|
+
- Add `#__parser_read_method__` method for read method detection
|
9
31
|
|
10
32
|
## 0.64 2021-07-26
|
11
33
|
|
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,72 +24,10 @@
|
|
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
|
-
- Graceful shutdown again:
|
59
|
-
- What happens to children when doing a graceful shutdown?
|
60
|
-
- What are the implications of passing graceful shutdown flag to children?
|
61
|
-
- What about errors while doing a graceful shutdown?
|
62
|
-
- What about graceful restarts?
|
63
|
-
- Some interesting discussions:
|
64
|
-
- https://trio.discourse.group/search?q=graceful%20shutdown
|
65
|
-
- https://github.com/python-trio/trio/issues/147
|
66
|
-
- https://github.com/python-trio/trio/issues/143
|
67
|
-
- https://trio.discourse.group/t/graceful-shutdown/93/2
|
68
|
-
- https://250bpm.com/blog:146/
|
69
|
-
- https://www.rodrigoaraujo.me/posts/golang-pattern-graceful-shutdown-of-concurrent-events/
|
70
|
-
- https://github.com/tj/go-gracefully
|
71
|
-
- `Fiber#finalize_children` should pass graceful shutdown flag to children
|
72
|
-
- A good use case is an HTTP server that on graceful shutdown:
|
73
|
-
- stops listening
|
74
|
-
- waits for all ongoing requests to finish, optionally with a timeout
|
75
|
-
|
76
29
|
## Roadmap for Polyphony 1.0
|
77
30
|
|
78
|
-
- check integration with rb-inotify
|
79
|
-
|
80
|
-
- Improve `#supervise`. It does not work as advertised, and seems to exhibit an
|
81
|
-
inconsistent behaviour (see supervisor example).
|
82
|
-
|
83
31
|
- Add test that mimics the original design for Monocrono:
|
84
32
|
- 256 fibers each waiting for a message
|
85
33
|
- When message received do some blocking work using a `ThreadPool`
|
@@ -92,7 +40,6 @@
|
|
92
40
|
|
93
41
|
-----------------------------------------------------
|
94
42
|
|
95
|
-
- Add `Backend#splice(in, out, nbytes)` API
|
96
43
|
- Adapter for io/console (what does `IO#raw` do?)
|
97
44
|
- Adapter for Pry and IRB (Which fixes #5 and #6)
|
98
45
|
- 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,32 @@ 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);
|
32
|
+
}
|
33
|
+
|
34
|
+
void backend_base_reset(struct Backend_base *base) {
|
35
|
+
runqueue_finalize(&base->runqueue);
|
36
|
+
runqueue_finalize(&base->parked_runqueue);
|
37
|
+
|
38
|
+
runqueue_initialize(&base->runqueue);
|
39
|
+
runqueue_initialize(&base->parked_runqueue);
|
40
|
+
|
41
|
+
base->currently_polling = 0;
|
42
|
+
base->op_count = 0;
|
43
|
+
base->switch_count = 0;
|
44
|
+
base->poll_count = 0;
|
45
|
+
base->pending_count = 0;
|
46
|
+
base->idle_gc_period = 0;
|
47
|
+
base->idle_gc_last_time = 0;
|
48
|
+
base->idle_proc = Qnil;
|
49
|
+
base->trace_proc = Qnil;
|
29
50
|
}
|
30
51
|
|
31
52
|
const unsigned int ANTI_STARVE_SWITCH_COUNT_THRESHOLD = 64;
|
@@ -91,7 +112,10 @@ void backend_base_schedule_fiber(VALUE thread, VALUE backend, struct Backend_bas
|
|
91
112
|
|
92
113
|
COND_TRACE(base, 4, SYM_fiber_schedule, fiber, value, prioritize ? Qtrue : Qfalse);
|
93
114
|
|
94
|
-
|
115
|
+
runqueue_t *runqueue = rb_ivar_get(fiber, ID_ivar_parked) == Qtrue ?
|
116
|
+
&base->parked_runqueue : &base->runqueue;
|
117
|
+
|
118
|
+
(prioritize ? runqueue_unshift : runqueue_push)(runqueue, fiber, value, already_runnable);
|
95
119
|
if (!already_runnable) {
|
96
120
|
rb_ivar_set(fiber, ID_ivar_runnable, Qtrue);
|
97
121
|
if (rb_thread_current() != thread) {
|
@@ -105,6 +129,13 @@ void backend_base_schedule_fiber(VALUE thread, VALUE backend, struct Backend_bas
|
|
105
129
|
}
|
106
130
|
}
|
107
131
|
|
132
|
+
inline void backend_base_park_fiber(struct Backend_base *base, VALUE fiber) {
|
133
|
+
runqueue_migrate(&base->runqueue, &base->parked_runqueue, fiber);
|
134
|
+
}
|
135
|
+
|
136
|
+
inline void backend_base_unpark_fiber(struct Backend_base *base, VALUE fiber) {
|
137
|
+
runqueue_migrate(&base->parked_runqueue, &base->runqueue, fiber);
|
138
|
+
}
|
108
139
|
|
109
140
|
inline void backend_trace(struct Backend_base *base, int argc, VALUE *argv) {
|
110
141
|
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;
|
@@ -31,8 +32,11 @@ struct Backend_base {
|
|
31
32
|
void backend_base_initialize(struct Backend_base *base);
|
32
33
|
void backend_base_finalize(struct Backend_base *base);
|
33
34
|
void backend_base_mark(struct Backend_base *base);
|
35
|
+
void backend_base_reset(struct Backend_base *base);
|
34
36
|
VALUE backend_base_switch_fiber(VALUE backend, struct Backend_base *base);
|
35
37
|
void backend_base_schedule_fiber(VALUE thread, VALUE backend, struct Backend_base *base, VALUE fiber, VALUE value, int prioritize);
|
38
|
+
void backend_base_park_fiber(struct Backend_base *base, VALUE fiber);
|
39
|
+
void backend_base_unpark_fiber(struct Backend_base *base, VALUE fiber);
|
36
40
|
void backend_trace(struct Backend_base *base, int argc, VALUE *argv);
|
37
41
|
struct backend_stats backend_base_stats(struct Backend_base *base);
|
38
42
|
|
@@ -104,7 +108,6 @@ VALUE Backend_sendv(VALUE self, VALUE io, VALUE ary, VALUE flags);
|
|
104
108
|
VALUE Backend_stats(VALUE self);
|
105
109
|
void backend_run_idle_tasks(struct Backend_base *base);
|
106
110
|
void io_verify_blocking_mode(rb_io_t *fptr, VALUE io, VALUE blocking);
|
107
|
-
|
108
111
|
void backend_setup_stats_symbols();
|
109
112
|
|
110
113
|
#endif /* BACKEND_COMMON_H */
|
@@ -106,9 +106,7 @@ VALUE Backend_post_fork(VALUE self) {
|
|
106
106
|
io_uring_queue_exit(&backend->ring);
|
107
107
|
io_uring_queue_init(backend->prepared_limit, &backend->ring, 0);
|
108
108
|
context_store_free(&backend->store);
|
109
|
-
backend->base
|
110
|
-
backend->base.pending_count = 0;
|
111
|
-
backend->pending_sqes = 0;
|
109
|
+
backend_base_reset(&backend->base);
|
112
110
|
|
113
111
|
return self;
|
114
112
|
}
|
@@ -229,7 +227,7 @@ inline void Backend_unschedule_fiber(VALUE self, VALUE fiber) {
|
|
229
227
|
Backend_t *backend;
|
230
228
|
GetBackend(self, backend);
|
231
229
|
|
232
|
-
runqueue_delete(&backend->base.runqueue, fiber);
|
230
|
+
runqueue_delete(&backend->base.runqueue, fiber);
|
233
231
|
}
|
234
232
|
|
235
233
|
inline VALUE Backend_switch_fiber(VALUE self) {
|
@@ -1248,7 +1246,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1248
1246
|
}
|
1249
1247
|
|
1250
1248
|
io_uring_sqe_set_data(last_sqe, ctx);
|
1251
|
-
unsigned int flags = (i == argc - 1) ? IOSQE_ASYNC : IOSQE_ASYNC
|
1249
|
+
unsigned int flags = (i == (argc - 1)) ? IOSQE_ASYNC : IOSQE_ASYNC | IOSQE_IO_LINK;
|
1252
1250
|
io_uring_sqe_set_flags(last_sqe, flags);
|
1253
1251
|
sqe_count++;
|
1254
1252
|
}
|
@@ -1474,6 +1472,20 @@ VALUE Backend_trace_proc_set(VALUE self, VALUE block) {
|
|
1474
1472
|
return self;
|
1475
1473
|
}
|
1476
1474
|
|
1475
|
+
void Backend_park_fiber(VALUE self, VALUE fiber) {
|
1476
|
+
Backend_t *backend;
|
1477
|
+
GetBackend(self, backend);
|
1478
|
+
|
1479
|
+
backend_base_park_fiber(&backend->base, fiber);
|
1480
|
+
}
|
1481
|
+
|
1482
|
+
void Backend_unpark_fiber(VALUE self, VALUE fiber) {
|
1483
|
+
Backend_t *backend;
|
1484
|
+
GetBackend(self, backend);
|
1485
|
+
|
1486
|
+
backend_base_unpark_fiber(&backend->base, fiber);
|
1487
|
+
}
|
1488
|
+
|
1477
1489
|
void Init_Backend() {
|
1478
1490
|
VALUE cBackend = rb_define_class_under(mPolyphony, "Backend", rb_cObject);
|
1479
1491
|
rb_define_alloc_func(cBackend, Backend_allocate);
|
@@ -157,6 +157,8 @@ VALUE Backend_post_fork(VALUE self) {
|
|
157
157
|
ev_loop_destroy(backend->ev_loop);
|
158
158
|
backend->ev_loop = EV_DEFAULT;
|
159
159
|
|
160
|
+
backend_base_reset(&backend->base);
|
161
|
+
|
160
162
|
return self;
|
161
163
|
}
|
162
164
|
|
@@ -1553,6 +1555,20 @@ VALUE Backend_trace_proc_set(VALUE self, VALUE block) {
|
|
1553
1555
|
return self;
|
1554
1556
|
}
|
1555
1557
|
|
1558
|
+
void Backend_park_fiber(VALUE self, VALUE fiber) {
|
1559
|
+
Backend_t *backend;
|
1560
|
+
GetBackend(self, backend);
|
1561
|
+
|
1562
|
+
backend_base_park_fiber(&backend->base, fiber);
|
1563
|
+
}
|
1564
|
+
|
1565
|
+
void Backend_unpark_fiber(VALUE self, VALUE fiber) {
|
1566
|
+
Backend_t *backend;
|
1567
|
+
GetBackend(self, backend);
|
1568
|
+
|
1569
|
+
backend_base_unpark_fiber(&backend->base, fiber);
|
1570
|
+
}
|
1571
|
+
|
1556
1572
|
void Init_Backend() {
|
1557
1573
|
ev_set_allocator(xrealloc);
|
1558
1574
|
|