polyphony 0.19 → 0.20
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/.gitignore +1 -1
- data/.rubocop.yml +87 -1
- data/CHANGELOG.md +35 -0
- data/Gemfile.lock +17 -6
- data/README.md +200 -139
- data/Rakefile +4 -4
- data/TODO.md +35 -7
- data/bin/poly +11 -0
- data/docs/getting-started/getting-started.md +1 -1
- data/docs/summary.md +3 -0
- data/docs/technical-overview/exception-handling.md +94 -0
- data/docs/technical-overview/fiber-scheduling.md +99 -0
- data/examples/core/cancel.rb +8 -4
- data/examples/core/channel_echo.rb +18 -17
- data/examples/core/defer.rb +12 -0
- data/examples/core/enumerator.rb +4 -4
- data/examples/core/fiber_error.rb +9 -0
- data/examples/core/fiber_error_with_backtrace.rb +73 -0
- data/examples/core/fork.rb +6 -6
- data/examples/core/genserver.rb +16 -8
- data/examples/core/lock.rb +3 -3
- data/examples/core/move_on.rb +4 -3
- data/examples/core/move_on_twice.rb +5 -5
- data/examples/core/move_on_with_ensure.rb +8 -11
- data/examples/core/move_on_with_value.rb +14 -0
- data/examples/core/{multiple_spawn.rb → multiple_spin.rb} +5 -5
- data/examples/core/nested_cancel.rb +5 -5
- data/examples/core/{nested_multiple_spawn.rb → nested_multiple_spin.rb} +6 -6
- data/examples/core/nested_spin.rb +17 -0
- data/examples/core/pingpong.rb +21 -0
- data/examples/core/pulse.rb +4 -5
- data/examples/core/resource.rb +6 -4
- data/examples/core/resource_cancel.rb +6 -9
- data/examples/core/resource_delegate.rb +3 -3
- data/examples/core/sleep.rb +3 -3
- data/examples/core/sleep_spin.rb +19 -0
- data/examples/core/snooze.rb +32 -0
- data/examples/core/spin.rb +14 -0
- data/examples/core/{spawn_cancel.rb → spin_cancel.rb} +6 -7
- data/examples/core/spin_error.rb +17 -0
- data/examples/core/spin_error_backtrace.rb +30 -0
- data/examples/core/spin_uncaught_error.rb +15 -0
- data/examples/core/supervisor.rb +8 -8
- data/examples/core/supervisor_with_cancel_scope.rb +7 -7
- data/examples/core/supervisor_with_error.rb +8 -8
- data/examples/core/supervisor_with_manual_move_on.rb +6 -7
- data/examples/core/suspend.rb +13 -0
- data/examples/core/thread.rb +1 -1
- data/examples/core/thread_cancel.rb +9 -11
- data/examples/core/thread_pool.rb +18 -14
- data/examples/core/throttle.rb +7 -7
- data/examples/core/timeout.rb +3 -3
- data/examples/fs/read.rb +7 -9
- data/examples/http/config.ru +7 -3
- data/examples/http/cuba.ru +22 -0
- data/examples/http/happy_eyeballs.rb +6 -4
- data/examples/http/http_client.rb +1 -1
- data/examples/http/http_get.rb +1 -1
- data/examples/http/http_parse_experiment.rb +21 -16
- data/examples/http/http_proxy.rb +28 -26
- data/examples/http/http_server.rb +10 -10
- data/examples/http/http_server_forked.rb +6 -5
- data/examples/http/http_server_throttled.rb +3 -3
- data/examples/http/http_ws_server.rb +11 -11
- data/examples/http/https_raw_client.rb +1 -1
- data/examples/http/https_server.rb +8 -8
- data/examples/http/https_wss_server.rb +13 -11
- data/examples/http/rack_server.rb +2 -2
- data/examples/http/rack_server_https.rb +4 -4
- data/examples/http/rack_server_https_forked.rb +5 -5
- data/examples/http/websocket_secure_server.rb +6 -6
- data/examples/http/websocket_server.rb +5 -5
- data/examples/interfaces/pg_client.rb +4 -4
- data/examples/interfaces/pg_pool.rb +13 -6
- data/examples/interfaces/pg_transaction.rb +5 -4
- data/examples/interfaces/redis_channels.rb +15 -11
- data/examples/interfaces/redis_client.rb +2 -2
- data/examples/interfaces/redis_pubsub.rb +2 -1
- data/examples/interfaces/redis_pubsub_perf.rb +13 -9
- data/examples/io/backticks.rb +11 -0
- data/examples/io/cat.rb +4 -5
- data/examples/io/echo_client.rb +9 -4
- data/examples/io/echo_client_from_stdin.rb +20 -0
- data/examples/io/echo_pipe.rb +7 -8
- data/examples/io/echo_server.rb +8 -6
- data/examples/io/echo_server_with_timeout.rb +13 -10
- data/examples/io/echo_stdin.rb +3 -3
- data/examples/io/httparty.rb +2 -2
- data/examples/io/httparty_multi.rb +8 -4
- data/examples/io/httparty_threaded.rb +6 -2
- data/examples/io/io_read.rb +2 -2
- data/examples/io/irb.rb +16 -4
- data/examples/io/net-http.rb +3 -3
- data/examples/io/open.rb +17 -0
- data/examples/io/system.rb +3 -3
- data/examples/io/tcpserver.rb +15 -0
- data/examples/io/tcpsocket.rb +6 -5
- data/examples/performance/multi_snooze.rb +29 -0
- data/examples/performance/{perf_snooze.rb → snooze.rb} +7 -5
- data/examples/performance/snooze_raw.rb +39 -0
- data/ext/gyro/async.c +165 -0
- data/ext/gyro/child.c +167 -0
- data/ext/{ev → gyro}/extconf.rb +4 -3
- data/ext/gyro/gyro.c +316 -0
- data/ext/{ev/ev.h → gyro/gyro.h} +12 -7
- data/ext/gyro/gyro_ext.c +23 -0
- data/ext/{ev → gyro}/io.c +65 -57
- data/ext/{ev → gyro}/libev.h +0 -0
- data/ext/gyro/signal.c +117 -0
- data/ext/{ev → gyro}/socket.c +61 -6
- data/ext/gyro/timer.c +199 -0
- data/ext/libev/Changes +35 -0
- data/ext/libev/README +2 -1
- data/ext/libev/ev.c +213 -151
- data/ext/libev/ev.h +95 -88
- data/ext/libev/ev_epoll.c +26 -15
- data/ext/libev/ev_kqueue.c +11 -5
- data/ext/libev/ev_linuxaio.c +642 -0
- data/ext/libev/ev_poll.c +13 -8
- data/ext/libev/ev_port.c +5 -2
- data/ext/libev/ev_vars.h +14 -3
- data/ext/libev/ev_wrap.h +16 -0
- data/lib/ev_ext.bundle +0 -0
- data/lib/polyphony.rb +46 -50
- data/lib/polyphony/auto_run.rb +12 -0
- data/lib/polyphony/core/cancel_scope.rb +11 -7
- data/lib/polyphony/core/channel.rb +16 -9
- data/lib/polyphony/core/coprocess.rb +101 -51
- data/lib/polyphony/core/exceptions.rb +14 -12
- data/lib/polyphony/core/resource_pool.rb +21 -8
- data/lib/polyphony/core/supervisor.rb +10 -5
- data/lib/polyphony/core/sync.rb +7 -6
- data/lib/polyphony/core/thread.rb +4 -4
- data/lib/polyphony/core/thread_pool.rb +4 -4
- data/lib/polyphony/core/throttler.rb +6 -4
- data/lib/polyphony/extensions/core.rb +253 -0
- data/lib/polyphony/extensions/io.rb +28 -16
- data/lib/polyphony/extensions/openssl.rb +2 -1
- data/lib/polyphony/extensions/socket.rb +47 -52
- data/lib/polyphony/http.rb +4 -3
- data/lib/polyphony/http/agent.rb +68 -57
- data/lib/polyphony/http/server.rb +5 -5
- data/lib/polyphony/http/server/http1.rb +268 -0
- data/lib/polyphony/http/server/http2.rb +62 -0
- data/lib/polyphony/http/server/http2_stream.rb +104 -0
- data/lib/polyphony/http/server/rack.rb +64 -0
- data/lib/polyphony/http/server/request.rb +119 -0
- data/lib/polyphony/net.rb +26 -15
- data/lib/polyphony/postgres.rb +17 -13
- data/lib/polyphony/redis.rb +16 -15
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony/websocket.rb +11 -4
- data/polyphony.gemspec +13 -9
- data/test/eg.rb +27 -0
- data/test/helper.rb +25 -0
- data/test/run.rb +5 -0
- data/test/test_async.rb +33 -0
- data/test/test_coprocess.rb +239 -77
- data/test/test_core.rb +95 -61
- data/test/test_gyro.rb +148 -0
- data/test/test_http_server.rb +313 -0
- data/test/test_io.rb +79 -27
- data/test/test_kernel.rb +22 -12
- data/test/test_signal.rb +36 -0
- data/test/test_timer.rb +24 -0
- metadata +89 -33
- data/examples/core/nested_async.rb +0 -17
- data/examples/core/next_tick.rb +0 -12
- data/examples/core/sleep_spawn.rb +0 -19
- data/examples/core/spawn.rb +0 -14
- data/examples/core/spawn_error.rb +0 -28
- data/examples/performance/perf_multi_snooze.rb +0 -21
- data/ext/ev/async.c +0 -168
- data/ext/ev/child.c +0 -169
- data/ext/ev/ev_ext.c +0 -23
- data/ext/ev/ev_module.c +0 -242
- data/ext/ev/signal.c +0 -119
- data/ext/ev/timer.c +0 -197
- data/lib/polyphony/core/fiber_pool.rb +0 -98
- data/lib/polyphony/extensions/kernel.rb +0 -169
- data/lib/polyphony/http/http1_adapter.rb +0 -254
- data/lib/polyphony/http/http2_adapter.rb +0 -157
- data/lib/polyphony/http/rack.rb +0 -25
- data/lib/polyphony/http/request.rb +0 -66
- data/test/test_ev.rb +0 -110
data/ext/gyro/child.c
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
#include "gyro.h"
|
2
|
+
|
3
|
+
struct Gyro_Child {
|
4
|
+
struct ev_child ev_child;
|
5
|
+
int active;
|
6
|
+
int pid;
|
7
|
+
VALUE self;
|
8
|
+
VALUE callback;
|
9
|
+
VALUE fiber;
|
10
|
+
};
|
11
|
+
|
12
|
+
static VALUE cGyro_Child = Qnil;
|
13
|
+
|
14
|
+
/* Allocator/deallocator */
|
15
|
+
static VALUE Gyro_Child_allocate(VALUE klass);
|
16
|
+
static void Gyro_Child_mark(void *ptr);
|
17
|
+
static void Gyro_Child_free(void *ptr);
|
18
|
+
static size_t Gyro_Child_size(const void *ptr);
|
19
|
+
|
20
|
+
/* Methods */
|
21
|
+
static VALUE Gyro_Child_initialize(VALUE self, VALUE pid);
|
22
|
+
|
23
|
+
static VALUE Gyro_Child_start(VALUE self);
|
24
|
+
static VALUE Gyro_Child_stop(VALUE self);
|
25
|
+
static VALUE Gyro_Child_await(VALUE self);
|
26
|
+
|
27
|
+
void Gyro_Child_callback(struct ev_loop *ev_loop, struct ev_child *child, int revents);
|
28
|
+
|
29
|
+
/* Child encapsulates an child watcher */
|
30
|
+
void Init_Gyro_Child() {
|
31
|
+
cGyro_Child = rb_define_class_under(mGyro, "Child", rb_cData);
|
32
|
+
rb_define_alloc_func(cGyro_Child, Gyro_Child_allocate);
|
33
|
+
|
34
|
+
rb_define_method(cGyro_Child, "initialize", Gyro_Child_initialize, 1);
|
35
|
+
rb_define_method(cGyro_Child, "start", Gyro_Child_start, 0);
|
36
|
+
rb_define_method(cGyro_Child, "stop", Gyro_Child_stop, 0);
|
37
|
+
rb_define_method(cGyro_Child, "await", Gyro_Child_await, 0);
|
38
|
+
}
|
39
|
+
|
40
|
+
static const rb_data_type_t Gyro_Child_type = {
|
41
|
+
"Gyro_Child",
|
42
|
+
{Gyro_Child_mark, Gyro_Child_free, Gyro_Child_size,},
|
43
|
+
0, 0,
|
44
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
45
|
+
};
|
46
|
+
|
47
|
+
static VALUE Gyro_Child_allocate(VALUE klass) {
|
48
|
+
struct Gyro_Child *child = (struct Gyro_Child *)xmalloc(sizeof(struct Gyro_Child));
|
49
|
+
return TypedData_Wrap_Struct(klass, &Gyro_Child_type, child);
|
50
|
+
}
|
51
|
+
|
52
|
+
static void Gyro_Child_mark(void *ptr) {
|
53
|
+
struct Gyro_Child *child = ptr;
|
54
|
+
if (child->callback != Qnil) {
|
55
|
+
rb_gc_mark(child->callback);
|
56
|
+
}
|
57
|
+
if (child->fiber != Qnil) {
|
58
|
+
rb_gc_mark(child->fiber);
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
static void Gyro_Child_free(void *ptr) {
|
63
|
+
struct Gyro_Child *child = ptr;
|
64
|
+
if (child->active) {
|
65
|
+
ev_child_stop(EV_DEFAULT, &child->ev_child);
|
66
|
+
}
|
67
|
+
xfree(child);
|
68
|
+
}
|
69
|
+
|
70
|
+
static size_t Gyro_Child_size(const void *ptr) {
|
71
|
+
return sizeof(struct Gyro_Child);
|
72
|
+
}
|
73
|
+
|
74
|
+
#define GetGyro_Child(obj, child) \
|
75
|
+
TypedData_Get_Struct((obj), struct Gyro_Child, &Gyro_Child_type, (child))
|
76
|
+
|
77
|
+
static VALUE Gyro_Child_initialize(VALUE self, VALUE pid) {
|
78
|
+
struct Gyro_Child *child;
|
79
|
+
|
80
|
+
GetGyro_Child(self, child);
|
81
|
+
|
82
|
+
child->self = self;
|
83
|
+
child->callback = Qnil;
|
84
|
+
child->fiber = Qnil;
|
85
|
+
child->pid = NUM2INT(pid);
|
86
|
+
child->active = 0;
|
87
|
+
|
88
|
+
ev_child_init(&child->ev_child, Gyro_Child_callback, child->pid, 0);
|
89
|
+
|
90
|
+
return Qnil;
|
91
|
+
}
|
92
|
+
|
93
|
+
void Gyro_Child_callback(struct ev_loop *ev_loop, struct ev_child *ev_child, int revents) {
|
94
|
+
VALUE fiber;
|
95
|
+
VALUE resume_value;
|
96
|
+
struct Gyro_Child *child = (struct Gyro_Child*)ev_child;
|
97
|
+
resume_value = INT2NUM(child->pid);
|
98
|
+
|
99
|
+
child->active = 0;
|
100
|
+
ev_child_stop(EV_DEFAULT, ev_child);
|
101
|
+
Gyro_del_watcher_ref(child->self);
|
102
|
+
|
103
|
+
if (child->fiber != Qnil) {
|
104
|
+
fiber = child->fiber;
|
105
|
+
child->fiber = Qnil;
|
106
|
+
SCHEDULE_FIBER(fiber, 1, resume_value);
|
107
|
+
}
|
108
|
+
else if (child->callback != Qnil) {
|
109
|
+
rb_funcall(child->callback, ID_call, 1, resume_value);
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
static VALUE Gyro_Child_start(VALUE self) {
|
114
|
+
struct Gyro_Child *child;
|
115
|
+
GetGyro_Child(self, child);
|
116
|
+
|
117
|
+
if (rb_block_given_p()) {
|
118
|
+
child->callback = rb_block_proc();
|
119
|
+
}
|
120
|
+
|
121
|
+
if (!child->active) {
|
122
|
+
ev_child_start(EV_DEFAULT, &child->ev_child);
|
123
|
+
child->active = 1;
|
124
|
+
Gyro_add_watcher_ref(self);
|
125
|
+
}
|
126
|
+
|
127
|
+
return self;
|
128
|
+
}
|
129
|
+
|
130
|
+
static VALUE Gyro_Child_stop(VALUE self) {
|
131
|
+
struct Gyro_Child *child;
|
132
|
+
GetGyro_Child(self, child);
|
133
|
+
|
134
|
+
if (child->active) {
|
135
|
+
ev_child_stop(EV_DEFAULT, &child->ev_child);
|
136
|
+
child->active = 0;
|
137
|
+
Gyro_del_watcher_ref(self);
|
138
|
+
}
|
139
|
+
|
140
|
+
return self;
|
141
|
+
}
|
142
|
+
|
143
|
+
static VALUE Gyro_Child_await(VALUE self) {
|
144
|
+
struct Gyro_Child *child;
|
145
|
+
VALUE ret;
|
146
|
+
|
147
|
+
GetGyro_Child(self, child);
|
148
|
+
|
149
|
+
child->fiber = rb_fiber_current();
|
150
|
+
child->active = 1;
|
151
|
+
ev_child_start(EV_DEFAULT, &child->ev_child);
|
152
|
+
Gyro_add_watcher_ref(self);
|
153
|
+
|
154
|
+
ret = YIELD_TO_REACTOR();
|
155
|
+
|
156
|
+
// fiber is resumed, check if resumed value is an exception
|
157
|
+
if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) {
|
158
|
+
if (child->active) {
|
159
|
+
child->active = 0;
|
160
|
+
ev_child_stop(EV_DEFAULT, &child->ev_child);
|
161
|
+
}
|
162
|
+
return rb_funcall(ret, ID_raise, 1, ret);
|
163
|
+
}
|
164
|
+
else {
|
165
|
+
return ret;
|
166
|
+
}
|
167
|
+
}
|
data/ext/{ev → gyro}/extconf.rb
RENAMED
@@ -6,6 +6,7 @@ require "mkmf"
|
|
6
6
|
|
7
7
|
have_header("unistd.h")
|
8
8
|
|
9
|
+
$defs << "-DEV_USE_LINUXAIO" if have_header("linux/aio_abi.h")
|
9
10
|
$defs << "-DEV_USE_SELECT" if have_header("sys/select.h")
|
10
11
|
$defs << "-DEV_USE_POLL" if have_type("port_event_t", "poll.h")
|
11
12
|
$defs << "-DEV_USE_EPOLL" if have_header("sys/epoll.h")
|
@@ -13,7 +14,7 @@ $defs << "-DEV_USE_KQUEUE" if have_header("sys/event.h") && have_header("s
|
|
13
14
|
$defs << "-DEV_USE_PORT" if have_type("port_event_t", "port.h")
|
14
15
|
$defs << "-DHAVE_SYS_RESOURCE_H" if have_header("sys/resource.h")
|
15
16
|
|
16
|
-
CONFIG["optflags"] << " -fno-strict-aliasing"
|
17
|
+
CONFIG["optflags"] << " -fno-strict-aliasing" unless RUBY_PLATFORM =~ /mswin/
|
17
18
|
|
18
|
-
dir_config "
|
19
|
-
create_makefile "
|
19
|
+
dir_config "gyro_ext"
|
20
|
+
create_makefile "gyro_ext"
|
data/ext/gyro/gyro.c
ADDED
@@ -0,0 +1,316 @@
|
|
1
|
+
#include "gyro.h"
|
2
|
+
|
3
|
+
static VALUE Gyro_run(VALUE self);
|
4
|
+
static VALUE Gyro_break(VALUE self);
|
5
|
+
static VALUE Gyro_start(VALUE self);
|
6
|
+
static VALUE Gyro_restart(VALUE self);
|
7
|
+
|
8
|
+
static VALUE Gyro_ref(VALUE self);
|
9
|
+
static VALUE Gyro_unref(VALUE self);
|
10
|
+
|
11
|
+
static VALUE Gyro_defer(VALUE self);
|
12
|
+
static VALUE Gyro_post_fork(VALUE self);
|
13
|
+
|
14
|
+
static VALUE Gyro_suspend(VALUE self);
|
15
|
+
|
16
|
+
static VALUE Fiber_safe_transfer(int argc, VALUE *argv, VALUE self);
|
17
|
+
static VALUE Fiber_schedule(int argc, VALUE *argv, VALUE self);
|
18
|
+
|
19
|
+
void Gyro_defer_callback(struct ev_loop *ev_loop, struct ev_idle *watcher, int revents);
|
20
|
+
|
21
|
+
VALUE mGyro;
|
22
|
+
|
23
|
+
VALUE Gyro_reactor_fiber;
|
24
|
+
VALUE Gyro_root_fiber;
|
25
|
+
VALUE Gyro_post_run_fiber;
|
26
|
+
|
27
|
+
static VALUE watcher_refs;
|
28
|
+
static VALUE deferred_head;
|
29
|
+
static VALUE deferred_tail;
|
30
|
+
static VALUE deferred_eol_marker;
|
31
|
+
|
32
|
+
static struct ev_idle idle_watcher;
|
33
|
+
static int deferred_active;
|
34
|
+
static int deferred_in_callback;
|
35
|
+
static int break_flag;
|
36
|
+
|
37
|
+
ID ID_call;
|
38
|
+
ID ID_caller;
|
39
|
+
ID ID_clear;
|
40
|
+
ID ID_deferred_next;
|
41
|
+
ID ID_deferred_prev;
|
42
|
+
ID ID_each;
|
43
|
+
ID ID_inspect;
|
44
|
+
ID ID_raise;
|
45
|
+
ID ID_read_watcher;
|
46
|
+
ID ID_scheduled_value;
|
47
|
+
ID ID_transfer;
|
48
|
+
ID ID_write_watcher;
|
49
|
+
ID ID_R;
|
50
|
+
ID ID_W;
|
51
|
+
ID ID_RW;
|
52
|
+
|
53
|
+
void Init_Gyro() {
|
54
|
+
mGyro = rb_define_module("Gyro");
|
55
|
+
|
56
|
+
rb_define_singleton_method(mGyro, "break", Gyro_break, 0);
|
57
|
+
rb_define_singleton_method(mGyro, "defer", Gyro_defer, 0);
|
58
|
+
rb_define_singleton_method(mGyro, "post_fork", Gyro_post_fork, 0);
|
59
|
+
rb_define_singleton_method(mGyro, "ref", Gyro_ref, 0);
|
60
|
+
rb_define_singleton_method(mGyro, "start", Gyro_start, 0);
|
61
|
+
rb_define_singleton_method(mGyro, "restart", Gyro_restart, 0);
|
62
|
+
rb_define_singleton_method(mGyro, "snooze", Gyro_snooze, 0);
|
63
|
+
rb_define_singleton_method(mGyro, "unref", Gyro_unref, 0);
|
64
|
+
|
65
|
+
rb_define_global_function("defer", Gyro_defer, 0);
|
66
|
+
rb_define_global_function("snooze", Gyro_snooze, 0);
|
67
|
+
rb_define_global_function("suspend", Gyro_suspend, 0);
|
68
|
+
|
69
|
+
VALUE cFiber = rb_const_get(rb_cObject, rb_intern("Fiber"));
|
70
|
+
rb_define_method(cFiber, "safe_transfer", Fiber_safe_transfer, -1);
|
71
|
+
rb_define_method(cFiber, "schedule", Fiber_schedule, -1);
|
72
|
+
|
73
|
+
ID_call = rb_intern("call");
|
74
|
+
ID_caller = rb_intern("caller");
|
75
|
+
ID_clear = rb_intern("clear");
|
76
|
+
ID_deferred_next = rb_intern("deferred_next");
|
77
|
+
ID_deferred_prev = rb_intern("deferred_prev");
|
78
|
+
ID_each = rb_intern("each");
|
79
|
+
ID_inspect = rb_intern("inspect");
|
80
|
+
ID_raise = rb_intern("raise");
|
81
|
+
ID_read_watcher = rb_intern("read_watcher");
|
82
|
+
ID_scheduled_value = rb_intern("@scheduled_value");
|
83
|
+
ID_transfer = rb_intern("transfer");
|
84
|
+
ID_write_watcher = rb_intern("write_watcher");
|
85
|
+
ID_R = rb_intern("r");
|
86
|
+
ID_W = rb_intern("w");
|
87
|
+
ID_RW = rb_intern("rw");
|
88
|
+
|
89
|
+
Gyro_root_fiber = rb_fiber_current();
|
90
|
+
Gyro_reactor_fiber = rb_fiber_new(Gyro_run, Qnil);
|
91
|
+
rb_gv_set("__reactor_fiber__", Gyro_reactor_fiber);
|
92
|
+
|
93
|
+
watcher_refs = rb_hash_new();
|
94
|
+
rb_global_variable(&watcher_refs);
|
95
|
+
|
96
|
+
deferred_head = Qnil;
|
97
|
+
deferred_tail = Qnil;
|
98
|
+
rb_global_variable(&deferred_head);
|
99
|
+
|
100
|
+
deferred_eol_marker = rb_funcall(rb_cObject, rb_intern("new"), 0);
|
101
|
+
rb_global_variable(&deferred_eol_marker);
|
102
|
+
|
103
|
+
ev_idle_init(&idle_watcher, Gyro_defer_callback);
|
104
|
+
deferred_active = 0;
|
105
|
+
deferred_in_callback = 0;
|
106
|
+
}
|
107
|
+
|
108
|
+
static VALUE Gyro_run(VALUE self) {
|
109
|
+
break_flag = 0;
|
110
|
+
Gyro_post_run_fiber = Qnil;
|
111
|
+
ev_run(EV_DEFAULT, 0);
|
112
|
+
rb_gv_set("__reactor_fiber__", Qnil);
|
113
|
+
|
114
|
+
if (Gyro_post_run_fiber != Qnil) {
|
115
|
+
rb_funcall(Gyro_post_run_fiber, ID_transfer, 0);
|
116
|
+
}
|
117
|
+
|
118
|
+
return Qnil;
|
119
|
+
}
|
120
|
+
|
121
|
+
static VALUE Gyro_break(VALUE self) {
|
122
|
+
break_flag = 1;
|
123
|
+
// make sure reactor fiber is alive
|
124
|
+
if (!RTEST(rb_fiber_alive_p(Gyro_reactor_fiber))) {
|
125
|
+
return Qnil;
|
126
|
+
}
|
127
|
+
|
128
|
+
if (deferred_active) {
|
129
|
+
deferred_active = 0;
|
130
|
+
ev_idle_stop(EV_DEFAULT, &idle_watcher);
|
131
|
+
}
|
132
|
+
ev_break(EV_DEFAULT, EVBREAK_ALL);
|
133
|
+
YIELD_TO_REACTOR();
|
134
|
+
return Qnil;
|
135
|
+
}
|
136
|
+
|
137
|
+
static VALUE Gyro_start(VALUE self) {
|
138
|
+
Gyro_post_run_fiber = Qnil;
|
139
|
+
deferred_head = Qnil;
|
140
|
+
Gyro_reactor_fiber = rb_fiber_new(Gyro_run, Qnil);
|
141
|
+
rb_gv_set("__reactor_fiber__", Gyro_reactor_fiber);
|
142
|
+
return Qnil;
|
143
|
+
}
|
144
|
+
|
145
|
+
static VALUE Gyro_restart(VALUE self) {
|
146
|
+
Gyro_post_run_fiber = rb_fiber_current();
|
147
|
+
Gyro_break(self);
|
148
|
+
// control will be transferred back to here after reactor loop is done
|
149
|
+
Gyro_start(self);
|
150
|
+
|
151
|
+
return Qnil;
|
152
|
+
}
|
153
|
+
|
154
|
+
static VALUE Gyro_ref(VALUE self) {
|
155
|
+
ev_ref(EV_DEFAULT);
|
156
|
+
return Qnil;
|
157
|
+
}
|
158
|
+
|
159
|
+
static VALUE Gyro_unref(VALUE self) {
|
160
|
+
ev_unref(EV_DEFAULT);
|
161
|
+
return Qnil;
|
162
|
+
}
|
163
|
+
|
164
|
+
void Gyro_add_watcher_ref(VALUE obj) {
|
165
|
+
rb_hash_aset(watcher_refs, rb_obj_id(obj), obj);
|
166
|
+
}
|
167
|
+
|
168
|
+
void Gyro_del_watcher_ref(VALUE obj) {
|
169
|
+
rb_hash_delete(watcher_refs, rb_obj_id(obj));
|
170
|
+
}
|
171
|
+
|
172
|
+
static void defer_add(VALUE item) {
|
173
|
+
if (NIL_P(deferred_head)) {
|
174
|
+
deferred_head = item;
|
175
|
+
deferred_tail = item;
|
176
|
+
rb_ivar_set(item, ID_deferred_next, Qnil);
|
177
|
+
rb_ivar_set(item, ID_deferred_prev, Qnil);
|
178
|
+
}
|
179
|
+
else {
|
180
|
+
rb_ivar_set(deferred_tail, ID_deferred_next, item);
|
181
|
+
rb_ivar_set(item, ID_deferred_prev, deferred_tail);
|
182
|
+
deferred_tail = item;
|
183
|
+
}
|
184
|
+
|
185
|
+
if (!deferred_active) {
|
186
|
+
deferred_active = 1;
|
187
|
+
ev_idle_start(EV_DEFAULT, &idle_watcher);
|
188
|
+
}
|
189
|
+
}
|
190
|
+
|
191
|
+
static void defer_remove(VALUE item) {
|
192
|
+
VALUE next = rb_ivar_get(item, ID_deferred_next);
|
193
|
+
VALUE prev = rb_ivar_get(item, ID_deferred_prev);
|
194
|
+
if (RTEST(prev)) {
|
195
|
+
rb_ivar_set(prev, ID_deferred_next, next);
|
196
|
+
}
|
197
|
+
if (RTEST(next)) {
|
198
|
+
rb_ivar_set(next, ID_deferred_prev, prev);
|
199
|
+
}
|
200
|
+
|
201
|
+
}
|
202
|
+
|
203
|
+
static VALUE Gyro_defer(VALUE self) {
|
204
|
+
VALUE proc = rb_block_proc();
|
205
|
+
if (RTEST(proc)) {
|
206
|
+
defer_add(proc);
|
207
|
+
}
|
208
|
+
return Qnil;
|
209
|
+
}
|
210
|
+
|
211
|
+
VALUE Gyro_snooze(VALUE self) {
|
212
|
+
VALUE ret;
|
213
|
+
VALUE fiber = rb_fiber_current();
|
214
|
+
defer_add(fiber);
|
215
|
+
|
216
|
+
ret = YIELD_TO_REACTOR();
|
217
|
+
|
218
|
+
if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) {
|
219
|
+
defer_remove(fiber);
|
220
|
+
return rb_funcall(ret, ID_raise, 1, ret);
|
221
|
+
}
|
222
|
+
else {
|
223
|
+
return ret;
|
224
|
+
}
|
225
|
+
}
|
226
|
+
|
227
|
+
static VALUE Gyro_post_fork(VALUE self) {
|
228
|
+
ev_loop_fork(EV_DEFAULT);
|
229
|
+
|
230
|
+
Gyro_reactor_fiber = rb_fiber_new(Gyro_run, Qnil);
|
231
|
+
rb_gv_set("__reactor_fiber__", Gyro_reactor_fiber);
|
232
|
+
Gyro_root_fiber = rb_fiber_current();
|
233
|
+
|
234
|
+
deferred_head = Qnil;
|
235
|
+
deferred_active = 0;
|
236
|
+
|
237
|
+
return Qnil;
|
238
|
+
}
|
239
|
+
|
240
|
+
VALUE run_deferred(VALUE item) {
|
241
|
+
if (rb_obj_is_proc(item)) {
|
242
|
+
rb_funcall(item, ID_call, 1, Qtrue);
|
243
|
+
}
|
244
|
+
else {
|
245
|
+
VALUE arg = rb_ivar_get(item, ID_scheduled_value);
|
246
|
+
if (RTEST(rb_obj_is_kind_of(arg, rb_eException))) {
|
247
|
+
rb_ivar_set(item, ID_scheduled_value, Qnil);
|
248
|
+
}
|
249
|
+
SCHEDULE_FIBER(item, 1, arg);
|
250
|
+
}
|
251
|
+
return Qnil;
|
252
|
+
}
|
253
|
+
|
254
|
+
void Gyro_defer_callback(struct ev_loop *ev_loop, struct ev_idle *watcher, int revents) {
|
255
|
+
deferred_in_callback = 1;
|
256
|
+
defer_add(deferred_eol_marker);
|
257
|
+
rb_ivar_set(deferred_eol_marker, ID_deferred_next, Qnil);
|
258
|
+
|
259
|
+
while (RTEST(deferred_head) && !break_flag) {
|
260
|
+
VALUE next = rb_ivar_get(deferred_head, ID_deferred_next);
|
261
|
+
if (deferred_head == deferred_eol_marker) {
|
262
|
+
deferred_head = next;
|
263
|
+
break;
|
264
|
+
}
|
265
|
+
run_deferred(deferred_head);
|
266
|
+
deferred_head = next;
|
267
|
+
}
|
268
|
+
|
269
|
+
if (NIL_P(deferred_head)) {
|
270
|
+
deferred_active = 0;
|
271
|
+
ev_idle_stop(EV_DEFAULT, &idle_watcher);
|
272
|
+
}
|
273
|
+
|
274
|
+
deferred_in_callback = 0;
|
275
|
+
}
|
276
|
+
|
277
|
+
static VALUE Gyro_suspend(VALUE self) {
|
278
|
+
if (!RTEST(rb_fiber_alive_p(Gyro_reactor_fiber))) {
|
279
|
+
return Qnil;
|
280
|
+
}
|
281
|
+
|
282
|
+
VALUE ret = YIELD_TO_REACTOR();
|
283
|
+
|
284
|
+
// fiber is resumed, check if resumed value is an exception
|
285
|
+
return RTEST(rb_obj_is_kind_of(ret, rb_eException)) ?
|
286
|
+
rb_funcall(ret, ID_raise, 1, ret) : ret;
|
287
|
+
}
|
288
|
+
|
289
|
+
static VALUE Fiber_safe_transfer(int argc, VALUE *argv, VALUE self) {
|
290
|
+
VALUE arg = (argc == 0) ? Qnil : argv[0];
|
291
|
+
VALUE ret = rb_funcall(self, ID_transfer, 1, arg);
|
292
|
+
|
293
|
+
// fiber is resumed, check if resumed value is an exception
|
294
|
+
return RTEST(rb_obj_is_kind_of(ret, rb_eException)) ?
|
295
|
+
rb_funcall(ret, ID_raise, 1, ret) : ret;
|
296
|
+
}
|
297
|
+
|
298
|
+
static VALUE Fiber_schedule(int argc, VALUE *argv, VALUE self) {
|
299
|
+
VALUE arg = (argc == 0) ? Qnil : argv[0];
|
300
|
+
rb_ivar_set(self, ID_scheduled_value, arg);
|
301
|
+
if (deferred_in_callback) {
|
302
|
+
// if a fiber is scheduled while processing deferred items, we want to avoid
|
303
|
+
// adding the same fiber again to the list of deferred item, since this will
|
304
|
+
// fuck up the linked list refs, and also lead to a race condition. To do
|
305
|
+
// this, we search the deferred items linked list for the given fiber, and
|
306
|
+
// return without readding it if found.
|
307
|
+
VALUE next = deferred_head;
|
308
|
+
while (RTEST(next)) {
|
309
|
+
if (next == self) return self;
|
310
|
+
if (next == deferred_eol_marker) break;
|
311
|
+
next = rb_ivar_get(next, ID_deferred_next);
|
312
|
+
}
|
313
|
+
}
|
314
|
+
defer_add(self);
|
315
|
+
return self;
|
316
|
+
}
|