polyphony 0.43.8 → 0.45.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +7 -1
  3. data/CHANGELOG.md +38 -0
  4. data/Gemfile.lock +13 -11
  5. data/README.md +20 -5
  6. data/Rakefile +1 -1
  7. data/TODO.md +16 -14
  8. data/bin/stress.rb +28 -0
  9. data/docs/_posts/2020-07-26-polyphony-0.44.md +77 -0
  10. data/docs/api-reference/thread.md +1 -1
  11. data/docs/getting-started/overview.md +14 -14
  12. data/docs/getting-started/tutorial.md +1 -1
  13. data/examples/adapters/sequel_mysql.rb +23 -0
  14. data/examples/adapters/sequel_mysql_pool.rb +33 -0
  15. data/examples/core/{xx-agent.rb → xx-backend.rb} +5 -5
  16. data/examples/core/xx-channels.rb +4 -2
  17. data/examples/core/xx-using-a-mutex.rb +2 -1
  18. data/examples/io/xx-pry.rb +18 -0
  19. data/examples/io/xx-rack_server.rb +71 -0
  20. data/examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb +1 -1
  21. data/ext/polyphony/backend.h +41 -0
  22. data/ext/polyphony/event.c +86 -0
  23. data/ext/polyphony/extconf.rb +1 -1
  24. data/ext/polyphony/fiber.c +0 -5
  25. data/ext/polyphony/{libev_agent.c → libev_backend.c} +234 -228
  26. data/ext/polyphony/polyphony.c +4 -0
  27. data/ext/polyphony/polyphony.h +16 -16
  28. data/ext/polyphony/polyphony_ext.c +4 -2
  29. data/ext/polyphony/queue.c +52 -12
  30. data/ext/polyphony/thread.c +55 -42
  31. data/lib/polyphony.rb +25 -39
  32. data/lib/polyphony/adapters/irb.rb +2 -17
  33. data/lib/polyphony/adapters/mysql2.rb +19 -0
  34. data/lib/polyphony/adapters/postgres.rb +5 -5
  35. data/lib/polyphony/adapters/process.rb +2 -2
  36. data/lib/polyphony/adapters/readline.rb +17 -0
  37. data/lib/polyphony/adapters/sequel.rb +45 -0
  38. data/lib/polyphony/core/channel.rb +3 -34
  39. data/lib/polyphony/core/exceptions.rb +11 -0
  40. data/lib/polyphony/core/global_api.rb +11 -6
  41. data/lib/polyphony/core/resource_pool.rb +22 -71
  42. data/lib/polyphony/core/sync.rb +48 -9
  43. data/lib/polyphony/core/throttler.rb +1 -1
  44. data/lib/polyphony/extensions/core.rb +37 -19
  45. data/lib/polyphony/extensions/fiber.rb +5 -1
  46. data/lib/polyphony/extensions/io.rb +7 -8
  47. data/lib/polyphony/extensions/openssl.rb +6 -6
  48. data/lib/polyphony/extensions/socket.rb +12 -22
  49. data/lib/polyphony/extensions/thread.rb +6 -5
  50. data/lib/polyphony/net.rb +2 -1
  51. data/lib/polyphony/version.rb +1 -1
  52. data/polyphony.gemspec +6 -3
  53. data/test/helper.rb +1 -1
  54. data/test/{test_agent.rb → test_backend.rb} +22 -22
  55. data/test/test_event.rb +1 -0
  56. data/test/test_fiber.rb +21 -5
  57. data/test/test_io.rb +1 -1
  58. data/test/test_kernel.rb +5 -0
  59. data/test/test_queue.rb +20 -0
  60. data/test/test_resource_pool.rb +34 -43
  61. data/test/test_signal.rb +5 -29
  62. data/test/test_sync.rb +52 -0
  63. metadata +74 -30
  64. data/.gitbook.yaml +0 -4
  65. data/lib/polyphony/event.rb +0 -17
@@ -7,6 +7,7 @@ ID ID_caller;
7
7
  ID ID_clear;
8
8
  ID ID_each;
9
9
  ID ID_inspect;
10
+ ID ID_invoke;
10
11
  ID ID_new;
11
12
  ID ID_raise;
12
13
  ID ID_ivar_running;
@@ -21,6 +22,8 @@ ID ID_R;
21
22
  ID ID_W;
22
23
  ID ID_RW;
