polyphony 0.34 → 0.41

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