polyphony 0.34 → 0.41

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +11 -2
  3. data/.gitignore +2 -2
  4. data/.rubocop.yml +30 -0
  5. data/CHANGELOG.md +34 -0
  6. data/Gemfile +0 -11
  7. data/Gemfile.lock +11 -10
  8. data/README.md +2 -1
  9. data/Rakefile +6 -2
  10. data/TODO.md +18 -95
  11. data/docs/_includes/head.html +40 -0
  12. data/docs/_includes/nav.html +5 -5
  13. data/docs/api-reference.md +1 -1
  14. data/docs/api-reference/fiber.md +18 -0
  15. data/docs/api-reference/gyro-async.md +57 -0
  16. data/docs/api-reference/gyro-child.md +29 -0
  17. data/docs/api-reference/gyro-queue.md +44 -0
  18. data/docs/api-reference/gyro-timer.md +51 -0
  19. data/docs/api-reference/gyro.md +25 -0
  20. data/docs/index.md +10 -7
  21. data/docs/main-concepts/design-principles.md +67 -9
  22. data/docs/main-concepts/extending.md +1 -1
  23. data/docs/main-concepts/fiber-scheduling.md +55 -72
  24. data/examples/core/xx-agent.rb +102 -0
  25. data/examples/core/xx-fork-cleanup.rb +22 -0
  26. data/examples/core/xx-sleeping.rb +14 -6
  27. data/examples/core/xx-timer-gc.rb +17 -0
  28. data/examples/io/tunnel.rb +48 -0
  29. data/examples/io/xx-irb.rb +1 -1
  30. data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +7 -6
  31. data/examples/performance/thread-vs-fiber/polyphony_server.rb +14 -25
  32. data/ext/{gyro → polyphony}/extconf.rb +2 -2
  33. data/ext/polyphony/fiber.c +112 -0
  34. data/ext/{gyro → polyphony}/libev.c +0 -0
  35. data/ext/{gyro → polyphony}/libev.h +0 -0
  36. data/ext/polyphony/libev_agent.c +503 -0
  37. data/ext/polyphony/libev_queue.c +214 -0
  38. data/ext/polyphony/polyphony.c +89 -0
  39. data/ext/{gyro/gyro.h → polyphony/polyphony.h} +49 -59
  40. data/ext/polyphony/polyphony_ext.c +23 -0
  41. data/ext/{gyro → polyphony}/socket.c +21 -19
  42. data/ext/{gyro → polyphony}/thread.c +55 -119
  43. data/ext/{gyro → polyphony}/tracing.c +1 -1
  44. data/lib/polyphony.rb +37 -44
  45. data/lib/polyphony/adapters/fs.rb +1 -4
  46. data/lib/polyphony/adapters/irb.rb +2 -2
  47. data/lib/polyphony/adapters/postgres.rb +6 -5
  48. data/lib/polyphony/adapters/process.rb +27 -23
  49. data/lib/polyphony/adapters/trace.rb +110 -105
  50. data/lib/polyphony/core/channel.rb +35 -35
  51. data/lib/polyphony/core/exceptions.rb +29 -29
  52. data/lib/polyphony/core/global_api.rb +94 -91
  53. data/lib/polyphony/core/resource_pool.rb +83 -83
  54. data/lib/polyphony/core/sync.rb +16 -16
  55. data/lib/polyphony/core/thread_pool.rb +49 -37
  56. data/lib/polyphony/core/throttler.rb +30 -23
  57. data/lib/polyphony/event.rb +27 -0
  58. data/lib/polyphony/extensions/core.rb +23 -14
  59. data/lib/polyphony/extensions/fiber.rb +269 -267
  60. data/lib/polyphony/extensions/io.rb +56 -26
  61. data/lib/polyphony/extensions/openssl.rb +5 -9
  62. data/lib/polyphony/extensions/socket.rb +29 -10
  63. data/lib/polyphony/extensions/thread.rb +19 -12
  64. data/lib/polyphony/net.rb +64 -60
  65. data/lib/polyphony/version.rb +1 -1
  66. data/polyphony.gemspec +3 -6
  67. data/test/helper.rb +14 -1
  68. data/test/stress.rb +17 -12
  69. data/test/test_agent.rb +77 -0
  70. data/test/{test_async.rb → test_event.rb} +17 -9
  71. data/test/test_ext.rb +25 -4
  72. data/test/test_fiber.rb +23 -14
  73. data/test/test_global_api.rb +5 -5
  74. data/test/test_io.rb +46 -24
  75. data/test/test_queue.rb +74 -0
  76. data/test/test_signal.rb +3 -40
  77. data/test/test_socket.rb +33 -0
  78. data/test/test_thread.rb +38 -16
  79. data/test/test_thread_pool.rb +3 -3
  80. data/test/test_throttler.rb +0 -1
  81. data/test/test_trace.rb +6 -5
  82. metadata +34 -39
  83. data/ext/gyro/async.c +0 -158
  84. data/ext/gyro/child.c +0 -117
  85. data/ext/gyro/gyro.c +0 -203
  86. data/ext/gyro/gyro_ext.c +0 -31
  87. data/ext/gyro/io.c +0 -447
  88. data/ext/gyro/queue.c +0 -142
  89. data/ext/gyro/selector.c +0 -183
  90. data/ext/gyro/signal.c +0 -108
  91. data/ext/gyro/timer.c +0 -154
  92. data/test/test_timer.rb +0 -56
