polyphony 0.34 → 0.41
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 +11 -2
- data/.gitignore +2 -2
- data/.rubocop.yml +30 -0
- data/CHANGELOG.md +34 -0
- data/Gemfile +0 -11
- data/Gemfile.lock +11 -10
- data/README.md +2 -1
- data/Rakefile +6 -2
- data/TODO.md +18 -95
- data/docs/_includes/head.html +40 -0
- data/docs/_includes/nav.html +5 -5
- data/docs/api-reference.md +1 -1
- data/docs/api-reference/fiber.md +18 -0
- data/docs/api-reference/gyro-async.md +57 -0
- data/docs/api-reference/gyro-child.md +29 -0
- data/docs/api-reference/gyro-queue.md +44 -0
- data/docs/api-reference/gyro-timer.md +51 -0
- data/docs/api-reference/gyro.md +25 -0
- data/docs/index.md +10 -7
- data/docs/main-concepts/design-principles.md +67 -9
- data/docs/main-concepts/extending.md +1 -1
- data/docs/main-concepts/fiber-scheduling.md +55 -72
- data/examples/core/xx-agent.rb +102 -0
- data/examples/core/xx-fork-cleanup.rb +22 -0
- data/examples/core/xx-sleeping.rb +14 -6
- data/examples/core/xx-timer-gc.rb +17 -0
- data/examples/io/tunnel.rb +48 -0
- data/examples/io/xx-irb.rb +1 -1
- data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +7 -6
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +14 -25
- data/ext/{gyro → polyphony}/extconf.rb +2 -2
- data/ext/polyphony/fiber.c +112 -0
- data/ext/{gyro → polyphony}/libev.c +0 -0
- data/ext/{gyro → polyphony}/libev.h +0 -0
- data/ext/polyphony/libev_agent.c +503 -0
- data/ext/polyphony/libev_queue.c +214 -0
- data/ext/polyphony/polyphony.c +89 -0
- data/ext/{gyro/gyro.h → polyphony/polyphony.h} +49 -59
- data/ext/polyphony/polyphony_ext.c +23 -0
- data/ext/{gyro → polyphony}/socket.c +21 -19
- data/ext/{gyro → polyphony}/thread.c +55 -119
- data/ext/{gyro → polyphony}/tracing.c +1 -1
- data/lib/polyphony.rb +37 -44
- data/lib/polyphony/adapters/fs.rb +1 -4
- data/lib/polyphony/adapters/irb.rb +2 -2
- data/lib/polyphony/adapters/postgres.rb +6 -5
- data/lib/polyphony/adapters/process.rb +27 -23
- data/lib/polyphony/adapters/trace.rb +110 -105
- data/lib/polyphony/core/channel.rb +35 -35
- data/lib/polyphony/core/exceptions.rb +29 -29
- data/lib/polyphony/core/global_api.rb +94 -91
- data/lib/polyphony/core/resource_pool.rb +83 -83
- data/lib/polyphony/core/sync.rb +16 -16
- data/lib/polyphony/core/thread_pool.rb +49 -37
- data/lib/polyphony/core/throttler.rb +30 -23
- data/lib/polyphony/event.rb +27 -0
- data/lib/polyphony/extensions/core.rb +23 -14
- data/lib/polyphony/extensions/fiber.rb +269 -267
- data/lib/polyphony/extensions/io.rb +56 -26
- data/lib/polyphony/extensions/openssl.rb +5 -9
- data/lib/polyphony/extensions/socket.rb +29 -10
- data/lib/polyphony/extensions/thread.rb +19 -12
- data/lib/polyphony/net.rb +64 -60
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +3 -6
- data/test/helper.rb +14 -1
- data/test/stress.rb +17 -12
- data/test/test_agent.rb +77 -0
- data/test/{test_async.rb → test_event.rb} +17 -9
- data/test/test_ext.rb +25 -4
- data/test/test_fiber.rb +23 -14
- data/test/test_global_api.rb +5 -5
- data/test/test_io.rb +46 -24
- data/test/test_queue.rb +74 -0
- data/test/test_signal.rb +3 -40
- data/test/test_socket.rb +33 -0
- data/test/test_thread.rb +38 -16
- data/test/test_thread_pool.rb +3 -3
- data/test/test_throttler.rb +0 -1
- data/test/test_trace.rb +6 -5
- metadata +34 -39
- data/ext/gyro/async.c +0 -158
- data/ext/gyro/child.c +0 -117
- data/ext/gyro/gyro.c +0 -203
- data/ext/gyro/gyro_ext.c +0 -31
- data/ext/gyro/io.c +0 -447
- data/ext/gyro/queue.c +0 -142
- data/ext/gyro/selector.c +0 -183
- data/ext/gyro/signal.c +0 -108
- data/ext/gyro/timer.c +0 -154
- data/test/test_timer.rb +0 -56
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
Exception.__disable_sanitized_backtrace__ = true
|
7
|
+
|
8
|
+
class Test
|
9
|
+
def test_sleep
|
10
|
+
puts "going to sleep"
|
11
|
+
sleep 1
|
12
|
+
puts "done sleeping"
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_spin
|
16
|
+
spin {
|
17
|
+
10.times {
|
18
|
+
STDOUT << '.'
|
19
|
+
sleep 0.1
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
puts "going to sleep\n"
|
24
|
+
sleep 1
|
25
|
+
puts 'woke up'
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_file
|
29
|
+
f = File.open(__FILE__, 'r')
|
30
|
+
puts Thread.current.agent.read(f, +'', 10000, true)
|
31
|
+
|
32
|
+
Thread.current.agent.write(STDOUT, "Write something: ")
|
33
|
+
str = +''
|
34
|
+
Thread.current.agent.read(STDIN, str, 5, false)
|
35
|
+
puts str
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_fork
|
39
|
+
pid = fork do
|
40
|
+
Thread.current.agent.post_fork
|
41
|
+
puts 'child going to sleep'
|
42
|
+
sleep 1
|
43
|
+
puts 'child done sleeping'
|
44
|
+
exit(42)
|
45
|
+
end
|
46
|
+
|
47
|
+
puts "Waiting for pid #{pid}"
|
48
|
+
result = Thread.current.agent.waitpid(pid)
|
49
|
+
puts "Done waiting"
|
50
|
+
p result
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_async
|
54
|
+
async = Polyphony::Event.new
|
55
|
+
|
56
|
+
spin {
|
57
|
+
puts "signaller starting"
|
58
|
+
sleep 1
|
59
|
+
puts "signal"
|
60
|
+
async.signal(:foo)
|
61
|
+
}
|
62
|
+
|
63
|
+
puts "awaiting event"
|
64
|
+
p async.await
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_queue
|
68
|
+
q = Gyro::Queue.new
|
69
|
+
spin {
|
70
|
+
10.times {
|
71
|
+
q << Time.now.to_f
|
72
|
+
sleep 0.2
|
73
|
+
}
|
74
|
+
q << :STOP
|
75
|
+
}
|
76
|
+
|
77
|
+
loop do
|
78
|
+
value = q.shift
|
79
|
+
break if value == :STOP
|
80
|
+
|
81
|
+
p value
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_thread
|
86
|
+
t = Thread.new do
|
87
|
+
puts "thread going to sleep"
|
88
|
+
sleep 0.2
|
89
|
+
puts "thread done sleeping"
|
90
|
+
end
|
91
|
+
|
92
|
+
t.await
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
t = Test.new
|
97
|
+
|
98
|
+
t.methods.select { |m| m =~ /^test_/ }.each do |m|
|
99
|
+
puts '*' * 40
|
100
|
+
puts m
|
101
|
+
t.send(m)
|
102
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
Exception.__disable_sanitized_backtrace__ = true
|
7
|
+
|
8
|
+
t = Thread.new do
|
9
|
+
async = Gyro::Async.new
|
10
|
+
spin { async.await }
|
11
|
+
sleep 100
|
12
|
+
end
|
13
|
+
|
14
|
+
sleep 0.5
|
15
|
+
|
16
|
+
Polyphony.fork do
|
17
|
+
puts "forked #{Process.pid}"
|
18
|
+
sleep 1
|
19
|
+
puts "done sleeping"
|
20
|
+
end
|
21
|
+
|
22
|
+
sleep 50
|
@@ -5,13 +5,21 @@ require 'polyphony'
|
|
5
5
|
|
6
6
|
Exception.__disable_sanitized_backtrace__ = true
|
7
7
|
|
8
|
-
spin {
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
}
|
8
|
+
# spin {
|
9
|
+
# 10.times {
|
10
|
+
# STDOUT << '.'
|
11
|
+
# sleep 0.1
|
12
|
+
# }
|
13
|
+
# }
|
14
14
|
|
15
15
|
puts 'going to sleep...'
|
16
16
|
sleep 1
|
17
17
|
puts 'woke up'
|
18
|
+
|
19
|
+
counter = 0
|
20
|
+
t = Polyphony::Throttler.new(5)
|
21
|
+
t.process do
|
22
|
+
p counter
|
23
|
+
counter += 1
|
24
|
+
t.stop if counter > 5
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
Exception.__disable_sanitized_backtrace__ = true
|
7
|
+
|
8
|
+
timers = 10.times.map do
|
9
|
+
spin do
|
10
|
+
t = Gyro::Timer.new(1, 1)
|
11
|
+
t.await
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
sleep 0.1
|
16
|
+
GC.start
|
17
|
+
sleep 0.1
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
Ports = ARGV[0..1]
|
7
|
+
EndPoints = []
|
8
|
+
|
9
|
+
def log(msg)
|
10
|
+
puts "#{Time.now.strftime('%Y-%m-%d %H:%M:%S.%3N')} #{msg}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def endpoint_loop(idx, peer_idx)
|
14
|
+
port = Ports[idx]
|
15
|
+
server = Polyphony::Net.tcp_listen(
|
16
|
+
'0.0.0.0',
|
17
|
+
port,
|
18
|
+
reuse_addr: true
|
19
|
+
)
|
20
|
+
# server = TCPServer.open('0.0.0.0', port)
|
21
|
+
log "Listening on port #{port}"
|
22
|
+
loop do
|
23
|
+
conn = server.accept
|
24
|
+
conn.binmode
|
25
|
+
EndPoints[idx] = conn
|
26
|
+
log "Client connected on port #{port} (#{conn.remote_address.inspect})"
|
27
|
+
while data = conn.readpartial(8192)
|
28
|
+
peer = EndPoints[peer_idx]
|
29
|
+
if peer
|
30
|
+
peer << data
|
31
|
+
log "#{idx} => #{peer_idx} #{data.inspect}"
|
32
|
+
else
|
33
|
+
log "#{idx}: #{data.inspect}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
EndPoints[idx] = nil
|
37
|
+
log "Connection closed on port #{port}"
|
38
|
+
rescue => e
|
39
|
+
log "Error on port #{port}: #{e.inspect}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
spin { endpoint_loop(0, 1) }
|
44
|
+
spin { endpoint_loop(1, 0) }
|
45
|
+
|
46
|
+
log "Tunneling port #{Ports[0]} to port #{Ports[1]}..."
|
47
|
+
sleep
|
48
|
+
|
data/examples/io/xx-irb.rb
CHANGED
@@ -20,22 +20,22 @@ end
|
|
20
20
|
|
21
21
|
def handle_client(socket)
|
22
22
|
parser = Http::Parser.new
|
23
|
-
|
23
|
+
reqs = []
|
24
24
|
parser.on_message_complete = proc do |env|
|
25
|
-
|
25
|
+
reqs << Object.new # parser
|
26
26
|
end
|
27
27
|
while (data = socket.readpartial(8192)) do
|
28
28
|
parser << data
|
29
|
-
|
29
|
+
while (req = reqs.shift)
|
30
30
|
handle_request(socket, req)
|
31
31
|
req = nil
|
32
|
-
snooze
|
32
|
+
# snooze
|
33
33
|
end
|
34
34
|
end
|
35
35
|
rescue IOError, SystemCallError => e
|
36
36
|
# do nothing
|
37
37
|
ensure
|
38
|
-
socket
|
38
|
+
socket&.close
|
39
39
|
parser.reset!
|
40
40
|
end
|
41
41
|
|
@@ -46,13 +46,14 @@ def handle_request(client, parser)
|
|
46
46
|
client.write "HTTP/1.1 #{status_code}\r\n#{headers}\r\n#{data}"
|
47
47
|
end
|
48
48
|
|
49
|
-
$incoming =
|
49
|
+
$incoming = Polyphony::Queue.new
|
50
50
|
|
51
51
|
$threads = (1..4).map {
|
52
52
|
Thread.new {
|
53
53
|
Thread.current.setup_fiber_scheduling
|
54
54
|
loop {
|
55
55
|
conn = $incoming.pop
|
56
|
+
puts "#{Thread.current.inspect} pop #{conn.inspect}"
|
56
57
|
spin { handle_client(conn) }
|
57
58
|
}
|
58
59
|
}
|
@@ -4,21 +4,10 @@ require 'bundler/setup'
|
|
4
4
|
require 'polyphony'
|
5
5
|
require 'http/parser'
|
6
6
|
|
7
|
-
|
8
|
-
def setup_async
|
9
|
-
self.on_message_complete = proc { @request_complete = true }
|
10
|
-
end
|
11
|
-
|
12
|
-
def parse(data)
|
13
|
-
self << data
|
14
|
-
return nil unless @request_complete
|
15
|
-
|
16
|
-
@request_complete = nil
|
17
|
-
self
|
18
|
-
end
|
19
|
-
end
|
7
|
+
$connection_count = 0
|
20
8
|
|
21
9
|
def handle_client(socket)
|
10
|
+
$connection_count += 1
|
22
11
|
parser = Http::Parser.new
|
23
12
|
reqs = []
|
24
13
|
parser.on_message_complete = proc do |env|
|
@@ -29,20 +18,20 @@ def handle_client(socket)
|
|
29
18
|
while (req = reqs.shift)
|
30
19
|
handle_request(socket, req)
|
31
20
|
req = nil
|
32
|
-
|
21
|
+
snooze
|
33
22
|
end
|
34
23
|
end
|
35
24
|
rescue IOError, SystemCallError => e
|
36
25
|
# do nothing
|
37
26
|
ensure
|
38
|
-
|
39
|
-
|
27
|
+
$connection_count -= 1
|
28
|
+
socket&.close
|
40
29
|
end
|
41
30
|
|
42
31
|
def handle_request(client, parser)
|
43
|
-
status_code = 200
|
32
|
+
status_code = "200 OK"
|
44
33
|
data = "Hello world!\n"
|
45
|
-
headers = "Content-Length: #{data.bytesize}\r\n"
|
34
|
+
headers = "Content-Type: text/plain\r\nContent-Length: #{data.bytesize}\r\n"
|
46
35
|
client.write "HTTP/1.1 #{status_code}\r\n#{headers}\r\n#{data}"
|
47
36
|
end
|
48
37
|
|
@@ -53,16 +42,16 @@ spin do
|
|
53
42
|
loop do
|
54
43
|
client = server.accept
|
55
44
|
spin { handle_client(client) }
|
56
|
-
# snooze
|
57
45
|
end
|
46
|
+
ensure
|
47
|
+
server&.close
|
58
48
|
end
|
59
49
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
50
|
+
# every(1) {
|
51
|
+
# stats = Thread.current.fiber_scheduling_stats
|
52
|
+
# stats[:connection_count] = $connection_count
|
53
|
+
# puts "#{Time.now} #{stats}"
|
54
|
+
# }
|
66
55
|
|
67
56
|
puts "pid #{Process.pid}"
|
68
57
|
suspend
|
@@ -16,5 +16,5 @@ $defs << "-DHAVE_SYS_RESOURCE_H" if have_header("sys/resource.h")
|
|
16
16
|
|
17
17
|
CONFIG["optflags"] << " -fno-strict-aliasing" unless RUBY_PLATFORM =~ /mswin/
|
18
18
|
|
19
|
-
dir_config "
|
20
|
-
create_makefile "
|
19
|
+
dir_config "polyphony_ext"
|
20
|
+
create_makefile "polyphony_ext"
|
@@ -0,0 +1,112 @@
|
|
1
|
+
#include "polyphony.h"
|
2
|
+
|
3
|
+
ID ID_fiber_trace;
|
4
|
+
ID ID_ivar_auto_watcher;
|
5
|
+
ID ID_trace_ev_loop_enter;
|
6
|
+
ID ID_trace_ev_loop_leave;
|
7
|
+
ID ID_trace_run;
|
8
|
+
ID ID_trace_runnable;
|
9
|
+
ID ID_trace_terminate;
|
10
|
+
ID ID_trace_wait;
|
11
|
+
|
12
|
+
VALUE cEvent = Qnil;
|
13
|
+
|
14
|
+
VALUE SYM_dead;
|
15
|
+
VALUE SYM_running;
|
16
|
+
VALUE SYM_runnable;
|
17
|
+
VALUE SYM_waiting;
|
18
|
+
|
19
|
+
VALUE SYM_fiber_create;
|
20
|
+
VALUE SYM_fiber_ev_loop_enter;
|
21
|
+
VALUE SYM_fiber_ev_loop_leave;
|
22
|
+
VALUE SYM_fiber_run;
|
23
|
+
VALUE SYM_fiber_schedule;
|
24
|
+
VALUE SYM_fiber_switchpoint;
|
25
|
+
VALUE SYM_fiber_terminate;
|
26
|
+
|
27
|
+
static VALUE Fiber_safe_transfer(int argc, VALUE *argv, VALUE self) {
|
28
|
+
VALUE arg = (argc == 0) ? Qnil : argv[0];
|
29
|
+
VALUE ret = rb_funcall(self, ID_transfer, 1, arg);
|
30
|
+
|
31
|
+
TEST_RESUME_EXCEPTION(ret);
|
32
|
+
RB_GC_GUARD(ret);
|
33
|
+
return ret;
|
34
|
+
}
|
35
|
+
|
36
|
+
inline VALUE Fiber_auto_watcher(VALUE self) {
|
37
|
+
VALUE watcher;
|
38
|
+
if (cEvent == Qnil) {
|
39
|
+
cEvent = rb_const_get(mPolyphony, rb_intern("Event"));
|
40
|
+
}
|
41
|
+
|
42
|
+
watcher = rb_ivar_get(self, ID_ivar_auto_watcher);
|
43
|
+
if (watcher == Qnil) {
|
44
|
+
watcher = rb_funcall(cEvent, ID_new, 0);
|
45
|
+
rb_ivar_set(self, ID_ivar_auto_watcher, watcher);
|
46
|
+
}
|
47
|
+
return watcher;
|
48
|
+
}
|
49
|
+
|
50
|
+
static VALUE Fiber_schedule(int argc, VALUE *argv, VALUE self) {
|
51
|
+
VALUE value = (argc == 0) ? Qnil : argv[0];
|
52
|
+
Fiber_make_runnable(self, value);
|
53
|
+
return self;
|
54
|
+
}
|
55
|
+
|
56
|
+
static VALUE Fiber_state(VALUE self) {
|
57
|
+
if (!rb_fiber_alive_p(self) || (rb_ivar_get(self, ID_ivar_running) == Qfalse))
|
58
|
+
return SYM_dead;
|
59
|
+
if (rb_fiber_current() == self) return SYM_running;
|
60
|
+
if (rb_ivar_get(self, ID_runnable) != Qnil) return SYM_runnable;
|
61
|
+
|
62
|
+
return SYM_waiting;
|
63
|
+
}
|
64
|
+
|
65
|
+
void Fiber_make_runnable(VALUE fiber, VALUE value) {
|
66
|
+
VALUE thread = rb_ivar_get(fiber, ID_ivar_thread);
|
67
|
+
if (thread != Qnil) {
|
68
|
+
Thread_schedule_fiber(thread, fiber, value);
|
69
|
+
}
|
70
|
+
else {
|
71
|
+
VALUE caller;
|
72
|
+
rb_warn("No thread set for fiber (fiber, value, caller):");
|
73
|
+
caller = rb_funcall(rb_cObject, rb_intern("caller"), 0);
|
74
|
+
INSPECT(3, fiber, value, caller);
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
void Init_Fiber() {
|
79
|
+
VALUE cFiber = rb_const_get(rb_cObject, rb_intern("Fiber"));
|
80
|
+
rb_define_method(cFiber, "safe_transfer", Fiber_safe_transfer, -1);
|
81
|
+
rb_define_method(cFiber, "schedule", Fiber_schedule, -1);
|
82
|
+
rb_define_method(cFiber, "state", Fiber_state, 0);
|
83
|
+
rb_define_method(cFiber, "auto_watcher", Fiber_auto_watcher, 0);
|
84
|
+
|
85
|
+
SYM_dead = ID2SYM(rb_intern("dead"));
|
86
|
+
SYM_running = ID2SYM(rb_intern("running"));
|
87
|
+
SYM_runnable = ID2SYM(rb_intern("runnable"));
|
88
|
+
SYM_waiting = ID2SYM(rb_intern("waiting"));
|
89
|
+
rb_global_variable(&SYM_dead);
|
90
|
+
rb_global_variable(&SYM_running);
|
91
|
+
rb_global_variable(&SYM_runnable);
|
92
|
+
rb_global_variable(&SYM_waiting);
|
93
|
+
|
94
|
+
ID_fiber_trace = rb_intern("__fiber_trace__");
|
95
|
+
ID_ivar_auto_watcher = rb_intern("@auto_watcher");
|
96
|
+
|
97
|
+
SYM_fiber_create = ID2SYM(rb_intern("fiber_create"));
|
98
|
+
SYM_fiber_ev_loop_enter = ID2SYM(rb_intern("fiber_ev_loop_enter"));
|
99
|
+
SYM_fiber_ev_loop_leave = ID2SYM(rb_intern("fiber_ev_loop_leave"));
|
100
|
+
SYM_fiber_run = ID2SYM(rb_intern("fiber_run"));
|
101
|
+
SYM_fiber_schedule = ID2SYM(rb_intern("fiber_schedule"));
|
102
|
+
SYM_fiber_switchpoint = ID2SYM(rb_intern("fiber_switchpoint"));
|
103
|
+
SYM_fiber_terminate = ID2SYM(rb_intern("fiber_terminate"));
|
104
|
+
|
105
|
+
rb_global_variable(&SYM_fiber_create);
|
106
|
+
rb_global_variable(&SYM_fiber_ev_loop_enter);
|
107
|
+
rb_global_variable(&SYM_fiber_ev_loop_leave);
|
108
|
+
rb_global_variable(&SYM_fiber_run);
|
109
|
+
rb_global_variable(&SYM_fiber_schedule);
|
110
|
+
rb_global_variable(&SYM_fiber_switchpoint);
|
111
|
+
rb_global_variable(&SYM_fiber_terminate);
|
112
|
+
}
|