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
@@ -2,6 +2,7 @@
2
2
 
3
3
  struct Gyro_Child {
4
4
  struct ev_child ev_child;
5
+ struct ev_loop *ev_loop;
5
6
  int active;
6
7
  int pid;
7
8
  VALUE self;
@@ -10,26 +11,23 @@ struct Gyro_Child {
10
11
 
11
12
  static VALUE cGyro_Child = Qnil;
12
13
 
13
- /* Allocator/deallocator */
14
- static VALUE Gyro_Child_allocate(VALUE klass);
15
- static void Gyro_Child_mark(void *ptr);
16
- static void Gyro_Child_free(void *ptr);
17
- static size_t Gyro_Child_size(const void *ptr);
18
-
19
- /* Methods */
20
- static VALUE Gyro_Child_initialize(VALUE self, VALUE pid);
21
-
22
- static VALUE Gyro_Child_await(VALUE self);
23
-
24
- void Gyro_Child_callback(struct ev_loop *ev_loop, struct ev_child *child, int revents);
14
+ static void Gyro_Child_mark(void *ptr) {
15
+ struct Gyro_Child *child = ptr;
16
+ if (child->fiber != Qnil) {
17
+ rb_gc_mark(child->fiber);
18
+ }
19
+ }
25
20
 
26
- /* Child encapsulates an child watcher */
27
- void Init_Gyro_Child() {
28
- cGyro_Child = rb_define_class_under(mGyro, "Child", rb_cData);
29
- rb_define_alloc_func(cGyro_Child, Gyro_Child_allocate);
21
+ static void Gyro_Child_free(void *ptr) {
22
+ struct Gyro_Child *child = ptr;
23
+ if (child->active) {
24
+ printf("Child watcher garbage collected while still active!\n");
25
+ }
26
+ xfree(child);
27
+ }
30
28
 
31
- rb_define_method(cGyro_Child, "initialize", Gyro_Child_initialize, 1);
32
- rb_define_method(cGyro_Child, "await", Gyro_Child_await, 0);
29
+ static size_t Gyro_Child_size(const void *ptr) {
30
+ return sizeof(struct Gyro_Child);
33
31
  }
34
32
 
35
33
  static const rb_data_type_t Gyro_Child_type = {
@@ -44,23 +42,22 @@ static VALUE Gyro_Child_allocate(VALUE klass) {
44
42
  return TypedData_Wrap_Struct(klass, &Gyro_Child_type, child);
45
43
  }
46
44
 
47
- static void Gyro_Child_mark(void *ptr) {
48
- struct Gyro_Child *child = ptr;
45
+ void Gyro_Child_callback(struct ev_loop *ev_loop, struct ev_child *ev_child, int revents) {
46
+ struct Gyro_Child *child = (struct Gyro_Child*)ev_child;
47
+
48
+ child->active = 0;
49
+ ev_child_stop(child->ev_loop, ev_child);
50
+
49
51
  if (child->fiber != Qnil) {
50
- rb_gc_mark(child->fiber);
51
- }
52
- }
52
+ VALUE fiber = child->fiber;
53
+ int exit_status = ev_child->rstatus >> 8; // weird, why should we do this?
53
54
 
54
- static void Gyro_Child_free(void *ptr) {
55
- struct Gyro_Child *child = ptr;
56
- if (child->active) {
57
- ev_child_stop(EV_DEFAULT, &child->ev_child);
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);
58
60
  }
59
- xfree(child);
60
- }
61
-
62
- static size_t Gyro_Child_size(const void *ptr) {
63
- return sizeof(struct Gyro_Child);
64
61
  }
65
62
 
66
63
  #define GetGyro_Child(obj, child) \
@@ -81,46 +78,40 @@ static VALUE Gyro_Child_initialize(VALUE self, VALUE pid) {
81
78
  return Qnil;
82
79
  }
83
80
 
84
- void Gyro_Child_callback(struct ev_loop *ev_loop, struct ev_child *ev_child, int revents) {
85
- struct Gyro_Child *child = (struct Gyro_Child*)ev_child;
86
-
87
- child->active = 0;
88
- ev_child_stop(EV_DEFAULT, ev_child);
89
-
90
- if (child->fiber != Qnil) {
91
- VALUE fiber = child->fiber;
92
- int exit_status = ev_child->rstatus >> 8; // weird, why should we do this?
93
-
94
- VALUE resume_value = rb_ary_new_from_args(
95
- 2, INT2NUM(ev_child->rpid), INT2NUM(exit_status)
96
- );
97
- child->fiber = Qnil;
98
- Gyro_schedule_fiber(fiber, resume_value);
99
- }
100
- }
101
-
102
81
  static VALUE Gyro_Child_await(VALUE self) {
103
82
  struct Gyro_Child *child;
104
83
  VALUE ret;
105
84
 
106
85
  GetGyro_Child(self, child);
107
86
 
108
- child->fiber = rb_fiber_current();
87
+ if (child->active)
109
88
  child->active = 1;
110
- ev_child_start(EV_DEFAULT, &child->ev_child);
89
+ child->fiber = rb_fiber_current();
90
+ child->ev_loop = Gyro_Selector_current_thread_ev_loop();
91
+ ev_child_start(child->ev_loop, &child->ev_child);
92
+
93
+ ret = Fiber_await();
94
+ RB_GC_GUARD(ret);
111
95
 
112
- ret = Gyro_await();
96
+ if (child->active) {
97
+ child->active = 0;
98
+ child->fiber = Qnil;
99
+ ev_child_stop(child->ev_loop, &child->ev_child);
100
+ }
113
101
 
114
102
  // fiber is resumed, check if resumed value is an exception
115
103
  if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) {
116
- printf("* child error\n");
117
- if (child->active) {
118
- child->active = 0;
119
- ev_child_stop(EV_DEFAULT, &child->ev_child);
120
- }
121
104
  return rb_funcall(rb_mKernel, ID_raise, 1, ret);
122
105
  }
123
106
  else {
124
107
  return ret;
125
108
  }
126
- }
109
+ }
110
+
111
+ void Init_Gyro_Child() {
112
+ cGyro_Child = rb_define_class_under(mGyro, "Child", rb_cData);
113
+ rb_define_alloc_func(cGyro_Child, Gyro_Child_allocate);
114
+
115
+ rb_define_method(cGyro_Child, "initialize", Gyro_Child_initialize, 1);
116
+ rb_define_method(cGyro_Child, "await", Gyro_Child_await, 0);
117
+ }
@@ -1,138 +1,49 @@
1
1
  #include "gyro.h"
2
2
 
3
- static VALUE Gyro_break_set(VALUE self);
4
- static VALUE Gyro_break_get(VALUE self);
5
-
6
- static VALUE Gyro_ref(VALUE self);
7
- static VALUE Gyro_unref(VALUE self);
8
-
9
- static VALUE Gyro_run(VALUE self);
10
- static VALUE Gyro_reset(VALUE self);
11
- static VALUE Gyro_post_fork(VALUE self);
12
- static VALUE Gyro_suspend(VALUE self);
13
-
14
- static VALUE Fiber_safe_transfer(int argc, VALUE *argv, VALUE self);
15
- static VALUE Fiber_schedule(int argc, VALUE *argv, VALUE self);
16
- static VALUE Fiber_state(VALUE self);
17
-
18
- static void Gyro_clear_scheduled_fibers();
19
-
20
3
  VALUE mGyro;
21
4
 
22
- int break_flag = 0;
23
- int ref_count = 0;
24
-
25
- static VALUE scheduled_head;
26
- static VALUE scheduled_tail;
27
-
28
5
  ID ID_call;
29
6
  ID ID_caller;
30
7
  ID ID_clear;
31
8
  ID ID_each;
32
9
  ID ID_inspect;
10
+ ID ID_new;
33
11
  ID ID_raise;
34
- ID ID_running;
12
+ ID ID_ivar_running;
35
13
  ID ID_scheduled;
36
- ID ID_scheduled_next;
37
14
  ID ID_scheduled_value;
15
+ ID ID_size;
16
+ ID ID_signal_bang;
17
+ ID ID_switch_fiber;
38
18
  ID ID_transfer;
39
19
  ID ID_R;
40
20
  ID ID_W;
41
21
  ID ID_RW;
42
22
 
43
- VALUE SYM_DEAD;
44
- VALUE SYM_RUNNING;
45
- VALUE SYM_SCHEDULED;
46
- VALUE SYM_SUSPENDED;
47
-
48
- void Init_Gyro() {
49
- mGyro = rb_define_module("Gyro");
50
-
51
- rb_define_singleton_method(mGyro, "ref", Gyro_ref, 0);
52
- rb_define_singleton_method(mGyro, "unref", Gyro_unref, 0);
53
-
54
- rb_define_singleton_method(mGyro, "run", Gyro_run, 0);
55
- rb_define_singleton_method(mGyro, "reset!", Gyro_reset, 0);
56
- rb_define_singleton_method(mGyro, "post_fork", Gyro_post_fork, 0);
57
- rb_define_singleton_method(mGyro, "snooze", Gyro_snooze, 0);
58
-
59
- rb_define_singleton_method(mGyro, "break!", Gyro_break_set, 0);
60
- rb_define_singleton_method(mGyro, "break?", Gyro_break_get, 0);
61
-
62
- rb_define_global_function("snooze", Gyro_snooze, 0);
63
- rb_define_global_function("suspend", Gyro_suspend, 0);
64
-
65
- VALUE cFiber = rb_const_get(rb_cObject, rb_intern("Fiber"));
66
- rb_define_method(cFiber, "safe_transfer", Fiber_safe_transfer, -1);
67
- rb_define_method(cFiber, "schedule", Fiber_schedule, -1);
68
- rb_define_method(cFiber, "state", Fiber_state, 0);
69
-
70
- ID_call = rb_intern("call");
71
- ID_caller = rb_intern("caller");
72
- ID_clear = rb_intern("clear");
73
- ID_each = rb_intern("each");
74
- ID_inspect = rb_intern("inspect");
75
- ID_raise = rb_intern("raise");
76
- ID_running = rb_intern("@running");
77
- ID_scheduled = rb_intern("scheduled");
78
- ID_scheduled_next = rb_intern("scheduled_next");
79
- ID_scheduled_value = rb_intern("scheduled_value");
80
- ID_transfer = rb_intern("transfer");
81
- ID_R = rb_intern("r");
82
- ID_W = rb_intern("w");
83
- ID_RW = rb_intern("rw");
84
-
85
- SYM_DEAD = ID2SYM(rb_intern("dead"));
86
- SYM_RUNNING = ID2SYM(rb_intern("running"));
87
- SYM_SCHEDULED = ID2SYM(rb_intern("scheduled"));
88
- SYM_SUSPENDED = ID2SYM(rb_intern("suspended"));
89
- rb_global_variable(&SYM_DEAD);
90
- rb_global_variable(&SYM_RUNNING);
91
- rb_global_variable(&SYM_SCHEDULED);
92
- rb_global_variable(&SYM_SUSPENDED);
93
-
94
- scheduled_head = Qnil;
95
- scheduled_tail = Qnil;
96
- rb_global_variable(&scheduled_head);
97
- }
98
-
99
- static VALUE Gyro_ref(VALUE self) {
100
- Gyro_ref_count_incr();
101
- return Qnil;
102
- }
103
-
104
- static VALUE Gyro_unref(VALUE self) {
105
- Gyro_ref_count_decr();
106
- return Qnil;
107
- }
108
-
109
- static VALUE Gyro_run(VALUE self) {
110
- return Gyro_run_next_fiber();
111
- }
23
+ ID ID_empty;
24
+ ID ID_pop;
25
+ ID ID_push;
112
26
 
113
- static VALUE Gyro_reset(VALUE self) {
114
- break_flag = 0;
115
- ref_count = 0;
27
+ VALUE SYM_dead;
28
+ VALUE SYM_running;
29
+ VALUE SYM_scheduled;
30
+ VALUE SYM_suspended;
116
31
 
117
- Gyro_clear_scheduled_fibers();
118
- return Qnil;
119
- }
32
+ // static VALUE Gyro_break_set(VALUE self) {
33
+ // break_flag = 1;
34
+ // ev_break(EV_DEFAULT, EVBREAK_ALL);
35
+ // return Qnil;
36
+ // }
120
37
 
121
- static VALUE Gyro_break_set(VALUE self) {
122
- break_flag = 1;
123
- ev_break(EV_DEFAULT, EVBREAK_ALL);
124
- return Qnil;
125
- }
126
-
127
- static VALUE Gyro_break_get(VALUE self) {
128
- return (break_flag == 0) ? Qfalse : Qtrue;
129
- }
38
+ // static VALUE Gyro_break_get(VALUE self) {
39
+ // return (break_flag == 0) ? Qfalse : Qtrue;
40
+ // }
130
41
 
131
42
  VALUE Gyro_snooze(VALUE self) {
132
43
  VALUE fiber = rb_fiber_current();
133
44
  Gyro_schedule_fiber(fiber, Qnil);
134
45
 
135
- VALUE ret = Gyro_run_next_fiber();
46
+ VALUE ret = Thread_switch_fiber(rb_thread_current());
136
47
  if (RTEST(rb_obj_is_kind_of(ret, rb_eException)))
137
48
  return rb_funcall(rb_mKernel, ID_raise, 1, ret);
138
49
  else
@@ -140,18 +51,22 @@ VALUE Gyro_snooze(VALUE self) {
140
51
  }
141
52
 
142
53
  static VALUE Gyro_post_fork(VALUE self) {
143
- ev_loop_fork(EV_DEFAULT);
144
- break_flag = 0;
145
- ref_count = 0;
146
-
147
- Gyro_clear_scheduled_fibers();
148
-
54
+ Thread_post_fork(rb_thread_current());
149
55
  return Qnil;
150
56
  }
151
57
 
58
+ static VALUE Gyro_ref(VALUE self) {
59
+ return Thread_ref(rb_thread_current());
60
+ }
61
+
62
+ static VALUE Gyro_unref(VALUE self) {
63
+ return Thread_unref(rb_thread_current());
64
+ }
65
+
152
66
  static VALUE Gyro_suspend(VALUE self) {
153
67
  rb_ivar_set(self, ID_scheduled_value, Qnil);
154
- VALUE ret = Gyro_run_next_fiber();
68
+ VALUE ret = Thread_switch_fiber(rb_thread_current());
69
+
155
70
  if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) {
156
71
  return rb_funcall(rb_mKernel, ID_raise, 1, ret);
157
72
  }
@@ -176,93 +91,70 @@ static VALUE Fiber_schedule(int argc, VALUE *argv, VALUE self) {
176
91
  }
177
92
 
178
93
  static VALUE Fiber_state(VALUE self) {
179
- if (!rb_fiber_alive_p(self) || (rb_ivar_get(self, ID_running) == Qfalse))
180
- return SYM_DEAD;
181
- if (rb_fiber_current() == self) return SYM_RUNNING;
182
- if (rb_ivar_get(self, ID_scheduled) != Qnil) return SYM_SCHEDULED;
94
+ if (!rb_fiber_alive_p(self) || (rb_ivar_get(self, ID_ivar_running) == Qfalse))
95
+ return SYM_dead;
96
+ if (rb_fiber_current() == self) return SYM_running;
97
+ if (rb_ivar_get(self, ID_scheduled) != Qnil) return SYM_scheduled;
183
98
 
184
- return SYM_SUSPENDED;
185
- }
186
-
187
- VALUE Gyro_await() {
188
- Gyro_ref_count_incr();
189
- VALUE ret = Gyro_run_next_fiber();
190
- Gyro_ref_count_decr();
191
- return ret;
192
- }
193
-
194
- VALUE Gyro_run_next_fiber() {
195
- while (1) {
196
- if (break_flag != 0) {
197
- return Qnil;
198
- }
199
- if ((scheduled_head != Qnil) || (ref_count == 0)) {
200
- break;
201
- }
202
- ev_run(EV_DEFAULT, EVRUN_ONCE);
203
- }
204
-
205
- // return if no fiber is scheduled
206
- if (scheduled_head == Qnil) {
207
- return Qnil;
208
- }
209
-
210
- // update scheduled linked list refs
211
- VALUE next_fiber = scheduled_head;
212
- VALUE next_next_fiber = rb_ivar_get(next_fiber, ID_scheduled_next);
213
- rb_ivar_set(next_fiber, ID_scheduled_next, Qnil);
214
- scheduled_head = next_next_fiber;
215
- if (scheduled_head == Qnil) {
216
- scheduled_tail = Qnil;
217
- }
218
-
219
- if (rb_fiber_alive_p(next_fiber) != Qtrue) {
220
- return Qnil;
221
- }
222
-
223
- // run next fiber
224
- VALUE value = rb_ivar_get(next_fiber, ID_scheduled_value);
225
- rb_ivar_set(next_fiber, ID_scheduled_value, Qnil);
226
- rb_ivar_set(next_fiber, ID_scheduled, Qnil);
227
- return rb_funcall(next_fiber, ID_transfer, 1, value);
99
+ return SYM_suspended;
228
100
  }
229
101
 
230
- void Gyro_schedule_fiber(VALUE fiber, VALUE value) {
102
+ inline void Gyro_schedule_fiber(VALUE fiber, VALUE value) {
231
103
  rb_ivar_set(fiber, ID_scheduled_value, value);
232
104
  // if fiber is already scheduled, we just set the scheduled value, then return
233
105
  if (rb_ivar_get(fiber, ID_scheduled) != Qnil)
234
106
  return;
235
107
 
236
108
  rb_ivar_set(fiber, ID_scheduled, Qtrue);
237
-
238
- // put fiber on scheduled list
239
- if (scheduled_head != Qnil) {
240
- VALUE last = scheduled_tail;
241
- rb_ivar_set(last, ID_scheduled_next, fiber);
242
- scheduled_tail = fiber;
243
- }
244
- else {
245
- scheduled_tail = scheduled_head = fiber;
246
- }
109
+ Thread_schedule_fiber(rb_thread_current(), fiber);
247
110
  }
248
111
 
249
- int Gyro_ref_count() {
250
- return ref_count;
251
- }
112
+ void Init_Gyro() {
113
+ mGyro = rb_define_module("Gyro");
252
114
 
253
- void Gyro_ref_count_incr() {
254
- ref_count += 1;
255
- }
115
+ rb_define_singleton_method(mGyro, "post_fork", Gyro_post_fork, 0);
116
+ rb_define_singleton_method(mGyro, "ref", Gyro_ref, 0);
117
+ rb_define_singleton_method(mGyro, "unref", Gyro_unref, 0);
256
118
 
257
- void Gyro_ref_count_decr() {
258
- ref_count -= 1;
259
- }
119
+ // rb_define_singleton_method(mGyro, "break!", Gyro_break_set, 0);
120
+ // rb_define_singleton_method(mGyro, "break?", Gyro_break_get, 0);
260
121
 
261
- static void Gyro_clear_scheduled_fibers() {
262
- while (scheduled_head != Qnil) {
263
- VALUE fiber = scheduled_head;
264
- scheduled_head = rb_ivar_get(fiber, ID_scheduled_next);
265
- rb_ivar_set(fiber, ID_scheduled_next, Qnil);
266
- }
267
- scheduled_tail = Qnil;
122
+ rb_define_global_function("snooze", Gyro_snooze, 0);
123
+ rb_define_global_function("suspend", Gyro_suspend, 0);
124
+
125
+ VALUE cFiber = rb_const_get(rb_cObject, rb_intern("Fiber"));
126
+ rb_define_method(cFiber, "safe_transfer", Fiber_safe_transfer, -1);
127
+ rb_define_method(cFiber, "schedule", Fiber_schedule, -1);
128
+ rb_define_method(cFiber, "state", Fiber_state, 0);
129
+
130
+ ID_call = rb_intern("call");
131
+ ID_caller = rb_intern("caller");
132
+ ID_clear = rb_intern("clear");
133
+ ID_each = rb_intern("each");
134
+ ID_inspect = rb_intern("inspect");
135
+ ID_new = rb_intern("new");
136
+ ID_raise = rb_intern("raise");
137
+ ID_ivar_running = rb_intern("@running");
138
+ ID_scheduled = rb_intern("scheduled");
139
+ ID_scheduled_value = rb_intern("scheduled_value");
140
+ ID_size = rb_intern("size");
141
+ ID_signal_bang = rb_intern("signal!");
142
+ ID_switch_fiber = rb_intern("switch_fiber");
143
+ ID_transfer = rb_intern("transfer");
144
+ ID_R = rb_intern("r");
145
+ ID_W = rb_intern("w");
146
+ ID_RW = rb_intern("rw");
147
+
148
+ ID_empty = rb_intern("empty?");
149
+ ID_pop = rb_intern("pop");
150
+ ID_push = rb_intern("push");
151
+
152
+ SYM_dead = ID2SYM(rb_intern("dead"));
153
+ SYM_running = ID2SYM(rb_intern("running"));
154
+ SYM_scheduled = ID2SYM(rb_intern("scheduled"));
155
+ SYM_suspended = ID2SYM(rb_intern("suspended"));
156
+ rb_global_variable(&SYM_dead);
157
+ rb_global_variable(&SYM_running);
158
+ rb_global_variable(&SYM_scheduled);
159
+ rb_global_variable(&SYM_suspended);
268
160
  }