polyphony 0.43.10 → 0.45.2
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/.rubocop.yml +8 -1
- data/CHANGELOG.md +37 -0
- data/Gemfile.lock +16 -6
- data/Rakefile +1 -1
- data/TODO.md +15 -10
- data/docs/_posts/2020-07-26-polyphony-0.44.md +77 -0
- data/docs/api-reference/thread.md +1 -1
- data/docs/getting-started/overview.md +14 -14
- data/docs/getting-started/tutorial.md +1 -1
- data/examples/adapters/redis_client.rb +3 -1
- data/examples/adapters/redis_pubsub_perf.rb +11 -8
- data/examples/adapters/sequel_mysql.rb +23 -0
- data/examples/adapters/sequel_mysql_pool.rb +33 -0
- data/examples/adapters/sequel_pg.rb +24 -0
- data/examples/core/{02-awaiting-fibers.rb → await.rb} +0 -0
- data/examples/core/{xx-channels.rb → channels.rb} +0 -0
- data/examples/core/deferring-an-operation.rb +16 -0
- data/examples/core/{xx-erlang-style-genserver.rb → erlang-style-genserver.rb} +16 -9
- data/examples/core/{xx-forking.rb → forking.rb} +1 -1
- data/examples/core/handling-signals.rb +11 -0
- data/examples/core/{03-interrupting.rb → interrupt.rb} +0 -0
- data/examples/core/{xx-pingpong.rb → pingpong.rb} +7 -5
- data/examples/core/{xx-recurrent-timer.rb → recurrent-timer.rb} +1 -1
- data/examples/core/{xx-resource_delegate.rb → resource_delegate.rb} +3 -4
- data/examples/core/{01-spinning-up-fibers.rb → spin.rb} +1 -1
- data/examples/core/{xx-spin_error_backtrace.rb → spin_error_backtrace.rb} +1 -1
- data/examples/core/{xx-supervise-process.rb → supervise-process.rb} +8 -5
- data/examples/core/supervisor.rb +20 -0
- data/examples/core/{xx-thread-sleep.rb → thread-sleep.rb} +0 -0
- data/examples/core/{xx-thread_pool.rb → thread_pool.rb} +0 -0
- data/examples/core/{xx-throttling.rb → throttling.rb} +0 -0
- data/examples/core/{xx-timeout.rb → timeout.rb} +0 -0
- data/examples/core/{xx-using-a-mutex.rb → using-a-mutex.rb} +0 -0
- data/examples/core/{xx-worker-thread.rb → worker-thread.rb} +2 -2
- data/examples/io/{xx-backticks.rb → backticks.rb} +0 -0
- data/examples/io/{xx-echo_client.rb → echo_client.rb} +1 -1
- data/examples/io/{xx-echo_client_from_stdin.rb → echo_client_from_stdin.rb} +2 -2
- data/examples/io/{xx-echo_pipe.rb → echo_pipe.rb} +1 -1
- data/examples/io/{xx-echo_server.rb → echo_server.rb} +0 -0
- data/examples/io/{xx-echo_server_with_timeout.rb → echo_server_with_timeout.rb} +1 -1
- data/examples/io/{xx-echo_stdin.rb → echo_stdin.rb} +0 -0
- data/examples/io/{xx-happy-eyeballs.rb → happy-eyeballs.rb} +0 -0
- data/examples/io/{xx-httparty.rb → httparty.rb} +4 -13
- data/examples/io/{xx-irb.rb → irb.rb} +0 -0
- data/examples/io/{xx-net-http.rb → net-http.rb} +0 -0
- data/examples/io/{xx-open.rb → open.rb} +0 -0
- data/examples/io/pry.rb +18 -0
- data/examples/io/rack_server.rb +71 -0
- data/examples/io/{xx-system.rb → system.rb} +1 -1
- data/examples/io/{xx-tcpserver.rb → tcpserver.rb} +0 -0
- data/examples/io/{xx-tcpsocket.rb → tcpsocket.rb} +0 -0
- data/examples/io/tunnel.rb +6 -1
- data/examples/io/{xx-zip.rb → zip.rb} +0 -0
- data/examples/performance/fiber_transfer.rb +2 -1
- data/examples/performance/fs_read.rb +5 -6
- data/examples/{io/xx-switch.rb → performance/switch.rb} +2 -1
- data/examples/performance/thread-vs-fiber/{xx-httparty_multi.rb → httparty_multi.rb} +3 -4
- data/examples/performance/thread-vs-fiber/{xx-httparty_threaded.rb → httparty_threaded.rb} +0 -0
- data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +1 -1
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +1 -1
- data/examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb +1 -1
- data/examples/performance/thread-vs-fiber/threaded_server.rb +1 -5
- data/examples/performance/thread_pool_perf.rb +6 -7
- data/ext/polyphony/backend.h +40 -0
- data/ext/polyphony/event.c +3 -3
- data/ext/polyphony/extconf.rb +1 -1
- data/ext/polyphony/fiber.c +66 -6
- data/ext/polyphony/{libev_agent.c → libev_backend.c} +239 -235
- data/ext/polyphony/polyphony.c +3 -3
- data/ext/polyphony/polyphony.h +15 -23
- data/ext/polyphony/polyphony_ext.c +3 -4
- data/ext/polyphony/queue.c +25 -12
- data/ext/polyphony/ring_buffer.c +0 -1
- data/ext/polyphony/thread.c +36 -33
- data/lib/polyphony.rb +25 -38
- data/lib/polyphony/adapters/fs.rb +1 -1
- data/lib/polyphony/adapters/irb.rb +2 -17
- data/lib/polyphony/adapters/mysql2.rb +19 -0
- data/lib/polyphony/adapters/postgres.rb +5 -5
- data/lib/polyphony/adapters/process.rb +2 -2
- data/lib/polyphony/adapters/readline.rb +17 -0
- data/lib/polyphony/adapters/redis.rb +1 -1
- data/lib/polyphony/adapters/sequel.rb +45 -0
- data/lib/polyphony/core/exceptions.rb +11 -0
- data/lib/polyphony/core/global_api.rb +17 -12
- data/lib/polyphony/core/resource_pool.rb +20 -7
- data/lib/polyphony/core/sync.rb +46 -8
- data/lib/polyphony/core/throttler.rb +1 -1
- data/lib/polyphony/extensions/core.rb +38 -25
- data/lib/polyphony/extensions/fiber.rb +12 -45
- data/lib/polyphony/extensions/io.rb +45 -12
- data/lib/polyphony/extensions/openssl.rb +6 -6
- data/lib/polyphony/extensions/socket.rb +22 -15
- data/lib/polyphony/extensions/thread.rb +6 -5
- data/lib/polyphony/net.rb +2 -1
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +7 -3
- data/test/helper.rb +1 -1
- data/test/{test_agent.rb → test_backend.rb} +22 -22
- data/test/test_fiber.rb +28 -11
- data/test/test_io.rb +17 -1
- data/test/test_kernel.rb +5 -0
- data/test/test_resource_pool.rb +50 -16
- data/test/test_signal.rb +5 -29
- data/test/test_socket.rb +17 -0
- data/test/test_sync.rb +52 -0
- metadata +126 -98
- data/.gitbook.yaml +0 -4
- data/examples/adapters/concurrent-ruby.rb +0 -9
- data/examples/core/04-handling-signals.rb +0 -19
- data/examples/core/xx-agent.rb +0 -102
- data/examples/core/xx-at_exit.rb +0 -29
- data/examples/core/xx-caller.rb +0 -12
- data/examples/core/xx-daemon.rb +0 -14
- data/examples/core/xx-deadlock.rb +0 -8
- data/examples/core/xx-deferring-an-operation.rb +0 -14
- data/examples/core/xx-exception-backtrace.rb +0 -40
- data/examples/core/xx-fork-cleanup.rb +0 -22
- data/examples/core/xx-fork-spin.rb +0 -42
- data/examples/core/xx-fork-terminate.rb +0 -27
- data/examples/core/xx-move_on.rb +0 -23
- data/examples/core/xx-queue-async.rb +0 -120
- data/examples/core/xx-readpartial.rb +0 -18
- data/examples/core/xx-signals.rb +0 -16
- data/examples/core/xx-sleep-forever.rb +0 -9
- data/examples/core/xx-sleeping.rb +0 -25
- data/examples/core/xx-snooze-starve.rb +0 -16
- data/examples/core/xx-spin-fork.rb +0 -49
- data/examples/core/xx-state-machine.rb +0 -51
- data/examples/core/xx-stop.rb +0 -20
- data/examples/core/xx-supervisors.rb +0 -21
- data/examples/core/xx-thread-selector-sleep.rb +0 -51
- data/examples/core/xx-thread-selector-snooze.rb +0 -46
- data/examples/core/xx-thread-snooze.rb +0 -34
- data/examples/core/xx-timer-gc.rb +0 -17
- data/examples/core/xx-trace.rb +0 -79
- data/examples/performance/xx-array.rb +0 -11
- data/examples/performance/xx-fiber-switch.rb +0 -9
- data/examples/performance/xx-snooze.rb +0 -15
- data/examples/xx-spin.rb +0 -32
- data/ext/polyphony/agent.h +0 -39
data/ext/polyphony/polyphony.c
CHANGED
|
@@ -7,8 +7,8 @@ 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
|
-
ID ID_raise;
|
|
12
12
|
ID ID_ivar_running;
|
|
13
13
|
ID ID_ivar_thread;
|
|
14
14
|
ID ID_runnable;
|
|
@@ -21,7 +21,7 @@ ID ID_R;
|
|
|
21
21
|
ID ID_W;
|
|
22
22
|
ID ID_RW;
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
backend_interface_t backend_interface;
|
|
25
25
|
|
|
26
26
|
VALUE Polyphony_snooze(VALUE self) {
|
|
27
27
|
VALUE ret;
|
|
@@ -60,10 +60,10 @@ void Init_Polyphony() {
|
|
|
60
60
|
ID_clear = rb_intern("clear");
|
|
61
61
|
ID_each = rb_intern("each");
|
|
62
62
|
ID_inspect = rb_intern("inspect");
|
|
63
|
+
ID_invoke = rb_intern("invoke");
|
|
63
64
|
ID_ivar_running = rb_intern("@running");
|
|
64
65
|
ID_ivar_thread = rb_intern("@thread");
|
|
65
66
|
ID_new = rb_intern("new");
|
|
66
|
-
ID_raise = rb_intern("raise");
|
|
67
67
|
ID_runnable = rb_intern("runnable");
|
|
68
68
|
ID_runnable_value = rb_intern("runnable_value");
|
|
69
69
|
ID_signal = rb_intern("signal");
|
data/ext/polyphony/polyphony.h
CHANGED
|
@@ -4,26 +4,28 @@
|
|
|
4
4
|
#include "ruby.h"
|
|
5
5
|
#include "ruby/io.h"
|
|
6
6
|
#include "libev.h"
|
|
7
|
-
#include "
|
|
7
|
+
#include "backend.h"
|
|
8
8
|
|
|
9
9
|
// debugging
|
|
10
10
|
#define OBJ_ID(obj) (NUM2LONG(rb_funcall(obj, rb_intern("object_id"), 0)))
|
|
11
|
-
#define INSPECT(obj) { VALUE s = rb_funcall(obj, rb_intern("inspect"), 0); printf("%s\n", StringValueCStr(s));}
|
|
12
|
-
#define
|
|
13
|
-
|
|
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__); \
|
|
14
18
|
}
|
|
15
19
|
|
|
16
20
|
#define TEST_EXCEPTION(ret) (RTEST(rb_obj_is_kind_of(ret, rb_eException)))
|
|
17
21
|
|
|
22
|
+
#define RAISE_EXCEPTION(e) rb_funcall(e, ID_invoke, 0);
|
|
18
23
|
#define TEST_RESUME_EXCEPTION(ret) if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) { \
|
|
19
|
-
return
|
|
24
|
+
return RAISE_EXCEPTION(ret); \
|
|
20
25
|
}
|
|
21
26
|
|
|
22
|
-
extern
|
|
23
|
-
|
|
24
|
-
// #define __AGENT__(call) __AGENT_PASTER__(call)
|
|
25
|
-
#define __AGENT__ (agent_interface)
|
|
26
|
-
|
|
27
|
+
extern backend_interface_t backend_interface;
|
|
28
|
+
#define __BACKEND__ (backend_interface)
|
|
27
29
|
|
|
28
30
|
extern VALUE mPolyphony;
|
|
29
31
|
extern VALUE cQueue;
|
|
@@ -35,7 +37,8 @@ extern ID ID_clear;
|
|
|
35
37
|
extern ID ID_each;
|
|
36
38
|
extern ID ID_fiber_trace;
|
|
37
39
|
extern ID ID_inspect;
|
|
38
|
-
extern ID
|
|
40
|
+
extern ID ID_invoke;
|
|
41
|
+
extern ID ID_ivar_backend;
|
|
39
42
|
extern ID ID_ivar_running;
|
|
40
43
|
extern ID ID_ivar_thread;
|
|
41
44
|
extern ID ID_new;
|
|
@@ -63,31 +66,20 @@ enum {
|
|
|
63
66
|
FIBER_STATE_SCHEDULED = 2
|
|
64
67
|
};
|
|
65
68
|
|
|
66
|
-
// watcher flags
|
|
67
|
-
enum {
|
|
68
|
-
// a watcher's active field will be set to this after fork
|
|
69
|
-
GYRO_WATCHER_POST_FORK = 0xFF
|
|
70
|
-
};
|
|
71
|
-
|
|
72
69
|
VALUE Fiber_auto_watcher(VALUE self);
|
|
73
70
|
void Fiber_make_runnable(VALUE fiber, VALUE value);
|
|
74
71
|
|
|
75
72
|
VALUE Queue_push(VALUE self, VALUE value);
|
|
76
73
|
VALUE Queue_unshift(VALUE self, VALUE value);
|
|
77
74
|
VALUE Queue_shift(VALUE self);
|
|
75
|
+
VALUE Queue_shift_all(VALUE self);
|
|
78
76
|
VALUE Queue_shift_no_wait(VALUE self);
|
|
79
77
|
VALUE Queue_clear(VALUE self);
|
|
80
78
|
VALUE Queue_delete(VALUE self, VALUE value);
|
|
81
79
|
long Queue_len(VALUE self);
|
|
82
80
|
void Queue_trace(VALUE self);
|
|
83
81
|
|
|
84
|
-
VALUE Polyphony_snooze(VALUE self);
|
|
85
|
-
|
|
86
82
|
VALUE Thread_schedule_fiber(VALUE thread, VALUE fiber, VALUE value);
|
|
87
83
|
VALUE Thread_switch_fiber(VALUE thread);
|
|
88
84
|
|
|
89
|
-
int io_setstrbuf(VALUE *str, long len);
|
|
90
|
-
void io_set_read_length(VALUE str, long n, int shrinkable);
|
|
91
|
-
VALUE io_enc_str(VALUE str, rb_io_t *fptr);
|
|
92
|
-
|
|
93
85
|
#endif /* POLYPHONY_H */
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
void Init_Fiber();
|
|
4
4
|
void Init_Polyphony();
|
|
5
|
-
void
|
|
5
|
+
void Init_LibevBackend();
|
|
6
6
|
void Init_Queue();
|
|
7
7
|
void Init_Event();
|
|
8
8
|
void Init_Thread();
|
|
@@ -12,12 +12,11 @@ void Init_polyphony_ext() {
|
|
|
12
12
|
ev_set_allocator(xrealloc);
|
|
13
13
|
|
|
14
14
|
Init_Polyphony();
|
|
15
|
-
|
|
15
|
+
|
|
16
|
+
Init_LibevBackend();
|
|
16
17
|
Init_Queue();
|
|
17
18
|
Init_Event();
|
|
18
|
-
|
|
19
19
|
Init_Fiber();
|
|
20
20
|
Init_Thread();
|
|
21
|
-
|
|
22
21
|
Init_Tracing();
|
|
23
22
|
}
|
data/ext/polyphony/queue.c
CHANGED
|
@@ -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,25 @@ VALUE Queue_shift(VALUE self) {
|
|
|
77
78
|
Queue_t *queue;
|
|
78
79
|
GetQueue(self, queue);
|
|
79
80
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
+
TEST_RESUME_EXCEPTION(switchpoint_result);
|
|
91
93
|
RB_GC_GUARD(switchpoint_result);
|
|
94
|
+
|
|
95
|
+
if (queue->values.count > 0)
|
|
96
|
+
return ring_buffer_shift(&queue->values);
|
|
92
97
|
}
|
|
93
98
|
|
|
94
|
-
return
|
|
99
|
+
return Qnil;
|
|
95
100
|
}
|
|
96
101
|
|
|
97
102
|
VALUE Queue_shift_no_wait(VALUE self) {
|
|
@@ -146,7 +151,7 @@ VALUE Queue_flush_waiters(VALUE self, VALUE value) {
|
|
|
146
151
|
while(1) {
|
|
147
152
|
VALUE fiber = ring_buffer_shift(&queue->shift_queue);
|
|
148
153
|
if (fiber == Qnil) return self;
|
|
149
|
-
|
|
154
|
+
|
|
150
155
|
Fiber_make_runnable(fiber, value);
|
|
151
156
|
}
|
|
152
157
|
}
|
|
@@ -158,6 +163,13 @@ VALUE Queue_empty_p(VALUE self) {
|
|
|
158
163
|
return (queue->values.count == 0) ? Qtrue : Qfalse;
|
|
159
164
|
}
|
|
160
165
|
|
|
166
|
+
VALUE Queue_pending_p(VALUE self) {
|
|
167
|
+
Queue_t *queue;
|
|
168
|
+
GetQueue(self, queue);
|
|
169
|
+
|
|
170
|
+
return (queue->shift_queue.count > 0) ? Qtrue : Qfalse;
|
|
171
|
+
}
|
|
172
|
+
|
|
161
173
|
VALUE Queue_size_m(VALUE self) {
|
|
162
174
|
Queue_t *queue;
|
|
163
175
|
GetQueue(self, queue);
|
|
@@ -190,5 +202,6 @@ void Init_Queue() {
|
|
|
190
202
|
rb_define_method(cQueue, "shift_all", Queue_shift_all, 0);
|
|
191
203
|
rb_define_method(cQueue, "flush_waiters", Queue_flush_waiters, 1);
|
|
192
204
|
rb_define_method(cQueue, "empty?", Queue_empty_p, 0);
|
|
205
|
+
rb_define_method(cQueue, "pending?", Queue_pending_p, 0);
|
|
193
206
|
rb_define_method(cQueue, "size", Queue_size_m, 0);
|
|
194
207
|
}
|
data/ext/polyphony/ring_buffer.c
CHANGED
data/ext/polyphony/thread.c
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#include "polyphony.h"
|
|
2
2
|
|
|
3
3
|
ID ID_deactivate_all_watchers_post_fork;
|
|
4
|
-
ID
|
|
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;
|
|
@@ -12,7 +12,7 @@ ID ID_stop;
|
|
|
12
12
|
|
|
13
13
|
static VALUE Thread_setup_fiber_scheduling(VALUE self) {
|
|
14
14
|
VALUE queue = rb_funcall(cQueue, ID_new, 0);
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
rb_ivar_set(self, ID_ivar_main_fiber, rb_fiber_current());
|
|
17
17
|
rb_ivar_set(self, ID_run_queue, queue);
|
|
18
18
|
|
|
@@ -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
|
|
24
|
-
return NUM2INT(
|
|
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
|
|
29
|
-
|
|
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
|
|
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 =
|
|
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;
|
|
@@ -64,7 +64,7 @@ VALUE Thread_schedule_fiber(VALUE self, VALUE fiber, VALUE value) {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
rb_ivar_set(fiber, ID_runnable_value, value);
|
|
67
|
-
|
|
67
|
+
COND_TRACE(3, SYM_fiber_schedule, fiber, value);
|
|
68
68
|
|
|
69
69
|
if (!already_runnable) {
|
|
70
70
|
queue = rb_ivar_get(self, ID_run_queue);
|
|
@@ -77,8 +77,8 @@ VALUE Thread_schedule_fiber(VALUE self, VALUE fiber, VALUE value) {
|
|
|
77
77
|
// event selector. Otherwise it's gonna be stuck waiting for an event to
|
|
78
78
|
// happen, not knowing that it there's already a fiber ready to run in its
|
|
79
79
|
// run queue.
|
|
80
|
-
VALUE
|
|
81
|
-
|
|
80
|
+
VALUE backend = rb_ivar_get(self,ID_ivar_backend);
|
|
81
|
+
__BACKEND__.wakeup(backend);
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
return self;
|
|
@@ -89,7 +89,7 @@ VALUE Thread_schedule_fiber_with_priority(VALUE self, VALUE fiber, VALUE value)
|
|
|
89
89
|
|
|
90
90
|
if (rb_fiber_alive_p(fiber) != Qtrue) return self;
|
|
91
91
|
|
|
92
|
-
|
|
92
|
+
COND_TRACE(3, SYM_fiber_schedule, fiber, value);
|
|
93
93
|
rb_ivar_set(fiber, ID_runnable_value, value);
|
|
94
94
|
|
|
95
95
|
queue = rb_ivar_get(self, ID_run_queue);
|
|
@@ -110,8 +110,8 @@ VALUE Thread_schedule_fiber_with_priority(VALUE self, VALUE fiber, VALUE value)
|
|
|
110
110
|
// event loop. Otherwise it's gonna be stuck waiting for an event to
|
|
111
111
|
// happen, not knowing that it there's already a fiber ready to run in its
|
|
112
112
|
// run queue.
|
|
113
|
-
VALUE
|
|
114
|
-
|
|
113
|
+
VALUE backend = rb_ivar_get(self, ID_ivar_backend);
|
|
114
|
+
__BACKEND__.wakeup(backend);
|
|
115
115
|
}
|
|
116
116
|
return self;
|
|
117
117
|
}
|
|
@@ -121,43 +121,39 @@ VALUE Thread_switch_fiber(VALUE self) {
|
|
|
121
121
|
VALUE queue = rb_ivar_get(self, ID_run_queue);
|
|
122
122
|
VALUE next_fiber;
|
|
123
123
|
VALUE value;
|
|
124
|
-
VALUE
|
|
124
|
+
VALUE backend = rb_ivar_get(self, ID_ivar_backend);
|
|
125
125
|
int ref_count;
|
|
126
|
-
int
|
|
126
|
+
int backend_was_polled = 0;
|
|
127
127
|
|
|
128
|
-
if (__tracing_enabled__)
|
|
129
|
-
|
|
130
|
-
rb_funcall(rb_cObject, ID_fiber_trace, 2, SYM_fiber_switchpoint, current_fiber);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
128
|
+
if (__tracing_enabled__ && (rb_ivar_get(current_fiber, ID_ivar_running) != Qfalse))
|
|
129
|
+
TRACE(2, SYM_fiber_switchpoint, current_fiber);
|
|
133
130
|
|
|
134
|
-
ref_count =
|
|
131
|
+
ref_count = __BACKEND__.ref_count(backend);
|
|
135
132
|
while (1) {
|
|
136
133
|
next_fiber = Queue_shift_no_wait(queue);
|
|
137
134
|
if (next_fiber != Qnil) {
|
|
138
|
-
if (
|
|
139
|
-
// this
|
|
140
|
-
|
|
141
|
-
__AGENT__.poll(agent, Qtrue, current_fiber, queue);
|
|
135
|
+
if (backend_was_polled == 0 && ref_count > 0) {
|
|
136
|
+
// this prevents event starvation in case the run queue never empties
|
|
137
|
+
__BACKEND__.poll(backend, Qtrue, current_fiber, queue);
|
|
142
138
|
}
|
|
143
139
|
break;
|
|
144
140
|
}
|
|
145
141
|
if (ref_count == 0) break;
|
|
146
142
|
|
|
147
|
-
|
|
148
|
-
|
|
143
|
+
__BACKEND__.poll(backend, Qnil, current_fiber, queue);
|
|
144
|
+
backend_was_polled = 1;
|
|
149
145
|
}
|
|
150
146
|
|
|
151
147
|
if (next_fiber == Qnil) return Qnil;
|
|
152
148
|
|
|
153
149
|
// run next fiber
|
|
154
150
|
value = rb_ivar_get(next_fiber, ID_runnable_value);
|
|
155
|
-
|
|
151
|
+
COND_TRACE(3, SYM_fiber_run, next_fiber, value);
|
|
156
152
|
|
|
157
153
|
rb_ivar_set(next_fiber, ID_runnable, Qnil);
|
|
158
154
|
RB_GC_GUARD(next_fiber);
|
|
159
155
|
RB_GC_GUARD(value);
|
|
160
|
-
return (next_fiber == current_fiber) ?
|
|
156
|
+
return (next_fiber == current_fiber) ?
|
|
161
157
|
value : rb_funcall(next_fiber, ID_transfer, 1, value);
|
|
162
158
|
}
|
|
163
159
|
|
|
@@ -175,12 +171,12 @@ VALUE Thread_reset_fiber_scheduling(VALUE self) {
|
|
|
175
171
|
}
|
|
176
172
|
|
|
177
173
|
VALUE Thread_fiber_break_out_of_ev_loop(VALUE self, VALUE fiber, VALUE resume_obj) {
|
|
178
|
-
VALUE
|
|
174
|
+
VALUE backend = rb_ivar_get(self, ID_ivar_backend);
|
|
179
175
|
if (fiber != Qnil) {
|
|
180
176
|
Thread_schedule_fiber_with_priority(self, fiber, resume_obj);
|
|
181
177
|
}
|
|
182
178
|
|
|
183
|
-
if (
|
|
179
|
+
if (__BACKEND__.wakeup(backend) == Qnil) {
|
|
184
180
|
// we're not inside the ev_loop, so we just do a switchpoint
|
|
185
181
|
Thread_switch_fiber(self);
|
|
186
182
|
}
|
|
@@ -188,6 +184,11 @@ VALUE Thread_fiber_break_out_of_ev_loop(VALUE self, VALUE fiber, VALUE resume_ob
|
|
|
188
184
|
return self;
|
|
189
185
|
}
|
|
190
186
|
|
|
187
|
+
VALUE Thread_debug(VALUE self) {
|
|
188
|
+
rb_ivar_set(self, rb_intern("@__debug__"), Qtrue);
|
|
189
|
+
return self;
|
|
190
|
+
}
|
|
191
|
+
|
|
191
192
|
void Init_Thread() {
|
|
192
193
|
rb_define_method(rb_cThread, "setup_fiber_scheduling", Thread_setup_fiber_scheduling, 0);
|
|
193
194
|
rb_define_method(rb_cThread, "reset_fiber_scheduling", Thread_reset_fiber_scheduling, 0);
|
|
@@ -200,8 +201,10 @@ void Init_Thread() {
|
|
|
200
201
|
rb_define_method(rb_cThread, "switch_fiber", Thread_switch_fiber, 0);
|
|
201
202
|
rb_define_method(rb_cThread, "run_queue_trace", Thread_run_queue_trace, 0);
|
|
202
203
|
|
|
204
|
+
rb_define_method(rb_cThread, "debug!", Thread_debug, 0);
|
|
205
|
+
|
|
203
206
|
ID_deactivate_all_watchers_post_fork = rb_intern("deactivate_all_watchers_post_fork");
|
|
204
|
-
|
|
207
|
+
ID_ivar_backend = rb_intern("@backend");
|
|
205
208
|
ID_ivar_join_wait_queue = rb_intern("@join_wait_queue");
|
|
206
209
|
ID_ivar_main_fiber = rb_intern("@main_fiber");
|
|
207
210
|
ID_ivar_result = rb_intern("@result");
|
data/lib/polyphony.rb
CHANGED
|
@@ -3,50 +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.
|
|
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
19
|
|
|
27
|
-
#
|
|
20
|
+
# Polyphony API
|
|
28
21
|
module Polyphony
|
|
29
22
|
class << self
|
|
30
|
-
def wait_for_signal(sig)
|
|
31
|
-
raise "should be reimplemented"
|
|
32
|
-
|
|
33
|
-
fiber = Fiber.current
|
|
34
|
-
# Polyphony.ref
|
|
35
|
-
old_trap = trap(sig) do
|
|
36
|
-
# Polyphony.unref
|
|
37
|
-
fiber.schedule(sig)
|
|
38
|
-
trap(sig, old_trap)
|
|
39
|
-
end
|
|
40
|
-
suspend
|
|
41
|
-
|
|
42
|
-
end
|
|
43
|
-
|
|
44
23
|
def fork(&block)
|
|
45
24
|
Kernel.fork do
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
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.
|
|
50
36
|
spin_forked_block(&block).transfer
|
|
51
37
|
end
|
|
52
38
|
end
|
|
@@ -57,7 +43,7 @@ module Polyphony
|
|
|
57
43
|
rescue SystemExit
|
|
58
44
|
# fall through to ensure
|
|
59
45
|
rescue Exception => e
|
|
60
|
-
e.full_message
|
|
46
|
+
warn e.full_message
|
|
61
47
|
exit!
|
|
62
48
|
ensure
|
|
63
49
|
exit_forked_process
|
|
@@ -65,16 +51,9 @@ module Polyphony
|
|
|
65
51
|
end
|
|
66
52
|
|
|
67
53
|
def run_forked_block(&block)
|
|
68
|
-
# A race condition can arise if a TERM or INT signal is received before
|
|
69
|
-
# the forked process has finished initializing. To prevent this we restore
|
|
70
|
-
# the default signal handlers, and then reinstall the custom Polyphony
|
|
71
|
-
# handlers just before running the given block.
|
|
72
|
-
trap('SIGTERM', 'DEFAULT')
|
|
73
|
-
trap('SIGINT', 'DEFAULT')
|
|
74
|
-
|
|
75
54
|
Thread.current.setup
|
|
76
55
|
Fiber.current.setup_main_fiber
|
|
77
|
-
Thread.current.
|
|
56
|
+
Thread.current.backend.post_fork
|
|
78
57
|
|
|
79
58
|
install_terminating_signal_handlers
|
|
80
59
|
|
|
@@ -123,12 +102,20 @@ module Polyphony
|
|
|
123
102
|
# processes (see Polyphony.fork).
|
|
124
103
|
at_exit do
|
|
125
104
|
next unless @original_pid == ::Process.pid
|
|
126
|
-
|
|
105
|
+
|
|
127
106
|
Polyphony.terminate_threads
|
|
128
107
|
Fiber.current.shutdown_all_children
|
|
129
108
|
end
|
|
130
109
|
end
|
|
131
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
|
|
132
119
|
end
|
|
133
120
|
|
|
134
121
|
Polyphony.install_terminating_signal_handlers
|