polyphony 0.36 → 0.38
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.
- 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
|
|