polyphony 0.21 → 0.22

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/CHANGELOG.md +11 -0
  4. data/Gemfile.lock +5 -5
  5. data/TODO.md +83 -20
  6. data/docs/technical-overview/design-principles.md +3 -3
  7. data/docs/technical-overview/faq.md +11 -0
  8. data/docs/technical-overview/fiber-scheduling.md +46 -33
  9. data/examples/core/sleep_spin.rb +2 -2
  10. data/examples/http/http2_raw.rb +135 -0
  11. data/examples/http/http_client.rb +14 -3
  12. data/examples/http/http_get.rb +28 -2
  13. data/examples/http/http_server.rb +3 -1
  14. data/examples/http/http_server_forked.rb +3 -1
  15. data/examples/interfaces/pg_pool.rb +1 -0
  16. data/examples/io/echo_server.rb +1 -0
  17. data/ext/gyro/async.c +7 -9
  18. data/ext/gyro/child.c +5 -8
  19. data/ext/gyro/extconf.rb +2 -0
  20. data/ext/gyro/gyro.c +159 -204
  21. data/ext/gyro/gyro.h +16 -6
  22. data/ext/gyro/io.c +7 -10
  23. data/ext/gyro/signal.c +3 -0
  24. data/ext/gyro/timer.c +9 -18
  25. data/lib/polyphony/auto_run.rb +12 -5
  26. data/lib/polyphony/core/coprocess.rb +1 -1
  27. data/lib/polyphony/core/resource_pool.rb +49 -15
  28. data/lib/polyphony/core/supervisor.rb +3 -2
  29. data/lib/polyphony/extensions/core.rb +16 -3
  30. data/lib/polyphony/extensions/io.rb +2 -0
  31. data/lib/polyphony/extensions/openssl.rb +60 -0
  32. data/lib/polyphony/extensions/socket.rb +0 -4
  33. data/lib/polyphony/http/client/agent.rb +127 -0
  34. data/lib/polyphony/http/client/http1.rb +129 -0
  35. data/lib/polyphony/http/client/http2.rb +180 -0
  36. data/lib/polyphony/http/client/response.rb +32 -0
  37. data/lib/polyphony/http/client/site_connection_manager.rb +109 -0
  38. data/lib/polyphony/http/server/request.rb +0 -1
  39. data/lib/polyphony/http.rb +1 -1
  40. data/lib/polyphony/net.rb +2 -1
  41. data/lib/polyphony/version.rb +1 -1
  42. data/lib/polyphony.rb +4 -4
  43. data/polyphony.gemspec +1 -0
  44. data/test/test_gyro.rb +42 -10
  45. data/test/test_resource_pool.rb +107 -0
  46. metadata +10 -4
  47. data/lib/polyphony/http/agent.rb +0 -250
data/ext/gyro/child.c CHANGED
@@ -82,19 +82,16 @@ static VALUE Gyro_Child_initialize(VALUE self, VALUE pid) {
82
82
  }
83
83
 
84
84
  void Gyro_Child_callback(struct ev_loop *ev_loop, struct ev_child *ev_child, int revents) {
85
- VALUE fiber;
86
- VALUE resume_value;
87
85
  struct Gyro_Child *child = (struct Gyro_Child*)ev_child;
88
- resume_value = INT2NUM(child->pid);
89
86
 
90
87
  child->active = 0;
91
88
  ev_child_stop(EV_DEFAULT, ev_child);
92
- Gyro_del_watcher_ref(child->self);
93
89
 
94
90
  if (child->fiber != Qnil) {
95
- fiber = child->fiber;
91
+ VALUE fiber = child->fiber;
92
+ VALUE resume_value = INT2NUM(child->pid);
96
93
  child->fiber = Qnil;
97
- SCHEDULE_FIBER(fiber, 1, resume_value);
94
+ Gyro_schedule_fiber(fiber, resume_value);
98
95
  }
99
96
  }
100
97
 