23
24
 
25
+ backend_interface_t backend_interface;
26
+
24
27
  VALUE Polyphony_snooze(VALUE self) {
25
28
  VALUE ret;
26
29
  VALUE fiber = rb_fiber_current();
@@ -58,6 +61,7 @@ void Init_Polyphony() {
58
61
  ID_clear = rb_intern("clear");
59
62
  ID_each = rb_intern("each");
60
63
  ID_inspect = rb_intern("inspect");
64
+ ID_invoke = rb_intern("invoke");
61
65
  ID_ivar_running = rb_intern("@running");
62
66
  ID_ivar_thread = rb_intern("@thread");
63
67
  ID_new = rb_intern("new");
@@ -4,20 +4,30 @@
4
4
  #include "ruby.h"
5
5
  #include "ruby/io.h"
6
6
  #include "libev.h"
7
+ #include "backend.h"
7
8
 
8
9
  // debugging
9
10
  #define OBJ_ID(obj) (NUM2LONG(rb_funcall(obj, rb_intern("object_id"), 0)))
10
- #define INSPECT(obj) { VALUE s = rb_funcall(obj, rb_intern("inspect"), 0); printf("%s\n", StringValueCStr(s));}
11
- #define FIBER_TRACE(...) if (__tracing_enabled__) { \
12
- rb_funcall(rb_cObject, ID_fiber_trace, __VA_ARGS__); \
11
+ #define INSPECT(str, obj) { printf(str); VALUE s = rb_funcall(obj, rb_intern("inspect"), 0); printf("%s\n", StringValueCStr(s)); }
12
+ #define TRACE_CALLER() { VALUE c = rb_funcall(rb_mKernel, rb_intern("caller"), 0); INSPECT("caller: ", c); }
13
+
14
+ // tracing
15
+ #define TRACE(...) rb_funcall(rb_cObject, ID_fiber_trace, __VA_ARGS__)
16
+ #define COND_TRACE(...) if (__tracing_enabled__) { \
17
+ TRACE(__VA_ARGS__); \
13
18
  }
14
19
 
15
20
  #define TEST_EXCEPTION(ret) (RTEST(rb_obj_is_kind_of(ret, rb_eException)))
16
21
 
22
+ #define RAISE_EXCEPTION(e) rb_funcall(e, ID_invoke, 0);
17
23
  #define TEST_RESUME_EXCEPTION(ret) if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) { \
18
- return rb_funcall(rb_mKernel, ID_raise, 1, ret); \
24
+ return RAISE_EXCEPTION(ret); \
19
25
  }
20
26
 
27
+
28
+ extern backend_interface_t backend_interface;
29
+ #define __BACKEND__ (backend_interface)
30
+
21
31
  extern VALUE mPolyphony;
22
32
  extern VALUE cQueue;
23
33
  extern VALUE cEvent;
@@ -28,7 +38,8 @@ extern ID ID_clear;
28
38
  extern ID ID_each;
29
39
  extern ID ID_fiber_trace;
30
40
  extern ID ID_inspect;
31
- extern ID ID_ivar_agent;
41
+ extern ID ID_invoke;
42
+ extern ID ID_ivar_backend;
32
43
  extern ID ID_ivar_running;
33
44
  extern ID ID_ivar_thread;
34
45
  extern ID ID_new;
@@ -65,17 +76,6 @@ enum {
65
76
  VALUE Fiber_auto_watcher(VALUE self);
66
77
  void Fiber_make_runnable(VALUE fiber, VALUE value);
67
78
 
68
- VALUE LibevAgent_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE queue);
69
- VALUE LibevAgent_break(VALUE self);
70
- VALUE LibevAgent_pending_count(VALUE self);
71
- VALUE LibevAgent_wait_io(VALUE self, VALUE io, VALUE write);
72
-
73
- VALUE LibevAgent_ref(VALUE self);
74
- VALUE LibevAgent_unref(VALUE self);
75
- int LibevAgent_ref_count(VALUE self);
76
- void LibevAgent_reset_ref_count(VALUE self);
77
- VALUE LibevAgent_wait_event(VALUE self, VALUE raise);
78
-
79
79
  VALUE Queue_push(VALUE self, VALUE value);
80
80
  VALUE Queue_unshift(VALUE self, VALUE value);
81
81
  VALUE Queue_shift(VALUE self);
