polyphony 0.26 → 0.27

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -3
  3. data/CHANGELOG.md +8 -0
  4. data/Gemfile.lock +1 -1
  5. data/TODO.md +34 -14
  6. data/examples/core/xx-mt-scheduler.rb +349 -0
  7. data/examples/core/xx-queue-async.rb +120 -0
  8. data/examples/core/xx-readpartial.rb +18 -0
  9. data/examples/core/xx-thread-selector-sleep.rb +51 -0
  10. data/examples/core/xx-thread-selector-snooze.rb +46 -0
  11. data/examples/core/xx-thread-sleep.rb +17 -0
  12. data/examples/core/xx-thread-snooze.rb +34 -0
  13. data/examples/performance/snooze.rb +5 -5
  14. data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +73 -0
  15. data/examples/performance/thread-vs-fiber/polyphony_server.rb +12 -4
  16. data/ext/gyro/async.c +58 -61
  17. data/ext/gyro/child.c +50 -59
  18. data/ext/gyro/gyro.c +84 -192
  19. data/ext/gyro/gyro.h +29 -2
  20. data/ext/gyro/gyro_ext.c +6 -0
  21. data/ext/gyro/io.c +87 -96
  22. data/ext/gyro/queue.c +109 -0
  23. data/ext/gyro/selector.c +117 -0
  24. data/ext/gyro/signal.c +44 -54
  25. data/ext/gyro/socket.c +15 -20
  26. data/ext/gyro/thread.c +203 -0
  27. data/ext/gyro/timer.c +79 -50
  28. data/ext/libev/ev.c +3 -0
  29. data/lib/polyphony.rb +7 -12
  30. data/lib/polyphony/core/global_api.rb +5 -1
  31. data/lib/polyphony/core/throttler.rb +6 -11
  32. data/lib/polyphony/extensions/core.rb +2 -0
  33. data/lib/polyphony/extensions/fiber.rb +11 -13
  34. data/lib/polyphony/extensions/thread.rb +52 -0
  35. data/lib/polyphony/version.rb +1 -1
  36. data/test/helper.rb +8 -3
  37. data/test/test_fiber.rb +2 -2
  38. data/test/test_global_api.rb +4 -5
  39. data/test/test_gyro.rb +3 -2
  40. data/test/test_io.rb +1 -0
  41. data/test/test_supervisor.rb +3 -3
  42. data/test/test_thread.rb +44 -0
  43. data/test/test_throttler.rb +41 -0
  44. data/test/test_timer.rb +13 -7
  45. metadata +17 -6
  46. data/examples/core/xx-thread_cancel.rb +0 -28
  47. data/examples/performance/thread.rb +0 -27
  48. data/lib/polyphony/core/thread.rb +0 -23