@@ -107,12 +104,12 @@ static VALUE Gyro_Child_await(VALUE self) {
107
104
  child->fiber = rb_fiber_current();
108
105
  child->active = 1;
109
106
  ev_child_start(EV_DEFAULT, &child->ev_child);
110
- Gyro_add_watcher_ref(self);
111
107
 
112
- ret = YIELD_TO_REACTOR();
108
+ ret = Gyro_yield();
113
109
 
114
110
  // fiber is resumed, check if resumed value is an exception
115
111
  if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) {
112
+ printf("* child error\n");
116
113
  if (child->active) {
117
114
  child->active = 0;
118
115
  ev_child_stop(EV_DEFAULT, &child->ev_child);
data/ext/gyro/extconf.rb CHANGED
@@ -16,5 +16,7 @@ $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
+ CONFIG["optflags"] << " -Wcomment"
20
+
19
21
  dir_config "gyro_ext"
20
22
  create_makefile "gyro_ext"
data/ext/gyro/gyro.c CHANGED
@@ -1,48 +1,40 @@
1
1
  #include "gyro.h"
2
2
 
3
- static VALUE Gyro_run(VALUE self);
4
- static VALUE Gyro_break(VALUE self);
5
- static VALUE Gyro_start(VALUE self);
6
- static VALUE Gyro_restart(VALUE self);
3
+ static VALUE Gyro_break_set(VALUE self);
4
+ static VALUE Gyro_break_get(VALUE self);
7
5
 
8
6
  static VALUE Gyro_ref(VALUE self);
9
7
  static VALUE Gyro_unref(VALUE self);
10
8
 
11
- static VALUE Gyro_defer(VALUE self);
9
+ static VALUE Gyro_reset(VALUE self);
12
10
  static VALUE Gyro_post_fork(VALUE self);
13
-
14
11
  static VALUE Gyro_suspend(VALUE self);
15
12
 
16
13
  static VALUE Fiber_safe_transfer(int argc, VALUE *argv, VALUE self);
17
14
  static VALUE Fiber_schedule(int argc, VALUE *argv, VALUE self);
15
+ static VALUE Fiber_state(VALUE self);
16
+ static VALUE Fiber_mark_as_done(VALUE self);
18
17
 
19
- void Gyro_defer_callback(struct ev_loop *ev_loop, struct ev_idle *watcher, int revents);
18
+ static void Gyro_clear_scheduled_fibers();
20
19
 
21
20
  VALUE mGyro;
22
21
 
23
- VALUE Gyro_reactor_fiber;
24
- VALUE Gyro_root_fiber;
25
- VALUE Gyro_post_run_fiber;
26
-
27
- static VALUE watcher_refs;
28
- static VALUE deferred_head;
29
- static VALUE deferred_tail;
30
- static VALUE deferred_eol_marker;
22
+ int break_flag = 0;
23
+ int ref_count = 0;
31
24
 
32
- static struct ev_idle idle_watcher;
33
- static int deferred_active;
34
- static int deferred_in_callback;
35
- static int break_flag;
25
+ static VALUE scheduled_head;
26
+ static VALUE scheduled_tail;
36
27
 
37
28
  ID ID_call;
38
29
  ID ID_caller;
39
30
  ID ID_clear;
40
- ID ID_deferred_next;
41
- ID ID_deferred_prev;
31
+ ID ID_done;
42
32
  ID ID_each;
43
33
  ID ID_inspect;
44
34
  ID ID_raise;
45
35
  ID ID_read_watcher;
36
+ ID ID_scheduled;
37
+ ID ID_scheduled_next;
46
38
  ID ID_scheduled_value;
47
39
  ID ID_transfer;
48
40
  ID ID_write_watcher;
@@ -50,267 +42,230 @@ ID ID_R;
50
42
  ID ID_W;
51
43
  ID ID_RW;
52
44
 
45
+ VALUE SYM_DEAD;
46
+ VALUE SYM_RUNNING;
47
+ VALUE SYM_PAUSED;
48
+ VALUE SYM_SCHEDULED;
49
+
53
50
  void Init_Gyro() {
54
51
  mGyro = rb_define_module("Gyro");
55
52
 
56
- rb_define_singleton_method(mGyro, "break", Gyro_break, 0);
57
- rb_define_singleton_method(mGyro, "defer", Gyro_defer, 0);
58
- rb_define_singleton_method(mGyro, "post_fork", Gyro_post_fork, 0);
59
53
  rb_define_singleton_method(mGyro, "ref", Gyro_ref, 0);
60
- rb_define_singleton_method(mGyro, "start", Gyro_start, 0);
61
- rb_define_singleton_method(mGyro, "restart", Gyro_restart, 0);
62
- rb_define_singleton_method(mGyro, "snooze", Gyro_snooze, 0);
63
54
  rb_define_singleton_method(mGyro, "unref", Gyro_unref, 0);
64
55
 
65
- rb_define_global_function("defer", Gyro_defer, 0);
56
+ rb_define_singleton_method(mGyro, "reset!", Gyro_reset, 0);
57
+ rb_define_singleton_method(mGyro, "post_fork", Gyro_post_fork, 0);
58
+ rb_define_singleton_method(mGyro, "snooze", Gyro_snooze, 0);
59
+
60
+ rb_define_singleton_method(mGyro, "break!", Gyro_break_set, 0);
61
+ rb_define_singleton_method(mGyro, "break?", Gyro_break_get, 0);
62
+
66
63
  rb_define_global_function("snooze", Gyro_snooze, 0);
67
64
  rb_define_global_function("suspend", Gyro_suspend, 0);
68
65
 
69
66
  VALUE cFiber = rb_const_get(rb_cObject, rb_intern("Fiber"));
70
67
  rb_define_method(cFiber, "safe_transfer", Fiber_safe_transfer, -1);
71
68
  rb_define_method(cFiber, "schedule", Fiber_schedule, -1);
69
+ rb_define_method(cFiber, "state", Fiber_state, 0);
70
+ rb_define_method(cFiber, "mark_as_done!", Fiber_mark_as_done, 0);
72
71
 
73
72
  ID_call = rb_intern("call");
74
73
  ID_caller = rb_intern("caller");
75
74
  ID_clear = rb_intern("clear");
76
- ID_deferred_next = rb_intern("deferred_next");
77
- ID_deferred_prev = rb_intern("deferred_prev");
75
+ ID_done = rb_intern("done");
78
76
  ID_each = rb_intern("each");
79
77
  ID_inspect = rb_intern("inspect");
80
78
  ID_raise = rb_intern("raise");
81
79
  ID_read_watcher = rb_intern("read_watcher");
82
- ID_scheduled_value = rb_intern("@scheduled_value");
80
+ ID_scheduled = rb_intern("scheduled");
81
+ ID_scheduled_next = rb_intern("scheduled_next");
82
+ ID_scheduled_value = rb_intern("scheduled_value");
83
83
  ID_transfer = rb_intern("transfer");
84
84
  ID_write_watcher = rb_intern("write_watcher");
85
85
  ID_R = rb_intern("r");
86
86
  ID_W = rb_intern("w");
87
87
  ID_RW = rb_intern("rw");
88
88
 
89
- Gyro_root_fiber = rb_fiber_current();
90
- Gyro_reactor_fiber = rb_fiber_new(Gyro_run, Qnil);
91
- rb_gv_set("__reactor_fiber__", Gyro_reactor_fiber);
92
-
93
- watcher_refs = rb_hash_new();
94
- rb_global_variable(&watcher_refs);
95
-
96
- deferred_head = Qnil;
97
- deferred_tail = Qnil;
98
- rb_global_variable(&deferred_head);
89
+ SYM_DEAD = ID2SYM(rb_intern("dead"));
90
+ SYM_RUNNING = ID2SYM(rb_intern("running"));
91
+ SYM_PAUSED = ID2SYM(rb_intern("paused"));
92
+ SYM_SCHEDULED = ID2SYM(rb_intern("scheduled"));
93
+ rb_global_variable(&SYM_DEAD);
94
+ rb_global_variable(&SYM_RUNNING);
95
+ rb_global_variable(&SYM_PAUSED);
96
+ rb_global_variable(&SYM_SCHEDULED);
97
+
98
+ scheduled_head = Qnil;
99
+ scheduled_tail = Qnil;
100
+ rb_global_variable(&scheduled_head);
101
+ }
99
102
 
100
- deferred_eol_marker = rb_funcall(rb_cObject, rb_intern("new"), 0);
101
- rb_global_variable(&deferred_eol_marker);
103
+ static VALUE Gyro_ref(VALUE self) {
104
+ Gyro_ref_count_incr();
105
+ return Qnil;
106
+ }
102
107
 
103
- ev_idle_init(&idle_watcher, Gyro_defer_callback);
104
- deferred_active = 0;
105
- deferred_in_callback = 0;
108
+ static VALUE Gyro_unref(VALUE self) {
109
+ Gyro_ref_count_decr();
110
+ return Qnil;
106
111
  }
107
112
 
108
- static VALUE Gyro_run(VALUE self) {
113
+ static VALUE Gyro_reset(VALUE self) {
109
114
  break_flag = 0;
110
- Gyro_post_run_fiber = Qnil;
111
- ev_run(EV_DEFAULT, 0);
112
- rb_gv_set("__reactor_fiber__", Qnil);
113
-
114
- if (Gyro_post_run_fiber != Qnil) {
115
- rb_funcall(Gyro_post_run_fiber, ID_transfer, 0);
116
- }
115
+ ref_count = 0;
117
116
 
117
+ Gyro_clear_scheduled_fibers();
118
118
  return Qnil;
119
119
  }
120
120
 
121
- static VALUE Gyro_break(VALUE self) {
121
+ static VALUE Gyro_break_set(VALUE self) {
122
122
  break_flag = 1;
123
- // make sure reactor fiber is alive
124
- if (!RTEST(rb_fiber_alive_p(Gyro_reactor_fiber))) {
125
- return Qnil;
126
- }
127
-
128
- if (deferred_active) {
129
- deferred_active = 0;
130
- ev_idle_stop(EV_DEFAULT, &idle_watcher);
131
- }
132
123
  ev_break(EV_DEFAULT, EVBREAK_ALL);
133
- YIELD_TO_REACTOR();
124
+ // printf("\n");
134
125
  return Qnil;
135
126
  }
136
127
 
137
- static VALUE Gyro_start(VALUE self) {
138
- Gyro_post_run_fiber = Qnil;
139
- deferred_head = Qnil;
140
- Gyro_reactor_fiber = rb_fiber_new(Gyro_run, Qnil);
141
- rb_gv_set("__reactor_fiber__", Gyro_reactor_fiber);
142
- return Qnil;
128
+ static VALUE Gyro_break_get(VALUE self) {
129
+ return (break_flag == 0) ? Qfalse : Qtrue;
143
130
  }
144
131
 
145
- static VALUE Gyro_restart(VALUE self) {
146
- Gyro_post_run_fiber = rb_fiber_current();
147
- Gyro_break(self);
148
- // control will be transferred back to here after reactor loop is done
149
- Gyro_start(self);
132
+ VALUE Gyro_snooze(VALUE self) {
133
+ VALUE fiber = rb_fiber_current();
134
+ Gyro_schedule_fiber(fiber, Qnil);
150
135
 
151
- return Qnil;
136
+ VALUE ret = Gyro_run();
137
+ if (RTEST(rb_obj_is_kind_of(ret, rb_eException)))
138
+ return rb_funcall(ret, ID_raise, 1, ret);
139
+ else
140
+ return ret;
152
141
  }
153
142
 
154
- static VALUE Gyro_ref(VALUE self) {
155
- ev_ref(EV_DEFAULT);
156
- return Qnil;
157
- }
143
+ static VALUE Gyro_post_fork(VALUE self) {
144
+ ev_loop_fork(EV_DEFAULT);
145
+ break_flag = 0;
146
+ ref_count = 0;
147
+
148
+ Gyro_clear_scheduled_fibers();
158
149
 
159
- static VALUE Gyro_unref(VALUE self) {
160
- ev_unref(EV_DEFAULT);
161
150
  return Qnil;
162
151
  }
163
152
 
164
- void Gyro_add_watcher_ref(VALUE obj) {
165
- rb_hash_aset(watcher_refs, rb_obj_id(obj), obj);
166
- }
167
-
168
- void Gyro_del_watcher_ref(VALUE obj) {
169
- rb_hash_delete(watcher_refs, rb_obj_id(obj));
170
- }
171
-
172
- static void defer_add(VALUE item) {
173
- if (NIL_P(deferred_head)) {
174
- deferred_head = item;
175
- deferred_tail = item;
176
- rb_ivar_set(item, ID_deferred_next, Qnil);
177
- rb_ivar_set(item, ID_deferred_prev, Qnil);
178
- }
179
- else {
180
- rb_ivar_set(deferred_tail, ID_deferred_next, item);
181
- rb_ivar_set(item, ID_deferred_prev, deferred_tail);
182
- deferred_tail = item;
183
- }
184
-
185
- if (!deferred_active) {
186
- deferred_active = 1;
187
- ev_idle_start(EV_DEFAULT, &idle_watcher);
153
+ static VALUE Gyro_suspend(VALUE self) {
154
+ VALUE ret = Gyro_run();
155
+ if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) {
156
+ return rb_funcall(ret, ID_raise, 1, ret);
188
157
  }
158
+ else
159
+ return ret;
189
160
  }
190
161
 
191
- static void defer_remove(VALUE item) {
192
- VALUE next = rb_ivar_get(item, ID_deferred_next);
193
- VALUE prev = rb_ivar_get(item, ID_deferred_prev);
194
- if (RTEST(prev)) {
195
- rb_ivar_set(prev, ID_deferred_next, next);
196
- }
197
- if (RTEST(next)) {
198
- rb_ivar_set(next, ID_deferred_prev, prev);
199
- }
162
+ static VALUE Fiber_safe_transfer(int argc, VALUE *argv, VALUE self) {
163
+ VALUE arg = (argc == 0) ? Qnil : argv[0];
164
+ VALUE ret = rb_funcall(self, ID_transfer, 1, arg);
200
165
 
166
+ // fiber is resumed, check if resumed value is an exception
167
+ return RTEST(rb_obj_is_kind_of(ret, rb_eException)) ?
168
+ rb_funcall(ret, ID_raise, 1, ret) : ret;
201
169
  }
202
170
 
203
- static VALUE Gyro_defer(VALUE self) {
204
- VALUE proc = rb_block_proc();
205
- if (RTEST(proc)) {
206
- defer_add(proc);
207
- }
208
- return Qnil;
171
+ static VALUE Fiber_schedule(int argc, VALUE *argv, VALUE self) {
172
+ VALUE value = (argc == 0) ? Qnil : argv[0];
173
+ Gyro_schedule_fiber(self, value);
174
+ return self;
209
175
  }
210
176
 
211
- VALUE Gyro_snooze(VALUE self) {
212
- VALUE ret;
213
- VALUE fiber = rb_fiber_current();
214
- defer_add(fiber);
215
-
216
- ret = YIELD_TO_REACTOR();
177
+ static VALUE Fiber_state(VALUE self) {
178
+ if (!rb_fiber_alive_p(self) || (rb_ivar_get(self, ID_done) != Qnil))
179
+ return SYM_DEAD;
180
+ if (rb_fiber_current() == self) return SYM_RUNNING;
181
+ if (rb_ivar_get(self, ID_scheduled) != Qnil) return SYM_SCHEDULED;
217
182
 
218
- if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) {
219
- defer_remove(fiber);
220
- return rb_funcall(ret, ID_raise, 1, ret);
221
- }
222
- else {
223
- return ret;
224
- }
183
+ return SYM_PAUSED;
225
184
  }
226
185
 
227
- static VALUE Gyro_post_fork(VALUE self) {
228
- ev_loop_fork(EV_DEFAULT);
229
-
230
- Gyro_reactor_fiber = rb_fiber_new(Gyro_run, Qnil);
231
- rb_gv_set("__reactor_fiber__", Gyro_reactor_fiber);
232
- Gyro_root_fiber = rb_fiber_current();
233
-
234
- deferred_head = Qnil;
235
- deferred_active = 0;
236
-
237
- return Qnil;
186
+ static VALUE Fiber_mark_as_done(VALUE self) {
187
+ rb_ivar_set(self, ID_done, Qtrue);
188
+ return self;
238
189
  }
239
190
 
240
- VALUE run_deferred(VALUE item) {
241
- if (rb_obj_is_proc(item)) {
242
- rb_funcall(item, ID_call, 1, Qtrue);
243
- }
244
- else {
245
- VALUE arg = rb_ivar_get(item, ID_scheduled_value);
246
- if (RTEST(rb_obj_is_kind_of(arg, rb_eException))) {
247
- rb_ivar_set(item, ID_scheduled_value, Qnil);
248
- }
249
- SCHEDULE_FIBER(item, 1, arg);
250
- }
251
- return Qnil;
191
+ VALUE Gyro_yield() {
192
+ Gyro_ref_count_incr();
193
+ VALUE ret = Gyro_run();
194
+ Gyro_ref_count_decr();
195
+ return ret;
252
196
  }
253
197
 
254
- void Gyro_defer_callback(struct ev_loop *ev_loop, struct ev_idle *watcher, int revents) {
255
- deferred_in_callback = 1;
256
- defer_add(deferred_eol_marker);
257
- rb_ivar_set(deferred_eol_marker, ID_deferred_next, Qnil);
258
-
259
- while (RTEST(deferred_head) && !break_flag) {
260
- VALUE next = rb_ivar_get(deferred_head, ID_deferred_next);
261
- if (deferred_head == deferred_eol_marker) {
262
- deferred_head = next;
198
+ VALUE Gyro_run() {
199
+ while (1) {
200
+ if (break_flag != 0) {
201
+ return Qnil;
202
+ }
203
+ if ((scheduled_head != Qnil) || (ref_count == 0)) {
263
204
  break;
264
205
  }
265
- run_deferred(deferred_head);
266
- deferred_head = next;
206
+ ev_run(EV_DEFAULT, EVRUN_ONCE);
267
207
  }
268
208
 
269
- if (NIL_P(deferred_head)) {
270
- deferred_active = 0;
271
- ev_idle_stop(EV_DEFAULT, &idle_watcher);
209
+ // return if no fiber is scheduled
210
+ if (scheduled_head == Qnil) {
211
+ return Qnil;
272
212
  }
273
213
 
274
- deferred_in_callback = 0;
275
- }
214
+ // update scheduled linked list refs
215
+ VALUE next_fiber = scheduled_head;
216
+ VALUE next_next_fiber = rb_ivar_get(next_fiber, ID_scheduled_next);
217
+ rb_ivar_set(next_fiber, ID_scheduled_next, Qnil);
218
+ scheduled_head = next_next_fiber;
219
+ if (scheduled_head == Qnil) {
220
+ scheduled_tail = Qnil;
221
+ }
276
222
 
277
- static VALUE Gyro_suspend(VALUE self) {
278
- if (!RTEST(rb_fiber_alive_p(Gyro_reactor_fiber))) {
223
+ if (rb_fiber_alive_p(next_fiber) != Qtrue)
279
224
  return Qnil;
280
- }
281
225
 
282
- VALUE ret = YIELD_TO_REACTOR();
226
+ // run next fiber
227
+ VALUE value = rb_ivar_get(next_fiber, ID_scheduled_value);
228
+ rb_ivar_set(next_fiber, ID_scheduled_value, Qnil);
229
+ rb_ivar_set(next_fiber, ID_scheduled, Qnil);
230
+ return rb_funcall(next_fiber, ID_transfer, 1, value);
231
+ }
283
232
 
284
- // fiber is resumed, check if resumed value is an exception
285
- return RTEST(rb_obj_is_kind_of(ret, rb_eException)) ?
286
- rb_funcall(ret, ID_raise, 1, ret) : ret;
233
+ void Gyro_schedule_fiber(VALUE fiber, VALUE value) {
234
+ rb_ivar_set(fiber, ID_scheduled_value, value);
235
+ // if fiber is already scheduled, we just set the scheduled value, then return
236
+ if (rb_ivar_get(fiber, ID_scheduled) != Qnil)
237
+ return;
238
+
239
+ rb_ivar_set(fiber, ID_scheduled, Qtrue);
240
+
241
+ // put fiber on scheduled list
242
+ if (scheduled_head != Qnil) {
243
+ VALUE last = scheduled_tail;
244
+ rb_ivar_set(last, ID_scheduled_next, fiber);
245
+ scheduled_tail = fiber;
246
+ }
247
+ else {
248
+ scheduled_tail = scheduled_head = fiber;
249
+ }
287
250
  }
288
251
 
289
- static VALUE Fiber_safe_transfer(int argc, VALUE *argv, VALUE self) {
290
- VALUE arg = (argc == 0) ? Qnil : argv[0];
291
- VALUE ret = rb_funcall(self, ID_transfer, 1, arg);
252
+ int Gyro_ref_count() {
253
+ return ref_count;
254
+ }
292
255
 
293
- // fiber is resumed, check if resumed value is an exception
294
- return RTEST(rb_obj_is_kind_of(ret, rb_eException)) ?
295
- rb_funcall(ret, ID_raise, 1, ret) : ret;
256
+ void Gyro_ref_count_incr() {
257
+ ref_count += 1;
296
258
  }
297
259
 
298
- static VALUE Fiber_schedule(int argc, VALUE *argv, VALUE self) {
299
- VALUE arg = (argc == 0) ? Qnil : argv[0];
300
- rb_ivar_set(self, ID_scheduled_value, arg);
301
- if (deferred_in_callback) {
302
- // if a fiber is scheduled while processing deferred items, we want to avoid
303
- // adding the same fiber again to the list of deferred item, since this will
304
- // fuck up the linked list refs, and also lead to a race condition. To do
305
- // this, we search the deferred items linked list for the given fiber, and
306
- // return without readding it if found.
307
- VALUE next = deferred_head;
308
- while (RTEST(next)) {
309
- if (next == self) return self;
310
- if (next == deferred_eol_marker) break;
311
- next = rb_ivar_get(next, ID_deferred_next);
312
- }
260
+ void Gyro_ref_count_decr() {
261
+ ref_count -= 1;
262
+ }
263
+
264
+ static void Gyro_clear_scheduled_fibers() {
265
+ while (scheduled_head != Qnil) {
266
+ VALUE fiber = scheduled_head;
267
+ scheduled_head = rb_ivar_get(fiber, ID_scheduled_next);
268
+ rb_ivar_set(fiber, ID_scheduled_next, Qnil);
313
269
  }
314
- defer_add(self);
315
- return self;
270
+ scheduled_tail = Qnil;
316
271
  }
data/ext/gyro/gyro.h CHANGED
@@ -5,10 +5,24 @@
5
5
  #include "ruby/io.h"
6
6
  #include "libev.h"
7
7
 
8
- void Gyro_add_watcher_ref(VALUE obj);
9
- void Gyro_del_watcher_ref(VALUE obj);
8
+ enum {
9
+ FIBER_STATE_NOT_SCHEDULED = 0,
10
+ FIBER_STATE_WAITING = 1,
11
+ FIBER_STATE_SCHEDULED = 2
12
+ };
13
+
14
+ // void Gyro_add_watcher_ref(VALUE obj);
15
+ // void Gyro_del_watcher_ref(VALUE obj);
10
16
  VALUE Gyro_snooze(VALUE self);
11
17
 
18
+ VALUE Gyro_run();
19
+ VALUE Gyro_yield();
20
+ void Gyro_schedule_fiber(VALUE fiber, VALUE value);
21
+
22
+ int Gyro_ref_count();
23
+ void Gyro_ref_count_incr();
24
+ void Gyro_ref_count_decr();
25
+
12
26
  VALUE IO_read_watcher(VALUE io);
13
27
  VALUE IO_write_watcher(VALUE io);
14
28
  VALUE Gyro_IO_await(VALUE self);
@@ -17,9 +31,6 @@ int io_setstrbuf(VALUE *str, long len);
17
31
  void io_set_read_length(VALUE str, long n, int shrinkable);
18
32
  VALUE io_enc_str(VALUE str, rb_io_t *fptr);
19
33
 
20
- #define SCHEDULE_FIBER(obj, args...) rb_funcall(obj, ID_transfer, args)
21
- #define YIELD_TO_REACTOR() rb_funcall(Gyro_reactor_fiber, ID_transfer, 0)
22
-
23
34
  #define OBJ_ID(obj) (NUM2LONG(rb_funcall(obj, rb_intern("object_id"), 0)))
24
35
 
25
36
  extern VALUE mGyro;
@@ -32,7 +43,6 @@ extern ID ID_caller;
32
43
  extern ID ID_clear;
33
44
  extern ID ID_each;
34
45
  extern ID ID_inspect;
35
- extern ID ID_next_deferred;
36
46
  extern ID ID_raise;
37
47
  extern ID ID_read_watcher;
38
48
  extern ID ID_scheduled_value;
data/ext/gyro/io.c CHANGED
@@ -102,18 +102,15 @@ static VALUE Gyro_IO_initialize(VALUE self, VALUE io_obj, VALUE event_mask) {
102
102
  }
103
103
 
104
104
  void Gyro_IO_callback(struct ev_loop *ev_loop, struct ev_io *ev_io, int revents) {
105
- VALUE fiber;
106
105
  struct Gyro_IO *io = (struct Gyro_IO*)ev_io;
107
106
 
107
+ ev_io_stop(EV_DEFAULT, ev_io);
108
+ io->active = 0;
109
+
108
110
  if (io->fiber != Qnil) {
109
- ev_io_stop(EV_DEFAULT, ev_io);
110
- io->active = 0;
111
- fiber = io->fiber;
111
+ VALUE fiber = io->fiber;
112
112
  io->fiber = Qnil;
113
- SCHEDULE_FIBER(fiber, 0);
114
- }
115
- else {
116
- ev_io_stop(EV_DEFAULT, ev_io);
113
+ Gyro_schedule_fiber(fiber, Qnil);
117
114
  }
118
115
  }
119
116
 
@@ -126,9 +123,10 @@ VALUE Gyro_IO_await(VALUE self) {
126
123
  io->fiber = rb_fiber_current();
127
124
  io->active = 1;
128
125
  ev_io_start(EV_DEFAULT, &io->ev_io);
129
- ret = YIELD_TO_REACTOR();
126
+ ret = Gyro_yield();
130
127
 
131
128
  // make sure io watcher is stopped
129
+ io->fiber = Qnil;
132
130
  if (io->active) {
133
131
  io->active = 0;
134
132
  ev_io_stop(EV_DEFAULT, &io->ev_io);
@@ -376,7 +374,6 @@ static VALUE IO_write(int argc, VALUE *argv, VALUE io) {
376
374
  if (e == EWOULDBLOCK || e == EAGAIN) {
377
375
  if (write_watcher == Qnil)
378
376
  write_watcher = IO_write_watcher(io);
379
- // write_watcher = rb_funcall(io, ID_write_watcher, 0);
380
377
  Gyro_IO_await(write_watcher);
381
378
  }
382
379
  else {
data/ext/gyro/signal.c CHANGED
@@ -79,6 +79,7 @@ static VALUE Gyro_Signal_initialize(VALUE self, VALUE sig) {
79
79
  ev_signal_init(&signal->ev_signal, Gyro_Signal_callback, signal->signum);
80
80
 
81
81
  signal->active = 1;
82
+ Gyro_ref_count_incr();
82
83
  ev_signal_start(EV_DEFAULT, &signal->ev_signal);
83
84
 
84
85
  return Qnil;
@@ -97,6 +98,7 @@ static VALUE Gyro_Signal_start(VALUE self) {
97
98
  GetGyro_Signal(self, signal);
98
99
 
99
100
  if (!signal->active) {
101
+ Gyro_ref_count_incr();
100
102
  ev_signal_start(EV_DEFAULT, &signal->ev_signal);
101
103
  signal->active = 1;
102
104
  }
@@ -109,6 +111,7 @@ static VALUE Gyro_Signal_stop(VALUE self) {
109
111
  GetGyro_Signal(self, signal);
110
112
 
111
113
  if (signal->active) {
114
+ Gyro_ref_count_decr();
112
115
  ev_signal_stop(EV_DEFAULT, &signal->ev_signal);
113
116
  signal->active = 0;
114
117
  }