@@ -2,8 +2,9 @@
2
2
 
3
3
  void Init_Fiber();
4
4
  void Init_Polyphony();
5
- void Init_LibevAgent();
5
+ void Init_LibevBackend();
6
6
  void Init_Queue();
7
+ void Init_Event();
7
8
  void Init_Thread();
8
9
  void Init_Tracing();
9
10
 
@@ -11,8 +12,9 @@ void Init_polyphony_ext() {
11
12
  ev_set_allocator(xrealloc);
12
13
 
13
14
  Init_Polyphony();
14
- Init_LibevAgent();
15
+ Init_LibevBackend();
15
16
  Init_Queue();
17
+ Init_Event();
16
18
 
17
19
  Init_Fiber();
18
20
  Init_Thread();
@@ -54,6 +54,7 @@ static VALUE Queue_initialize(VALUE self) {
54
54
  VALUE Queue_push(VALUE self, VALUE value) {
55
55
  Queue_t *queue;
56
56
  GetQueue(self, queue);
57
+
57
58
  if (queue->shift_queue.count > 0) {
58
59
  VALUE fiber = ring_buffer_shift(&queue->shift_queue);
59
60
  if (fiber != Qnil) Fiber_make_runnable(fiber, Qnil);
@@ -77,21 +78,26 @@ VALUE Queue_shift(VALUE self) {
77
78
  Queue_t *queue;
78
79
  GetQueue(self, queue);
79
80
 
80
- if (queue->values.count == 0) {
81
- VALUE agent = rb_ivar_get(rb_thread_current(), ID_ivar_agent);
82
- VALUE fiber = rb_fiber_current();
83
- VALUE switchpoint_result = Qnil;
81
+ VALUE fiber = rb_fiber_current();
82
+ VALUE thread = rb_thread_current();
83
+ VALUE backend = rb_ivar_get(thread, ID_ivar_backend);
84
+
85
+ while (1) {
84
86
  ring_buffer_push(&queue->shift_queue, fiber);
85
- switchpoint_result = LibevAgent_wait_event(agent, Qnil);
86
- if (RTEST(rb_obj_is_kind_of(switchpoint_result, rb_eException))) {
87
- ring_buffer_delete(&queue->shift_queue, fiber);
87
+ if (queue->values.count > 0) Fiber_make_runnable(fiber, Qnil);
88
+
89
+ VALUE switchpoint_result = __BACKEND__.wait_event(backend, Qnil);
90
+ ring_buffer_delete(&queue->shift_queue, fiber);
91
+
92
+ if (RTEST(rb_obj_is_kind_of(switchpoint_result, rb_eException)))
88
93
  return rb_funcall(rb_mKernel, ID_raise, 1, switchpoint_result);
89
- }
90
- RB_GC_GUARD(agent);
91
94
  RB_GC_GUARD(switchpoint_result);
95
+
96
+ if (queue->values.count > 0)
97
+ return ring_buffer_shift(&queue->values);
92
98
  }
93
99
 
94
- return ring_buffer_shift(&queue->values);
100
+ return Qnil;
95
101
  }
96
102
 
97
103
  VALUE Queue_shift_no_wait(VALUE self) {
@@ -139,6 +145,18 @@ VALUE Queue_shift_all(VALUE self) {
139
145
  return ring_buffer_shift_all(&queue->values);
140
146
  }
141
147
 
148
+ VALUE Queue_flush_waiters(VALUE self, VALUE value) {
149
+ Queue_t *queue;
150
+ GetQueue(self, queue);
151
+
152
+ while(1) {
153
+ VALUE fiber = ring_buffer_shift(&queue->shift_queue);
154
+ if (fiber == Qnil) return self;
155
+
156
+ Fiber_make_runnable(fiber, value);
157
+ }
158
+ }
159
+
142
160
  VALUE Queue_empty_p(VALUE self) {
143
161
  Queue_t *queue;
144
162
  GetQueue(self, queue);
@@ -146,6 +164,27 @@ VALUE Queue_empty_p(VALUE self) {
146
164
  return (queue->values.count == 0) ? Qtrue : Qfalse;
147
165
  }
148
166
 
167
+ VALUE Queue_pending_p(VALUE self) {
168
+ Queue_t *queue;
169
+ GetQueue(self, queue);
170
+
171
+ return (queue->shift_queue.count > 0) ? Qtrue : Qfalse;
172
+ }
173
+
174
+ VALUE Queue_size_m(VALUE self) {
175
+ Queue_t *queue;
176
+ GetQueue(self, queue);
177
+
178
+ return INT2NUM(queue->values.count);
179
+ }
180
+
181
+ void Queue_trace(VALUE self) {
182
+ Queue_t *queue;
183
+ GetQueue(self, queue);
184
+
185
+ printf("run queue size: %d count: %d\n", queue->values.size, queue->values.count);
186
+ }
187
+
149
188
  void Init_Queue() {
150
189
  cQueue = rb_define_class_under(mPolyphony, "Queue", rb_cData);
151
190
  rb_define_alloc_func(cQueue, Queue_allocate);
@@ -162,7 +201,8 @@ void Init_Queue() {
162
201
 
163
202
  rb_define_method(cQueue, "shift_each", Queue_shift_each, 0);
164
203
  rb_define_method(cQueue, "shift_all", Queue_shift_all, 0);
204
+ rb_define_method(cQueue, "flush_waiters", Queue_flush_waiters, 1);
165
205
  rb_define_method(cQueue, "empty?", Queue_empty_p, 0);
206
+ rb_define_method(cQueue, "pending?", Queue_pending_p, 0);
207
+ rb_define_method(cQueue, "size", Queue_size_m, 0);
166
208
  }
167
-
168
-
@@ -1,7 +1,7 @@
1
1
  #include "polyphony.h"
2
2
 
3
3
  ID ID_deactivate_all_watchers_post_fork;
4
- ID ID_ivar_agent;
4
+ ID ID_ivar_backend;
5
5
  ID ID_ivar_join_wait_queue;
6
6
  ID ID_ivar_main_fiber;
7
7
  ID ID_ivar_result;
@@ -20,20 +20,20 @@ static VALUE Thread_setup_fiber_scheduling(VALUE self) {
20
20
  }
21
21
 
22
22
  int Thread_fiber_ref_count(VALUE self) {
23
- VALUE agent = rb_ivar_get(self, ID_ivar_agent);
24
- return NUM2INT(LibevAgent_ref_count(agent));
23
+ VALUE backend = rb_ivar_get(self, ID_ivar_backend);
24
+ return NUM2INT(__BACKEND__.ref_count(backend));
25
25
  }
26
26
 
27
27
  inline void Thread_fiber_reset_ref_count(VALUE self) {
28
- VALUE agent = rb_ivar_get(self, ID_ivar_agent);
29
- LibevAgent_reset_ref_count(agent);
28
+ VALUE backend = rb_ivar_get(self, ID_ivar_backend);
29
+ __BACKEND__.reset_ref_count(backend);
30
30
  }
31
31
 
32
32
  static VALUE SYM_scheduled_fibers;
33
33
  static VALUE SYM_pending_watchers;
34
34
 
35
35
  static VALUE Thread_fiber_scheduling_stats(VALUE self) {
36
- VALUE agent = rb_ivar_get(self,ID_ivar_agent);
36
+ VALUE backend = rb_ivar_get(self,ID_ivar_backend);
37
37
  VALUE stats = rb_hash_new();
38
38
  VALUE queue = rb_ivar_get(self, ID_run_queue);
39
39
  long pending_count;
@@ -41,7 +41,7 @@ static VALUE Thread_fiber_scheduling_stats(VALUE self) {
41
41
  long scheduled_count = RARRAY_LEN(queue);
42
42
  rb_hash_aset(stats, SYM_scheduled_fibers, INT2NUM(scheduled_count));
43
43
 
44
- pending_count = LibevAgent_pending_count(agent);
44
+ pending_count = __BACKEND__.pending_count(backend);
45
45
  rb_hash_aset(stats, SYM_pending_watchers, INT2NUM(pending_count));
46
46
 
47
47
  return stats;
@@ -52,25 +52,34 @@ VALUE Thread_schedule_fiber(VALUE self, VALUE fiber, VALUE value) {
52
52
 
53
53
  if (rb_fiber_alive_p(fiber) != Qtrue) return self;
54
54
 
55
- FIBER_TRACE(3, SYM_fiber_schedule, fiber, value);
56
- // if fiber is already scheduled, just set the scheduled value, then return
57
- rb_ivar_set(fiber, ID_runnable_value, value);
58
- if (rb_ivar_get(fiber, ID_runnable) != Qnil) {
59
- return self;
55
+ int already_runnable = rb_ivar_get(fiber, ID_runnable) != Qnil;
56
+
57
+ if (already_runnable) {
58
+ VALUE current_runnable_value = rb_ivar_get(fiber, ID_runnable_value);
59
+
60
+ // If the fiber is already runnable and the runnable value is an exception,
61
+ // we don't update the value, in order to prevent a race condition where
62
+ // exceptions will be lost (see issue #33)
63
+ if (TEST_EXCEPTION(current_runnable_value)) return self;
60
64
  }
61
65
 
62
- queue = rb_ivar_get(self, ID_run_queue);
63
- Queue_push(queue, fiber);
64
- rb_ivar_set(fiber, ID_runnable, Qtrue);
66
+ rb_ivar_set(fiber, ID_runnable_value, value);
67
+ COND_TRACE(3, SYM_fiber_schedule, fiber, value);
65
68
 
66
- if (rb_thread_current() != self) {
67
- // if the fiber scheduling is done across threads, we need to make sure the
68
- // target thread is woken up in case it is in the middle of running its
69
- // event selector. Otherwise it's gonna be stuck waiting for an event to
70
- // happen, not knowing that it there's already a fiber ready to run in its
71
- // run queue.
72
- VALUE agent = rb_ivar_get(self,ID_ivar_agent);
73
- LibevAgent_break(agent);
69
+ if (!already_runnable) {
70
+ queue = rb_ivar_get(self, ID_run_queue);
71
+ Queue_push(queue, fiber);
72
+ rb_ivar_set(fiber, ID_runnable, Qtrue);
73
+
74
+ if (rb_thread_current() != self) {
75
+ // If the fiber scheduling is done across threads, we need to make sure the
76
+ // target thread is woken up in case it is in the middle of running its
77
+ // event selector. Otherwise it's gonna be stuck waiting for an event to
78
+ // happen, not knowing that it there's already a fiber ready to run in its
79
+ // run queue.
80
+ VALUE backend = rb_ivar_get(self,ID_ivar_backend);
81
+ __BACKEND__.wakeup(backend);
82
+ }
74
83
  }
75
84
  return self;
76
85
  }
@@ -80,7 +89,7 @@ VALUE Thread_schedule_fiber_with_priority(VALUE self, VALUE fiber, VALUE value)
80
89
 
81
90
  if (rb_fiber_alive_p(fiber) != Qtrue) return self;
82
91
 
83
- FIBER_TRACE(3, SYM_fiber_schedule, fiber, value);
92
+ COND_TRACE(3, SYM_fiber_schedule, fiber, value);
84
93
  rb_ivar_set(fiber, ID_runnable_value, value);
85
94
 
86
95
  queue = rb_ivar_get(self, ID_run_queue);
@@ -101,8 +110,8 @@ VALUE Thread_schedule_fiber_with_priority(VALUE self, VALUE fiber, VALUE value)
101
110
  // event loop. Otherwise it's gonna be stuck waiting for an event to
102
111
  // happen, not knowing that it there's already a fiber ready to run in its
103
112
  // run queue.
104
- VALUE agent = rb_ivar_get(self, ID_ivar_agent);
105
- LibevAgent_break(agent);
113
+ VALUE backend = rb_ivar_get(self, ID_ivar_backend);
114
+ __BACKEND__.wakeup(backend);
106
115
  }
107
116
  return self;
108
117
  }
@@ -112,38 +121,35 @@ VALUE Thread_switch_fiber(VALUE self) {
112
121
  VALUE queue = rb_ivar_get(self, ID_run_queue);
113
122
  VALUE next_fiber;
114
123
  VALUE value;
115
- VALUE agent = rb_ivar_get(self, ID_ivar_agent);
124
+ VALUE backend = rb_ivar_get(self, ID_ivar_backend);
116
125
  int ref_count;
117
- int agent_was_polled = 0;1;
126
+ int backend_was_polled = 0;
118
127
 
119
- if (__tracing_enabled__) {
120
- if (rb_ivar_get(current_fiber, ID_ivar_running) != Qfalse) {
121
- rb_funcall(rb_cObject, ID_fiber_trace, 2, SYM_fiber_switchpoint, current_fiber);
122
- }
123
- }
128
+ if (__tracing_enabled__ && (rb_ivar_get(current_fiber, ID_ivar_running) != Qfalse))
129
+ TRACE(2, SYM_fiber_switchpoint, current_fiber);
124
130
 
125
- ref_count = LibevAgent_ref_count(agent);
131
+ ref_count = __BACKEND__.ref_count(backend);
126
132
  while (1) {
127
133
  next_fiber = Queue_shift_no_wait(queue);
128
134
  if (next_fiber != Qnil) {
129
- if (agent_was_polled == 0 && ref_count > 0) {
135
+ if (backend_was_polled == 0 && ref_count > 0) {
130
136
  // this mechanism prevents event starvation in case the run queue never
131
137
  // empties
132
- LibevAgent_poll(agent, Qtrue, current_fiber, queue);
138
+ __BACKEND__.poll(backend, Qtrue, current_fiber, queue);
133
139
  }
134
140
  break;
135
141
  }
136
142
  if (ref_count == 0) break;
137
143
 
138
- LibevAgent_poll(agent, Qnil, current_fiber, queue);
139
- agent_was_polled = 1;
144
+ __BACKEND__.poll(backend, Qnil, current_fiber, queue);
145
+ backend_was_polled = 1;
140
146
  }
141
147
 
142
148
  if (next_fiber == Qnil) return Qnil;
143
149
 
144
150
  // run next fiber
145
151
  value = rb_ivar_get(next_fiber, ID_runnable_value);
146
- FIBER_TRACE(3, SYM_fiber_run, next_fiber, value);
152
+ COND_TRACE(3, SYM_fiber_run, next_fiber, value);
147
153
 
148
154
  rb_ivar_set(next_fiber, ID_runnable, Qnil);
149
155
  RB_GC_GUARD(next_fiber);
@@ -166,12 +172,12 @@ VALUE Thread_reset_fiber_scheduling(VALUE self) {
166
172
  }
167
173
 
168
174
  VALUE Thread_fiber_break_out_of_ev_loop(VALUE self, VALUE fiber, VALUE resume_obj) {
169
- VALUE agent = rb_ivar_get(self, ID_ivar_agent);
175
+ VALUE backend = rb_ivar_get(self, ID_ivar_backend);
170
176
  if (fiber != Qnil) {
171
177
  Thread_schedule_fiber_with_priority(self, fiber, resume_obj);
172
178
  }
173
179
 
174
- if (LibevAgent_break(agent) == Qnil) {
180
+ if (__BACKEND__.wakeup(backend) == Qnil) {
175
181
  // we're not inside the ev_loop, so we just do a switchpoint
176
182
  Thread_switch_fiber(self);
177
183
  }
@@ -179,6 +185,11 @@ VALUE Thread_fiber_break_out_of_ev_loop(VALUE self, VALUE fiber, VALUE resume_ob
179
185
  return self;
180
186
  }
181
187
 
188
+ VALUE Thread_debug(VALUE self) {
189
+ rb_ivar_set(self, rb_intern("@__debug__"), Qtrue);
190
+ return self;
191
+ }
192
+
182
193
  void Init_Thread() {
183
194
  rb_define_method(rb_cThread, "setup_fiber_scheduling", Thread_setup_fiber_scheduling, 0);
184
195
  rb_define_method(rb_cThread, "reset_fiber_scheduling", Thread_reset_fiber_scheduling, 0);
@@ -191,8 +202,10 @@ void Init_Thread() {
191
202
  rb_define_method(rb_cThread, "switch_fiber", Thread_switch_fiber, 0);
192
203
  rb_define_method(rb_cThread, "run_queue_trace", Thread_run_queue_trace, 0);
193
204
 
205
+ rb_define_method(rb_cThread, "debug!", Thread_debug, 0);
206
+
194
207
  ID_deactivate_all_watchers_post_fork = rb_intern("deactivate_all_watchers_post_fork");
195
- ID_ivar_agent = rb_intern("@agent");
208
+ ID_ivar_backend = rb_intern("@backend");
196
209
  ID_ivar_join_wait_queue = rb_intern("@join_wait_queue");
197
210
  ID_ivar_main_fiber = rb_intern("@main_fiber");
198
211
  ID_ivar_result = rb_intern("@result");
@@ -3,51 +3,36 @@
3
3
  require 'fiber'
4
4
  require_relative './polyphony_ext'
5
5
 
6
- module Polyphony
7
- # replace core Queue class with our own
8
- verbose = $VERBOSE
9
- $VERBOSE = nil
10
- Object.const_set(:Queue, Polyphony::Queue)
11
- $VERBOSE = verbose
12
- end
13
-
14
6
  require_relative './polyphony/extensions/core'
15
7
  require_relative './polyphony/extensions/thread'
16
8
  require_relative './polyphony/extensions/fiber'
17
9
  require_relative './polyphony/extensions/io'
18
10
 
19
11
  Thread.current.setup_fiber_scheduling
20
- Thread.current.agent = Polyphony::LibevAgent.new
12
+ Thread.current.backend = Polyphony::Backend.new
21
13
 
22
14
  require_relative './polyphony/core/global_api'
23
15
  require_relative './polyphony/core/resource_pool'
16
+ require_relative './polyphony/core/sync'
24
17
  require_relative './polyphony/net'
25
18
  require_relative './polyphony/adapters/process'
26
- require_relative './polyphony/event'
27
19
 
28
- # Main Polyphony API
20
+ # Polyphony API
29
21
  module Polyphony
30
22
  class << self
31
- def wait_for_signal(sig)
32
- raise "should be reimplemented"
33
-
34
- fiber = Fiber.current
35
- # Polyphony.ref
36
- old_trap = trap(sig) do
37
- # Polyphony.unref
38
- fiber.schedule(sig)
39
- trap(sig, old_trap)
40
- end
41
- suspend
42
-
43
- end
44
-
45
23
  def fork(&block)
46
24
  Kernel.fork do
47
- # # Since the fiber doing the fork will become the main fiber of the
48
- # # forked process, we leave it behind by transferring to a new fiber
49
- # # created in the context of the forked process, which rescues *all*
50
- # # exceptions, including Interrupt and SystemExit.
25
+ # A race condition can arise if a TERM or INT signal is received before
26
+ # the forked process has finished initializing. To prevent this we restore
27
+ # the default signal handlers, and then reinstall the custom Polyphony
28
+ # handlers just before running the given block.
29
+ trap('SIGTERM', 'DEFAULT')
30
+ trap('SIGINT', 'DEFAULT')
31
+
32
+ # Since the fiber doing the fork will become the main fiber of the
33
+ # forked process, we leave it behind by transferring to a new fiber
34
+ # created in the context of the forked process, which rescues *all*
35
+ # exceptions, including Interrupt and SystemExit.
51
36
  spin_forked_block(&block).transfer
52
37
  end
53
38
  end
@@ -58,7 +43,7 @@ module Polyphony
58
43
  rescue SystemExit
59
44
  # fall through to ensure
60
45
  rescue Exception => e
61
- e.full_message
46
+ warn e.full_message
62
47
  exit!
63
48
  ensure
64
49
  exit_forked_process
@@ -66,16 +51,9 @@ module Polyphony
66
51
  end
67
52
 
68
53
  def run_forked_block(&block)
69
- # A race condition can arise if a TERM or INT signal is received before
70
- # the forked process has finished initializing. To prevent this we restore
71
- # the default signal handlers, and then reinstall the custom Polyphony
72
- # handlers just before running the given block.
73
- trap('SIGTERM', 'DEFAULT')
74
- trap('SIGINT', 'DEFAULT')
75
-
76
54
  Thread.current.setup
77
55
  Fiber.current.setup_main_fiber
78
- Thread.current.agent.post_fork
56
+ Thread.current.backend.post_fork
79
57
 
80
58
  install_terminating_signal_handlers
81
59
 
@@ -124,12 +102,20 @@ module Polyphony
124
102
  # processes (see Polyphony.fork).
125
103
  at_exit do
126
104
  next unless @original_pid == ::Process.pid
127
-
105
+
128
106
  Polyphony.terminate_threads
129
107
  Fiber.current.shutdown_all_children
130
108
  end
131
109
  end
132
110
  end
111
+
112
+ # replace core Queue class with our own
113
+ verbose = $VERBOSE
114
+ $VERBOSE = nil
115
+ Object.const_set(:Queue, Polyphony::Queue)
116
+ Object.const_set(:Mutex, Polyphony::Mutex)
117
+ Object.const_set(:ConditionVariable, Polyphony::ConditionVariable)
118
+ $VERBOSE = verbose
133
119
  end
134
120
 
135
121
  Polyphony.install_terminating_signal_handlers