polyphony 0.41 → 0.43.3
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 +30 -0
- data/Gemfile.lock +6 -6
- data/README.md +0 -1
- data/Rakefile +1 -1
- data/TODO.md +18 -9
- data/docs/_config.yml +56 -7
- data/docs/_sass/custom/custom.scss +6 -26
- data/docs/_sass/overrides.scss +0 -46
- data/docs/{user-guide → _user-guide}/all-about-timers.md +0 -0
- data/docs/_user-guide/index.md +9 -0
- data/docs/{user-guide → _user-guide}/web-server.md +0 -0
- data/docs/api-reference/index.md +9 -0
- data/docs/api-reference/polyphony-process.md +1 -1
- data/docs/api-reference/thread.md +1 -1
- data/docs/faq.md +21 -11
- data/docs/favicon.ico +0 -0
- data/docs/getting-started/index.md +10 -0
- data/docs/getting-started/installing.md +2 -6
- data/docs/getting-started/overview.md +486 -0
- data/docs/getting-started/tutorial.md +27 -19
- data/docs/index.md +6 -2
- data/docs/main-concepts/concurrency.md +0 -5
- data/docs/main-concepts/design-principles.md +2 -12
- data/docs/main-concepts/index.md +9 -0
- data/docs/polyphony-logo.png +0 -0
- data/examples/adapters/concurrent-ruby.rb +9 -0
- data/examples/adapters/redis_blpop.rb +12 -0
- data/examples/core/01-spinning-up-fibers.rb +1 -0
- data/examples/core/03-interrupting.rb +4 -1
- data/examples/core/04-handling-signals.rb +19 -0
- data/examples/core/xx-daemon.rb +14 -0
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +6 -18
- data/examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb +58 -0
- data/examples/performance/xx-array.rb +11 -0
- data/examples/performance/xx-fiber-switch.rb +9 -0
- data/examples/performance/xx-snooze.rb +15 -0
- data/ext/polyphony/fiber.c +0 -3
- data/ext/polyphony/libev_agent.c +303 -81
- data/ext/polyphony/libev_queue.c +8 -5
- data/ext/polyphony/polyphony.c +0 -16
- data/ext/polyphony/polyphony.h +6 -6
- data/ext/polyphony/polyphony_ext.c +0 -2
- data/ext/polyphony/thread.c +8 -42
- data/lib/polyphony.rb +29 -2
- data/lib/polyphony/adapters/redis.rb +3 -2
- data/lib/polyphony/core/channel.rb +2 -2
- data/lib/polyphony/core/global_api.rb +6 -4
- data/lib/polyphony/core/resource_pool.rb +19 -9
- data/lib/polyphony/extensions/core.rb +8 -3
- data/lib/polyphony/extensions/fiber.rb +0 -12
- data/lib/polyphony/extensions/io.rb +4 -0
- data/lib/polyphony/extensions/openssl.rb +34 -10
- data/lib/polyphony/extensions/socket.rb +2 -2
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +1 -1
- data/test/test_agent.rb +59 -6
- data/test/test_fiber.rb +3 -3
- data/test/test_global_api.rb +48 -15
- data/test/test_resource_pool.rb +12 -0
- data/test/test_socket.rb +5 -4
- data/test/test_throttler.rb +6 -5
- metadata +21 -21
- data/docs/_includes/head.html +0 -40
- data/docs/_includes/nav.html +0 -51
- data/docs/_includes/prevnext.html +0 -17
- data/docs/_layouts/default.html +0 -106
- data/docs/api-reference.md +0 -11
- data/docs/api-reference/gyro-async.md +0 -57
- data/docs/api-reference/gyro-child.md +0 -29
- data/docs/api-reference/gyro-queue.md +0 -44
- data/docs/api-reference/gyro-timer.md +0 -51
- data/docs/api-reference/gyro.md +0 -25
- data/docs/getting-started.md +0 -10
- data/docs/main-concepts.md +0 -10
- data/docs/user-guide.md +0 -10
- data/examples/core/forever_sleep.rb +0 -19
- data/ext/polyphony/socket.c +0 -213
data/ext/polyphony/libev_queue.c
CHANGED
@@ -120,11 +120,12 @@ static VALUE LibevQueue_initialize(VALUE self) {
|
|
120
120
|
|
121
121
|
VALUE LibevQueue_push(VALUE self, VALUE value) {
|
122
122
|
LibevQueue_t *queue;
|
123
|
-
struct async_watcher *watcher;
|
124
123
|
GetQueue(self, queue);
|
125
|
-
|
126
|
-
|
127
|
-
|
124
|
+
if (queue->shift_queue.count > 0) {
|
125
|
+
struct async_watcher *watcher = async_queue_pop(&queue->shift_queue);
|
126
|
+
if (watcher) {
|
127
|
+
ev_async_send(watcher->ev_loop, &watcher->async);
|
128
|
+
}
|
128
129
|
}
|
129
130
|
rb_ary_push(queue->items, value);
|
130
131
|
return self;
|
@@ -137,6 +138,8 @@ void async_queue_callback(struct ev_loop *ev_loop, struct ev_async *ev_async, in
|
|
137
138
|
Fiber_make_runnable(watcher->fiber, Qnil);
|
138
139
|
}
|
139
140
|
|
141
|
+
VALUE libev_agent_await(VALUE self);
|
142
|
+
|
140
143
|
VALUE LibevQueue_shift(VALUE self) {
|
141
144
|
LibevQueue_t *queue;
|
142
145
|
GetQueue(self, queue);
|
@@ -152,7 +155,7 @@ VALUE LibevQueue_shift(VALUE self) {
|
|
152
155
|
ev_async_init(&watcher.async, async_queue_callback);
|
153
156
|
ev_async_start(watcher.ev_loop, &watcher.async);
|
154
157
|
|
155
|
-
switchpoint_result =
|
158
|
+
switchpoint_result = libev_agent_await(agent);
|
156
159
|
ev_async_stop(watcher.ev_loop, &watcher.async);
|
157
160
|
|
158
161
|
if (RTEST(rb_obj_is_kind_of(switchpoint_result, rb_eException))) {
|
data/ext/polyphony/polyphony.c
CHANGED
@@ -7,11 +7,8 @@ ID ID_call;
|
|
7
7
|
ID ID_caller;
|
8
8
|
ID ID_clear;
|
9
9
|
ID ID_each;
|
10
|
-
ID ID_empty;
|
11
10
|
ID ID_inspect;
|
12
11
|
ID ID_new;
|
13
|
-
ID ID_pop;
|
14
|
-
ID ID_push;
|
15
12
|
ID ID_raise;
|
16
13
|
ID ID_ivar_running;
|
17
14
|
ID ID_ivar_thread;
|
@@ -36,14 +33,6 @@ VALUE Polyphony_snooze(VALUE self) {
|
|
36
33
|
return ret;
|
37
34
|
}
|
38
35
|
|
39
|
-
static VALUE Polyphony_ref(VALUE self) {
|
40
|
-
return Thread_ref(rb_thread_current());
|
41
|
-
}
|
42
|
-
|
43
|
-
static VALUE Polyphony_unref(VALUE self) {
|
44
|
-
return Thread_unref(rb_thread_current());
|
45
|
-
}
|
46
|
-
|
47
36
|
static VALUE Polyphony_suspend(VALUE self) {
|
48
37
|
VALUE ret = Thread_switch_fiber(rb_thread_current());
|
49
38
|
|
@@ -60,9 +49,7 @@ VALUE Polyphony_trace(VALUE self, VALUE enabled) {
|
|
60
49
|
void Init_Polyphony() {
|
61
50
|
mPolyphony = rb_define_module("Polyphony");
|
62
51
|
|
63
|
-
rb_define_singleton_method(mPolyphony, "ref", Polyphony_ref, 0);
|
64
52
|
rb_define_singleton_method(mPolyphony, "trace", Polyphony_trace, 1);
|
65
|
-
rb_define_singleton_method(mPolyphony, "unref", Polyphony_unref, 0);
|
66
53
|
|
67
54
|
rb_define_global_function("snooze", Polyphony_snooze, 0);
|
68
55
|
rb_define_global_function("suspend", Polyphony_suspend, 0);
|
@@ -72,13 +59,10 @@ void Init_Polyphony() {
|
|
72
59
|
ID_caller = rb_intern("caller");
|
73
60
|
ID_clear = rb_intern("clear");
|
74
61
|
ID_each = rb_intern("each");
|
75
|
-
ID_empty = rb_intern("empty?");
|
76
62
|
ID_inspect = rb_intern("inspect");
|
77
63
|
ID_ivar_running = rb_intern("@running");
|
78
64
|
ID_ivar_thread = rb_intern("@thread");
|
79
65
|
ID_new = rb_intern("new");
|
80
|
-
ID_pop = rb_intern("pop");
|
81
|
-
ID_push = rb_intern("push");
|
82
66
|
ID_raise = rb_intern("raise");
|
83
67
|
ID_runnable = rb_intern("runnable");
|
84
68
|
ID_runnable_value = rb_intern("runnable_value");
|
data/ext/polyphony/polyphony.h
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
|
8
8
|
// debugging
|
9
9
|
#define OBJ_ID(obj) (NUM2LONG(rb_funcall(obj, rb_intern("object_id"), 0)))
|
10
|
-
#define INSPECT(
|
10
|
+
#define INSPECT(obj) { VALUE s = rb_funcall(obj, rb_intern("inspect"), 0); printf("%s\n", StringValueCStr(s));}
|
11
11
|
#define FIBER_TRACE(...) if (__tracing_enabled__) { \
|
12
12
|
rb_funcall(rb_cObject, ID_fiber_trace, __VA_ARGS__); \
|
13
13
|
}
|
@@ -66,22 +66,22 @@ enum {
|
|
66
66
|
VALUE Fiber_auto_watcher(VALUE self);
|
67
67
|
void Fiber_make_runnable(VALUE fiber, VALUE value);
|
68
68
|
|
69
|
-
VALUE Polyphony_switchpoint();
|
70
|
-
|
71
69
|
VALUE LibevAgent_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE queue);
|
72
70
|
VALUE LibevAgent_break(VALUE self);
|
73
71
|
VALUE LibevAgent_pending_count(VALUE self);
|
74
72
|
VALUE LibevAgent_wait_io(VALUE self, VALUE io, VALUE write);
|
75
73
|
|
74
|
+
VALUE LibevAgent_ref(VALUE self);
|
75
|
+
VALUE LibevAgent_unref(VALUE self);
|
76
|
+
int LibevAgent_ref_count(VALUE self);
|
77
|
+
void LibevAgent_reset_ref_count(VALUE self);
|
78
|
+
|
76
79
|
VALUE Polyphony_snooze(VALUE self);
|
77
80
|
|
78
81
|
VALUE Polyphony_Queue_push(VALUE self, VALUE value);
|
79
82
|
|
80
|
-
VALUE Thread_post_fork(VALUE thread);
|
81
|
-
VALUE Thread_ref(VALUE thread);
|
82
83
|
VALUE Thread_schedule_fiber(VALUE thread, VALUE fiber, VALUE value);
|
83
84
|
VALUE Thread_switch_fiber(VALUE thread);
|
84
|
-
VALUE Thread_unref(VALUE thread);
|
85
85
|
|
86
86
|
int io_setstrbuf(VALUE *str, long len);
|
87
87
|
void io_set_read_length(VALUE str, long n, int shrinkable);
|
@@ -4,7 +4,6 @@ void Init_Fiber();
|
|
4
4
|
void Init_Polyphony();
|
5
5
|
void Init_LibevAgent();
|
6
6
|
void Init_LibevQueue();
|
7
|
-
void Init_Socket();
|
8
7
|
void Init_Thread();
|
9
8
|
void Init_Tracing();
|
10
9
|
|
@@ -16,7 +15,6 @@ void Init_polyphony_ext() {
|
|
16
15
|
Init_LibevQueue();
|
17
16
|
|
18
17
|
Init_Fiber();
|
19
|
-
Init_Socket();
|
20
18
|
Init_Thread();
|
21
19
|
|
22
20
|
Init_Tracing();
|
data/ext/polyphony/thread.c
CHANGED
@@ -1,15 +1,11 @@
|
|
1
1
|
#include "polyphony.h"
|
2
2
|
|
3
3
|
ID ID_deactivate_all_watchers_post_fork;
|
4
|
-
ID ID_empty;
|
5
|
-
ID ID_fiber_ref_count;
|
6
4
|
ID ID_ivar_agent;
|
7
5
|
ID ID_ivar_join_wait_queue;
|
8
6
|
ID ID_ivar_main_fiber;
|
9
7
|
ID ID_ivar_result;
|
10
8
|
ID ID_ivar_terminated;
|
11
|
-
ID ID_pop;
|
12
|
-
ID ID_push;
|
13
9
|
ID ID_run_queue;
|
14
10
|
ID ID_runnable_next;
|
15
11
|
ID ID_stop;
|
@@ -18,34 +14,20 @@ static VALUE Thread_setup_fiber_scheduling(VALUE self) {
|
|
18
14
|
VALUE queue;
|
19
15
|
|
20
16
|
rb_ivar_set(self, ID_ivar_main_fiber, rb_fiber_current());
|
21
|
-
rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(0));
|
22
17
|
queue = rb_ary_new();
|
23
18
|
rb_ivar_set(self, ID_run_queue, queue);
|
24
19
|
|
25
20
|
return self;
|
26
21
|
}
|
27
22
|
|
28
|
-
VALUE Thread_ref(VALUE self) {
|
29
|
-
VALUE count = rb_ivar_get(self, ID_fiber_ref_count);
|
30
|
-
int new_count = NUM2INT(count) + 1;
|
31
|
-
rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(new_count));
|
32
|
-
return self;
|
33
|
-
}
|
34
|
-
|
35
|
-
VALUE Thread_unref(VALUE self) {
|
36
|
-
VALUE count = rb_ivar_get(self, ID_fiber_ref_count);
|
37
|
-
int new_count = NUM2INT(count) - 1;
|
38
|
-
rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(new_count));
|
39
|
-
return self;
|
40
|
-
}
|
41
|
-
|
42
23
|
int Thread_fiber_ref_count(VALUE self) {
|
43
|
-
VALUE
|
44
|
-
return NUM2INT(
|
24
|
+
VALUE agent = rb_ivar_get(self, ID_ivar_agent);
|
25
|
+
return NUM2INT(LibevAgent_ref_count(agent));
|
45
26
|
}
|
46
27
|
|
47
|
-
void Thread_fiber_reset_ref_count(VALUE self) {
|
48
|
-
|
28
|
+
inline void Thread_fiber_reset_ref_count(VALUE self) {
|
29
|
+
VALUE agent = rb_ivar_get(self, ID_ivar_agent);
|
30
|
+
LibevAgent_reset_ref_count(agent);
|
49
31
|
}
|
50
32
|
|
51
33
|
static VALUE SYM_scheduled_fibers;
|
@@ -140,8 +122,8 @@ VALUE Thread_switch_fiber(VALUE self) {
|
|
140
122
|
}
|
141
123
|
}
|
142
124
|
|
125
|
+
ref_count = LibevAgent_ref_count(agent);
|
143
126
|
while (1) {
|
144
|
-
ref_count = Thread_fiber_ref_count(self);
|
145
127
|
next_fiber = rb_ary_shift(queue);
|
146
128
|
if (next_fiber != Qnil) {
|
147
129
|
if (ref_count > 0) {
|
@@ -165,7 +147,8 @@ VALUE Thread_switch_fiber(VALUE self) {
|
|
165
147
|
rb_ivar_set(next_fiber, ID_runnable, Qnil);
|
166
148
|
RB_GC_GUARD(next_fiber);
|
167
149
|
RB_GC_GUARD(value);
|
168
|
-
return
|
150
|
+
return (next_fiber == current_fiber) ?
|
151
|
+
value : rb_funcall(next_fiber, ID_transfer, 1, value);
|
169
152
|
}
|
170
153
|
|
171
154
|
VALUE Thread_reset_fiber_scheduling(VALUE self) {
|
@@ -175,16 +158,6 @@ VALUE Thread_reset_fiber_scheduling(VALUE self) {
|
|
175
158
|
return self;
|
176
159
|
}
|
177
160
|
|
178
|
-
VALUE Polyphony_switchpoint() {
|
179
|
-
VALUE ret;
|
180
|
-
VALUE thread = rb_thread_current();
|
181
|
-
Thread_ref(thread);
|
182
|
-
ret = Thread_switch_fiber(thread);
|
183
|
-
Thread_unref(thread);
|
184
|
-
RB_GC_GUARD(ret);
|
185
|
-
return ret;
|
186
|
-
}
|
187
|
-
|
188
161
|
VALUE Thread_fiber_break_out_of_ev_loop(VALUE self, VALUE fiber, VALUE resume_obj) {
|
189
162
|
VALUE agent = rb_ivar_get(self, ID_ivar_agent);
|
190
163
|
if (fiber != Qnil) {
|
@@ -200,9 +173,6 @@ VALUE Thread_fiber_break_out_of_ev_loop(VALUE self, VALUE fiber, VALUE resume_ob
|
|
200
173
|
}
|
201
174
|
|
202
175
|
void Init_Thread() {
|
203
|
-
rb_define_method(rb_cThread, "fiber_ref", Thread_ref, 0);
|
204
|
-
rb_define_method(rb_cThread, "fiber_unref", Thread_unref, 0);
|
205
|
-
|
206
176
|
rb_define_method(rb_cThread, "setup_fiber_scheduling", Thread_setup_fiber_scheduling, 0);
|
207
177
|
rb_define_method(rb_cThread, "reset_fiber_scheduling", Thread_reset_fiber_scheduling, 0);
|
208
178
|
rb_define_method(rb_cThread, "fiber_scheduling_stats", Thread_fiber_scheduling_stats, 0);
|
@@ -214,15 +184,11 @@ void Init_Thread() {
|
|
214
184
|
rb_define_method(rb_cThread, "switch_fiber", Thread_switch_fiber, 0);
|
215
185
|
|
216
186
|
ID_deactivate_all_watchers_post_fork = rb_intern("deactivate_all_watchers_post_fork");
|
217
|
-
ID_empty = rb_intern("empty?");
|
218
|
-
ID_fiber_ref_count = rb_intern("fiber_ref_count");
|
219
187
|
ID_ivar_agent = rb_intern("@agent");
|
220
188
|
ID_ivar_join_wait_queue = rb_intern("@join_wait_queue");
|
221
189
|
ID_ivar_main_fiber = rb_intern("@main_fiber");
|
222
190
|
ID_ivar_result = rb_intern("@result");
|
223
191
|
ID_ivar_terminated = rb_intern("@terminated");
|
224
|
-
ID_pop = rb_intern("pop");
|
225
|
-
ID_push = rb_intern("push");
|
226
192
|
ID_run_queue = rb_intern("run_queue");
|
227
193
|
ID_runnable_next = rb_intern("runnable_next");
|
228
194
|
ID_stop = rb_intern("stop");
|
data/lib/polyphony.rb
CHANGED
@@ -6,6 +6,12 @@ require_relative './polyphony_ext'
|
|
6
6
|
module Polyphony
|
7
7
|
# Map Queue to Libev queue implementation
|
8
8
|
Queue = LibevQueue
|
9
|
+
|
10
|
+
# replace core Queue class with our own
|
11
|
+
verbose = $VERBOSE
|
12
|
+
$VERBOSE = nil
|
13
|
+
Object.const_set(:Queue, Polyphony::Queue)
|
14
|
+
$VERBOSE = verbose
|
9
15
|
end
|
10
16
|
|
11
17
|
require_relative './polyphony/extensions/core'
|
@@ -26,14 +32,17 @@ require_relative './polyphony/event'
|
|
26
32
|
module Polyphony
|
27
33
|
class << self
|
28
34
|
def wait_for_signal(sig)
|
35
|
+
raise "should be reimplemented"
|
36
|
+
|
29
37
|
fiber = Fiber.current
|
30
|
-
Polyphony.ref
|
38
|
+
# Polyphony.ref
|
31
39
|
old_trap = trap(sig) do
|
32
|
-
Polyphony.unref
|
40
|
+
# Polyphony.unref
|
33
41
|
fiber.schedule(sig)
|
34
42
|
trap(sig, old_trap)
|
35
43
|
end
|
36
44
|
suspend
|
45
|
+
|
37
46
|
end
|
38
47
|
|
39
48
|
def fork(&block)
|
@@ -111,7 +120,25 @@ module Polyphony
|
|
111
120
|
threads.each(&:kill)
|
112
121
|
threads.each(&:join)
|
113
122
|
end
|
123
|
+
|
124
|
+
attr_accessor :original_pid
|
125
|
+
|
126
|
+
def install_at_exit_handler
|
127
|
+
@original_pid = ::Process.pid
|
128
|
+
|
129
|
+
# This at_exit handler is needed only when the original process exits. Due to
|
130
|
+
# the behaviour of fibers on fork (and especially on exit from forked
|
131
|
+
# processes,) we use a separate mechanism to terminate fibers in forked
|
132
|
+
# processes (see Polyphony.fork).
|
133
|
+
at_exit do
|
134
|
+
next unless @original_pid == ::Process.pid
|
135
|
+
|
136
|
+
Polyphony.terminate_threads
|
137
|
+
Fiber.current.shutdown_all_children
|
138
|
+
end
|
139
|
+
end
|
114
140
|
end
|
115
141
|
end
|
116
142
|
|
117
143
|
Polyphony.install_terminating_signal_handlers
|
144
|
+
Polyphony.install_at_exit_handler
|
@@ -6,7 +6,7 @@ require 'redis'
|
|
6
6
|
require 'hiredis/reader'
|
7
7
|
|
8
8
|
# Polyphony-based Redis driver
|
9
|
-
class
|
9
|
+
class Polyphony::RedisDriver
|
10
10
|
def self.connect(config)
|
11
11
|
raise 'unix sockets not supported' if config[:scheme] == 'unix'
|
12
12
|
|
@@ -43,6 +43,7 @@ class Driver
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def format_command(args)
|
46
|
+
args = args.flatten
|
46
47
|
(+"*#{args.size}\r\n").tap do |s|
|
47
48
|
args.each do |a|
|
48
49
|
a = a.to_s
|
@@ -63,4 +64,4 @@ class Driver
|
|
63
64
|
end
|
64
65
|
end
|
65
66
|
|
66
|
-
Redis::Connection.drivers <<
|
67
|
+
Redis::Connection.drivers << Polyphony::RedisDriver
|
@@ -26,7 +26,7 @@ module Polyphony
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def receive
|
29
|
-
|
29
|
+
Thread.current.agent.ref
|
30
30
|
if @payload_queue.empty?
|
31
31
|
@waiting_queue << Fiber.current
|
32
32
|
suspend
|
@@ -34,7 +34,7 @@ module Polyphony
|
|
34
34
|
receive_from_queue
|
35
35
|
end
|
36
36
|
ensure
|
37
|
-
|
37
|
+
Thread.current.agent.unref
|
38
38
|
end
|
39
39
|
|
40
40
|
def receive_from_queue
|
@@ -15,11 +15,13 @@ module Polyphony
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
def cancel_after(interval, &block)
|
18
|
+
def cancel_after(interval, with_exception: Polyphony::Cancel, &block)
|
19
19
|
fiber = ::Fiber.current
|
20
20
|
canceller = spin do
|
21
21
|
sleep interval
|
22
|
-
|
22
|
+
exception = with_exception.is_a?(Class) ?
|
23
|
+
with_exception.new : RuntimeError.new(with_exception)
|
24
|
+
fiber.schedule exception
|
23
25
|
end
|
24
26
|
block ? cancel_after_wrap_block(canceller, &block) : canceller
|
25
27
|
end
|
@@ -100,10 +102,10 @@ module Polyphony
|
|
100
102
|
end
|
101
103
|
|
102
104
|
def sleep_forever
|
103
|
-
Thread.current.
|
105
|
+
Thread.current.agent.ref
|
104
106
|
suspend
|
105
107
|
ensure
|
106
|
-
Thread.current.
|
108
|
+
Thread.current.agent.unref
|
107
109
|
end
|
108
110
|
|
109
111
|
def throttled_loop(rate, count: nil, &block)
|
@@ -13,6 +13,7 @@ module Polyphony
|
|
13
13
|
|
14
14
|
@stock = []
|
15
15
|
@queue = []
|
16
|
+
@acquired_resources = {}
|
16
17
|
|
17
18
|
@limit = opts[:limit] || 4
|
18
19
|
@size = 0
|
@@ -23,16 +24,25 @@ module Polyphony
|
|
23
24
|
end
|
24
25
|
|
25
26
|
def acquire
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
27
|
+
fiber = Fiber.current
|
28
|
+
if @acquired_resources[fiber]
|
29
|
+
yield @acquired_resources[fiber]
|
30
|
+
else
|
31
|
+
begin
|
32
|
+
Thread.current.agent.ref
|
33
|
+
resource = wait_for_resource
|
34
|
+
return unless resource
|
35
|
+
|
36
|
+
@acquired_resources[fiber] = resource
|
37
|
+
yield resource
|
38
|
+
ensure
|
39
|
+
@acquired_resources[fiber] = nil
|
40
|
+
Thread.current.agent.unref
|
41
|
+
release(resource) if resource
|
42
|
+
end
|
43
|
+
end
|
34
44
|
end
|
35
|
-
|
45
|
+
|
36
46
|
def wait_for_resource
|
37
47
|
fiber = Fiber.current
|
38
48
|
@queue << fiber
|
@@ -8,8 +8,6 @@ require_relative '../core/exceptions'
|
|
8
8
|
|
9
9
|
# Exeption overrides
|
10
10
|
class ::Exception
|
11
|
-
EXIT_EXCEPTION_CLASSES = [::Interrupt, ::SystemExit].freeze
|
12
|
-
|
13
11
|
class << self
|
14
12
|
attr_accessor :__disable_sanitized_backtrace__
|
15
13
|
end
|
@@ -24,7 +22,7 @@ class ::Exception
|
|
24
22
|
|
25
23
|
alias_method :orig_backtrace, :backtrace
|
26
24
|
def backtrace
|
27
|
-
unless @first_backtrace_call
|
25
|
+
unless @first_backtrace_call
|
28
26
|
@first_backtrace_call = true
|
29
27
|
return orig_backtrace
|
30
28
|
end
|
@@ -59,6 +57,12 @@ module ::Process
|
|
59
57
|
fiber.define_singleton_method(:pid) { pid }
|
60
58
|
fiber
|
61
59
|
end
|
60
|
+
|
61
|
+
alias_method :orig_daemon, :daemon
|
62
|
+
def daemon(*args)
|
63
|
+
orig_daemon(*args)
|
64
|
+
Polyphony.original_pid = Process.pid
|
65
|
+
end
|
62
66
|
end
|
63
67
|
end
|
64
68
|
|
@@ -93,6 +97,7 @@ module ::Kernel
|
|
93
97
|
def gets(*_args)
|
94
98
|
if !ARGV.empty? || @gets_fiber
|
95
99
|
@gets_fiber ||= Fiber.new(&ARGV_GETS_LOOP)
|
100
|
+
@gets_fiber.thread = Thread.current
|
96
101
|
result = @gets_fiber.alive? && @gets_fiber.safe_transfer(Fiber.current)
|
97
102
|
return result if result
|
98
103
|
|