polyphony 0.22 → 0.23

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/Gemfile.lock +9 -1
  4. data/TODO.md +13 -38
  5. data/docs/summary.md +19 -5
  6. data/docs/technical-overview/faq.md +12 -0
  7. data/examples/core/01-spinning-up-coprocesses.rb +2 -6
  8. data/examples/core/02-awaiting-coprocesses.rb +3 -1
  9. data/examples/core/03-interrupting.rb +3 -1
  10. data/examples/core/04-no-auto-run.rb +1 -3
  11. data/examples/core/cancel.rb +1 -1
  12. data/examples/core/channel_echo.rb +3 -1
  13. data/examples/core/defer.rb +3 -1
  14. data/examples/core/enumerator.rb +3 -1
  15. data/examples/core/error_bubbling.rb +35 -0
  16. data/examples/core/fork.rb +1 -1
  17. data/examples/core/genserver.rb +1 -1
  18. data/examples/core/lock.rb +3 -1
  19. data/examples/core/move_on.rb +1 -1
  20. data/examples/core/move_on_twice.rb +1 -1
  21. data/examples/core/move_on_with_ensure.rb +1 -1
  22. data/examples/core/move_on_with_value.rb +1 -1
  23. data/examples/core/multiple_spin.rb +3 -1
  24. data/examples/core/nested_cancel.rb +1 -1
  25. data/examples/core/nested_multiple_spin.rb +3 -1
  26. data/examples/core/nested_spin.rb +3 -1
  27. data/examples/core/pulse.rb +1 -1
  28. data/examples/core/resource.rb +1 -1
  29. data/examples/core/resource_cancel.rb +2 -2
  30. data/examples/core/resource_delegate.rb +1 -1
  31. data/examples/core/sleep.rb +1 -1
  32. data/examples/core/sleep_spin.rb +3 -1
  33. data/examples/core/snooze.rb +1 -1
  34. data/examples/core/spin_error.rb +2 -1
  35. data/examples/core/spin_error_backtrace.rb +1 -1
  36. data/examples/core/spin_uncaught_error.rb +3 -1
  37. data/examples/core/supervisor.rb +1 -1
  38. data/examples/core/supervisor_with_cancel_scope.rb +1 -1
  39. data/examples/core/supervisor_with_error.rb +3 -1
  40. data/examples/core/supervisor_with_manual_move_on.rb +1 -1
  41. data/examples/core/suspend.rb +1 -1
  42. data/examples/core/thread.rb +3 -3
  43. data/examples/core/thread_cancel.rb +6 -3
  44. data/examples/core/thread_pool.rb +8 -52
  45. data/examples/core/thread_pool_perf.rb +63 -0
  46. data/examples/core/throttle.rb +3 -1
  47. data/examples/core/timeout.rb +1 -1
  48. data/examples/core/wait_for_signal.rb +4 -2
  49. data/examples/fs/read.rb +1 -1
  50. data/examples/http/http2_raw.rb +1 -1
  51. data/examples/http/http_get.rb +1 -1
  52. data/examples/http/http_server.rb +2 -1
  53. data/examples/http/http_server_graceful.rb +3 -1
  54. data/examples/http/http_ws_server.rb +0 -2
  55. data/examples/http/https_wss_server.rb +0 -2
  56. data/examples/http/websocket_secure_server.rb +0 -2
  57. data/examples/http/websocket_server.rb +0 -2
  58. data/examples/interfaces/redis_channels.rb +3 -1
  59. data/examples/interfaces/redis_pubsub.rb +3 -1
  60. data/examples/interfaces/redis_pubsub_perf.rb +3 -1
  61. data/examples/io/backticks.rb +1 -1
  62. data/examples/io/cat.rb +1 -1
  63. data/examples/io/echo_client.rb +1 -1
  64. data/examples/io/echo_client_from_stdin.rb +3 -1
  65. data/examples/io/echo_pipe.rb +1 -1
  66. data/examples/io/echo_server.rb +1 -1
  67. data/examples/io/echo_server_with_timeout.rb +1 -1
  68. data/examples/io/echo_stdin.rb +1 -1
  69. data/examples/io/httparty_multi.rb +1 -1
  70. data/examples/io/io_read.rb +1 -1
  71. data/examples/io/irb.rb +1 -1
  72. data/examples/io/net-http.rb +1 -1
  73. data/examples/io/open.rb +1 -1
  74. data/examples/io/system.rb +1 -1
  75. data/examples/io/tcpserver.rb +1 -1
  76. data/examples/io/tcpsocket.rb +1 -1
  77. data/examples/performance/multi_snooze.rb +1 -1
  78. data/examples/performance/snooze.rb +18 -10
  79. data/ext/gyro/async.c +16 -9
  80. data/ext/gyro/child.c +2 -2
  81. data/ext/gyro/gyro.c +17 -10
  82. data/ext/gyro/gyro.h +2 -2
  83. data/ext/gyro/io.c +2 -2
  84. data/ext/gyro/signal.c +33 -35
  85. data/ext/gyro/timer.c +6 -73
  86. data/lib/polyphony.rb +6 -8
  87. data/lib/polyphony/core/cancel_scope.rb +32 -21
  88. data/lib/polyphony/core/coprocess.rb +26 -23
  89. data/lib/polyphony/core/global_api.rb +86 -0
  90. data/lib/polyphony/core/resource_pool.rb +1 -1
  91. data/lib/polyphony/core/supervisor.rb +47 -13
  92. data/lib/polyphony/core/thread.rb +10 -36
  93. data/lib/polyphony/core/thread_pool.rb +6 -26
  94. data/lib/polyphony/extensions/core.rb +30 -100
  95. data/lib/polyphony/extensions/io.rb +10 -7
  96. data/lib/polyphony/extensions/openssl.rb +18 -28
  97. data/lib/polyphony/http/client/agent.rb +15 -11
  98. data/lib/polyphony/http/client/http2.rb +1 -1
  99. data/lib/polyphony/version.rb +1 -1
  100. data/polyphony.gemspec +1 -0
  101. data/test/coverage.rb +45 -0
  102. data/test/helper.rb +15 -5
  103. data/test/test_async.rb +4 -4
  104. data/test/test_cancel_scope.rb +109 -0
  105. data/test/test_coprocess.rb +80 -36
  106. data/test/{test_core.rb → test_global_api.rb} +67 -13
  107. data/test/test_gyro.rb +1 -5
  108. data/test/test_io.rb +2 -2
  109. data/test/test_resource_pool.rb +19 -0
  110. data/test/test_signal.rb +10 -5
  111. data/test/test_supervisor.rb +168 -0
  112. data/test/test_timer.rb +31 -5
  113. metadata +23 -4
  114. data/lib/polyphony/auto_run.rb +0 -19