@@ -0,0 +1,117 @@
1
+ #include "gyro.h"
2
+
3
+ struct Gyro_Selector {
4
+ struct ev_loop *ev_loop;
5
+ };
6
+
7
+ VALUE cGyro_Selector = Qnil;
8
+
9
+ static void Gyro_Selector_mark(void *ptr) {
10
+ // struct Gyro_Selector *selector = ptr;
11
+ }
12
+
13
+ static void Gyro_Selector_free(void *ptr) {
14
+ struct Gyro_Selector *selector = ptr;
15
+ if (selector->ev_loop && !ev_is_default_loop(selector->ev_loop)) {
16
+ // printf("Selector garbage collected before being stopped!\n");
17
+ ev_loop_destroy(selector->ev_loop);
18
+ }
19
+ xfree(selector);
20
+ }
21
+
22
+ static size_t Gyro_Selector_size(const void *ptr) {
23
+ return sizeof(struct Gyro_Selector);
24
+ }
25
+
26
+ static const rb_data_type_t Gyro_Selector_type = {
27
+ "Gyro_Selector",
28
+ {Gyro_Selector_mark, Gyro_Selector_free, Gyro_Selector_size,},
29
+ 0, 0,
30
+ RUBY_TYPED_FREE_IMMEDIATELY,
31
+ };
32
+
33
+ static VALUE Gyro_Selector_allocate(VALUE klass) {
34
+ struct Gyro_Selector *selector = (struct Gyro_Selector *)xmalloc(sizeof(struct Gyro_Selector));
35
+ return TypedData_Wrap_Struct(klass, &Gyro_Selector_type, selector);
36
+ }
37
+
38
+ #define GetGyro_Selector(obj, selector) \
39
+ TypedData_Get_Struct((obj), struct Gyro_Selector, &Gyro_Selector_type, (selector))
40
+
41
+ inline struct ev_loop *Gyro_Selector_ev_loop(VALUE self) {
42
+ struct Gyro_Selector *selector;
43
+ GetGyro_Selector(self, selector);
44
+
45
+ return selector->ev_loop;
46
+ }
47
+
48
+ inline struct ev_loop *Gyro_Selector_current_thread_ev_loop() {
49
+ struct Gyro_Selector *selector;
50
+ GetGyro_Selector(Thread_current_event_selector(), selector);
51
+
52
+ return selector->ev_loop;
53
+ }
54
+
55
+ long Gyro_Selector_pending_count(VALUE self) {
56
+ struct Gyro_Selector *selector;
57
+ GetGyro_Selector(self, selector);
58
+
59
+ return ev_pending_count(selector->ev_loop);
60
+ }
61
+
62
+ static VALUE Gyro_Selector_initialize(VALUE self, VALUE thread) {
63
+ struct Gyro_Selector *selector;
64
+ GetGyro_Selector(self, selector);
65
+
66
+ int use_default_loop = (rb_thread_current() == rb_thread_main());
67
+ selector->ev_loop = use_default_loop ? EV_DEFAULT : ev_loop_new(EVFLAG_NOSIGMASK);
68
+
69
+ return Qnil;
70
+ }
71
+
72
+ inline VALUE Gyro_Selector_run(VALUE self) {
73
+ struct Gyro_Selector *selector;
74
+ GetGyro_Selector(self, selector);
75
+ if (selector->ev_loop) {
76
+ ev_run(selector->ev_loop, EVRUN_ONCE);
77
+ }
78
+ return Qnil;
79
+ }
80
+
81
+ VALUE Gyro_Selector_stop(VALUE self) {
82
+ struct Gyro_Selector *selector;
83
+ GetGyro_Selector(self, selector);
84
+
85
+ if (selector->ev_loop && !ev_is_default_loop(selector->ev_loop)) {
86
+ // ev_loop_destroy(selector->ev_loop);
87
+ // selector->ev_loop = 0;
88
+ }
89
+ return Qnil;
90
+ }
91
+
92
+ inline static VALUE Gyro_Selector_wait_readable(VALUE self, VALUE io) {
93
+ VALUE watcher = IO_read_watcher(io);
94
+ return Gyro_IO_await(watcher);
95
+ }
96
+
97
+ inline static VALUE Gyro_Selector_wait_writable(VALUE self, VALUE io) {
98
+ VALUE watcher = IO_write_watcher(io);
99
+ return Gyro_IO_await(watcher);
100
+ }
101
+
102
+ inline static VALUE Gyro_Selector_wait_timeout(VALUE self, VALUE duration) {
103
+ VALUE watcher = rb_funcall(cGyro_Timer, ID_new, 2, duration, Qnil);
104
+ return Gyro_Timer_await(watcher);
105
+ }
106
+
107
+ void Init_Gyro_Selector() {
108
+ cGyro_Selector = rb_define_class_under(mGyro, "Selector", rb_cData);
109
+ rb_define_alloc_func(cGyro_Selector, Gyro_Selector_allocate);
110
+
111
+ rb_define_method(cGyro_Selector, "initialize", Gyro_Selector_initialize, 1);
112
+ rb_define_method(cGyro_Selector, "run", Gyro_Selector_run, 0);
113
+ rb_define_method(cGyro_Selector, "stop", Gyro_Selector_stop, 0);
114
+ rb_define_method(cGyro_Selector, "wait_readable", Gyro_Selector_wait_readable, 1);
115
+ rb_define_method(cGyro_Selector, "wait_writable", Gyro_Selector_wait_writable, 1);
116
+ rb_define_method(cGyro_Selector, "wait_timeout", Gyro_Selector_wait_timeout, 1);
117
+ }
@@ -2,6 +2,7 @@
2
2
 
