polyphony 0.34 → 0.36
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/Gemfile.lock +1 -1
- data/TODO.md +7 -7
- 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 +8 -6
- data/docs/main-concepts/fiber-scheduling.md +55 -72
- data/examples/core/xx-timer-gc.rb +17 -0
- data/ext/gyro/async.c +48 -58
- data/ext/gyro/child.c +48 -38
- data/ext/gyro/fiber.c +113 -0
- data/ext/gyro/gyro.c +12 -106
- data/ext/gyro/gyro.h +54 -50
- data/ext/gyro/gyro_ext.c +2 -0
- data/ext/gyro/io.c +70 -43
- data/ext/gyro/queue.c +5 -5
- data/ext/gyro/selector.c +33 -11
- data/ext/gyro/signal.c +44 -34
- data/ext/gyro/socket.c +6 -7
- data/ext/gyro/thread.c +1 -1
- data/ext/gyro/timer.c +42 -62
- data/lib/polyphony/adapters/irb.rb +1 -1
- data/lib/polyphony/core/thread_pool.rb +3 -3
- data/lib/polyphony/extensions/fiber.rb +1 -1
- data/lib/polyphony/extensions/thread.rb +2 -2
- data/lib/polyphony/version.rb +1 -1
- data/test/test_async.rb +2 -2
- data/test/test_fiber.rb +4 -4
- data/test/test_global_api.rb +1 -1
- data/test/test_thread_pool.rb +1 -1
- metadata +9 -2
@@ -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
|
data/ext/gyro/async.c
CHANGED
@@ -4,8 +4,10 @@ struct Gyro_Async {
|
|
4
4
|
struct ev_async ev_async;
|
5
5
|
struct ev_loop *ev_loop;
|
6
6
|
int active;
|
7
|
+
VALUE self;
|
7
8
|
VALUE fiber;
|
8
9
|
VALUE value;
|
10
|
+
VALUE selector;
|
9
11
|
};
|
10
12
|
|
11
13
|
VALUE cGyro_Async = Qnil;
|
@@ -18,12 +20,16 @@ static void Gyro_Async_mark(void *ptr) {
|
|
18
20
|
if (async->value != Qnil) {
|
19
21
|
rb_gc_mark(async->value);
|
20
22
|
}
|
23
|
+
if (async->selector != Qnil) {
|
24
|
+
rb_gc_mark(async->selector);
|
25
|
+
}
|
21
26
|
}
|
22
27
|
|
23
28
|
static void Gyro_Async_free(void *ptr) {
|
24
29
|
struct Gyro_Async *async = ptr;
|
25
30
|
if (async->active) {
|
26
|
-
|
31
|
+
ev_clear_pending(async->ev_loop, &async->ev_async);
|
32
|
+
ev_async_stop(async->ev_loop, &async->ev_async);
|
27
33
|
}
|
28
34
|
xfree(async);
|
29
35
|
}
|
@@ -35,26 +41,42 @@ static size_t Gyro_Async_size(const void *ptr) {
|
|
35
41
|
static const rb_data_type_t Gyro_Async_type = {
|
36
42
|
"Gyro_Async",
|
37
43
|
{Gyro_Async_mark, Gyro_Async_free, Gyro_Async_size,},
|
38
|
-
0, 0,
|
39
|
-
RUBY_TYPED_FREE_IMMEDIATELY,
|
44
|
+
0, 0, 0
|
40
45
|
};
|
41
46
|
|
42
47
|
static VALUE Gyro_Async_allocate(VALUE klass) {
|
43
|
-
struct Gyro_Async *async = (struct Gyro_Async
|
48
|
+
struct Gyro_Async *async = ALLOC(struct Gyro_Async);
|
44
49
|
return TypedData_Wrap_Struct(klass, &Gyro_Async_type, async);
|
45
50
|
}
|
46
51
|
|
47
|
-
void
|
48
|
-
|
52
|
+
inline void Gyro_Async_activate(struct Gyro_Async *async) {
|
53
|
+
if (async->active) return;
|
49
54
|
|
50
|
-
|
55
|
+
async->active = 1;
|
56
|
+
async->fiber = rb_fiber_current();
|
57
|
+
async->selector = Thread_current_event_selector();
|
58
|
+
async->ev_loop = Gyro_Selector_ev_loop(async->selector);
|
59
|
+
Gyro_Selector_add_active_watcher(async->selector, async->self);
|
60
|
+
ev_async_start(async->ev_loop, &async->ev_async);
|
61
|
+
}
|
62
|
+
|
63
|
+
inline void Gyro_Async_deactivate(struct Gyro_Async *async) {
|
64
|
+
if (!async->active) return;
|
65
|
+
|
66
|
+
ev_async_stop(async->ev_loop, &async->ev_async);
|
67
|
+
Gyro_Selector_remove_active_watcher(async->selector, async->self);
|
51
68
|
async->active = 0;
|
69
|
+
async->ev_loop = 0;
|
70
|
+
async->selector = Qnil;
|
71
|
+
async->fiber = Qnil;
|
72
|
+
async->value = Qnil;
|
73
|
+
}
|
52
74
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
75
|
+
void Gyro_Async_callback(struct ev_loop *ev_loop, struct ev_async *ev_async, int revents) {
|
76
|
+
struct Gyro_Async *async = (struct Gyro_Async*)ev_async;
|
77
|
+
|
78
|
+
Fiber_make_runnable(async->fiber, async->value);
|
79
|
+
Gyro_Async_deactivate(async);
|
58
80
|
}
|
59
81
|
|
60
82
|
#define GetGyro_Async(obj, async) \
|
@@ -64,12 +86,14 @@ static VALUE Gyro_Async_initialize(VALUE self) {
|
|
64
86
|
struct Gyro_Async *async;
|
65
87
|
GetGyro_Async(self, async);
|
66
88
|
|
89
|
+
async->self = self;
|
67
90
|
async->fiber = Qnil;
|
68
91
|
async->value = Qnil;
|
92
|
+
async->selector = Qnil;
|
69
93
|
async->active = 0;
|
94
|
+
async->ev_loop = 0;
|
70
95
|
|
71
96
|
ev_async_init(&async->ev_async, Gyro_Async_callback);
|
72
|
-
async->ev_loop = 0;
|
73
97
|
|
74
98
|
return Qnil;
|
75
99
|
}
|
@@ -79,7 +103,7 @@ static VALUE Gyro_Async_signal(int argc, VALUE *argv, VALUE self) {
|
|
79
103
|
GetGyro_Async(self, async);
|
80
104
|
|
81
105
|
if (!async->active) {
|
82
|
-
// printf("signal
|
106
|
+
// printf("signal called before await\n");
|
83
107
|
return Qnil;
|
84
108
|
}
|
85
109
|
|
@@ -91,68 +115,34 @@ static VALUE Gyro_Async_signal(int argc, VALUE *argv, VALUE self) {
|
|
91
115
|
|
92
116
|
VALUE Gyro_Async_await(VALUE self) {
|
93
117
|
struct Gyro_Async *async;
|
94
|
-
VALUE ret;
|
95
|
-
|
96
118
|
GetGyro_Async(self, async);
|
97
119
|
|
98
|
-
async
|
99
|
-
|
100
|
-
|
101
|
-
async->ev_loop = Gyro_Selector_current_thread_ev_loop();
|
102
|
-
ev_async_start(async->ev_loop, &async->ev_async);
|
103
|
-
}
|
120
|
+
Gyro_Async_activate(async);
|
121
|
+
VALUE ret = Gyro_switchpoint();
|
122
|
+
Gyro_Async_deactivate(async);
|
104
123
|
|
105
|
-
ret
|
124
|
+
TEST_RESUME_EXCEPTION(ret);
|
106
125
|
RB_GC_GUARD(ret);
|
107
|
-
|
108
|
-
if (async->active) {
|
109
|
-
async->active = 0;
|
110
|
-
async->fiber = Qnil;
|
111
|
-
ev_async_stop(async->ev_loop, &async->ev_async);
|
112
|
-
async->value = Qnil;
|
113
|
-
}
|
114
|
-
|
115
|
-
// fiber is resumed
|
116
|
-
if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) {
|
117
|
-
return rb_funcall(rb_mKernel, ID_raise, 1, ret);
|
118
|
-
}
|
119
|
-
else {
|
120
|
-
return ret;
|
121
|
-
}
|
126
|
+
return ret;
|
122
127
|
}
|
123
128
|
|
124
129
|
VALUE Gyro_Async_await_no_raise(VALUE self) {
|
125
130
|
struct Gyro_Async *async;
|
126
|
-
VALUE ret;
|
127
|
-
|
128
131
|
GetGyro_Async(self, async);
|
129
132
|
|
130
|
-
async
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
ev_async_start(async->ev_loop, &async->ev_async);
|
135
|
-
}
|
136
|
-
|
137
|
-
ret = Fiber_await();
|
133
|
+
Gyro_Async_activate(async);
|
134
|
+
VALUE ret = Gyro_switchpoint();
|
135
|
+
Gyro_Async_deactivate(async);
|
136
|
+
|
138
137
|
RB_GC_GUARD(ret);
|
139
|
-
|
140
|
-
if (async->active) {
|
141
|
-
async->active = 0;
|
142
|
-
async->fiber = Qnil;
|
143
|
-
ev_async_stop(async->ev_loop, &async->ev_async);
|
144
|
-
async->value = Qnil;
|
145
|
-
}
|
146
|
-
|
147
138
|
return ret;
|
148
139
|
}
|
149
140
|
|
150
|
-
|
151
141
|
void Init_Gyro_Async() {
|
152
142
|
cGyro_Async = rb_define_class_under(mGyro, "Async", rb_cData);
|
153
143
|
rb_define_alloc_func(cGyro_Async, Gyro_Async_allocate);
|
154
144
|
|
155
145
|
rb_define_method(cGyro_Async, "initialize", Gyro_Async_initialize, 0);
|
156
|
-
rb_define_method(cGyro_Async, "signal
|
146
|
+
rb_define_method(cGyro_Async, "signal", Gyro_Async_signal, -1);
|
157
147
|
rb_define_method(cGyro_Async, "await", Gyro_Async_await, 0);
|
158
148
|
}
|
data/ext/gyro/child.c
CHANGED
@@ -7,6 +7,7 @@ struct Gyro_Child {
|
|
7
7
|
int pid;
|
8
8
|
VALUE self;
|
9
9
|
VALUE fiber;
|
10
|
+
VALUE selector;
|
10
11
|
};
|
11
12
|
|
12
13
|
static VALUE cGyro_Child = Qnil;
|
@@ -16,12 +17,16 @@ static void Gyro_Child_mark(void *ptr) {
|
|
16
17
|
if (child->fiber != Qnil) {
|
17
18
|
rb_gc_mark(child->fiber);
|
18
19
|
}
|
20
|
+
if (child->selector != Qnil) {
|
21
|
+
rb_gc_mark(child->selector);
|
22
|
+
}
|
19
23
|
}
|
20
24
|
|
21
25
|
static void Gyro_Child_free(void *ptr) {
|
22
26
|
struct Gyro_Child *child = ptr;
|
23
27
|
if (child->active) {
|
24
|
-
|
28
|
+
ev_clear_pending(child->ev_loop, &child->ev_child);
|
29
|
+
ev_child_stop(child->ev_loop, &child->ev_child);
|
25
30
|
}
|
26
31
|
xfree(child);
|
27
32
|
}
|
@@ -33,31 +38,51 @@ static size_t Gyro_Child_size(const void *ptr) {
|
|
33
38
|
static const rb_data_type_t Gyro_Child_type = {
|
34
39
|
"Gyro_Child",
|
35
40
|
{Gyro_Child_mark, Gyro_Child_free, Gyro_Child_size,},
|
36
|
-
0, 0,
|
37
|
-
RUBY_TYPED_FREE_IMMEDIATELY,
|
41
|
+
0, 0, 0
|
38
42
|
};
|
39
43
|
|
40
44
|
static VALUE Gyro_Child_allocate(VALUE klass) {
|
41
|
-
struct Gyro_Child *child = (struct Gyro_Child
|
45
|
+
struct Gyro_Child *child = ALLOC(struct Gyro_Child);
|
42
46
|
return TypedData_Wrap_Struct(klass, &Gyro_Child_type, child);
|
43
47
|
}
|
44
48
|
|
49
|
+
inline void Gyro_Child_activate(struct Gyro_Child *child) {
|
50
|
+
if (child->active) return;
|
51
|
+
|
52
|
+
child->active = 1;
|
53
|
+
child->fiber = rb_fiber_current();
|
54
|
+
child->selector = Thread_current_event_selector();
|
55
|
+
child->ev_loop = Gyro_Selector_ev_loop(child->selector);
|
56
|
+
Gyro_Selector_add_active_watcher(child->selector, child->self);
|
57
|
+
ev_child_start(child->ev_loop, &child->ev_child);
|
58
|
+
}
|
59
|
+
|
60
|
+
inline void Gyro_Child_deactivate(struct Gyro_Child *child) {
|
61
|
+
if (!child->active) return;
|
62
|
+
|
63
|
+
ev_child_stop(child->ev_loop, &child->ev_child);
|
64
|
+
Gyro_Selector_remove_active_watcher(child->selector, child->self);
|
65
|
+
child->active = 0;
|
66
|
+
child->ev_loop = 0;
|
67
|
+
child->selector = Qnil;
|
68
|
+
child->fiber = Qnil;
|
69
|
+
}
|
70
|
+
|
71
|
+
VALUE Gyro_Child_resume_value(struct ev_child *ev_child) {
|
72
|
+
int exit_status = ev_child->rstatus >> 8; // weird, why should we do this?
|
73
|
+
|
74
|
+
return rb_ary_new_from_args(
|
75
|
+
2, INT2NUM(ev_child->rpid), INT2NUM(exit_status)
|
76
|
+
);
|
77
|
+
}
|
78
|
+
|
45
79
|
void Gyro_Child_callback(struct ev_loop *ev_loop, struct ev_child *ev_child, int revents) {
|
46
80
|
struct Gyro_Child *child = (struct Gyro_Child*)ev_child;
|
47
81
|
|
48
|
-
|
49
|
-
|
82
|
+
VALUE resume_value = Gyro_Child_resume_value(ev_child);
|
83
|
+
Fiber_make_runnable(child->fiber, resume_value);
|
50
84
|
|
51
|
-
|
52
|
-
VALUE fiber = child->fiber;
|
53
|
-
int exit_status = ev_child->rstatus >> 8; // weird, why should we do this?
|
54
|
-
|
55
|
-
VALUE resume_value = rb_ary_new_from_args(
|
56
|
-
2, INT2NUM(ev_child->rpid), INT2NUM(exit_status)
|
57
|
-
);
|
58
|
-
child->fiber = Qnil;
|
59
|
-
Gyro_schedule_fiber(fiber, resume_value);
|
60
|
-
}
|
85
|
+
Gyro_Child_deactivate(child);
|
61
86
|
}
|
62
87
|
|
63
88
|
#define GetGyro_Child(obj, child) \
|
@@ -70,8 +95,10 @@ static VALUE Gyro_Child_initialize(VALUE self, VALUE pid) {
|
|
70
95
|
|
71
96
|
child->self = self;
|
72
97
|
child->fiber = Qnil;
|
98
|
+
child->selector = Qnil;
|
73
99
|
child->pid = NUM2INT(pid);
|
74
100
|
child->active = 0;
|
101
|
+
child->ev_loop = 0;
|
75
102
|
|
76
103
|
ev_child_init(&child->ev_child, Gyro_Child_callback, child->pid, 0);
|
77
104
|
|
@@ -80,32 +107,15 @@ static VALUE Gyro_Child_initialize(VALUE self, VALUE pid) {
|
|
80
107
|
|
81
108
|
static VALUE Gyro_Child_await(VALUE self) {
|
82
109
|
struct Gyro_Child *child;
|
83
|
-
VALUE ret;
|
84
|
-
|
85
110
|
GetGyro_Child(self, child);
|
86
111
|
|
87
|
-
|
88
|
-
|
89
|
-
child
|
90
|
-
child->ev_loop = Gyro_Selector_current_thread_ev_loop();
|
91
|
-
ev_child_start(child->ev_loop, &child->ev_child);
|
112
|
+
Gyro_Child_activate(child);
|
113
|
+
VALUE ret = Gyro_switchpoint();
|
114
|
+
Gyro_Child_deactivate(child);
|
92
115
|
|
93
|
-
ret
|
116
|
+
TEST_RESUME_EXCEPTION(ret);
|
94
117
|
RB_GC_GUARD(ret);
|
95
|
-
|
96
|
-
if (child->active) {
|
97
|
-
child->active = 0;
|
98
|
-
child->fiber = Qnil;
|
99
|
-
ev_child_stop(child->ev_loop, &child->ev_child);
|
100
|
-
}
|
101
|
-
|
102
|
-
// fiber is resumed, check if resumed value is an exception
|
103
|
-
if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) {
|
104
|
-
return rb_funcall(rb_mKernel, ID_raise, 1, ret);
|
105
|
-
}
|
106
|
-
else {
|
107
|
-
return ret;
|
108
|
-
}
|
118
|
+
return ret;
|
109
119
|
}
|
110
120
|
|
111
121
|
void Init_Gyro_Child() {
|
data/ext/gyro/fiber.c
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
#include "gyro.h"
|
2
|
+
|
3
|
+
ID ID_fiber_trace;
|
4
|
+
ID ID_ivar_auto_async;
|
5
|
+
ID ID_ivar_auto_io;
|
6
|
+
ID ID_trace_ev_loop_enter;
|
7
|
+
ID ID_trace_ev_loop_leave;
|
8
|
+
ID ID_trace_run;
|
9
|
+
ID ID_trace_runnable;
|
10
|
+
ID ID_trace_terminate;
|
11
|
+
ID ID_trace_wait;
|
12
|
+
|
13
|
+
VALUE SYM_dead;
|
14
|
+
VALUE SYM_running;
|
15
|
+
VALUE SYM_runnable;
|
16
|
+
VALUE SYM_waiting;
|
17
|
+
|
18
|
+
VALUE SYM_fiber_create;
|
19
|
+
VALUE SYM_fiber_ev_loop_enter;
|
20
|
+
VALUE SYM_fiber_ev_loop_leave;
|
21
|
+
VALUE SYM_fiber_run;
|
22
|
+
VALUE SYM_fiber_schedule;
|
23
|
+
VALUE SYM_fiber_switchpoint;
|
24
|
+
VALUE SYM_fiber_terminate;
|
25
|
+
|
26
|
+
static VALUE Fiber_safe_transfer(int argc, VALUE *argv, VALUE self) {
|
27
|
+
VALUE arg = (argc == 0) ? Qnil : argv[0];
|
28
|
+
VALUE ret = rb_funcall(self, ID_transfer, 1, arg);
|
29
|
+
|
30
|
+
TEST_RESUME_EXCEPTION(ret);
|
31
|
+
RB_GC_GUARD(ret);
|
32
|
+
return ret;
|
33
|
+
}
|
34
|
+
|
35
|
+
inline VALUE Fiber_auto_async(VALUE self) {
|
36
|
+
VALUE async = rb_ivar_get(self, ID_ivar_auto_async);
|
37
|
+
if (async == Qnil) {
|
38
|
+
async = rb_funcall(cGyro_Async, ID_new, 0);
|
39
|
+
rb_ivar_set(self, ID_ivar_auto_async, async);
|
40
|
+
}
|
41
|
+
return async;
|
42
|
+
}
|
43
|
+
|
44
|
+
inline VALUE Fiber_auto_io(VALUE self) {
|
45
|
+
VALUE io = rb_ivar_get(self, ID_ivar_auto_io);
|
46
|
+
if (io == Qnil) {
|
47
|
+
io = rb_funcall(cGyro_IO, ID_new, 2, Qnil, Qnil);
|
48
|
+
rb_ivar_set(self, ID_ivar_auto_io, io);
|
49
|
+
}
|
50
|
+
return io;
|
51
|
+
}
|
52
|
+
|
53
|
+
static VALUE Fiber_schedule(int argc, VALUE *argv, VALUE self) {
|
54
|
+
VALUE value = (argc == 0) ? Qnil : argv[0];
|
55
|
+
Fiber_make_runnable(self, value);
|
56
|
+
return self;
|
57
|
+
}
|
58
|
+
|
59
|
+
static VALUE Fiber_state(VALUE self) {
|
60
|
+
if (!rb_fiber_alive_p(self) || (rb_ivar_get(self, ID_ivar_running) == Qfalse))
|
61
|
+
return SYM_dead;
|
62
|
+
if (rb_fiber_current() == self) return SYM_running;
|
63
|
+
if (rb_ivar_get(self, ID_runnable) != Qnil) return SYM_runnable;
|
64
|
+
|
65
|
+
return SYM_waiting;
|
66
|
+
}
|
67
|
+
|
68
|
+
void Fiber_make_runnable(VALUE fiber, VALUE value) {
|
69
|
+
VALUE thread = rb_ivar_get(fiber, ID_ivar_thread);
|
70
|
+
if (thread != Qnil) {
|
71
|
+
Thread_schedule_fiber(thread, fiber, value);
|
72
|
+
}
|
73
|
+
else {
|
74
|
+
rb_warn("No thread set for fiber");
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
void Init_Fiber() {
|
79
|
+
VALUE cFiber = rb_const_get(rb_cObject, rb_intern("Fiber"));
|
80
|
+
rb_define_method(cFiber, "auto_async", Fiber_auto_async, 0);
|
81
|
+
rb_define_method(cFiber, "safe_transfer", Fiber_safe_transfer, -1);
|
82
|
+
rb_define_method(cFiber, "schedule", Fiber_schedule, -1);
|
83
|
+
rb_define_method(cFiber, "state", Fiber_state, 0);
|
84
|
+
|
85
|
+
ID_ivar_auto_async = rb_intern("@auto_async");
|
86
|
+
|
87
|
+
SYM_dead = ID2SYM(rb_intern("dead"));
|
88
|
+
SYM_running = ID2SYM(rb_intern("running"));
|
89
|
+
SYM_runnable = ID2SYM(rb_intern("runnable"));
|
90
|
+
SYM_waiting = ID2SYM(rb_intern("waiting"));
|
91
|
+
rb_global_variable(&SYM_dead);
|
92
|
+
rb_global_variable(&SYM_running);
|
93
|
+
rb_global_variable(&SYM_runnable);
|
94
|
+
rb_global_variable(&SYM_waiting);
|
95
|
+
|
96
|
+
ID_fiber_trace = rb_intern("__fiber_trace__");
|
97
|
+
|
98
|
+
SYM_fiber_create = ID2SYM(rb_intern("fiber_create"));
|
99
|
+
SYM_fiber_ev_loop_enter = ID2SYM(rb_intern("fiber_ev_loop_enter"));
|
100
|
+
SYM_fiber_ev_loop_leave = ID2SYM(rb_intern("fiber_ev_loop_leave"));
|
101
|
+
SYM_fiber_run = ID2SYM(rb_intern("fiber_run"));
|
102
|
+
SYM_fiber_schedule = ID2SYM(rb_intern("fiber_schedule"));
|
103
|
+
SYM_fiber_switchpoint = ID2SYM(rb_intern("fiber_switchpoint"));
|
104
|
+
SYM_fiber_terminate = ID2SYM(rb_intern("fiber_terminate"));
|
105
|
+
|
106
|
+
rb_global_variable(&SYM_fiber_create);
|
107
|
+
rb_global_variable(&SYM_fiber_ev_loop_enter);
|
108
|
+
rb_global_variable(&SYM_fiber_ev_loop_leave);
|
109
|
+
rb_global_variable(&SYM_fiber_run);
|
110
|
+
rb_global_variable(&SYM_fiber_schedule);
|
111
|
+
rb_global_variable(&SYM_fiber_switchpoint);
|
112
|
+
rb_global_variable(&SYM_fiber_terminate);
|
113
|
+
}
|