@@ -1,4 +1,4 @@
1
- #include "gyro.h"
1
+ #include "polyphony.h"
2
2
  #include <sys/socket.h>
3
3
 
4
4
  static VALUE cTCPSocket;
@@ -71,8 +71,8 @@ static VALUE BasicSocket_send(int argc, VALUE *argv, VALUE sock) {
71
71
  ssize_t n;
72
72
  rb_blocking_function_t *func;
73
73
  const char *funcname;
74
- VALUE write_watcher = Qnil;
75
-
74
+ VALUE agent = Qnil;
75
+
76
76
  rb_scan_args(argc, argv, "21", &arg.mesg, &flags, &to);
77
77
 
78
78
  StringValue(arg.mesg);
@@ -94,10 +94,9 @@ static VALUE BasicSocket_send(int argc, VALUE *argv, VALUE sock) {
94
94
  arg.fd = fptr->fd;
95
95
  arg.flags = NUM2INT(flags);
96
96
  while ((n = (ssize_t)func(&arg)) < 0) {
97
- if (write_watcher == Qnil) {
98
- write_watcher = IO_write_watcher(sock);
99
- }
100
- Gyro_IO_await(write_watcher);
97
+ if (NIL_P(agent))
98
+ agent = rb_ivar_get(rb_thread_current(), ID_ivar_agent);
99
+ LibevAgent_wait_io(agent, sock, Qtrue);
101
100
  }
102
101
  return SSIZET2NUM(n);
103
102
  }
@@ -113,7 +112,7 @@ static VALUE BasicSocket_recv(int argc, VALUE *argv, VALUE sock) {
113
112
  rb_io_t *fptr;
114
113
  long n;
115
114
  int shrinkable;
116
- VALUE read_watcher = Qnil;
115
+ VALUE agent = Qnil;
117
116
 
118
117
 
119
118
  VALUE str = argc >= 3 ? argv[2] : Qnil;
@@ -132,9 +131,9 @@ static VALUE BasicSocket_recv(int argc, VALUE *argv, VALUE sock) {
132
131
  if (n < 0) {
133
132
  int e = errno;
134
133
  if (e == EWOULDBLOCK || e == EAGAIN) {
135
- if (read_watcher == Qnil)
136
- read_watcher = IO_read_watcher(sock);
137
- Gyro_IO_await(read_watcher);
134
+ if (NIL_P(agent))
135
+ agent = rb_ivar_get(rb_thread_current(), ID_ivar_agent);
136
+ LibevAgent_wait_io(agent, sock, Qnil);
138
137
  }
139
138
  else
140
139
  rb_syserr_fail(e, strerror(e));
@@ -158,7 +157,7 @@ static VALUE Socket_accept(VALUE sock) {
158
157
  int fd;
159
158
  struct sockaddr addr;
160
159
  socklen_t len = (socklen_t)sizeof addr;
161
- VALUE read_watcher = Qnil;
160
+ VALUE agent = Qnil;
162
161
 
163
162
  GetOpenFile(sock, fptr);
164
163
  rb_io_set_nonblock(fptr);
@@ -169,9 +168,9 @@ static VALUE Socket_accept(VALUE sock) {
169
168
  if (fd < 0) {
170
169
  int e = errno;
171
170
  if (e == EWOULDBLOCK || e == EAGAIN) {
172
- if (read_watcher == Qnil)
173
- read_watcher = IO_read_watcher(sock);
174
- Gyro_IO_await(read_watcher);
171
+ if (NIL_P(agent))
172
+ agent = rb_ivar_get(rb_thread_current(), ID_ivar_agent);
173
+ LibevAgent_wait_io(agent, sock, Qnil);
175
174
  }
176
175
  else
177
176
  rb_syserr_fail(e, strerror(e));
@@ -197,15 +196,18 @@ static VALUE Socket_accept(VALUE sock) {
197
196
  }
198
197
 
199
198
  void Init_Socket() {
199
+ VALUE cBasicSocket;
200
+ VALUE cSocket;
201
+
200
202
  rb_require("socket");
201
- VALUE cBasicSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
203
+ cBasicSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
202
204
 
203
205
  rb_define_method(cBasicSocket, "send", BasicSocket_send, -1);
204
206
  rb_define_method(cBasicSocket, "recv", BasicSocket_recv, -1);
205
207
 
206
- VALUE cSocket = rb_const_get(rb_cObject, rb_intern("Socket"));
207
-
208
- rb_define_method(cSocket, "accept", Socket_accept, 0);
208
+ cSocket = rb_const_get(rb_cObject, rb_intern("Socket"));
209
+
210
+ // rb_define_method(cSocket, "accept", Socket_accept, 0);
209
211
 
210
212
  cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
211
213
  }
@@ -1,64 +1,26 @@
1
- #include "gyro.h"
2
-
3
- static VALUE cQueue;
4
-
5
- static ID ID_create_event_selector;
6
- static ID ID_empty;
7
- static ID ID_fiber_ref_count;
8
- static ID ID_ivar_event_selector_proc;
9
- static ID ID_ivar_event_selector;
10
- static ID ID_ivar_join_wait_queue;
11
- static ID ID_ivar_main_fiber;
12
- static ID ID_ivar_result;
13
- static ID ID_ivar_terminated;
14
- static ID ID_pop;
15
- static ID ID_push;
16
- static ID ID_run_queue;
17
- // static ID ID_run_queue_head;
18
- // static ID ID_run_queue_tail;
19
- static ID ID_runnable_next;
20
- static ID ID_stop;
21
-
22
- VALUE event_selector_factory_proc(RB_BLOCK_CALL_FUNC_ARGLIST(args, klass)) {
23
- return rb_funcall(klass, ID_new, 1, rb_ary_entry(args, 0));
24
- }
25
-
26
- static VALUE Thread_event_selector_set_proc(VALUE self, VALUE proc) {
27
- if (!rb_obj_is_proc(proc)) {
28
- proc = rb_proc_new(event_selector_factory_proc, proc);
29
- }
30
- rb_ivar_set(self, ID_ivar_event_selector_proc, proc);
31
- return self;
32
- }
33
-
34
- static VALUE Thread_create_event_selector(VALUE self, VALUE thread) {
35
- VALUE selector_proc = rb_ivar_get(self, ID_ivar_event_selector_proc);
36
- if (selector_proc == Qnil) {
37
- rb_raise(rb_eRuntimeError, "No event_selector_proc defined");
38
- }
39
-
40
- return rb_funcall(selector_proc, ID_call, 1, thread);
41
- }
1
+ #include "polyphony.h"
2
+
3
+ ID ID_deactivate_all_watchers_post_fork;
4
+ ID ID_empty;
5
+ ID ID_fiber_ref_count;
6
+ ID ID_ivar_agent;
7
+ ID ID_ivar_join_wait_queue;
8
+ ID ID_ivar_main_fiber;
9
+ ID ID_ivar_result;
10
+ ID ID_ivar_terminated;
11
+ ID ID_pop;
12
+ ID ID_push;
13
+ ID ID_run_queue;
14
+ ID ID_runnable_next;
15
+ ID ID_stop;
42
16
 
43
17
  static VALUE Thread_setup_fiber_scheduling(VALUE self) {
18
+ VALUE queue;
19
+
44
20
  rb_ivar_set(self, ID_ivar_main_fiber, rb_fiber_current());
45
21
  rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(0));
46
- VALUE queue = rb_ary_new();
22
+ queue = rb_ary_new();
47
23
  rb_ivar_set(self, ID_run_queue, queue);
48
- VALUE selector = rb_funcall(rb_cThread, ID_create_event_selector, 1, self);
49
- rb_ivar_set(self, ID_ivar_event_selector, selector);
50
-
51
- return self;
52
- }
53
-
54
- static VALUE Thread_stop_event_selector(VALUE self) {
55
- VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
56
- if (selector != Qnil) {
57
- rb_funcall(selector, ID_stop, 0);
58
- }
59
- // Nullify the selector in order to prevent running the
60
- // selector after the thread is done running.
61
- rb_ivar_set(self, ID_ivar_event_selector, Qnil);
62
24
 
63
25
  return self;
64
26
  }
@@ -90,23 +52,24 @@ static VALUE SYM_scheduled_fibers;
90
52
  static VALUE SYM_pending_watchers;
91
53
 
92
54
  static VALUE Thread_fiber_scheduling_stats(VALUE self) {
55
+ VALUE agent = rb_ivar_get(self,ID_ivar_agent);
93
56
  VALUE stats = rb_hash_new();
94
57
  VALUE queue = rb_ivar_get(self, ID_run_queue);
95
- VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
96
-
58
+ long pending_count;
59
+
97
60
  long scheduled_count = RARRAY_LEN(queue);
98
61
  rb_hash_aset(stats, SYM_scheduled_fibers, INT2NUM(scheduled_count));
99
62
 
100
- long pending_count = Gyro_Selector_pending_count(selector);
63
+ pending_count = LibevAgent_pending_count(agent);
101
64
  rb_hash_aset(stats, SYM_pending_watchers, INT2NUM(pending_count));
102
65
 
103
66
  return stats;
104
67
  }
105
68
 
106
69
  VALUE Thread_schedule_fiber(VALUE self, VALUE fiber, VALUE value) {
107
- if (rb_fiber_alive_p(fiber) != Qtrue) {
108
- return self;
109
- }
70
+ VALUE queue;
71
+
72
+ if (rb_fiber_alive_p(fiber) != Qtrue) return self;
110
73
 
111
74
  FIBER_TRACE(3, SYM_fiber_schedule, fiber, value);
112
75
  // if fiber is already scheduled, just set the scheduled value, then return
@@ -115,7 +78,7 @@ VALUE Thread_schedule_fiber(VALUE self, VALUE fiber, VALUE value) {
115
78
  return self;
116
79
  }
117
80
 
118
- VALUE queue = rb_ivar_get(self, ID_run_queue);
81
+ queue = rb_ivar_get(self, ID_run_queue);
119
82
  rb_ary_push(queue, fiber);
120
83
  rb_ivar_set(fiber, ID_runnable, Qtrue);
121
84
 
@@ -125,22 +88,21 @@ VALUE Thread_schedule_fiber(VALUE self, VALUE fiber, VALUE value) {
125
88
  // event selector. Otherwise it's gonna be stuck waiting for an event to
126
89
  // happen, not knowing that it there's already a fiber ready to run in its
127
90
  // run queue.
128
- VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
129
- if (selector != Qnil) {
130
- Gyro_Selector_break_out_of_ev_loop(selector);
131
- }
91
+ VALUE agent = rb_ivar_get(self,ID_ivar_agent);
92
+ LibevAgent_break(agent);
132
93
  }
133
94
  return self;
134
95
  }
135
96
 
136
97
  VALUE Thread_schedule_fiber_with_priority(VALUE self, VALUE fiber, VALUE value) {
137
- if (rb_fiber_alive_p(fiber) != Qtrue) {
138
- return self;
139
- }
98
+ VALUE queue;
99
+
100
+ if (rb_fiber_alive_p(fiber) != Qtrue) return self;
101
+
140
102
  FIBER_TRACE(3, SYM_fiber_schedule, fiber, value);
141
103
  rb_ivar_set(fiber, ID_runnable_value, value);
142
104
 
143
- VALUE queue = rb_ivar_get(self, ID_run_queue);
105
+ queue = rb_ivar_get(self, ID_run_queue);
144
106
 
145
107
  // if fiber is already scheduled, remove it from the run queue
146
108
  if (rb_ivar_get(fiber, ID_runnable) != Qnil) {
@@ -155,56 +117,49 @@ VALUE Thread_schedule_fiber_with_priority(VALUE self, VALUE fiber, VALUE value)
155
117
  if (rb_thread_current() != self) {
156
118
  // if the fiber scheduling is done across threads, we need to make sure the
157
119
  // target thread is woken up in case it is in the middle of running its
158
- // event selector. Otherwise it's gonna be stuck waiting for an event to
120
+ // event loop. Otherwise it's gonna be stuck waiting for an event to
159
121
  // happen, not knowing that it there's already a fiber ready to run in its
160
122
  // run queue.
161
- VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
162
- if (selector != Qnil) {
163
- Gyro_Selector_break_out_of_ev_loop(selector);
164
- }
123
+ VALUE agent = rb_ivar_get(self, ID_ivar_agent);
124
+ LibevAgent_break(agent);
165
125
  }
166
126
  return self;
167
127
  }
168
128
 
169
129
  VALUE Thread_switch_fiber(VALUE self) {
170
130
  VALUE current_fiber = rb_fiber_current();
131
+ VALUE queue = rb_ivar_get(self, ID_run_queue);
132
+ VALUE next_fiber;
133
+ VALUE value;
134
+ VALUE agent = rb_ivar_get(self, ID_ivar_agent);
135
+ int ref_count;
136
+
171
137
  if (__tracing_enabled__) {
172
138
  if (rb_ivar_get(current_fiber, ID_ivar_running) != Qfalse) {
173
139
  rb_funcall(rb_cObject, ID_fiber_trace, 2, SYM_fiber_switchpoint, current_fiber);
174
140
  }
175
141
  }
176
- VALUE queue = rb_ivar_get(self, ID_run_queue);
177
- VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
178
-
179
- VALUE next_fiber;
180
142
 
181
143
  while (1) {
144
+ ref_count = Thread_fiber_ref_count(self);
182
145
  next_fiber = rb_ary_shift(queue);
183
- // if (break_flag != 0) {
184
- // return Qnil;
185
- // }
186
- int ref_count = Thread_fiber_ref_count(self);
187
146
  if (next_fiber != Qnil) {
188
147
  if (ref_count > 0) {
189
148
  // this mechanism prevents event starvation in case the run queue never
190
149
  // empties
191
- Gyro_Selector_run_no_wait(selector, current_fiber, RARRAY_LEN(queue));
150
+ LibevAgent_poll(agent, Qtrue, current_fiber, queue);
192
151
  }
193
152
  break;
194
153
  }
195
- if (ref_count == 0) {
196
- break;
197
- }
154
+ if (ref_count == 0) break;
198
155
 
199
- Gyro_Selector_run(selector, current_fiber);
156
+ LibevAgent_poll(agent, Qnil, current_fiber, queue);
200
157
  }
201
158
 
202
- if (next_fiber == Qnil) {
203
- return Qnil;
204
- }
159
+ if (next_fiber == Qnil) return Qnil;
205
160
 
206
161
  // run next fiber
207
- VALUE value = rb_ivar_get(next_fiber, ID_runnable_value);
162
+ value = rb_ivar_get(next_fiber, ID_runnable_value);
208
163
  FIBER_TRACE(3, SYM_fiber_run, next_fiber, value);
209
164
 
210
165
  rb_ivar_set(next_fiber, ID_runnable, Qnil);
@@ -220,33 +175,23 @@ VALUE Thread_reset_fiber_scheduling(VALUE self) {
220
175
  return self;
221
176
  }
222
177
 
223
- VALUE Thread_post_fork(VALUE self) {
224
- VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
225
- Gyro_Selector_post_fork(selector);
226
-
227
- return self;
228
- }
229
-
230
- VALUE Fiber_await() {
178
+ VALUE Polyphony_switchpoint() {
179
+ VALUE ret;
231
180
  VALUE thread = rb_thread_current();
232
181
  Thread_ref(thread);
233
- VALUE ret = Thread_switch_fiber(thread);
182
+ ret = Thread_switch_fiber(thread);
234
183
  Thread_unref(thread);
235
184
  RB_GC_GUARD(ret);
236
185
  return ret;
237
186
  }
238
187
 
239
- VALUE Thread_current_event_selector() {
240
- return rb_ivar_get(rb_thread_current(), ID_ivar_event_selector);
241
- }
242
-
243
188
  VALUE Thread_fiber_break_out_of_ev_loop(VALUE self, VALUE fiber, VALUE resume_obj) {
244
- VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
189
+ VALUE agent = rb_ivar_get(self, ID_ivar_agent);
245
190
  if (fiber != Qnil) {
246
191
  Thread_schedule_fiber_with_priority(self, fiber, resume_obj);
247
192
  }
248
193
 
249
- if (Gyro_Selector_break_out_of_ev_loop(selector) == Qnil) {
194
+ if (LibevAgent_break(agent) == Qnil) {
250
195
  // we're not inside the ev_loop, so we just do a switchpoint
251
196
  Thread_switch_fiber(self);
252
197
  }
@@ -255,18 +200,10 @@ VALUE Thread_fiber_break_out_of_ev_loop(VALUE self, VALUE fiber, VALUE resume_ob
255
200
  }
256
201
 
257
202
  void Init_Thread() {
258
- cQueue = rb_const_get(rb_cObject, rb_intern("Queue"));
259
-
260
- rb_define_singleton_method(rb_cThread, "event_selector=", Thread_event_selector_set_proc, 1);
261
- rb_define_singleton_method(rb_cThread, "create_event_selector", Thread_create_event_selector, 1);
262
-
263
203
  rb_define_method(rb_cThread, "fiber_ref", Thread_ref, 0);
264
204
  rb_define_method(rb_cThread, "fiber_unref", Thread_unref, 0);
265
205
 
266
- rb_define_method(rb_cThread, "post_fork", Thread_post_fork, 0);
267
-
268
206
  rb_define_method(rb_cThread, "setup_fiber_scheduling", Thread_setup_fiber_scheduling, 0);
269
- rb_define_method(rb_cThread, "stop_event_selector", Thread_stop_event_selector, 0);
270
207
  rb_define_method(rb_cThread, "reset_fiber_scheduling", Thread_reset_fiber_scheduling, 0);
271
208
  rb_define_method(rb_cThread, "fiber_scheduling_stats", Thread_fiber_scheduling_stats, 0);
272
209
  rb_define_method(rb_cThread, "break_out_of_ev_loop", Thread_fiber_break_out_of_ev_loop, 2);
@@ -276,11 +213,10 @@ void Init_Thread() {
276
213
  Thread_schedule_fiber_with_priority, 2);
277
214
  rb_define_method(rb_cThread, "switch_fiber", Thread_switch_fiber, 0);
278
215
 
279
- ID_create_event_selector = rb_intern("create_event_selector");
216
+ ID_deactivate_all_watchers_post_fork = rb_intern("deactivate_all_watchers_post_fork");
280
217
  ID_empty = rb_intern("empty?");
281
218
  ID_fiber_ref_count = rb_intern("fiber_ref_count");
282
- ID_ivar_event_selector = rb_intern("@event_selector");
283
- ID_ivar_event_selector_proc = rb_intern("@event_selector_proc");
219
+ ID_ivar_agent = rb_intern("@agent");
284
220
  ID_ivar_join_wait_queue = rb_intern("@join_wait_queue");
285
221
  ID_ivar_main_fiber = rb_intern("@main_fiber");
286
222
  ID_ivar_result = rb_intern("@result");
@@ -1,4 +1,4 @@
1
- #include "gyro.h"
1
+ #include "polyphony.h"
2
2
 
3
3
  int __tracing_enabled__ = 0;
4
4
 
@@ -1,50 +1,35 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'modulation/gem'
3
+ require 'fiber'
4
+ require_relative './polyphony_ext'
4
5
 
5
- export_default :Polyphony
6
+ module Polyphony
7
+ # Map Queue to Libev queue implementation
8
+ Queue = LibevQueue
9
+ end
6
10
 
7
- require 'fiber'
8
- require_relative './gyro_ext'
11
+ require_relative './polyphony/extensions/core'
12
+ require_relative './polyphony/extensions/thread'
13
+ require_relative './polyphony/extensions/fiber'
14
+ require_relative './polyphony/extensions/io'
9
15
 
10
- Thread.event_selector = Gyro::Selector
11
16
  Thread.current.setup_fiber_scheduling
17
+ Thread.current.agent = Polyphony::LibevAgent.new
12
18
 
13
- import './polyphony/extensions/core'
14
- import './polyphony/extensions/thread'
15
- import './polyphony/extensions/fiber'
16
- import './polyphony/extensions/io'
19
+ require_relative './polyphony/core/global_api'
20
+ require_relative './polyphony/core/resource_pool'
21
+ require_relative './polyphony/net'
22
+ require_relative './polyphony/adapters/process'
23
+ require_relative './polyphony/event'
17
24
 
18
25
  # Main Polyphony API
19
26
  module Polyphony
20
- GlobalAPI = import './polyphony/core/global_api'
21
- ::Object.include GlobalAPI
22
-
23
- exceptions = import './polyphony/core/exceptions'
24
- Cancel = exceptions::Cancel
25
- MoveOn = exceptions::MoveOn
26
- Restart = exceptions::Restart
27
- Terminate = exceptions::Terminate
28
-
29
- Net = import './polyphony/net'
30
-
31
- auto_import(
32
- Channel: './polyphony/core/channel',
33
- FS: './polyphony/adapters/fs',
34
- Process: './polyphony/adapters/process',
35
- ResourcePool: './polyphony/core/resource_pool',
36
- Sync: './polyphony/core/sync',
37
- ThreadPool: './polyphony/core/thread_pool',
38
- Throttler: './polyphony/core/throttler',
39
- Trace: './polyphony/adapters/trace'
40
- )
41
-
42
27
  class << self
43
28
  def wait_for_signal(sig)
44
29
  fiber = Fiber.current
45
- Gyro.ref
30
+ Polyphony.ref
46
31
  old_trap = trap(sig) do
47
- Gyro.unref
32
+ Polyphony.unref
48
33
  fiber.schedule(sig)
49
34
  trap(sig, old_trap)
50
35
  end
@@ -53,10 +38,10 @@ module Polyphony
53
38
 
54
39
  def fork(&block)
55
40
  Kernel.fork do
56
- # Since the fiber doing the fork will become the main fiber of the
57
- # forked process, we leave it behind by transferring to a new fiber
58
- # created in the context of the forked process, which rescues *all*
59
- # exceptions, including Interrupt and SystemExit.
41
+ # # Since the fiber doing the fork will become the main fiber of the
42
+ # # forked process, we leave it behind by transferring to a new fiber
43
+ # # created in the context of the forked process, which rescues *all*
44
+ # # exceptions, including Interrupt and SystemExit.
60
45
  spin_forked_block(&block).transfer
61
46
  end
62
47
  end
@@ -64,12 +49,13 @@ module Polyphony
64
49
  def spin_forked_block(&block)
65
50
  Fiber.new do
66
51
  run_forked_block(&block)
67
- exit_forked_process
68
- rescue ::SystemExit
69
- exit_forked_process
52
+ rescue SystemExit
53
+ # fall through to ensure
70
54
  rescue Exception => e
71
55
  e.full_message
72
56
  exit!
57
+ ensure
58
+ exit_forked_process
73
59
  end
74
60
  end
75
61
 
@@ -81,9 +67,9 @@ module Polyphony
81
67
  trap('SIGTERM', 'DEFAULT')
82
68
  trap('SIGINT', 'DEFAULT')
83
69
 
84
- Thread.current.post_fork
85
70
  Thread.current.setup
86
71
  Fiber.current.setup_main_fiber
72
+ Thread.current.agent.post_fork
87
73
 
88
74
  install_terminating_signal_handlers
89
75
 
@@ -91,14 +77,13 @@ module Polyphony
91
77
  end
92
78
 
93
79
  def exit_forked_process
80
+ terminate_threads
94
81
  Fiber.current.shutdown_all_children
82
+
95
83
  # Since fork could be called from any fiber, we explicitly call exit here.
96
84
  # Otherwise, the fiber might want to pass execution to another fiber that
97
85
  # previously transferred execution to the forking fiber, but doesn't exist
98
86
  # anymore...
99
- #
100
- # The call to exit will invoke the at_exit handler we use to terminate the
101
- # (forked) main fiber's child fibers.
102
87
  exit
103
88
  end
104
89
 
@@ -118,6 +103,14 @@ module Polyphony
118
103
  install_terminating_signal_handler('SIGTERM', ::SystemExit)
119
104
  install_terminating_signal_handler('SIGINT', ::Interrupt)
120
105
  end
106
+
107
+ def terminate_threads
108
+ threads = Thread.list - [Thread.current]
109
+ return if threads.empty?
110
+
111
+ threads.each(&:kill)
112
+ threads.each(&:join)
113
+ end
121
114
  end
122
115
  end
123
116