polyphony 0.22 → 0.23

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 (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