polyphony 0.21 → 0.22

Sign up to get free protection for your applications and to get access to all the features.
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
  }