@@ -105,7 +105,7 @@ static VALUE Gyro_Child_await(VALUE self) {
105
105
  child->active = 1;
106
106
  ev_child_start(EV_DEFAULT, &child->ev_child);
107
107
 
108
- ret = Gyro_yield();
108
+ ret = Gyro_await();
109
109
 
110
110
  // fiber is resumed, check if resumed value is an exception
111
111
  if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) {
@@ -114,7 +114,7 @@ static VALUE Gyro_Child_await(VALUE self) {
114
114
  child->active = 0;
115
115
  ev_child_stop(EV_DEFAULT, &child->ev_child);
116
116
  }
117
- return rb_funcall(ret, ID_raise, 1, ret);
117
+ return rb_funcall(rb_mKernel, ID_raise, 1, ret);
118
118
  }
119
119
  else {
120
120
  return ret;
@@ -6,6 +6,7 @@ static VALUE Gyro_break_get(VALUE self);
6
6
  static VALUE Gyro_ref(VALUE self);
7
7
  static VALUE Gyro_unref(VALUE self);
8
8
 
9
+ static VALUE Gyro_run(VALUE self);
9
10
  static VALUE Gyro_reset(VALUE self);
10
11
  static VALUE Gyro_post_fork(VALUE self);
11
12
  static VALUE Gyro_suspend(VALUE self);
@@ -53,6 +54,7 @@ void Init_Gyro() {
53
54
  rb_define_singleton_method(mGyro, "ref", Gyro_ref, 0);
54
55
  rb_define_singleton_method(mGyro, "unref", Gyro_unref, 0);
55
56
 
57
+ rb_define_singleton_method(mGyro, "run", Gyro_run, 0);
56
58
  rb_define_singleton_method(mGyro, "reset!", Gyro_reset, 0);
57
59
  rb_define_singleton_method(mGyro, "post_fork", Gyro_post_fork, 0);
58
60
  rb_define_singleton_method(mGyro, "snooze", Gyro_snooze, 0);
@@ -110,6 +112,10 @@ static VALUE Gyro_unref(VALUE self) {
110
112
  return Qnil;
111
113
  }
112
114
 
115
+ static VALUE Gyro_run(VALUE self) {
116
+ return Gyro_run_next_fiber();
117
+ }
118
+
113
119
  static VALUE Gyro_reset(VALUE self) {
114
120
  break_flag = 0;
115
121
  ref_count = 0;
@@ -121,7 +127,6 @@ static VALUE Gyro_reset(VALUE self) {
121
127
  static VALUE Gyro_break_set(VALUE self) {
122
128
  break_flag = 1;
123
129
  ev_break(EV_DEFAULT, EVBREAK_ALL);
124
- // printf("\n");
125
130
  return Qnil;
126
131
  }
127
132
 
@@ -133,9 +138,9 @@ VALUE Gyro_snooze(VALUE self) {
133
138
  VALUE fiber = rb_fiber_current();
134
139
  Gyro_schedule_fiber(fiber, Qnil);
135
140
 
136
- VALUE ret = Gyro_run();
141
+ VALUE ret = Gyro_run_next_fiber();
137
142
  if (RTEST(rb_obj_is_kind_of(ret, rb_eException)))
138
- return rb_funcall(ret, ID_raise, 1, ret);
143
+ return rb_funcall(rb_mKernel, ID_raise, 1, ret);
139
144
  else
140
145
  return ret;
141
146
  }
@@ -151,9 +156,10 @@ static VALUE Gyro_post_fork(VALUE self) {
151
156
  }
152
157
 
153
158
  static VALUE Gyro_suspend(VALUE self) {
154
- VALUE ret = Gyro_run();
159
+ rb_ivar_set(self, ID_scheduled_value, Qnil);
160
+ VALUE ret = Gyro_run_next_fiber();
155
161
  if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) {
156
- return rb_funcall(ret, ID_raise, 1, ret);
162
+ return rb_funcall(rb_mKernel, ID_raise, 1, ret);
157
163
  }
158
164
  else
159
165
  return ret;
@@ -165,7 +171,7 @@ static VALUE Fiber_safe_transfer(int argc, VALUE *argv, VALUE self) {
165
171
 
166
172
  // fiber is resumed, check if resumed value is an exception
167
173
  return RTEST(rb_obj_is_kind_of(ret, rb_eException)) ?
168
- rb_funcall(ret, ID_raise, 1, ret) : ret;
174
+ rb_funcall(rb_mKernel, ID_raise, 1, ret) : ret;
169
175
  }
170
176
 
171
177
  static VALUE Fiber_schedule(int argc, VALUE *argv, VALUE self) {
@@ -188,14 +194,14 @@ static VALUE Fiber_mark_as_done(VALUE self) {
188
194
  return self;
189
195
  }
190
196
 
191
- VALUE Gyro_yield() {
197
+ VALUE Gyro_await() {
192
198
  Gyro_ref_count_incr();
193
- VALUE ret = Gyro_run();
199
+ VALUE ret = Gyro_run_next_fiber();
194
200
  Gyro_ref_count_decr();
195
201
  return ret;
196
202
  }
197
203
 
198
- VALUE Gyro_run() {
204
+ VALUE Gyro_run_next_fiber() {
199
205
  while (1) {
200
206
  if (break_flag != 0) {
201
207
  return Qnil;
@@ -220,8 +226,9 @@ VALUE Gyro_run() {
220
226
  scheduled_tail = Qnil;
221
227
  }
222
228
 
223
- if (rb_fiber_alive_p(next_fiber) != Qtrue)
229
+ if (rb_fiber_alive_p(next_fiber) != Qtrue) {
224
230
  return Qnil;
231
+ }
225
232
 
226
233
  // run next fiber
227
234
  VALUE value = rb_ivar_get(next_fiber, ID_scheduled_value);
@@ -15,8 +15,8 @@ enum {
15
15
  // void Gyro_del_watcher_ref(VALUE obj);
16
16
  VALUE Gyro_snooze(VALUE self);
17
17
 
18
- VALUE Gyro_run();
19
- VALUE Gyro_yield();
18
+ VALUE Gyro_run_next_fiber();
19
+ VALUE Gyro_await();
20
20
  void Gyro_schedule_fiber(VALUE fiber, VALUE value);
21
21
 
22
22
  int Gyro_ref_count();
@@ -123,7 +123,7 @@ VALUE Gyro_IO_await(VALUE self) {
123
123
  io->fiber = rb_fiber_current();
124
124
  io->active = 1;
125
125
  ev_io_start(EV_DEFAULT, &io->ev_io);
126
- ret = Gyro_yield();
126
+ ret = Gyro_await();
127
127
 
128
128
  // make sure io watcher is stopped
129
129
  io->fiber = Qnil;
@@ -134,7 +134,7 @@ VALUE Gyro_IO_await(VALUE self) {
134
134
 
135
135
  // fiber is resumed, check if resumed value is an exception
136
136
  if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) {
137
- return rb_funcall(ret, ID_raise, 1, ret);
137
+ return rb_funcall(rb_mKernel, ID_raise, 1, ret);
138
138
  }
139
139
  else {
140
140
  return Qnil;
@@ -4,7 +4,7 @@ struct Gyro_Signal {
4
4
  struct ev_signal ev_signal;
5
5
  int active;
6
6
  int signum;
7
- VALUE callback;
7
+ VALUE fiber;
8
8
  };
9
9
 
10
10
  static VALUE cGyro_Signal = Qnil;
@@ -18,8 +18,7 @@ static size_t Gyro_Signal_size(const void *ptr);
18
18
  /* Methods */
19
19
  static VALUE Gyro_Signal_initialize(VALUE self, VALUE sig);
20
20
 
21
- static VALUE Gyro_Signal_start(VALUE self);
22
- static VALUE Gyro_Signal_stop(VALUE self);
21
+ static VALUE Gyro_Signal_await(VALUE self);
23
22
 
24
23
  void Gyro_Signal_callback(struct ev_loop *ev_loop, struct ev_signal *signal, int revents);
25
24
 
@@ -29,8 +28,7 @@ void Init_Gyro_Signal() {
29
28
  rb_define_alloc_func(cGyro_Signal, Gyro_Signal_allocate);
30
29
 
31
30
  rb_define_method(cGyro_Signal, "initialize", Gyro_Signal_initialize, 1);
32
- rb_define_method(cGyro_Signal, "start", Gyro_Signal_start, 0);
33
- rb_define_method(cGyro_Signal, "stop", Gyro_Signal_stop, 0);
31
+ rb_define_method(cGyro_Signal, "await", Gyro_Signal_await, 0);
34
32
  }
35
33
 
36
34
  static const rb_data_type_t Gyro_Signal_type = {
@@ -47,8 +45,8 @@ static VALUE Gyro_Signal_allocate(VALUE klass) {
47
45
 
48
46
  static void Gyro_Signal_mark(void *ptr) {
49
47
  struct Gyro_Signal *signal = ptr;
50
- if (signal->callback != Qnil) {
51
- rb_gc_mark(signal->callback);
48
+ if (signal->fiber != Qnil) {
49
+ rb_gc_mark(signal->fiber);
52
50
  }
53
51
  }
54
52
 
@@ -72,15 +70,11 @@ static VALUE Gyro_Signal_initialize(VALUE self, VALUE sig) {
72
70
  GetGyro_Signal(self, signal);
73
71
  signal->signum = NUM2INT(signum);
74
72
 
75
- if (rb_block_given_p()) {
76
- signal->callback = rb_block_proc();
77
- }
78
-
79
73
  ev_signal_init(&signal->ev_signal, Gyro_Signal_callback, signal->signum);
80
74
 
81
- signal->active = 1;
82
- Gyro_ref_count_incr();
83
- ev_signal_start(EV_DEFAULT, &signal->ev_signal);
75
+ // signal->active = 1;
76
+ // Gyro_ref_count_incr();
77
+ // ev_signal_start(EV_DEFAULT, &signal->ev_signal);
84
78
 
85
79
  return Qnil;
86
80
  }
@@ -88,33 +82,37 @@ static VALUE Gyro_Signal_initialize(VALUE self, VALUE sig) {
88
82
  void Gyro_Signal_callback(struct ev_loop *ev_loop, struct ev_signal *ev_signal, int revents) {
89
83
  struct Gyro_Signal *signal = (struct Gyro_Signal*)ev_signal;
90
84
 
91
- if (signal->callback != Qnil) {
92
- rb_funcall(signal->callback, ID_call, 1, INT2NUM(signal->signum));
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));
93
92
  }
94
93
  }
95
94
 
96
- static VALUE Gyro_Signal_start(VALUE self) {
95
+ static VALUE Gyro_Signal_await(VALUE self) {
97
96
  struct Gyro_Signal *signal;
97
+ VALUE ret;
98
+
98
99
  GetGyro_Signal(self, signal);
99
100
 
100
- if (!signal->active) {
101
- Gyro_ref_count_incr();
102
- ev_signal_start(EV_DEFAULT, &signal->ev_signal);
103
- signal->active = 1;
104
- }
105
-
106
- return self;
107
- }
101
+ signal->fiber = rb_fiber_current();
102
+ signal->active = 1;
103
+ ev_signal_start(EV_DEFAULT, &signal->ev_signal);
108
104
 
109
- static VALUE Gyro_Signal_stop(VALUE self) {
110
- struct Gyro_Signal *signal;
111
- GetGyro_Signal(self, signal);
105
+ ret = Gyro_await();
112
106
 
113
- if (signal->active) {
114
- Gyro_ref_count_decr();
115
- ev_signal_stop(EV_DEFAULT, &signal->ev_signal);
116
- signal->active = 0;
107
+ // fiber is resumed, check if resumed value is an exception
108
+ signal->fiber = Qnil;
109
+ 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
+ return rb_funcall(rb_mKernel, ID_raise, 1, ret);
117
115
  }
118
-
119
- return self;
120
- }
116
+ else
117
+ return ret;
118
+ }
@@ -6,7 +6,6 @@ struct Gyro_Timer {
6
6
  double after;
7
7
  double repeat;
8
8
  VALUE self;
9
- VALUE callback;
10
9
  VALUE fiber;
11
10
  };
12
11
 
@@ -21,9 +20,6 @@ static size_t Gyro_Timer_size(const void *ptr);
21
20
  /* Methods */
22
21
  static VALUE Gyro_Timer_initialize(VALUE self, VALUE after, VALUE repeat);
23
22
 
24
- static VALUE Gyro_Timer_start(VALUE self);
25
- static VALUE Gyro_Timer_stop(VALUE self);
26
- static VALUE Gyro_Timer_reset(VALUE self);
27
23
  static VALUE Gyro_Timer_await(VALUE self);
28
24
 
29
25
  void Gyro_Timer_callback(struct ev_loop *ev_loop, struct ev_timer *timer, int revents);
@@ -34,9 +30,6 @@ void Init_Gyro_Timer() {
34
30
  rb_define_alloc_func(cGyro_Timer, Gyro_Timer_allocate);
35
31
 
36
32
  rb_define_method(cGyro_Timer, "initialize", Gyro_Timer_initialize, 2);
37
- rb_define_method(cGyro_Timer, "start", Gyro_Timer_start, 0);
38
- rb_define_method(cGyro_Timer, "stop", Gyro_Timer_stop, 0);
39
- rb_define_method(cGyro_Timer, "reset", Gyro_Timer_reset, 0);
40
33
  rb_define_method(cGyro_Timer, "await", Gyro_Timer_await, 0);
41
34
  }
42
35
 
@@ -54,9 +47,6 @@ static VALUE Gyro_Timer_allocate(VALUE klass) {
54
47
 
55
48
  static void Gyro_Timer_mark(void *ptr) {
56
49
  struct Gyro_Timer *timer = ptr;
57
- if (timer->callback != Qnil) {
58
- rb_gc_mark(timer->callback);
59
- }
60
50
  if (timer->fiber != Qnil) {
61
51
  rb_gc_mark(timer->fiber);
62
52
  }
@@ -83,7 +73,6 @@ static VALUE Gyro_Timer_initialize(VALUE self, VALUE after, VALUE repeat) {
83
73
  GetGyro_Timer(self, timer);
84
74
 
85
75
  timer->self = self;
86
- timer->callback = Qnil;
87
76
  timer->fiber = Qnil;
88
77
  timer->after = NUM2DBL(after);
89
78
  timer->repeat = NUM2DBL(repeat);
@@ -105,63 +94,9 @@ void Gyro_Timer_callback(struct ev_loop *ev_loop, struct ev_timer *ev_timer, int
105
94
  VALUE fiber = timer->fiber;
106
95
  VALUE resume_value = DBL2NUM(timer->after);
107
96
 
108
- ev_timer_stop(EV_DEFAULT, ev_timer);
109
- timer->active = 0;
110
97
  timer->fiber = Qnil;
111
98
  Gyro_schedule_fiber(fiber, resume_value);
112
99
  }
113
- else if (timer->callback != Qnil) {
114
- Gyro_ref_count_decr();
115
- rb_funcall(timer->callback, ID_call, 1, Qtrue);
116
- }
117
- }
118
-
119
- static VALUE Gyro_Timer_start(VALUE self) {
120
- struct Gyro_Timer *timer;
121
- GetGyro_Timer(self, timer);
122
-
123
- if (rb_block_given_p()) {
124
- Gyro_ref_count_incr();
125
- timer->callback = rb_block_proc();
126
- }
127
-
128
- if (!timer->active) {
129
- ev_timer_start(EV_DEFAULT, &timer->ev_timer);
130
- timer->active = 1;
131
- }
132
-
133
- return self;
134
- }
135
-
136
- static VALUE Gyro_Timer_stop(VALUE self) {
137
- struct Gyro_Timer *timer;
138
- GetGyro_Timer(self, timer);
139
-
140
- if (timer->active) {
141
- ev_timer_stop(EV_DEFAULT, &timer->ev_timer);
142
- timer->active = 0;
143
- }
144
-
145
- return self;
146
- }
147
-
148
- static VALUE Gyro_Timer_reset(VALUE self) {
149
- struct Gyro_Timer *timer;
150
- int prev_active;
151
- GetGyro_Timer(self, timer);
152
-
153
- prev_active = timer->active;
154
-
155
- if (prev_active) {
156
- ev_timer_stop(EV_DEFAULT, &timer->ev_timer);
157
- }
158
- ev_timer_set(&timer->ev_timer, timer->after, timer->repeat);
159
- ev_timer_start(EV_DEFAULT, &timer->ev_timer);
160
- if (!prev_active) {
161
- timer->active = 1;
162
- }
163
-
164
- return self;
165
100
  }
166
101
 
167
102
  static VALUE Gyro_Timer_await(VALUE self) {
@@ -171,19 +106,17 @@ static VALUE Gyro_Timer_await(VALUE self) {
171
106
  GetGyro_Timer(self, timer);
172
107
 
173
108
  timer->fiber = rb_fiber_current();
174
- timer->active = 1;
175
- ev_timer_start(EV_DEFAULT, &timer->ev_timer);
109
+ if (timer->active != 1) {
110
+ timer->active = 1;
111
+ ev_timer_start(EV_DEFAULT, &timer->ev_timer);
112
+ }
176
113
 
177
- ret = Gyro_yield();
114
+ ret = Gyro_await();
178
115
 
179
116
  // fiber is resumed, check if resumed value is an exception
180
117
  timer->fiber = Qnil;
181
118
  if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) {
182
- if (timer->active) {
183
- timer->active = 0;
184
- ev_timer_stop(EV_DEFAULT, &timer->ev_timer);
185
- }
186
- return rb_funcall(ret, ID_raise, 1, ret);
119
+ return rb_funcall(rb_mKernel, ID_raise, 1, ret);
187
120
  }
188
121
  else
189
122
  return ret;
@@ -12,6 +12,9 @@ import './polyphony/extensions/io'
12
12
 
13
13
  # Main Polyphony API
14
14
  module Polyphony
15
+ GlobalAPI = import './polyphony/core/global_api'
16
+ ::Object.include GlobalAPI
17
+
15
18
  exceptions = import './polyphony/core/exceptions'
16
19
  Cancel = exceptions::Cancel
17
20
  MoveOn = exceptions::MoveOn
@@ -56,13 +59,6 @@ module Polyphony
56
59
  pid = Kernel.fork do
57
60
  setup_forked_process
58
61
  block.()
59
-
60
- # We cannot simply depend on the at_exit block (see polyphony/auto_run)
61
- # to yield to the reactor fiber. Doing that will raise a FiberError
62
- # complaining: "fiber called across stack rewinding barrier". Apparently
63
- # this is a bug in Ruby, so the workaround is to yield just before
64
- # exiting.
65
- suspend
66
62
  end
67
63
  Gyro.reset!
68
64
  pid
@@ -71,14 +67,16 @@ module Polyphony
71
67
  def reset!
72
68
  # Fiber.root.scheduled_value = nil
73
69
  Gyro.reset!
70
+ Coprocess.map.clear
71
+ Fiber.set_root_fiber
74
72
  end
75
73
 
76
74
  private
77
75
 
78
76
  def setup_forked_process
77
+ Coprocess.map.delete Fiber.root
79
78
  Gyro.post_fork
80
79
  Fiber.set_root_fiber
81
- Fiber.current.coprocess = Coprocess.new(Fiber.current)
82
80
  end
83
81
  end
84
82
  end
@@ -10,6 +10,8 @@ Exceptions = import('./exceptions')
10
10
  class CancelScope
11
11
  def initialize(opts = {}, &block)
12
12
  @opts = opts
13
+ @fibers = []
14
+ start_timeout_waiter if @opts[:timeout]
13
15
  call(&block) if block
14
16
  end
15
17
 
@@ -19,33 +21,49 @@ class CancelScope
19
21
 
20
22
  def cancel!
21
23
  @cancelled = true
22
- @fiber.cancelled = true
23
- @fiber.transfer error_class.new(self, @opts[:value])
24
+ @fibers.each do |f|
25
+ f.cancelled = true
26
+ f.schedule error_class.new(self, @opts[:value])
27
+ end
28
+ @on_cancel&.()
24
29
  end
25
30
 
26
- def start_timeout
27
- @timeout = Gyro::Timer.new(@opts[:timeout], 0)
28
- @timeout.start { cancel! }
31
+ def start_timeout_waiter
32
+ @timeout_waiter = spin do
33
+ sleep @opts[:timeout]
34
+ @timeout_waiter = nil
35
+ cancel!
36
+ end
29
37
  end
30
38
 
31
- def reset_timeout
32
- @timeout.reset
39
+ def stop_timeout_waiter
40
+ return unless @timeout_waiter
41
+
42
+ @timeout_waiter.stop
43
+ @timeout_waiter = nil
33
44
  end
34
45
 
35
- def disable
36
- @timeout&.stop
46
+ def reset_timeout
47
+ return unless @timeout_waiter
48
+
49
+ @timeout_waiter.stop
50
+ start_timeout_waiter
37
51
  end
38
52
 
53
+ # def disable
54
+ # @timeout&.stop
55
+ # end
56
+
39
57
  def call
40
- start_timeout if @opts[:timeout]
41
- @fiber = Fiber.current
42
- @fiber.cancelled = nil
58
+ fiber = Fiber.current
59
+ @fibers << fiber
60
+ fiber.cancelled = nil
43
61
  yield self
44
62
  rescue Exceptions::MoveOn => e
45
63
  e.scope == self ? e.value : raise(e)
46
64
  ensure
47
- @timeout&.stop
48
- protect(&@on_cancel) if @cancelled && @on_cancel
65
+ @fibers.delete fiber
66
+ stop_timeout_waiter if @fibers.empty? && @timeout_waiter
49
67
  end
50
68
 
51
69
  def on_cancel(&block)
@@ -55,11 +73,4 @@ class CancelScope
55
73
  def cancelled?
56
74
  @cancelled
57
75
  end
58
-
59
- def protect(&block)
60
- @fiber.cancelled = false
61
- block.()
62
- ensure
63
- @fiber.cancelled = @cancelled
64
- end
65
76
  end