polyphony 0.36 → 0.38
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/Gemfile +0 -11
- data/Gemfile.lock +1 -3
- data/Rakefile +4 -0
- data/TODO.md +12 -10
- data/docs/index.md +2 -1
- data/examples/core/xx-fork-cleanup.rb +22 -0
- data/ext/gyro/async.c +27 -13
- data/ext/gyro/child.c +29 -15
- data/ext/gyro/fiber.c +3 -1
- data/ext/gyro/gyro.c +0 -6
- data/ext/gyro/gyro.h +6 -0
- data/ext/gyro/io.c +24 -9
- data/ext/gyro/queue.c +21 -21
- data/ext/gyro/selector.c +23 -0
- data/ext/gyro/signal.c +24 -9
- data/ext/gyro/thread.c +12 -2
- data/ext/gyro/timer.c +33 -18
- data/lib/polyphony.rb +27 -36
- data/lib/polyphony/adapters/fs.rb +1 -4
- data/lib/polyphony/adapters/process.rb +29 -25
- data/lib/polyphony/adapters/trace.rb +129 -124
- data/lib/polyphony/core/channel.rb +36 -36
- data/lib/polyphony/core/exceptions.rb +29 -29
- data/lib/polyphony/core/global_api.rb +92 -91
- data/lib/polyphony/core/resource_pool.rb +84 -84
- data/lib/polyphony/core/sync.rb +17 -17
- data/lib/polyphony/core/thread_pool.rb +49 -37
- data/lib/polyphony/core/throttler.rb +25 -25
- data/lib/polyphony/extensions/core.rb +3 -3
- data/lib/polyphony/extensions/fiber.rb +269 -267
- data/lib/polyphony/extensions/openssl.rb +1 -1
- data/lib/polyphony/extensions/socket.rb +2 -1
- data/lib/polyphony/extensions/thread.rb +3 -3
- data/lib/polyphony/net.rb +71 -67
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +0 -3
- data/test/stress.rb +17 -12
- data/test/test_thread.rb +1 -0
- data/test/test_thread_pool.rb +2 -2
- data/test/test_throttler.rb +0 -1
- metadata +3 -16
data/ext/gyro/queue.c
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
#include "gyro.h"
|
2
2
|
|
3
3
|
struct Gyro_Queue {
|
4
|
-
VALUE
|
5
|
-
VALUE
|
4
|
+
VALUE items;
|
5
|
+
VALUE shift_waiters;
|
6
6
|
};
|
7
7
|
|
8
8
|
VALUE cGyro_Queue = Qnil;
|
9
9
|
|
10
10
|
static void Gyro_Queue_mark(void *ptr) {
|
11
11
|
struct Gyro_Queue *queue = ptr;
|
12
|
-
if (queue->
|
13
|
-
rb_gc_mark(queue->
|
12
|
+
if (queue->items != Qnil) {
|
13
|
+
rb_gc_mark(queue->items);
|
14
14
|
}
|
15
|
-
if (queue->
|
16
|
-
rb_gc_mark(queue->
|
15
|
+
if (queue->shift_waiters != Qnil) {
|
16
|
+
rb_gc_mark(queue->shift_waiters);
|
17
17
|
}
|
18
18
|
}
|
19
19
|
|
@@ -43,22 +43,22 @@ static VALUE Gyro_Queue_initialize(VALUE self) {
|
|
43
43
|
struct Gyro_Queue *queue;
|
44
44
|
GetGyro_Queue(self, queue);
|
45
45
|
|
46
|
-
queue->
|
47
|
-
queue->
|
46
|
+
queue->items = rb_ary_new();
|
47
|
+
queue->shift_waiters = rb_ary_new();
|
48
48
|
|
49
|
-
return
|
49
|
+
return self;
|
50
50
|
}
|
51
51
|
|
52
52
|
VALUE Gyro_Queue_push(VALUE self, VALUE value) {
|
53
53
|
struct Gyro_Queue *queue;
|
54
54
|
GetGyro_Queue(self, queue);
|
55
55
|
|
56
|
-
if (RARRAY_LEN(queue->
|
57
|
-
VALUE async = rb_ary_shift(queue->
|
56
|
+
if (RARRAY_LEN(queue->shift_waiters) > 0) {
|
57
|
+
VALUE async = rb_ary_shift(queue->shift_waiters);
|
58
58
|
rb_funcall(async, ID_signal, 1, Qnil);
|
59
59
|
}
|
60
60
|
|
61
|
-
rb_ary_push(queue->
|
61
|
+
rb_ary_push(queue->items, value);
|
62
62
|
return self;
|
63
63
|
}
|
64
64
|
|
@@ -66,33 +66,33 @@ VALUE Gyro_Queue_shift(VALUE self) {
|
|
66
66
|
struct Gyro_Queue *queue;
|
67
67
|
GetGyro_Queue(self, queue);
|
68
68
|
|
69
|
-
if (RARRAY_LEN(queue->
|
69
|
+
if (RARRAY_LEN(queue->items) == 0) {
|
70
70
|
VALUE async = Fiber_auto_async(rb_fiber_current());
|
71
|
-
rb_ary_push(queue->
|
71
|
+
rb_ary_push(queue->shift_waiters, async);
|
72
72
|
VALUE ret = Gyro_Async_await_no_raise(async);
|
73
73
|
if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) {
|
74
|
-
rb_ary_delete(queue->
|
74
|
+
rb_ary_delete(queue->shift_waiters, async);
|
75
75
|
return rb_funcall(rb_mKernel, ID_raise, 1, ret);
|
76
76
|
}
|
77
77
|
RB_GC_GUARD(ret);
|
78
78
|
}
|
79
79
|
|
80
|
-
return rb_ary_shift(queue->
|
80
|
+
return rb_ary_shift(queue->items);
|
81
81
|
}
|
82
82
|
|
83
83
|
VALUE Gyro_Queue_shift_no_wait(VALUE self) {
|
84
84
|
struct Gyro_Queue *queue;
|
85
85
|
GetGyro_Queue(self, queue);
|
86
86
|
|
87
|
-
return rb_ary_shift(queue->
|
87
|
+
return rb_ary_shift(queue->items);
|
88
88
|
}
|
89
89
|
|
90
90
|
VALUE Gyro_Queue_shift_each(VALUE self) {
|
91
91
|
struct Gyro_Queue *queue;
|
92
92
|
GetGyro_Queue(self, queue);
|
93
93
|
|
94
|
-
VALUE old_queue = queue->
|
95
|
-
queue->
|
94
|
+
VALUE old_queue = queue->items;
|
95
|
+
queue->items = rb_ary_new();
|
96
96
|
|
97
97
|
if (rb_block_given_p()) {
|
98
98
|
long len = RARRAY_LEN(old_queue);
|
@@ -112,7 +112,7 @@ VALUE Gyro_Queue_clear(VALUE self) {
|
|
112
112
|
struct Gyro_Queue *queue;
|
113
113
|
GetGyro_Queue(self, queue);
|
114
114
|
|
115
|
-
rb_ary_clear(queue->
|
115
|
+
rb_ary_clear(queue->items);
|
116
116
|
return self;
|
117
117
|
}
|
118
118
|
|
@@ -120,7 +120,7 @@ VALUE Gyro_Queue_empty_p(VALUE self) {
|
|
120
120
|
struct Gyro_Queue *queue;
|
121
121
|
GetGyro_Queue(self, queue);
|
122
122
|
|
123
|
-
return (RARRAY_LEN(queue->
|
123
|
+
return (RARRAY_LEN(queue->items) == 0) ? Qtrue : Qfalse;
|
124
124
|
}
|
125
125
|
|
126
126
|
void Init_Gyro_Queue() {
|
data/ext/gyro/selector.c
CHANGED
@@ -174,6 +174,26 @@ VALUE Gyro_Selector_break_out_of_ev_loop(VALUE self) {
|
|
174
174
|
return Qnil;
|
175
175
|
}
|
176
176
|
|
177
|
+
ID ID_deactivate_post_fork;
|
178
|
+
|
179
|
+
static int deactivate_watcher(VALUE key, VALUE value, VALUE _) {
|
180
|
+
rb_funcall(key, ID_deactivate_post_fork, 0);
|
181
|
+
return ST_CONTINUE;
|
182
|
+
}
|
183
|
+
|
184
|
+
VALUE Gyro_Selector_deactivate_all_watchers_post_fork(VALUE self) {
|
185
|
+
struct Gyro_Selector *selector;
|
186
|
+
GetGyro_Selector(self, selector);
|
187
|
+
|
188
|
+
VALUE old_active_watchers = selector->active_watchers;
|
189
|
+
selector->active_watchers = rb_hash_new();
|
190
|
+
|
191
|
+
rb_hash_foreach(old_active_watchers, deactivate_watcher, Qnil);
|
192
|
+
|
193
|
+
RB_GC_GUARD(old_active_watchers);
|
194
|
+
return self;
|
195
|
+
}
|
196
|
+
|
177
197
|
inline static VALUE Gyro_Selector_wait_readable(VALUE self, VALUE io) {
|
178
198
|
VALUE watcher = IO_read_watcher(io);
|
179
199
|
return Gyro_IO_await(watcher);
|
@@ -202,4 +222,7 @@ void Init_Gyro_Selector() {
|
|
202
222
|
rb_define_method(cGyro_Selector, "wait_writable", Gyro_Selector_wait_writable, 1);
|
203
223
|
rb_define_method(cGyro_Selector, "wait_timeout", Gyro_Selector_wait_timeout, 1);
|
204
224
|
rb_define_method(cGyro_Selector, "break_out_of_ev_loop", Gyro_Selector_break_out_of_ev_loop, 0);
|
225
|
+
rb_define_method(cGyro_Selector, "deactivate_all_watchers_post_fork", Gyro_Selector_deactivate_all_watchers_post_fork, 0);
|
226
|
+
|
227
|
+
ID_deactivate_post_fork = rb_intern("deactivate_post_fork");
|
205
228
|
}
|
data/ext/gyro/signal.c
CHANGED
@@ -24,11 +24,15 @@ static void Gyro_Signal_mark(void *ptr) {
|
|
24
24
|
|
25
25
|
static void Gyro_Signal_free(void *ptr) {
|
26
26
|
struct Gyro_Signal *signal = ptr;
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
switch (signal->active) {
|
28
|
+
case GYRO_WATCHER_POST_FORK:
|
29
|
+
return;
|
30
|
+
case 1:
|
31
|
+
ev_clear_pending(signal->ev_loop, &signal->ev_signal);
|
32
|
+
ev_signal_stop(signal->ev_loop, &signal->ev_signal);
|
33
|
+
default:
|
34
|
+
xfree(signal);
|
30
35
|
}
|
31
|
-
xfree(signal);
|
32
36
|
}
|
33
37
|
|
34
38
|
static size_t Gyro_Signal_size(const void *ptr) {
|
@@ -46,7 +50,7 @@ static VALUE Gyro_Signal_allocate(VALUE klass) {
|
|
46
50
|
return TypedData_Wrap_Struct(klass, &Gyro_Signal_type, signal);
|
47
51
|
}
|
48
52
|
|
49
|
-
inline void
|
53
|
+
inline void signal_activate(struct Gyro_Signal *signal) {
|
50
54
|
if (signal->active) return;
|
51
55
|
|
52
56
|
signal->active = 1;
|
@@ -57,7 +61,7 @@ inline void Gyro_Signal_activate(struct Gyro_Signal *signal) {
|
|
57
61
|
ev_signal_start(signal->ev_loop, &signal->ev_signal);
|
58
62
|
}
|
59
63
|
|
60
|
-
inline void
|
64
|
+
inline void signal_deactivate(struct Gyro_Signal *signal) {
|
61
65
|
if (!signal->active) return;
|
62
66
|
|
63
67
|
ev_signal_stop(signal->ev_loop, &signal->ev_signal);
|
@@ -72,7 +76,7 @@ void Gyro_Signal_callback(struct ev_loop *ev_loop, struct ev_signal *ev_signal,
|
|
72
76
|
struct Gyro_Signal *signal = (struct Gyro_Signal*)ev_signal;
|
73
77
|
|
74
78
|
Fiber_make_runnable(signal->fiber, INT2NUM(signal->signum));
|
75
|
-
|
79
|
+
signal_deactivate(signal);
|
76
80
|
}
|
77
81
|
|
78
82
|
#define GetGyro_Signal(obj, signal) \
|
@@ -100,19 +104,30 @@ static VALUE Gyro_Signal_await(VALUE self) {
|
|
100
104
|
struct Gyro_Signal *signal;
|
101
105
|
GetGyro_Signal(self, signal);
|
102
106
|
|
103
|
-
|
107
|
+
signal_activate(signal);
|
104
108
|
VALUE ret = Gyro_switchpoint();
|
105
|
-
|
109
|
+
signal_deactivate(signal);
|
106
110
|
|
107
111
|
TEST_RESUME_EXCEPTION(ret);
|
108
112
|
RB_GC_GUARD(ret);
|
109
113
|
return ret;
|
110
114
|
}
|
111
115
|
|
116
|
+
VALUE Gyro_Signal_deactivate_post_fork(VALUE self) {
|
117
|
+
struct Gyro_Signal *signal;
|
118
|
+
GetGyro_Signal(self, signal);
|
119
|
+
|
120
|
+
if (signal->active)
|
121
|
+
signal->active = GYRO_WATCHER_POST_FORK;
|
122
|
+
|
123
|
+
return self;
|
124
|
+
}
|
125
|
+
|
112
126
|
void Init_Gyro_Signal() {
|
113
127
|
cGyro_Signal = rb_define_class_under(mGyro, "Signal", rb_cData);
|
114
128
|
rb_define_alloc_func(cGyro_Signal, Gyro_Signal_allocate);
|
115
129
|
|
116
130
|
rb_define_method(cGyro_Signal, "initialize", Gyro_Signal_initialize, 1);
|
117
131
|
rb_define_method(cGyro_Signal, "await", Gyro_Signal_await, 0);
|
132
|
+
rb_define_method(cGyro_Signal, "deactivate_post_fork", Gyro_Signal_deactivate_post_fork, 0);
|
118
133
|
}
|
data/ext/gyro/thread.c
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
static VALUE cQueue;
|
4
4
|
|
5
5
|
static ID ID_create_event_selector;
|
6
|
+
static ID ID_deactivate_all_watchers_post_fork;
|
6
7
|
static ID ID_empty;
|
7
8
|
static ID ID_fiber_ref_count;
|
8
9
|
static ID ID_ivar_event_selector_proc;
|
@@ -14,8 +15,6 @@ static ID ID_ivar_terminated;
|
|
14
15
|
static ID ID_pop;
|
15
16
|
static ID ID_push;
|
16
17
|
static ID ID_run_queue;
|
17
|
-
// static ID ID_run_queue_head;
|
18
|
-
// static ID ID_run_queue_tail;
|
19
18
|
static ID ID_runnable_next;
|
20
19
|
static ID ID_stop;
|
21
20
|
|
@@ -63,6 +62,15 @@ static VALUE Thread_stop_event_selector(VALUE self) {
|
|
63
62
|
return self;
|
64
63
|
}
|
65
64
|
|
65
|
+
static VALUE Thread_deactivate_all_watchers_post_fork(VALUE self) {
|
66
|
+
VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
|
67
|
+
if (selector != Qnil) {
|
68
|
+
rb_funcall(selector, ID_deactivate_all_watchers_post_fork, 0);
|
69
|
+
}
|
70
|
+
|
71
|
+
return self;
|
72
|
+
}
|
73
|
+
|
66
74
|
VALUE Thread_ref(VALUE self) {
|
67
75
|
VALUE count = rb_ivar_get(self, ID_fiber_ref_count);
|
68
76
|
int new_count = NUM2INT(count) + 1;
|
@@ -267,6 +275,7 @@ void Init_Thread() {
|
|
267
275
|
|
268
276
|
rb_define_method(rb_cThread, "setup_fiber_scheduling", Thread_setup_fiber_scheduling, 0);
|
269
277
|
rb_define_method(rb_cThread, "stop_event_selector", Thread_stop_event_selector, 0);
|
278
|
+
rb_define_method(rb_cThread, "deactivate_all_watchers_post_fork", Thread_deactivate_all_watchers_post_fork, 0);
|
270
279
|
rb_define_method(rb_cThread, "reset_fiber_scheduling", Thread_reset_fiber_scheduling, 0);
|
271
280
|
rb_define_method(rb_cThread, "fiber_scheduling_stats", Thread_fiber_scheduling_stats, 0);
|
272
281
|
rb_define_method(rb_cThread, "break_out_of_ev_loop", Thread_fiber_break_out_of_ev_loop, 2);
|
@@ -277,6 +286,7 @@ void Init_Thread() {
|
|
277
286
|
rb_define_method(rb_cThread, "switch_fiber", Thread_switch_fiber, 0);
|
278
287
|
|
279
288
|
ID_create_event_selector = rb_intern("create_event_selector");
|
289
|
+
ID_deactivate_all_watchers_post_fork = rb_intern("deactivate_all_watchers_post_fork");
|
280
290
|
ID_empty = rb_intern("empty?");
|
281
291
|
ID_fiber_ref_count = rb_intern("fiber_ref_count");
|
282
292
|
ID_ivar_event_selector = rb_intern("@event_selector");
|
data/ext/gyro/timer.c
CHANGED
@@ -25,11 +25,15 @@ static void Gyro_Timer_mark(void *ptr) {
|
|
25
25
|
|
26
26
|
static void Gyro_Timer_free(void *ptr) {
|
27
27
|
struct Gyro_Timer *timer = ptr;
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
switch (timer->active) {
|
29
|
+
case GYRO_WATCHER_POST_FORK:
|
30
|
+
return;
|
31
|
+
case 1:
|
32
|
+
ev_clear_pending(timer->ev_loop, &timer->ev_timer);
|
33
|
+
ev_timer_stop(timer->ev_loop, &timer->ev_timer);
|
34
|
+
default:
|
35
|
+
xfree(timer);
|
31
36
|
}
|
32
|
-
xfree(timer);
|
33
37
|
}
|
34
38
|
|
35
39
|
static size_t Gyro_Timer_size(const void *ptr) {
|
@@ -50,7 +54,7 @@ static VALUE Gyro_Timer_allocate(VALUE klass) {
|
|
50
54
|
#define GetGyro_Timer(obj, timer) \
|
51
55
|
TypedData_Get_Struct((obj), struct Gyro_Timer, &Gyro_Timer_type, (timer))
|
52
56
|
|
53
|
-
inline void
|
57
|
+
inline void timer_activate(struct Gyro_Timer *timer) {
|
54
58
|
timer->fiber = rb_fiber_current();
|
55
59
|
timer->selector = Thread_current_event_selector();
|
56
60
|
timer->ev_loop = Gyro_Selector_ev_loop(timer->selector);
|
@@ -62,7 +66,7 @@ inline void Gyro_Timer_activate(struct Gyro_Timer *timer) {
|
|
62
66
|
ev_timer_start(timer->ev_loop, &timer->ev_timer);
|
63
67
|
}
|
64
68
|
|
65
|
-
inline void
|
69
|
+
inline void timer_deactivate(struct Gyro_Timer *timer, int non_recurring_only) {
|
66
70
|
if (!timer->active) return;
|
67
71
|
|
68
72
|
if (!timer->repeat || !non_recurring_only) {
|
@@ -82,7 +86,7 @@ void Gyro_Timer_callback(struct ev_loop *ev_loop, struct ev_timer *ev_timer, int
|
|
82
86
|
struct Gyro_Timer *timer = (struct Gyro_Timer*)ev_timer;
|
83
87
|
|
84
88
|
Fiber_make_runnable(timer->fiber, DBL2NUM(timer->after));
|
85
|
-
|
89
|
+
timer_deactivate(timer, 1);
|
86
90
|
}
|
87
91
|
|
88
92
|
static VALUE Gyro_Timer_initialize(VALUE self, VALUE after, VALUE repeat) {
|
@@ -90,13 +94,13 @@ static VALUE Gyro_Timer_initialize(VALUE self, VALUE after, VALUE repeat) {
|
|
90
94
|
|
91
95
|
GetGyro_Timer(self, timer);
|
92
96
|
|
93
|
-
timer->self
|
94
|
-
timer->fiber
|
95
|
-
timer->selector
|
96
|
-
timer->after
|
97
|
-
timer->repeat
|
98
|
-
timer->active
|
99
|
-
timer->ev_loop
|
97
|
+
timer->self = self;
|
98
|
+
timer->fiber = Qnil;
|
99
|
+
timer->selector = Qnil;
|
100
|
+
timer->after = NUM2DBL(after);
|
101
|
+
timer->repeat = NUM2DBL(repeat);
|
102
|
+
timer->active = 0;
|
103
|
+
timer->ev_loop = 0;
|
100
104
|
|
101
105
|
ev_timer_init(&timer->ev_timer, Gyro_Timer_callback, timer->after, timer->repeat);
|
102
106
|
|
@@ -107,7 +111,7 @@ VALUE Gyro_Timer_stop(VALUE self) {
|
|
107
111
|
struct Gyro_Timer *timer;
|
108
112
|
GetGyro_Timer(self, timer);
|
109
113
|
|
110
|
-
|
114
|
+
timer_deactivate(timer, 0);
|
111
115
|
return self;
|
112
116
|
}
|
113
117
|
|
@@ -115,20 +119,31 @@ VALUE Gyro_Timer_await(VALUE self) {
|
|
115
119
|
struct Gyro_Timer *timer;
|
116
120
|
GetGyro_Timer(self, timer);
|
117
121
|
|
118
|
-
|
122
|
+
timer_activate(timer);
|
119
123
|
VALUE ret = Gyro_switchpoint();
|
120
|
-
|
124
|
+
timer_deactivate(timer, 1);
|
121
125
|
|
122
126
|
TEST_RESUME_EXCEPTION(ret);
|
123
127
|
RB_GC_GUARD(ret);
|
124
128
|
return ret;
|
125
129
|
}
|
126
130
|
|
131
|
+
VALUE Gyro_Timer_deactivate_post_fork(VALUE self) {
|
132
|
+
struct Gyro_Timer *timer;
|
133
|
+
GetGyro_Timer(self, timer);
|
134
|
+
|
135
|
+
if (timer->active)
|
136
|
+
timer->active = GYRO_WATCHER_POST_FORK;
|
137
|
+
|
138
|
+
return self;
|
139
|
+
}
|
140
|
+
|
127
141
|
void Init_Gyro_Timer() {
|
128
142
|
cGyro_Timer = rb_define_class_under(mGyro, "Timer", rb_cData);
|
129
143
|
rb_define_alloc_func(cGyro_Timer, Gyro_Timer_allocate);
|
130
144
|
|
131
145
|
rb_define_method(cGyro_Timer, "initialize", Gyro_Timer_initialize, 2);
|
132
|
-
rb_define_method(cGyro_Timer, "stop", Gyro_Timer_stop, 0);
|
133
146
|
rb_define_method(cGyro_Timer, "await", Gyro_Timer_await, 0);
|
147
|
+
rb_define_method(cGyro_Timer, "deactivate_post_fork", Gyro_Timer_deactivate_post_fork, 0);
|
148
|
+
rb_define_method(cGyro_Timer, "stop", Gyro_Timer_stop, 0);
|
134
149
|
}
|
data/lib/polyphony.rb
CHANGED
@@ -1,44 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'modulation/gem'
|
4
|
-
|
5
|
-
export_default :Polyphony
|
6
|
-
|
7
3
|
require 'fiber'
|
8
4
|
require_relative './gyro_ext'
|
9
5
|
|
10
6
|
Thread.event_selector = Gyro::Selector
|
11
7
|
Thread.current.setup_fiber_scheduling
|
12
8
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
9
|
+
require_relative './polyphony/extensions/core'
|
10
|
+
require_relative './polyphony/extensions/thread'
|
11
|
+
require_relative './polyphony/extensions/fiber'
|
12
|
+
require_relative './polyphony/extensions/io'
|
13
|
+
|
14
|
+
require_relative './polyphony/core/global_api'
|
15
|
+
require_relative './polyphony/core/resource_pool'
|
16
|
+
require_relative './polyphony/net'
|
17
|
+
|
18
|
+
require_relative './polyphony/adapters/process'
|
17
19
|
|
18
20
|
# Main Polyphony API
|
19
21
|
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
22
|
class << self
|
43
23
|
def wait_for_signal(sig)
|
44
24
|
fiber = Fiber.current
|
@@ -52,7 +32,10 @@ module Polyphony
|
|
52
32
|
end
|
53
33
|
|
54
34
|
def fork(&block)
|
35
|
+
old_threads = Thread.list - [Thread.current]
|
55
36
|
Kernel.fork do
|
37
|
+
old_threads.each(&:deactivate_all_watchers_post_fork)
|
38
|
+
|
56
39
|
# Since the fiber doing the fork will become the main fiber of the
|
57
40
|
# forked process, we leave it behind by transferring to a new fiber
|
58
41
|
# created in the context of the forked process, which rescues *all*
|
@@ -64,12 +47,13 @@ module Polyphony
|
|
64
47
|
def spin_forked_block(&block)
|
65
48
|
Fiber.new do
|
66
49
|
run_forked_block(&block)
|
67
|
-
|
68
|
-
|
69
|
-
exit_forked_process
|
50
|
+
rescue SystemExit
|
51
|
+
# fall through to ensure
|
70
52
|
rescue Exception => e
|
71
53
|
e.full_message
|
72
54
|
exit!
|
55
|
+
ensure
|
56
|
+
exit_forked_process
|
73
57
|
end
|
74
58
|
end
|
75
59
|
|
@@ -91,14 +75,13 @@ module Polyphony
|
|
91
75
|
end
|
92
76
|
|
93
77
|
def exit_forked_process
|
78
|
+
terminate_threads
|
94
79
|
Fiber.current.shutdown_all_children
|
80
|
+
|
95
81
|
# Since fork could be called from any fiber, we explicitly call exit here.
|
96
82
|
# Otherwise, the fiber might want to pass execution to another fiber that
|
97
83
|
# previously transferred execution to the forking fiber, but doesn't exist
|
98
84
|
# 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
85
|
exit
|
103
86
|
end
|
104
87
|
|
@@ -118,6 +101,14 @@ module Polyphony
|
|
118
101
|
install_terminating_signal_handler('SIGTERM', ::SystemExit)
|
119
102
|
install_terminating_signal_handler('SIGINT', ::Interrupt)
|
120
103
|
end
|
104
|
+
|
105
|
+
def terminate_threads
|
106
|
+
threads = Thread.list - [Thread.current]
|
107
|
+
return if threads.empty?
|
108
|
+
|
109
|
+
threads.each(&:kill)
|
110
|
+
threads.each(&:join)
|
111
|
+
end
|
121
112
|
end
|
122
113
|
end
|
123
114
|
|