3
3
  struct Gyro_Signal {
4
4
  struct ev_signal ev_signal;
5
+ struct ev_loop *ev_loop;
5
6
  int active;
6
7
  int signum;
7
8
  VALUE fiber;
@@ -9,26 +10,24 @@ struct Gyro_Signal {
9
10
 
10
11
  static VALUE cGyro_Signal = Qnil;
11
12
 
12
- /* Allocator/deallocator */
13
- static VALUE Gyro_Signal_allocate(VALUE klass);
14
- static void Gyro_Signal_mark(void *ptr);
15
- static void Gyro_Signal_free(void *ptr);
16
- static size_t Gyro_Signal_size(const void *ptr);
17
-
18
- /* Methods */
19
- static VALUE Gyro_Signal_initialize(VALUE self, VALUE sig);
20
-
21
- static VALUE Gyro_Signal_await(VALUE self);
22
-
23
- void Gyro_Signal_callback(struct ev_loop *ev_loop, struct ev_signal *signal, int revents);
13
+ static void Gyro_Signal_mark(void *ptr) {
14
+ struct Gyro_Signal *signal = ptr;
15
+ if (signal->fiber != Qnil) {
16
+ rb_gc_mark(signal->fiber);
17
+ }
18
+ }
24
19
 
25
- /* Signal encapsulates a signal watcher */
26
- void Init_Gyro_Signal() {
27
- cGyro_Signal = rb_define_class_under(mGyro, "Signal", rb_cData);
28
- rb_define_alloc_func(cGyro_Signal, Gyro_Signal_allocate);
20
+ static void Gyro_Signal_free(void *ptr) {
21
+ struct Gyro_Signal *signal = ptr;
22
+ if (signal->active) {
23
+ printf("Signal watcher garbage collected while still active!\n");
24
+ // ev_signal_stop(signal->ev_loop, &signal->ev_signal);
25
+ }
26
+ xfree(signal);
27
+ }
29
28
 
30
- rb_define_method(cGyro_Signal, "initialize", Gyro_Signal_initialize, 1);
31
- rb_define_method(cGyro_Signal, "await", Gyro_Signal_await, 0);
29
+ static size_t Gyro_Signal_size(const void *ptr) {
30
+ return sizeof(struct Gyro_Signal);
32
31
  }
33
32
 
34
33
  static const rb_data_type_t Gyro_Signal_type = {
@@ -43,21 +42,17 @@ static VALUE Gyro_Signal_allocate(VALUE klass) {
43
42
  return TypedData_Wrap_Struct(klass, &Gyro_Signal_type, signal);
44
43
  }
45
44
 
46
- static void Gyro_Signal_mark(void *ptr) {
47
- struct Gyro_Signal *signal = ptr;
48
- if (signal->fiber != Qnil) {
49
- rb_gc_mark(signal->fiber);
50
- }
51
- }
45
+ void Gyro_Signal_callback(struct ev_loop *ev_loop, struct ev_signal *ev_signal, int revents) {
46
+ struct Gyro_Signal *signal = (struct Gyro_Signal*)ev_signal;
52
47
 
53
- static void Gyro_Signal_free(void *ptr) {
54
- struct Gyro_Signal *signal = ptr;
55
- ev_signal_stop(EV_DEFAULT, &signal->ev_signal);
56
- xfree(signal);
57
- }
48
+ if (signal->fiber != Qnil) {
49
+ VALUE fiber = signal->fiber;
58
50
 
59
- static size_t Gyro_Signal_size(const void *ptr) {
60
- return sizeof(struct Gyro_Signal);
51
+ ev_signal_stop(signal->ev_loop, ev_signal);
52
+ signal->active = 0;
53
+ signal->fiber = Qnil;
54
+ Gyro_schedule_fiber(fiber, INT2NUM(signal->signum));
55
+ }
61
56
  }
62
57
 
63
58
  #define GetGyro_Signal(obj, signal) \
@@ -72,26 +67,9 @@ static VALUE Gyro_Signal_initialize(VALUE self, VALUE sig) {
72
67
 
73
68
  ev_signal_init(&signal->ev_signal, Gyro_Signal_callback, signal->signum);
74
69
 
75
- // signal->active = 1;
76
- // Gyro_ref_count_incr();
77
- // ev_signal_start(EV_DEFAULT, &signal->ev_signal);
78
-
79
70
  return Qnil;
80
71
  }
81
72
 
82
- void Gyro_Signal_callback(struct ev_loop *ev_loop, struct ev_signal *ev_signal, int revents) {
83
- struct Gyro_Signal *signal = (struct Gyro_Signal*)ev_signal;
84
-
85
- if (signal->fiber != Qnil) {
86
- VALUE fiber = signal->fiber;
87
-
88
- ev_signal_stop(EV_DEFAULT, ev_signal);
89
- signal->active = 0;
90
- signal->fiber = Qnil;
91
- Gyro_schedule_fiber(fiber, INT2NUM(signal->signum));
92
- }
93
- }
94
-
95
73
  static VALUE Gyro_Signal_await(VALUE self) {
96
74
  struct Gyro_Signal *signal;
97
75
  VALUE ret;
@@ -100,19 +78,31 @@ static VALUE Gyro_Signal_await(VALUE self) {
100
78
 
101
79
  signal->fiber = rb_fiber_current();
102
80
  signal->active = 1;
103
- ev_signal_start(EV_DEFAULT, &signal->ev_signal);
81
+ signal->ev_loop = Gyro_Selector_current_thread_ev_loop();
82
+ ev_signal_start(signal->ev_loop, &signal->ev_signal);
104
83
 
105
- ret = Gyro_await();
84
+ ret = Fiber_await();
85
+ RB_GC_GUARD(ret);
86
+
87
+ if (signal->active) {
88
+ signal->active = 0;
89
+ signal->fiber = Qnil;
90
+ ev_signal_stop(signal->ev_loop, &signal->ev_signal);
91
+ }
106
92
 
107
93
  // fiber is resumed, check if resumed value is an exception
108
94
  signal->fiber = Qnil;
109
95
  if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) {
110
- if (signal->active) {
111
- signal->active = 0;
112
- ev_signal_stop(EV_DEFAULT, &signal->ev_signal);
113
- }
114
96
  return rb_funcall(rb_mKernel, ID_raise, 1, ret);
115
97
  }
116
98
  else
117
99
  return ret;
118
100
  }
101
+
102
+ void Init_Gyro_Signal() {
103
+ cGyro_Signal = rb_define_class_under(mGyro, "Signal", rb_cData);
104
+ rb_define_alloc_func(cGyro_Signal, Gyro_Signal_allocate);
105
+
106
+ rb_define_method(cGyro_Signal, "initialize", Gyro_Signal_initialize, 1);
107
+ rb_define_method(cGyro_Signal, "await", Gyro_Signal_await, 0);
108
+ }
@@ -1,27 +1,8 @@
1
1
  #include "gyro.h"
2
2
  #include <sys/socket.h>
3
3
 
4
- static VALUE BasicSocket_send(int argc, VALUE *argv, VALUE io);
5
- static VALUE BasicSocket_recv(int argc, VALUE *argv, VALUE io);
6
-
7
- static VALUE Socket_accept(VALUE sock);
8
-
9
4
  static VALUE cTCPSocket;
10
5
 
11
- void Init_Socket() {
12
- rb_require("socket");
13
- VALUE cBasicSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
14
-
15
- rb_define_method(cBasicSocket, "send", BasicSocket_send, -1);
16
- rb_define_method(cBasicSocket, "recv", BasicSocket_recv, -1);
17
-
18
- VALUE cSocket = rb_const_get(rb_cObject, rb_intern("Socket"));
19
-
20
- rb_define_method(cSocket, "accept", Socket_accept, 0);
21
-
22
- cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
23
- }
24
-
25
6
  ///////////////////////////////////////////////////////////////////////////
26
7
 
27
8
  struct rsock_send_arg {
@@ -213,4 +194,18 @@ static VALUE Socket_accept(VALUE sock) {
213
194
  return connection;
214
195
  }
215
196
  }
216
- }
197
+ }
198
+
199
+ void Init_Socket() {
200
+ rb_require("socket");
201
+ VALUE cBasicSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
202
+
203
+ rb_define_method(cBasicSocket, "send", BasicSocket_send, -1);
204
+ rb_define_method(cBasicSocket, "recv", BasicSocket_recv, -1);
205
+
206
+ VALUE cSocket = rb_const_get(rb_cObject, rb_intern("Socket"));
207
+
208
+ rb_define_method(cSocket, "accept", Socket_accept, 0);
209
+
210
+ cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
211
+ }
@@ -0,0 +1,203 @@
1
+ #include "gyro.h"
2
+
3
+ static VALUE cQueue;
4
+
5
+ static ID ID_create_event_selector;
6
+ static ID ID_ivar_event_selector;
7
+ static ID ID_ivar_event_selector_proc;
8
+ static ID ID_fiber_ref_count;
9
+ static ID ID_run_queue;
10
+ static ID ID_ivar_main_fiber;
11
+ static ID ID_stop;
12
+
13
+ static ID ID_scheduled;
14
+
15
+ static ID ID_empty;
16
+ static ID ID_pop;
17
+ static ID ID_push;
18
+
19
+ VALUE event_selector_factory_proc(RB_BLOCK_CALL_FUNC_ARGLIST(args, klass)) {
20
+ return rb_funcall(klass, ID_new, 1, rb_ary_entry(args, 0));
21
+ }
22
+
23
+ static VALUE Thread_event_selector_set_proc(VALUE self, VALUE proc) {
24
+ if (!rb_obj_is_proc(proc)) {
25
+ proc = rb_proc_new(event_selector_factory_proc, proc);
26
+ }
27
+ rb_ivar_set(self, ID_ivar_event_selector_proc, proc);
28
+ return self;
29
+ }
30
+
31
+ static VALUE Thread_create_event_selector(VALUE self, VALUE thread) {
32
+ VALUE selector_proc = rb_ivar_get(self, ID_ivar_event_selector_proc);
33
+ if (selector_proc == Qnil) {
34
+ rb_raise(rb_eRuntimeError, "No event_selector_proc defined");
35
+ }
36
+
37
+ return rb_funcall(selector_proc, ID_call, 1, thread);
38
+ }
39
+
40
+ static VALUE Thread_setup_fiber_scheduling(VALUE self) {
41
+ rb_ivar_set(self, ID_ivar_main_fiber, rb_fiber_current());
42
+ rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(0));
43
+ VALUE queue = rb_ary_new();
44
+ rb_ivar_set(self, ID_run_queue, queue);
45
+ VALUE selector = rb_funcall(rb_cThread, ID_create_event_selector, 1, self);
46
+ rb_ivar_set(self, ID_ivar_event_selector, selector);
47
+
48
+ return self;
49
+ }
50
+
51
+ static VALUE Thread_stop_event_selector(VALUE self) {
52
+ VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
53
+ if (selector != Qnil) {
54
+ rb_funcall(selector, ID_stop, 0);
55
+ }
56
+
57
+ return self;
58
+ }
59
+
60
+ inline VALUE Thread_ref(VALUE self) {
61
+ VALUE count = rb_ivar_get(self, ID_fiber_ref_count);
62
+ int new_count = NUM2INT(count) + 1;
63
+ rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(new_count));
64
+ return self;
65
+ }
66
+
67
+ inline VALUE Thread_unref(VALUE self) {
68
+ VALUE count = rb_ivar_get(self, ID_fiber_ref_count);
69
+ int new_count = NUM2INT(count) - 1;
70
+ rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(new_count));
71
+ return self;
72
+ }
73
+
74
+ inline int Thread_fiber_ref_count(VALUE self) {
75
+ VALUE count = rb_ivar_get(self, ID_fiber_ref_count);
76
+ return NUM2INT(count);
77
+ }
78
+
79
+ inline void Thread_fiber_reset_ref_count(VALUE self) {
80
+ rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(0));
81
+ }
82
+
83
+ static VALUE SYM_scheduled_fibers;
84
+ static VALUE SYM_pending_watchers;
85
+
86
+ static VALUE Thread_fiber_scheduling_stats(VALUE self) {
87
+ VALUE stats = rb_hash_new();
88
+ VALUE queue = rb_ivar_get(self, ID_run_queue);
89
+ VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
90
+
91
+ long scheduled_count = RARRAY_LEN(queue);
92
+ rb_hash_aset(stats, SYM_scheduled_fibers, INT2NUM(scheduled_count));
93
+
94
+ long pending_count = Gyro_Selector_pending_count(selector);
95
+ rb_hash_aset(stats, SYM_pending_watchers, INT2NUM(pending_count));
96
+
97
+ return stats;
98
+ }
99
+
100
+ inline VALUE Thread_schedule_fiber(VALUE self, VALUE fiber) {
101
+ VALUE queue = rb_ivar_get(self, ID_run_queue);
102
+ rb_ary_push(queue, fiber);
103
+ return self;
104
+ }
105
+
106
+ VALUE Thread_switch_fiber(VALUE self) {
107
+ VALUE queue = rb_ivar_get(self, ID_run_queue);
108
+ VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
109
+ long scheduled_count;
110
+
111
+ while (1) {
112
+ scheduled_count = RARRAY_LEN(queue);
113
+ // if (break_flag != 0) {
114
+ // return Qnil;
115
+ // }
116
+ if ((scheduled_count > 0) || (Thread_fiber_ref_count(self) == 0)) {
117
+ break;
118
+ }
119
+
120
+ Gyro_Selector_run(selector);
121
+ }
122
+
123
+ VALUE next_fiber;
124
+ // while (1) {
125
+ if (scheduled_count == 0) {
126
+ return Qnil;
127
+ }
128
+ next_fiber = rb_ary_shift(queue);
129
+ // break;
130
+ // if (rb_fiber_alive_p(next_fiber) == Qtrue) {
131
+ // break;
132
+ // }
133
+ // }
134
+
135
+ // run next fiber
136
+ VALUE value = rb_ivar_get(next_fiber, ID_scheduled_value);
137
+ rb_ivar_set(next_fiber, ID_scheduled, Qnil);
138
+ RB_GC_GUARD(next_fiber);
139
+ RB_GC_GUARD(value);
140
+ return rb_funcall(next_fiber, ID_transfer, 1, value);
141
+ }
142
+
143
+ VALUE Thread_reset_fiber_scheduling(VALUE self) {
144
+ VALUE queue = rb_ivar_get(self, ID_run_queue);
145
+ rb_ary_clear(queue);
146
+ Thread_fiber_reset_ref_count(self);
147
+ return self;
148
+ }
149
+
150
+ VALUE Thread_post_fork(VALUE self) {
151
+ ev_loop_fork(EV_DEFAULT);
152
+ Thread_setup_fiber_scheduling(self);
153
+ return self;
154
+ }
155
+
156
+ inline VALUE Fiber_await() {
157
+ VALUE thread = rb_thread_current();
158
+ Thread_ref(thread);
159
+ VALUE ret = Thread_switch_fiber(thread);
160
+ Thread_unref(thread);
161
+ RB_GC_GUARD(ret);
162
+ return ret;
163
+ }
164
+
165
+ inline VALUE Thread_current_event_selector() {
166
+ return rb_ivar_get(rb_thread_current(), ID_ivar_event_selector);
167
+ }
168
+
169
+ void Init_Thread() {
170
+ cQueue = rb_const_get(rb_cObject, rb_intern("Queue"));
171
+
172
+ rb_define_singleton_method(rb_cThread, "event_selector=", Thread_event_selector_set_proc, 1);
173
+ rb_define_singleton_method(rb_cThread, "create_event_selector", Thread_create_event_selector, 1);
174
+
175
+ rb_define_method(rb_cThread, "fiber_ref", Thread_ref, 0);
176
+ rb_define_method(rb_cThread, "fiber_unref", Thread_unref, 0);
177
+
178
+ rb_define_method(rb_cThread, "setup_fiber_scheduling", Thread_setup_fiber_scheduling, 0);
179
+ rb_define_method(rb_cThread, "stop_event_selector", Thread_stop_event_selector, 0);
180
+ rb_define_method(rb_cThread, "reset_fiber_scheduling", Thread_reset_fiber_scheduling, 0);
181
+ rb_define_method(rb_cThread, "fiber_scheduling_stats", Thread_fiber_scheduling_stats, 0);
182
+
183
+ rb_define_method(rb_cThread, "schedule_fiber", Thread_schedule_fiber, 1);
184
+ rb_define_method(rb_cThread, "switch_fiber", Thread_switch_fiber, 0);
185
+
186
+
187
+ ID_create_event_selector = rb_intern("create_event_selector");
188
+ ID_ivar_event_selector = rb_intern("@event_selector");
189
+ ID_ivar_event_selector_proc = rb_intern("@event_selector_proc");
190
+ ID_ivar_main_fiber = rb_intern("@main_fiber");
191
+ ID_fiber_ref_count = rb_intern("fiber_ref_count");
192
+ ID_run_queue = rb_intern("run_queue");
193
+ ID_scheduled = rb_intern("scheduled");
194
+ ID_empty = rb_intern("empty?");
195
+ ID_pop = rb_intern("pop");
196
+ ID_push = rb_intern("push");
197
+ ID_stop = rb_intern("stop");
198
+
199
+ SYM_scheduled_fibers = ID2SYM(rb_intern("scheduled_fibers"));
200
+ SYM_pending_watchers = ID2SYM(rb_intern("pending_watchers"));
201
+ rb_global_variable(&SYM_scheduled_fibers);
202
+ rb_global_variable(&SYM_pending_watchers);
203
+ }