polyphony 0.43.11 → 0.45.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +8 -1
- data/CHANGELOG.md +40 -0
- data/Gemfile.lock +18 -8
- data/Rakefile +1 -1
- data/TODO.md +22 -9
- 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/raw.rb +14 -0
- data/examples/io/reline.rb +18 -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} +237 -238
- data/ext/polyphony/polyphony.c +3 -3
- data/ext/polyphony/polyphony.h +15 -20
- data/ext/polyphony/polyphony_ext.c +3 -4
- data/ext/polyphony/queue.c +5 -6
- data/ext/polyphony/ring_buffer.c +0 -1
- data/ext/polyphony/thread.c +36 -33
- data/lib/polyphony.rb +26 -39
- 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 -5
- 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 +30 -30
- data/lib/polyphony/extensions/fiber.rb +30 -49
- data/lib/polyphony/extensions/io.rb +60 -16
- data/lib/polyphony/extensions/openssl.rb +6 -6
- data/lib/polyphony/extensions/socket.rb +14 -15
- data/lib/polyphony/extensions/thread.rb +6 -5
- 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 +29 -12
- data/test/test_io.rb +59 -1
- data/test/test_kernel.rb +5 -0
- data/test/test_resource_pool.rb +29 -4
- data/test/test_signal.rb +16 -37
- data/test/test_socket.rb +17 -0
- data/test/test_sync.rb +52 -0
- metadata +127 -97
- 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 -41
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,23 +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(str, obj) { printf(str); 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
|
-
#define
|
27
|
+
extern backend_interface_t backend_interface;
|
28
|
+
#define __BACKEND__ (backend_interface)
|
24
29
|
|
25
30
|
extern VALUE mPolyphony;
|
26
31
|
extern VALUE cQueue;
|
@@ -32,7 +37,8 @@ extern ID ID_clear;
|
|
32
37
|
extern ID ID_each;
|
33
38
|
extern ID ID_fiber_trace;
|
34
39
|
extern ID ID_inspect;
|
35
|
-
extern ID
|
40
|
+
extern ID ID_invoke;
|
41
|
+
extern ID ID_ivar_backend;
|
36
42
|
extern ID ID_ivar_running;
|
37
43
|
extern ID ID_ivar_thread;
|
38
44
|
extern ID ID_new;
|
@@ -60,31 +66,20 @@ enum {
|
|
60
66
|
FIBER_STATE_SCHEDULED = 2
|
61
67
|
};
|
62
68
|
|
63
|
-
// watcher flags
|
64
|
-
enum {
|
65
|
-
// a watcher's active field will be set to this after fork
|
66
|
-
GYRO_WATCHER_POST_FORK = 0xFF
|
67
|
-
};
|
68
|
-
|
69
69
|
VALUE Fiber_auto_watcher(VALUE self);
|
70
70
|
void Fiber_make_runnable(VALUE fiber, VALUE value);
|
71
71
|
|
72
72
|
VALUE Queue_push(VALUE self, VALUE value);
|
73
73
|
VALUE Queue_unshift(VALUE self, VALUE value);
|
74
74
|
VALUE Queue_shift(VALUE self);
|
75
|
+
VALUE Queue_shift_all(VALUE self);
|
75
76
|
VALUE Queue_shift_no_wait(VALUE self);
|
76
77
|
VALUE Queue_clear(VALUE self);
|
77
78
|
VALUE Queue_delete(VALUE self, VALUE value);
|
78
79
|
long Queue_len(VALUE self);
|
79
80
|
void Queue_trace(VALUE self);
|
80
81
|
|
81
|
-
VALUE Polyphony_snooze(VALUE self);
|
82
|
-
|
83
82
|
VALUE Thread_schedule_fiber(VALUE thread, VALUE fiber, VALUE value);
|
84
83
|
VALUE Thread_switch_fiber(VALUE thread);
|
85
84
|
|
86
|
-
int io_setstrbuf(VALUE *str, long len);
|
87
|
-
void io_set_read_length(VALUE str, long n, int shrinkable);
|
88
|
-
VALUE io_enc_str(VALUE str, rb_io_t *fptr);
|
89
|
-
|
90
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
@@ -80,17 +80,16 @@ VALUE Queue_shift(VALUE self) {
|
|
80
80
|
|
81
81
|
VALUE fiber = rb_fiber_current();
|
82
82
|
VALUE thread = rb_thread_current();
|
83
|
-
VALUE
|
83
|
+
VALUE backend = rb_ivar_get(thread, ID_ivar_backend);
|
84
84
|
|
85
85
|
while (1) {
|
86
86
|
ring_buffer_push(&queue->shift_queue, fiber);
|
87
87
|
if (queue->values.count > 0) Fiber_make_runnable(fiber, Qnil);
|
88
|
-
|
89
|
-
VALUE switchpoint_result =
|
88
|
+
|
89
|
+
VALUE switchpoint_result = __BACKEND__.wait_event(backend, Qnil);
|
90
90
|
ring_buffer_delete(&queue->shift_queue, fiber);
|
91
91
|
|
92
|
-
|
93
|
-
return rb_funcall(rb_mKernel, ID_raise, 1, switchpoint_result);
|
92
|
+
TEST_RESUME_EXCEPTION(switchpoint_result);
|
94
93
|
RB_GC_GUARD(switchpoint_result);
|
95
94
|
|
96
95
|
if (queue->values.count > 0)
|
@@ -152,7 +151,7 @@ VALUE Queue_flush_waiters(VALUE self, VALUE value) {
|
|
152
151
|
while(1) {
|
153
152
|
VALUE fiber = ring_buffer_shift(&queue->shift_queue);
|
154
153
|
if (fiber == Qnil) return self;
|
155
|
-
|
154
|
+
|
156
155
|
Fiber_make_runnable(fiber, value);
|
157
156
|
}
|
158
157
|
}
|
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
|
@@ -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
|
|
@@ -97,10 +76,10 @@ module Polyphony
|
|
97
76
|
end
|
98
77
|
|
99
78
|
def install_terminating_signal_handlers
|
100
|
-
trap('SIGTERM'
|
79
|
+
trap('SIGTERM') { raise SystemExit }
|
101
80
|
orig_trap('SIGINT') do
|
102
81
|
orig_trap('SIGINT') { exit! }
|
103
|
-
|
82
|
+
Fiber.schedule_priority_oob_fiber { raise Interrupt }
|
104
83
|
end
|
105
84
|
end
|
106
85
|
|
@@ -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
|