polyphony 0.26 → 0.27

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.
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
+ }