polyphony 0.39 → 0.43.1
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/.github/workflows/test.yml +11 -2
- data/.gitignore +2 -2
- data/.rubocop.yml +30 -0
- data/CHANGELOG.md +23 -4
- data/Gemfile.lock +15 -12
- data/README.md +2 -1
- data/Rakefile +3 -3
- data/TODO.md +27 -97
- 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/fiber.md +2 -2
- 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 +69 -21
- data/docs/main-concepts/extending.md +1 -1
- data/docs/main-concepts/index.md +9 -0
- data/docs/polyphony-logo.png +0 -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-agent.rb +102 -0
- data/examples/core/xx-sleeping.rb +14 -6
- data/examples/io/tunnel.rb +48 -0
- data/examples/io/xx-irb.rb +1 -1
- data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +7 -6
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +13 -36
- 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/{gyro → polyphony}/extconf.rb +2 -2
- data/ext/{gyro → polyphony}/fiber.c +17 -23
- data/ext/{gyro → polyphony}/libev.c +0 -0
- data/ext/{gyro → polyphony}/libev.h +0 -0
- data/ext/polyphony/libev_agent.c +718 -0
- data/ext/polyphony/libev_queue.c +216 -0
- data/ext/polyphony/polyphony.c +73 -0
- data/ext/{gyro/gyro.h → polyphony/polyphony.h} +19 -39
- data/ext/polyphony/polyphony_ext.c +21 -0
- data/ext/polyphony/thread.c +200 -0
- data/ext/{gyro → polyphony}/tracing.c +1 -1
- data/lib/polyphony.rb +19 -14
- data/lib/polyphony/adapters/irb.rb +1 -1
- data/lib/polyphony/adapters/postgres.rb +6 -5
- data/lib/polyphony/adapters/process.rb +5 -5
- data/lib/polyphony/adapters/trace.rb +28 -28
- data/lib/polyphony/core/channel.rb +3 -3
- data/lib/polyphony/core/exceptions.rb +1 -1
- data/lib/polyphony/core/global_api.rb +13 -11
- data/lib/polyphony/core/resource_pool.rb +3 -3
- data/lib/polyphony/core/sync.rb +2 -2
- data/lib/polyphony/core/thread_pool.rb +6 -6
- data/lib/polyphony/core/throttler.rb +13 -6
- data/lib/polyphony/event.rb +27 -0
- data/lib/polyphony/extensions/core.rb +22 -14
- data/lib/polyphony/extensions/fiber.rb +4 -4
- data/lib/polyphony/extensions/io.rb +59 -25
- data/lib/polyphony/extensions/openssl.rb +36 -16
- data/lib/polyphony/extensions/socket.rb +28 -10
- data/lib/polyphony/extensions/thread.rb +16 -9
- data/lib/polyphony/net.rb +9 -9
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +4 -4
- data/test/helper.rb +12 -8
- data/test/test_agent.rb +124 -0
- data/test/{test_async.rb → test_event.rb} +15 -7
- data/test/test_ext.rb +25 -4
- data/test/test_fiber.rb +19 -10
- data/test/test_global_api.rb +11 -11
- data/test/test_io.rb +44 -29
- data/test/test_queue.rb +74 -0
- data/test/test_signal.rb +3 -40
- data/test/test_socket.rb +34 -0
- data/test/test_thread.rb +38 -17
- data/test/test_thread_pool.rb +2 -2
- data/test/test_throttler.rb +5 -3
- data/test/test_trace.rb +6 -5
- metadata +41 -43
- 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/gyro/async.c +0 -162
- data/ext/gyro/child.c +0 -141
- data/ext/gyro/gyro.c +0 -103
- data/ext/gyro/gyro_ext.c +0 -33
- data/ext/gyro/io.c +0 -489
- data/ext/gyro/queue.c +0 -142
- data/ext/gyro/selector.c +0 -228
- data/ext/gyro/signal.c +0 -133
- data/ext/gyro/socket.c +0 -210
- data/ext/gyro/thread.c +0 -308
- data/ext/gyro/timer.c +0 -151
- data/test/test_timer.rb +0 -32
data/ext/gyro/socket.c
DELETED
@@ -1,210 +0,0 @@
|
|
1
|
-
#include "gyro.h"
|
2
|
-
#include <sys/socket.h>
|
3
|
-
|
4
|
-
static VALUE cTCPSocket;
|
5
|
-
|
6
|
-
///////////////////////////////////////////////////////////////////////////
|
7
|
-
|
8
|
-
struct rsock_send_arg {
|
9
|
-
int fd, flags;
|
10
|
-
VALUE mesg;
|
11
|
-
struct sockaddr *to;
|
12
|
-
socklen_t tolen;
|
13
|
-
};
|
14
|
-
|
15
|
-
#define StringValue(v) rb_string_value(&(v))
|
16
|
-
#define IS_ADDRINFO(obj) rb_typeddata_is_kind_of((obj), &addrinfo_type)
|
17
|
-
|
18
|
-
VALUE
|
19
|
-
rsock_sockaddr_string_value(volatile VALUE *v)
|
20
|
-
{
|
21
|
-
// VALUE val = *v;
|
22
|
-
// if (IS_ADDRINFO(val)) {
|
23
|
-
// *v = addrinfo_to_sockaddr(val);
|
24
|
-
// }
|
25
|
-
StringValue(*v);
|
26
|
-
return *v;
|
27
|
-
}
|
28
|
-
|
29
|
-
#define SockAddrStringValue(v) rsock_sockaddr_string_value(&(v))
|
30
|
-
#define RSTRING_LENINT(str) rb_long2int(RSTRING_LEN(str))
|
31
|
-
#ifndef RSTRING_SOCKLEN
|
32
|
-
# define RSTRING_SOCKLEN (socklen_t)RSTRING_LENINT
|
33
|
-
#endif
|
34
|
-
|
35
|
-
#if defined __APPLE__
|
36
|
-
# define do_write_retry(code) do {ret = code;} while (ret == -1 && errno == EPROTOTYPE)
|
37
|
-
#else
|
38
|
-
# define do_write_retry(code) ret = code
|
39
|
-
#endif
|
40
|
-
|
41
|
-
VALUE
|
42
|
-
rsock_sendto_blocking(void *data)
|
43
|
-
{
|
44
|
-
struct rsock_send_arg *arg = data;
|
45
|
-
VALUE mesg = arg->mesg;
|
46
|
-
ssize_t ret;
|
47
|
-
do_write_retry(sendto(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
|
48
|
-
arg->flags, arg->to, arg->tolen));
|
49
|
-
return (VALUE)ret;
|
50
|
-
}
|
51
|
-
|
52
|
-
VALUE
|
53
|
-
rsock_send_blocking(void *data)
|
54
|
-
{
|
55
|
-
struct rsock_send_arg *arg = data;
|
56
|
-
VALUE mesg = arg->mesg;
|
57
|
-
ssize_t ret;
|
58
|
-
do_write_retry(send(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
|
59
|
-
arg->flags));
|
60
|
-
return (VALUE)ret;
|
61
|
-
}
|
62
|
-
|
63
|
-
///////////////////////////////////////////////////////////////////////////
|
64
|
-
|
65
|
-
static VALUE BasicSocket_send(int argc, VALUE *argv, VALUE sock) {
|
66
|
-
VALUE underlying_socket = rb_iv_get(sock, "@io");
|
67
|
-
if (!NIL_P(underlying_socket)) sock = underlying_socket;
|
68
|
-
struct rsock_send_arg arg;
|
69
|
-
VALUE flags, to;
|
70
|
-
rb_io_t *fptr;
|
71
|
-
ssize_t n;
|
72
|
-
rb_blocking_function_t *func;
|
73
|
-
const char *funcname;
|
74
|
-
VALUE write_watcher = Qnil;
|
75
|
-
|
76
|
-
rb_scan_args(argc, argv, "21", &arg.mesg, &flags, &to);
|
77
|
-
|
78
|
-
StringValue(arg.mesg);
|
79
|
-
|
80
|
-
if (!NIL_P(to)) {
|
81
|
-
SockAddrStringValue(to);
|
82
|
-
to = rb_str_new4(to);
|
83
|
-
arg.to = (struct sockaddr *)RSTRING_PTR(to);
|
84
|
-
arg.tolen = RSTRING_SOCKLEN(to);
|
85
|
-
func = rsock_sendto_blocking;
|
86
|
-
funcname = "sendto(2)";
|
87
|
-
}
|
88
|
-
else {
|
89
|
-
func = rsock_send_blocking;
|
90
|
-
funcname = "send(2)";
|
91
|
-
}
|
92
|
-
GetOpenFile(sock, fptr);
|
93
|
-
rb_io_set_nonblock(fptr);
|
94
|
-
arg.fd = fptr->fd;
|
95
|
-
arg.flags = NUM2INT(flags);
|
96
|
-
while ((n = (ssize_t)func(&arg)) < 0) {
|
97
|
-
if (NIL_P(write_watcher))
|
98
|
-
write_watcher = Gyro_IO_auto_io(fptr->fd, EV_WRITE);
|
99
|
-
Gyro_IO_await(write_watcher);
|
100
|
-
}
|
101
|
-
return SSIZET2NUM(n);
|
102
|
-
}
|
103
|
-
|
104
|
-
static VALUE BasicSocket_recv(int argc, VALUE *argv, VALUE sock) {
|
105
|
-
VALUE underlying_socket = rb_iv_get(sock, "@io");
|
106
|
-
if (!NIL_P(underlying_socket)) sock = underlying_socket;
|
107
|
-
long len = argc >= 1 ? NUM2LONG(argv[0]) : 8192;
|
108
|
-
if (len < 0) {
|
109
|
-
rb_raise(rb_eArgError, "negative length %ld given", len);
|
110
|
-
}
|
111
|
-
|
112
|
-
rb_io_t *fptr;
|
113
|
-
long n;
|
114
|
-
int shrinkable;
|
115
|
-
VALUE read_watcher = Qnil;
|
116
|
-
|
117
|
-
|
118
|
-
VALUE str = argc >= 3 ? argv[2] : Qnil;
|
119
|
-
|
120
|
-
shrinkable = io_setstrbuf(&str, len);
|
121
|
-
OBJ_TAINT(str);
|
122
|
-
GetOpenFile(sock, fptr);
|
123
|
-
// rb_io_set_nonblock(fptr);
|
124
|
-
rb_io_check_byte_readable(fptr);
|
125
|
-
|
126
|
-
if (len == 0)
|
127
|
-
return str;
|
128
|
-
|
129
|
-
while (1) {
|
130
|
-
n = recv(fptr->fd, RSTRING_PTR(str), len, MSG_DONTWAIT);
|
131
|
-
if (n < 0) {
|
132
|
-
int e = errno;
|
133
|
-
if (e == EWOULDBLOCK || e == EAGAIN) {
|
134
|
-
if (NIL_P(read_watcher))
|
135
|
-
read_watcher = Gyro_IO_auto_io(fptr->fd, EV_READ);
|
136
|
-
Gyro_IO_await(read_watcher);
|
137
|
-
}
|
138
|
-
else
|
139
|
-
rb_syserr_fail(e, strerror(e));
|
140
|
-
// rb_syserr_fail_path(e, fptr->pathv);
|
141
|
-
}
|
142
|
-
else
|
143
|
-
break;
|
144
|
-
}
|
145
|
-
|
146
|
-
io_set_read_length(str, n, shrinkable);
|
147
|
-
io_enc_str(str, fptr);
|
148
|
-
|
149
|
-
if (n == 0)
|
150
|
-
return Qnil;
|
151
|
-
|
152
|
-
return str;
|
153
|
-
}
|
154
|
-
|
155
|
-
static VALUE Socket_accept(VALUE sock) {
|
156
|
-
rb_io_t *fptr;
|
157
|
-
int fd;
|
158
|
-
struct sockaddr addr;
|
159
|
-
socklen_t len = (socklen_t)sizeof addr;
|
160
|
-
VALUE read_watcher = Qnil;
|
161
|
-
|
162
|
-
GetOpenFile(sock, fptr);
|
163
|
-
rb_io_set_nonblock(fptr);
|
164
|
-
|
165
|
-
while (1) {
|
166
|
-
fd = accept(fptr->fd, &addr, &len);
|
167
|
-
|
168
|
-
if (fd < 0) {
|
169
|
-
int e = errno;
|
170
|
-
if (e == EWOULDBLOCK || e == EAGAIN) {
|
171
|
-
if (NIL_P(read_watcher))
|
172
|
-
read_watcher = Gyro_IO_auto_io(fptr->fd, EV_READ);
|
173
|
-
Gyro_IO_await(read_watcher);
|
174
|
-
}
|
175
|
-
else
|
176
|
-
rb_syserr_fail(e, strerror(e));
|
177
|
-
// rb_syserr_fail_path(e, fptr->pathv);
|
178
|
-
}
|
179
|
-
else {
|
180
|
-
VALUE connection = rb_obj_alloc(cTCPSocket);
|
181
|
-
rb_io_t *fp;
|
182
|
-
MakeOpenFile(connection, fp);
|
183
|
-
rb_update_max_fd(fd);
|
184
|
-
fp->fd = fd;
|
185
|
-
fp->mode = FMODE_READWRITE | FMODE_DUPLEX;
|
186
|
-
rb_io_ascii8bit_binmode(connection);
|
187
|
-
rb_io_set_nonblock(fp);
|
188
|
-
rb_io_synchronized(fp);
|
189
|
-
// if (rsock_do_not_reverse_lookup) {
|
190
|
-
// fp->mode |= FMODE_NOREVLOOKUP;
|
191
|
-
// }
|
192
|
-
|
193
|
-
return connection;
|
194
|
-
}
|
195
|
-
}
|
196
|
-
}
|
197
|
-
|
198
|
-
void Init_Socket() {
|
199
|
-
rb_require("socket");
|
200
|
-
VALUE cBasicSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
|
201
|
-
|
202
|
-
rb_define_method(cBasicSocket, "send", BasicSocket_send, -1);
|
203
|
-
rb_define_method(cBasicSocket, "recv", BasicSocket_recv, -1);
|
204
|
-
|
205
|
-
VALUE cSocket = rb_const_get(rb_cObject, rb_intern("Socket"));
|
206
|
-
|
207
|
-
rb_define_method(cSocket, "accept", Socket_accept, 0);
|
208
|
-
|
209
|
-
cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
|
210
|
-
}
|
data/ext/gyro/thread.c
DELETED
@@ -1,308 +0,0 @@
|
|
1
|
-
#include "gyro.h"
|
2
|
-
|
3
|
-
static VALUE cQueue;
|
4
|
-
|
5
|
-
static ID ID_create_event_selector;
|
6
|
-
static ID ID_deactivate_all_watchers_post_fork;
|
7
|
-
static ID ID_empty;
|
8
|
-
static ID ID_fiber_ref_count;
|
9
|
-
static ID ID_ivar_event_selector_proc;
|
10
|
-
static ID ID_ivar_event_selector;
|
11
|
-
static ID ID_ivar_join_wait_queue;
|
12
|
-
static ID ID_ivar_main_fiber;
|
13
|
-
static ID ID_ivar_result;
|
14
|
-
static ID ID_ivar_terminated;
|
15
|
-
static ID ID_pop;
|
16
|
-
static ID ID_push;
|
17
|
-
static ID ID_run_queue;
|
18
|
-
static ID ID_runnable_next;
|
19
|
-
static ID ID_stop;
|
20
|
-
|
21
|
-
VALUE event_selector_factory_proc(RB_BLOCK_CALL_FUNC_ARGLIST(args, klass)) {
|
22
|
-
return rb_funcall(klass, ID_new, 1, rb_ary_entry(args, 0));
|
23
|
-
}
|
24
|
-
|
25
|
-
static VALUE Thread_event_selector_set_proc(VALUE self, VALUE proc) {
|
26
|
-
if (!rb_obj_is_proc(proc)) {
|
27
|
-
proc = rb_proc_new(event_selector_factory_proc, proc);
|
28
|
-
}
|
29
|
-
rb_ivar_set(self, ID_ivar_event_selector_proc, proc);
|
30
|
-
return self;
|
31
|
-
}
|
32
|
-
|
33
|
-
static VALUE Thread_create_event_selector(VALUE self, VALUE thread) {
|
34
|
-
VALUE selector_proc = rb_ivar_get(self, ID_ivar_event_selector_proc);
|
35
|
-
if (selector_proc == Qnil) {
|
36
|
-
rb_raise(rb_eRuntimeError, "No event_selector_proc defined");
|
37
|
-
}
|
38
|
-
|
39
|
-
return rb_funcall(selector_proc, ID_call, 1, thread);
|
40
|
-
}
|
41
|
-
|
42
|
-
static VALUE Thread_setup_fiber_scheduling(VALUE self) {
|
43
|
-
rb_ivar_set(self, ID_ivar_main_fiber, rb_fiber_current());
|
44
|
-
rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(0));
|
45
|
-
VALUE queue = rb_ary_new();
|
46
|
-
rb_ivar_set(self, ID_run_queue, queue);
|
47
|
-
VALUE selector = rb_funcall(rb_cThread, ID_create_event_selector, 1, self);
|
48
|
-
rb_ivar_set(self, ID_ivar_event_selector, selector);
|
49
|
-
|
50
|
-
return self;
|
51
|
-
}
|
52
|
-
|
53
|
-
static VALUE Thread_stop_event_selector(VALUE self) {
|
54
|
-
VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
|
55
|
-
if (selector != Qnil) {
|
56
|
-
rb_funcall(selector, ID_stop, 0);
|
57
|
-
}
|
58
|
-
// Nullify the selector in order to prevent running the
|
59
|
-
// selector after the thread is done running.
|
60
|
-
rb_ivar_set(self, ID_ivar_event_selector, Qnil);
|
61
|
-
|
62
|
-
return self;
|
63
|
-
}
|
64
|
-
|
65
|
-
static VALUE Thread_deactivate_all_watchers_post_fork(VALUE self) {
|
66
|
-
VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
|
67
|
-
if (selector != Qnil) {
|
68
|
-
rb_funcall(selector, ID_deactivate_all_watchers_post_fork, 0);
|
69
|
-
}
|
70
|
-
|
71
|
-
return self;
|
72
|
-
}
|
73
|
-
|
74
|
-
VALUE Thread_ref(VALUE self) {
|
75
|
-
VALUE count = rb_ivar_get(self, ID_fiber_ref_count);
|
76
|
-
int new_count = NUM2INT(count) + 1;
|
77
|
-
rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(new_count));
|
78
|
-
return self;
|
79
|
-
}
|
80
|
-
|
81
|
-
VALUE Thread_unref(VALUE self) {
|
82
|
-
VALUE count = rb_ivar_get(self, ID_fiber_ref_count);
|
83
|
-
int new_count = NUM2INT(count) - 1;
|
84
|
-
rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(new_count));
|
85
|
-
return self;
|
86
|
-
}
|
87
|
-
|
88
|
-
int Thread_fiber_ref_count(VALUE self) {
|
89
|
-
VALUE count = rb_ivar_get(self, ID_fiber_ref_count);
|
90
|
-
return NUM2INT(count);
|
91
|
-
}
|
92
|
-
|
93
|
-
void Thread_fiber_reset_ref_count(VALUE self) {
|
94
|
-
rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(0));
|
95
|
-
}
|
96
|
-
|
97
|
-
static VALUE SYM_scheduled_fibers;
|
98
|
-
static VALUE SYM_pending_watchers;
|
99
|
-
|
100
|
-
static VALUE Thread_fiber_scheduling_stats(VALUE self) {
|
101
|
-
VALUE stats = rb_hash_new();
|
102
|
-
VALUE queue = rb_ivar_get(self, ID_run_queue);
|
103
|
-
VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
|
104
|
-
|
105
|
-
long scheduled_count = RARRAY_LEN(queue);
|
106
|
-
rb_hash_aset(stats, SYM_scheduled_fibers, INT2NUM(scheduled_count));
|
107
|
-
|
108
|
-
long pending_count = Gyro_Selector_pending_count(selector);
|
109
|
-
rb_hash_aset(stats, SYM_pending_watchers, INT2NUM(pending_count));
|
110
|
-
|
111
|
-
return stats;
|
112
|
-
}
|
113
|
-
|
114
|
-
VALUE Thread_schedule_fiber(VALUE self, VALUE fiber, VALUE value) {
|
115
|
-
if (rb_fiber_alive_p(fiber) != Qtrue) {
|
116
|
-
return self;
|
117
|
-
}
|
118
|
-
|
119
|
-
FIBER_TRACE(3, SYM_fiber_schedule, fiber, value);
|
120
|
-
// if fiber is already scheduled, just set the scheduled value, then return
|
121
|
-
rb_ivar_set(fiber, ID_runnable_value, value);
|
122
|
-
if (rb_ivar_get(fiber, ID_runnable) != Qnil) {
|
123
|
-
return self;
|
124
|
-
}
|
125
|
-
|
126
|
-
VALUE queue = rb_ivar_get(self, ID_run_queue);
|
127
|
-
rb_ary_push(queue, fiber);
|
128
|
-
rb_ivar_set(fiber, ID_runnable, Qtrue);
|
129
|
-
|
130
|
-
if (rb_thread_current() != self) {
|
131
|
-
// if the fiber scheduling is done across threads, we need to make sure the
|
132
|
-
// target thread is woken up in case it is in the middle of running its
|
133
|
-
// event selector. Otherwise it's gonna be stuck waiting for an event to
|
134
|
-
// happen, not knowing that it there's already a fiber ready to run in its
|
135
|
-
// run queue.
|
136
|
-
VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
|
137
|
-
if (selector != Qnil) {
|
138
|
-
Gyro_Selector_break_out_of_ev_loop(selector);
|
139
|
-
}
|
140
|
-
}
|
141
|
-
return self;
|
142
|
-
}
|
143
|
-
|
144
|
-
VALUE Thread_schedule_fiber_with_priority(VALUE self, VALUE fiber, VALUE value) {
|
145
|
-
if (rb_fiber_alive_p(fiber) != Qtrue) {
|
146
|
-
return self;
|
147
|
-
}
|
148
|
-
FIBER_TRACE(3, SYM_fiber_schedule, fiber, value);
|
149
|
-
rb_ivar_set(fiber, ID_runnable_value, value);
|
150
|
-
|
151
|
-
VALUE queue = rb_ivar_get(self, ID_run_queue);
|
152
|
-
|
153
|
-
// if fiber is already scheduled, remove it from the run queue
|
154
|
-
if (rb_ivar_get(fiber, ID_runnable) != Qnil) {
|
155
|
-
rb_ary_delete(queue, fiber);
|
156
|
-
} else {
|
157
|
-
rb_ivar_set(fiber, ID_runnable, Qtrue);
|
158
|
-
}
|
159
|
-
|
160
|
-
// the fiber is given priority by putting it at the front of the run queue
|
161
|
-
rb_ary_unshift(queue, fiber);
|
162
|
-
|
163
|
-
if (rb_thread_current() != self) {
|
164
|
-
// if the fiber scheduling is done across threads, we need to make sure the
|
165
|
-
// target thread is woken up in case it is in the middle of running its
|
166
|
-
// event selector. Otherwise it's gonna be stuck waiting for an event to
|
167
|
-
// happen, not knowing that it there's already a fiber ready to run in its
|
168
|
-
// run queue.
|
169
|
-
VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
|
170
|
-
if (selector != Qnil) {
|
171
|
-
Gyro_Selector_break_out_of_ev_loop(selector);
|
172
|
-
}
|
173
|
-
}
|
174
|
-
return self;
|
175
|
-
}
|
176
|
-
|
177
|
-
VALUE Thread_switch_fiber(VALUE self) {
|
178
|
-
VALUE current_fiber = rb_fiber_current();
|
179
|
-
if (__tracing_enabled__) {
|
180
|
-
if (rb_ivar_get(current_fiber, ID_ivar_running) != Qfalse) {
|
181
|
-
rb_funcall(rb_cObject, ID_fiber_trace, 2, SYM_fiber_switchpoint, current_fiber);
|
182
|
-
}
|
183
|
-
}
|
184
|
-
VALUE queue = rb_ivar_get(self, ID_run_queue);
|
185
|
-
VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
|
186
|
-
|
187
|
-
VALUE next_fiber;
|
188
|
-
|
189
|
-
while (1) {
|
190
|
-
next_fiber = rb_ary_shift(queue);
|
191
|
-
// if (break_flag != 0) {
|
192
|
-
// return Qnil;
|
193
|
-
// }
|
194
|
-
int ref_count = Thread_fiber_ref_count(self);
|
195
|
-
if (next_fiber != Qnil) {
|
196
|
-
if (ref_count > 0) {
|
197
|
-
// this mechanism prevents event starvation in case the run queue never
|
198
|
-
// empties
|
199
|
-
Gyro_Selector_run_no_wait(selector, current_fiber, RARRAY_LEN(queue));
|
200
|
-
}
|
201
|
-
break;
|
202
|
-
}
|
203
|
-
if (ref_count == 0) {
|
204
|
-
break;
|
205
|
-
}
|
206
|
-
|
207
|
-
Gyro_Selector_run(selector, current_fiber);
|
208
|
-
}
|
209
|
-
|
210
|
-
if (next_fiber == Qnil) {
|
211
|
-
return Qnil;
|
212
|
-
}
|
213
|
-
|
214
|
-
// run next fiber
|
215
|
-
VALUE value = rb_ivar_get(next_fiber, ID_runnable_value);
|
216
|
-
FIBER_TRACE(3, SYM_fiber_run, next_fiber, value);
|
217
|
-
|
218
|
-
rb_ivar_set(next_fiber, ID_runnable, Qnil);
|
219
|
-
RB_GC_GUARD(next_fiber);
|
220
|
-
RB_GC_GUARD(value);
|
221
|
-
return rb_funcall(next_fiber, ID_transfer, 1, value);
|
222
|
-
}
|
223
|
-
|
224
|
-
VALUE Thread_reset_fiber_scheduling(VALUE self) {
|
225
|
-
VALUE queue = rb_ivar_get(self, ID_run_queue);
|
226
|
-
rb_ary_clear(queue);
|
227
|
-
Thread_fiber_reset_ref_count(self);
|
228
|
-
return self;
|
229
|
-
}
|
230
|
-
|
231
|
-
VALUE Thread_post_fork(VALUE self) {
|
232
|
-
VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
|
233
|
-
Gyro_Selector_post_fork(selector);
|
234
|
-
|
235
|
-
return self;
|
236
|
-
}
|
237
|
-
|
238
|
-
VALUE Gyro_switchpoint() {
|
239
|
-
VALUE thread = rb_thread_current();
|
240
|
-
Thread_ref(thread);
|
241
|
-
VALUE ret = Thread_switch_fiber(thread);
|
242
|
-
Thread_unref(thread);
|
243
|
-
RB_GC_GUARD(ret);
|
244
|
-
return ret;
|
245
|
-
}
|
246
|
-
|
247
|
-
VALUE Thread_current_event_selector() {
|
248
|
-
return rb_ivar_get(rb_thread_current(), ID_ivar_event_selector);
|
249
|
-
}
|
250
|
-
|
251
|
-
VALUE Thread_fiber_break_out_of_ev_loop(VALUE self, VALUE fiber, VALUE resume_obj) {
|
252
|
-
VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
|
253
|
-
if (fiber != Qnil) {
|
254
|
-
Thread_schedule_fiber_with_priority(self, fiber, resume_obj);
|
255
|
-
}
|
256
|
-
|
257
|
-
if (Gyro_Selector_break_out_of_ev_loop(selector) == Qnil) {
|
258
|
-
// we're not inside the ev_loop, so we just do a switchpoint
|
259
|
-
Thread_switch_fiber(self);
|
260
|
-
}
|
261
|
-
|
262
|
-
return self;
|
263
|
-
}
|
264
|
-
|
265
|
-
void Init_Thread() {
|
266
|
-
cQueue = rb_const_get(rb_cObject, rb_intern("Queue"));
|
267
|
-
|
268
|
-
rb_define_singleton_method(rb_cThread, "event_selector=", Thread_event_selector_set_proc, 1);
|
269
|
-
rb_define_singleton_method(rb_cThread, "create_event_selector", Thread_create_event_selector, 1);
|
270
|
-
|
271
|
-
rb_define_method(rb_cThread, "fiber_ref", Thread_ref, 0);
|
272
|
-
rb_define_method(rb_cThread, "fiber_unref", Thread_unref, 0);
|
273
|
-
|
274
|
-
rb_define_method(rb_cThread, "post_fork", Thread_post_fork, 0);
|
275
|
-
|
276
|
-
rb_define_method(rb_cThread, "setup_fiber_scheduling", Thread_setup_fiber_scheduling, 0);
|
277
|
-
rb_define_method(rb_cThread, "stop_event_selector", Thread_stop_event_selector, 0);
|
278
|
-
rb_define_method(rb_cThread, "deactivate_all_watchers_post_fork", Thread_deactivate_all_watchers_post_fork, 0);
|
279
|
-
rb_define_method(rb_cThread, "reset_fiber_scheduling", Thread_reset_fiber_scheduling, 0);
|
280
|
-
rb_define_method(rb_cThread, "fiber_scheduling_stats", Thread_fiber_scheduling_stats, 0);
|
281
|
-
rb_define_method(rb_cThread, "break_out_of_ev_loop", Thread_fiber_break_out_of_ev_loop, 2);
|
282
|
-
|
283
|
-
rb_define_method(rb_cThread, "schedule_fiber", Thread_schedule_fiber, 2);
|
284
|
-
rb_define_method(rb_cThread, "schedule_fiber_with_priority",
|
285
|
-
Thread_schedule_fiber_with_priority, 2);
|
286
|
-
rb_define_method(rb_cThread, "switch_fiber", Thread_switch_fiber, 0);
|
287
|
-
|
288
|
-
ID_create_event_selector = rb_intern("create_event_selector");
|
289
|
-
ID_deactivate_all_watchers_post_fork = rb_intern("deactivate_all_watchers_post_fork");
|
290
|
-
ID_empty = rb_intern("empty?");
|
291
|
-
ID_fiber_ref_count = rb_intern("fiber_ref_count");
|
292
|
-
ID_ivar_event_selector = rb_intern("@event_selector");
|
293
|
-
ID_ivar_event_selector_proc = rb_intern("@event_selector_proc");
|
294
|
-
ID_ivar_join_wait_queue = rb_intern("@join_wait_queue");
|
295
|
-
ID_ivar_main_fiber = rb_intern("@main_fiber");
|
296
|
-
ID_ivar_result = rb_intern("@result");
|
297
|
-
ID_ivar_terminated = rb_intern("@terminated");
|
298
|
-
ID_pop = rb_intern("pop");
|
299
|
-
ID_push = rb_intern("push");
|
300
|
-
ID_run_queue = rb_intern("run_queue");
|
301
|
-
ID_runnable_next = rb_intern("runnable_next");
|
302
|
-
ID_stop = rb_intern("stop");
|
303
|
-
|
304
|
-
SYM_scheduled_fibers = ID2SYM(rb_intern("scheduled_fibers"));
|
305
|
-
SYM_pending_watchers = ID2SYM(rb_intern("pending_watchers"));
|
306
|
-
rb_global_variable(&SYM_scheduled_fibers);
|
307
|
-
rb_global_variable(&SYM_pending_watchers);
|
308
|
-
}
|