polyphony 0.26 → 0.27
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -3
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +1 -1
- data/TODO.md +34 -14
- data/examples/core/xx-mt-scheduler.rb +349 -0
- data/examples/core/xx-queue-async.rb +120 -0
- data/examples/core/xx-readpartial.rb +18 -0
- data/examples/core/xx-thread-selector-sleep.rb +51 -0
- data/examples/core/xx-thread-selector-snooze.rb +46 -0
- data/examples/core/xx-thread-sleep.rb +17 -0
- data/examples/core/xx-thread-snooze.rb +34 -0
- data/examples/performance/snooze.rb +5 -5
- data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +73 -0
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +12 -4
- data/ext/gyro/async.c +58 -61
- data/ext/gyro/child.c +50 -59
- data/ext/gyro/gyro.c +84 -192
- data/ext/gyro/gyro.h +29 -2
- data/ext/gyro/gyro_ext.c +6 -0
- data/ext/gyro/io.c +87 -96
- data/ext/gyro/queue.c +109 -0
- data/ext/gyro/selector.c +117 -0
- data/ext/gyro/signal.c +44 -54
- data/ext/gyro/socket.c +15 -20
- data/ext/gyro/thread.c +203 -0
- data/ext/gyro/timer.c +79 -50
- data/ext/libev/ev.c +3 -0
- data/lib/polyphony.rb +7 -12
- data/lib/polyphony/core/global_api.rb +5 -1
- data/lib/polyphony/core/throttler.rb +6 -11
- data/lib/polyphony/extensions/core.rb +2 -0
- data/lib/polyphony/extensions/fiber.rb +11 -13
- data/lib/polyphony/extensions/thread.rb +52 -0
- data/lib/polyphony/version.rb +1 -1
- data/test/helper.rb +8 -3
- data/test/test_fiber.rb +2 -2
- data/test/test_global_api.rb +4 -5
- data/test/test_gyro.rb +3 -2
- data/test/test_io.rb +1 -0
- data/test/test_supervisor.rb +3 -3
- data/test/test_thread.rb +44 -0
- data/test/test_throttler.rb +41 -0
- data/test/test_timer.rb +13 -7
- metadata +17 -6
- data/examples/core/xx-thread_cancel.rb +0 -28
- data/examples/performance/thread.rb +0 -27
- data/lib/polyphony/core/thread.rb +0 -23
data/ext/gyro/selector.c
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
#include "gyro.h"
|
2
|
+
|
3
|
+
struct Gyro_Selector {
|
4
|
+
struct ev_loop *ev_loop;
|
5
|
+
};
|
6
|
+
|
7
|
+
VALUE cGyro_Selector = Qnil;
|
8
|
+
|
9
|
+
static void Gyro_Selector_mark(void *ptr) {
|
10
|
+
// struct Gyro_Selector *selector = ptr;
|
11
|
+
}
|
12
|
+
|
13
|
+
static void Gyro_Selector_free(void *ptr) {
|
14
|
+
struct Gyro_Selector *selector = ptr;
|
15
|
+
if (selector->ev_loop && !ev_is_default_loop(selector->ev_loop)) {
|
16
|
+
// printf("Selector garbage collected before being stopped!\n");
|
17
|
+
ev_loop_destroy(selector->ev_loop);
|
18
|
+
}
|
19
|
+
xfree(selector);
|
20
|
+
}
|
21
|
+
|
22
|
+
static size_t Gyro_Selector_size(const void *ptr) {
|
23
|
+
return sizeof(struct Gyro_Selector);
|
24
|
+
}
|
25
|
+
|
26
|
+
static const rb_data_type_t Gyro_Selector_type = {
|
27
|
+
"Gyro_Selector",
|
28
|
+
{Gyro_Selector_mark, Gyro_Selector_free, Gyro_Selector_size,},
|
29
|
+
0, 0,
|
30
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
31
|
+
};
|
32
|
+
|
33
|
+
static VALUE Gyro_Selector_allocate(VALUE klass) {
|
34
|
+
struct Gyro_Selector *selector = (struct Gyro_Selector *)xmalloc(sizeof(struct Gyro_Selector));
|
35
|
+
return TypedData_Wrap_Struct(klass, &Gyro_Selector_type, selector);
|
36
|
+
}
|
37
|
+
|
38
|
+
#define GetGyro_Selector(obj, selector) \
|
39
|
+
TypedData_Get_Struct((obj), struct Gyro_Selector, &Gyro_Selector_type, (selector))
|
40
|
+
|
41
|
+
inline struct ev_loop *Gyro_Selector_ev_loop(VALUE self) {
|
42
|
+
struct Gyro_Selector *selector;
|
43
|
+
GetGyro_Selector(self, selector);
|
44
|
+
|
45
|
+
return selector->ev_loop;
|
46
|
+
}
|
47
|
+
|
48
|
+
inline struct ev_loop *Gyro_Selector_current_thread_ev_loop() {
|
49
|
+
struct Gyro_Selector *selector;
|
50
|
+
GetGyro_Selector(Thread_current_event_selector(), selector);
|
51
|
+
|
52
|
+
return selector->ev_loop;
|
53
|
+
}
|
54
|
+
|
55
|
+
long Gyro_Selector_pending_count(VALUE self) {
|
56
|
+
struct Gyro_Selector *selector;
|
57
|
+
GetGyro_Selector(self, selector);
|
58
|
+
|
59
|
+
return ev_pending_count(selector->ev_loop);
|
60
|
+
}
|
61
|
+
|
62
|
+
static VALUE Gyro_Selector_initialize(VALUE self, VALUE thread) {
|
63
|
+
struct Gyro_Selector *selector;
|
64
|
+
GetGyro_Selector(self, selector);
|
65
|
+
|
66
|
+
int use_default_loop = (rb_thread_current() == rb_thread_main());
|
67
|
+
selector->ev_loop = use_default_loop ? EV_DEFAULT : ev_loop_new(EVFLAG_NOSIGMASK);
|
68
|
+
|
69
|
+
return Qnil;
|
70
|
+
}
|
71
|
+
|
72
|
+
inline VALUE Gyro_Selector_run(VALUE self) {
|
73
|
+
struct Gyro_Selector *selector;
|
74
|
+
GetGyro_Selector(self, selector);
|
75
|
+
if (selector->ev_loop) {
|
76
|
+
ev_run(selector->ev_loop, EVRUN_ONCE);
|
77
|
+
}
|
78
|
+
return Qnil;
|
79
|
+
}
|
80
|
+
|
81
|
+
VALUE Gyro_Selector_stop(VALUE self) {
|
82
|
+
struct Gyro_Selector *selector;
|
83
|
+
GetGyro_Selector(self, selector);
|
84
|
+
|
85
|
+
if (selector->ev_loop && !ev_is_default_loop(selector->ev_loop)) {
|
86
|
+
// ev_loop_destroy(selector->ev_loop);
|
87
|
+
// selector->ev_loop = 0;
|
88
|
+
}
|
89
|
+
return Qnil;
|
90
|
+
}
|
91
|
+
|
92
|
+
inline static VALUE Gyro_Selector_wait_readable(VALUE self, VALUE io) {
|
93
|
+
VALUE watcher = IO_read_watcher(io);
|
94
|
+
return Gyro_IO_await(watcher);
|
95
|
+
}
|
96
|
+
|
97
|
+
inline static VALUE Gyro_Selector_wait_writable(VALUE self, VALUE io) {
|
98
|
+
VALUE watcher = IO_write_watcher(io);
|
99
|
+
return Gyro_IO_await(watcher);
|
100
|
+
}
|
101
|
+
|
102
|
+
inline static VALUE Gyro_Selector_wait_timeout(VALUE self, VALUE duration) {
|
103
|
+
VALUE watcher = rb_funcall(cGyro_Timer, ID_new, 2, duration, Qnil);
|
104
|
+
return Gyro_Timer_await(watcher);
|
105
|
+
}
|
106
|
+
|
107
|
+
void Init_Gyro_Selector() {
|
108
|
+
cGyro_Selector = rb_define_class_under(mGyro, "Selector", rb_cData);
|
109
|
+
rb_define_alloc_func(cGyro_Selector, Gyro_Selector_allocate);
|
110
|
+
|
111
|
+
rb_define_method(cGyro_Selector, "initialize", Gyro_Selector_initialize, 1);
|
112
|
+
rb_define_method(cGyro_Selector, "run", Gyro_Selector_run, 0);
|
113
|
+
rb_define_method(cGyro_Selector, "stop", Gyro_Selector_stop, 0);
|
114
|
+
rb_define_method(cGyro_Selector, "wait_readable", Gyro_Selector_wait_readable, 1);
|
115
|
+
rb_define_method(cGyro_Selector, "wait_writable", Gyro_Selector_wait_writable, 1);
|
116
|
+
rb_define_method(cGyro_Selector, "wait_timeout", Gyro_Selector_wait_timeout, 1);
|
117
|
+
}
|
data/ext/gyro/signal.c
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
struct Gyro_Signal {
|
4
4
|
struct ev_signal ev_signal;
|
5
|
+
struct ev_loop *ev_loop;
|
5
6
|
int active;
|
6
7
|
int signum;
|
7
8
|
VALUE fiber;
|
@@ -9,26 +10,24 @@ struct Gyro_Signal {
|
|
9
10
|
|
10
11
|
static VALUE cGyro_Signal = Qnil;
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
/* Methods */
|
19
|
-
static VALUE Gyro_Signal_initialize(VALUE self, VALUE sig);
|
20
|
-
|
21
|
-
static VALUE Gyro_Signal_await(VALUE self);
|
22
|
-
|
23
|
-
void Gyro_Signal_callback(struct ev_loop *ev_loop, struct ev_signal *signal, int revents);
|
13
|
+
static void Gyro_Signal_mark(void *ptr) {
|
14
|
+
struct Gyro_Signal *signal = ptr;
|
15
|
+
if (signal->fiber != Qnil) {
|
16
|
+
rb_gc_mark(signal->fiber);
|
17
|
+
}
|
18
|
+
}
|
24
19
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
20
|
+
static void Gyro_Signal_free(void *ptr) {
|
21
|
+
struct Gyro_Signal *signal = ptr;
|
22
|
+
if (signal->active) {
|
23
|
+
printf("Signal watcher garbage collected while still active!\n");
|
24
|
+
// ev_signal_stop(signal->ev_loop, &signal->ev_signal);
|
25
|
+
}
|
26
|
+
xfree(signal);
|
27
|
+
}
|
29
28
|
|
30
|
-
|
31
|
-
|
29
|
+
static size_t Gyro_Signal_size(const void *ptr) {
|
30
|
+
return sizeof(struct Gyro_Signal);
|
32
31
|
}
|
33
32
|
|
34
33
|
static const rb_data_type_t Gyro_Signal_type = {
|
@@ -43,21 +42,17 @@ static VALUE Gyro_Signal_allocate(VALUE klass) {
|
|
43
42
|
return TypedData_Wrap_Struct(klass, &Gyro_Signal_type, signal);
|
44
43
|
}
|
45
44
|
|
46
|
-
|
47
|
-
struct Gyro_Signal *signal =
|
48
|
-
if (signal->fiber != Qnil) {
|
49
|
-
rb_gc_mark(signal->fiber);
|
50
|
-
}
|
51
|
-
}
|
45
|
+
void Gyro_Signal_callback(struct ev_loop *ev_loop, struct ev_signal *ev_signal, int revents) {
|
46
|
+
struct Gyro_Signal *signal = (struct Gyro_Signal*)ev_signal;
|
52
47
|
|
53
|
-
|
54
|
-
|
55
|
-
ev_signal_stop(EV_DEFAULT, &signal->ev_signal);
|
56
|
-
xfree(signal);
|
57
|
-
}
|
48
|
+
if (signal->fiber != Qnil) {
|
49
|
+
VALUE fiber = signal->fiber;
|
58
50
|
|
59
|
-
|
60
|
-
|
51
|
+
ev_signal_stop(signal->ev_loop, ev_signal);
|
52
|
+
signal->active = 0;
|
53
|
+
signal->fiber = Qnil;
|
54
|
+
Gyro_schedule_fiber(fiber, INT2NUM(signal->signum));
|
55
|
+
}
|
61
56
|
}
|
62
57
|
|
63
58
|
#define GetGyro_Signal(obj, signal) \
|
@@ -72,26 +67,9 @@ static VALUE Gyro_Signal_initialize(VALUE self, VALUE sig) {
|
|
72
67
|
|
73
68
|
ev_signal_init(&signal->ev_signal, Gyro_Signal_callback, signal->signum);
|
74
69
|
|
75
|
-
// signal->active = 1;
|
76
|
-
// Gyro_ref_count_incr();
|
77
|
-
// ev_signal_start(EV_DEFAULT, &signal->ev_signal);
|
78
|
-
|
79
70
|
return Qnil;
|
80
71
|
}
|
81
72
|
|
82
|
-
void Gyro_Signal_callback(struct ev_loop *ev_loop, struct ev_signal *ev_signal, int revents) {
|
83
|
-
struct Gyro_Signal *signal = (struct Gyro_Signal*)ev_signal;
|
84
|
-
|
85
|
-
if (signal->fiber != Qnil) {
|
86
|
-
VALUE fiber = signal->fiber;
|
87
|
-
|
88
|
-
ev_signal_stop(EV_DEFAULT, ev_signal);
|
89
|
-
signal->active = 0;
|
90
|
-
signal->fiber = Qnil;
|
91
|
-
Gyro_schedule_fiber(fiber, INT2NUM(signal->signum));
|
92
|
-
}
|
93
|
-
}
|
94
|
-
|
95
73
|
static VALUE Gyro_Signal_await(VALUE self) {
|
96
74
|
struct Gyro_Signal *signal;
|
97
75
|
VALUE ret;
|
@@ -100,19 +78,31 @@ static VALUE Gyro_Signal_await(VALUE self) {
|
|
100
78
|
|
101
79
|
signal->fiber = rb_fiber_current();
|
102
80
|
signal->active = 1;
|
103
|
-
|
81
|
+
signal->ev_loop = Gyro_Selector_current_thread_ev_loop();
|
82
|
+
ev_signal_start(signal->ev_loop, &signal->ev_signal);
|
104
83
|
|
105
|
-
ret =
|
84
|
+
ret = Fiber_await();
|
85
|
+
RB_GC_GUARD(ret);
|
86
|
+
|
87
|
+
if (signal->active) {
|
88
|
+
signal->active = 0;
|
89
|
+
signal->fiber = Qnil;
|
90
|
+
ev_signal_stop(signal->ev_loop, &signal->ev_signal);
|
91
|
+
}
|
106
92
|
|
107
93
|
// fiber is resumed, check if resumed value is an exception
|
108
94
|
signal->fiber = Qnil;
|
109
95
|
if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) {
|
110
|
-
if (signal->active) {
|
111
|
-
signal->active = 0;
|
112
|
-
ev_signal_stop(EV_DEFAULT, &signal->ev_signal);
|
113
|
-
}
|
114
96
|
return rb_funcall(rb_mKernel, ID_raise, 1, ret);
|
115
97
|
}
|
116
98
|
else
|
117
99
|
return ret;
|
118
100
|
}
|
101
|
+
|
102
|
+
void Init_Gyro_Signal() {
|
103
|
+
cGyro_Signal = rb_define_class_under(mGyro, "Signal", rb_cData);
|
104
|
+
rb_define_alloc_func(cGyro_Signal, Gyro_Signal_allocate);
|
105
|
+
|
106
|
+
rb_define_method(cGyro_Signal, "initialize", Gyro_Signal_initialize, 1);
|
107
|
+
rb_define_method(cGyro_Signal, "await", Gyro_Signal_await, 0);
|
108
|
+
}
|
data/ext/gyro/socket.c
CHANGED
@@ -1,27 +1,8 @@
|
|
1
1
|
#include "gyro.h"
|
2
2
|
#include <sys/socket.h>
|
3
3
|
|
4
|
-
static VALUE BasicSocket_send(int argc, VALUE *argv, VALUE io);
|
5
|
-
static VALUE BasicSocket_recv(int argc, VALUE *argv, VALUE io);
|
6
|
-
|
7
|
-
static VALUE Socket_accept(VALUE sock);
|
8
|
-
|
9
4
|
static VALUE cTCPSocket;
|
10
5
|
|
11
|
-
void Init_Socket() {
|
12
|
-
rb_require("socket");
|
13
|
-
VALUE cBasicSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
|
14
|
-
|
15
|
-
rb_define_method(cBasicSocket, "send", BasicSocket_send, -1);
|
16
|
-
rb_define_method(cBasicSocket, "recv", BasicSocket_recv, -1);
|
17
|
-
|
18
|
-
VALUE cSocket = rb_const_get(rb_cObject, rb_intern("Socket"));
|
19
|
-
|
20
|
-
rb_define_method(cSocket, "accept", Socket_accept, 0);
|
21
|
-
|
22
|
-
cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
|
23
|
-
}
|
24
|
-
|
25
6
|
///////////////////////////////////////////////////////////////////////////
|
26
7
|
|
27
8
|
struct rsock_send_arg {
|
@@ -213,4 +194,18 @@ static VALUE Socket_accept(VALUE sock) {
|
|
213
194
|
return connection;
|
214
195
|
}
|
215
196
|
}
|
216
|
-
}
|
197
|
+
}
|
198
|
+
|
199
|
+
void Init_Socket() {
|
200
|
+
rb_require("socket");
|
201
|
+
VALUE cBasicSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
|
202
|
+
|
203
|
+
rb_define_method(cBasicSocket, "send", BasicSocket_send, -1);
|
204
|
+
rb_define_method(cBasicSocket, "recv", BasicSocket_recv, -1);
|
205
|
+
|
206
|
+
VALUE cSocket = rb_const_get(rb_cObject, rb_intern("Socket"));
|
207
|
+
|
208
|
+
rb_define_method(cSocket, "accept", Socket_accept, 0);
|
209
|
+
|
210
|
+
cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
|
211
|
+
}
|
data/ext/gyro/thread.c
ADDED
@@ -0,0 +1,203 @@
|
|
1
|
+
#include "gyro.h"
|
2
|
+
|
3
|
+
static VALUE cQueue;
|
4
|
+
|
5
|
+
static ID ID_create_event_selector;
|
6
|
+
static ID ID_ivar_event_selector;
|
7
|
+
static ID ID_ivar_event_selector_proc;
|
8
|
+
static ID ID_fiber_ref_count;
|
9
|
+
static ID ID_run_queue;
|
10
|
+
static ID ID_ivar_main_fiber;
|
11
|
+
static ID ID_stop;
|
12
|
+
|
13
|
+
static ID ID_scheduled;
|
14
|
+
|
15
|
+
static ID ID_empty;
|
16
|
+
static ID ID_pop;
|
17
|
+
static ID ID_push;
|
18
|
+
|
19
|
+
VALUE event_selector_factory_proc(RB_BLOCK_CALL_FUNC_ARGLIST(args, klass)) {
|
20
|
+
return rb_funcall(klass, ID_new, 1, rb_ary_entry(args, 0));
|
21
|
+
}
|
22
|
+
|
23
|
+
static VALUE Thread_event_selector_set_proc(VALUE self, VALUE proc) {
|
24
|
+
if (!rb_obj_is_proc(proc)) {
|
25
|
+
proc = rb_proc_new(event_selector_factory_proc, proc);
|
26
|
+
}
|
27
|
+
rb_ivar_set(self, ID_ivar_event_selector_proc, proc);
|
28
|
+
return self;
|
29
|
+
}
|
30
|
+
|
31
|
+
static VALUE Thread_create_event_selector(VALUE self, VALUE thread) {
|
32
|
+
VALUE selector_proc = rb_ivar_get(self, ID_ivar_event_selector_proc);
|
33
|
+
if (selector_proc == Qnil) {
|
34
|
+
rb_raise(rb_eRuntimeError, "No event_selector_proc defined");
|
35
|
+
}
|
36
|
+
|
37
|
+
return rb_funcall(selector_proc, ID_call, 1, thread);
|
38
|
+
}
|
39
|
+
|
40
|
+
static VALUE Thread_setup_fiber_scheduling(VALUE self) {
|
41
|
+
rb_ivar_set(self, ID_ivar_main_fiber, rb_fiber_current());
|
42
|
+
rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(0));
|
43
|
+
VALUE queue = rb_ary_new();
|
44
|
+
rb_ivar_set(self, ID_run_queue, queue);
|
45
|
+
VALUE selector = rb_funcall(rb_cThread, ID_create_event_selector, 1, self);
|
46
|
+
rb_ivar_set(self, ID_ivar_event_selector, selector);
|
47
|
+
|
48
|
+
return self;
|
49
|
+
}
|
50
|
+
|
51
|
+
static VALUE Thread_stop_event_selector(VALUE self) {
|
52
|
+
VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
|
53
|
+
if (selector != Qnil) {
|
54
|
+
rb_funcall(selector, ID_stop, 0);
|
55
|
+
}
|
56
|
+
|
57
|
+
return self;
|
58
|
+
}
|
59
|
+
|
60
|
+
inline VALUE Thread_ref(VALUE self) {
|
61
|
+
VALUE count = rb_ivar_get(self, ID_fiber_ref_count);
|
62
|
+
int new_count = NUM2INT(count) + 1;
|
63
|
+
rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(new_count));
|
64
|
+
return self;
|
65
|
+
}
|
66
|
+
|
67
|
+
inline VALUE Thread_unref(VALUE self) {
|
68
|
+
VALUE count = rb_ivar_get(self, ID_fiber_ref_count);
|
69
|
+
int new_count = NUM2INT(count) - 1;
|
70
|
+
rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(new_count));
|
71
|
+
return self;
|
72
|
+
}
|
73
|
+
|
74
|
+
inline int Thread_fiber_ref_count(VALUE self) {
|
75
|
+
VALUE count = rb_ivar_get(self, ID_fiber_ref_count);
|
76
|
+
return NUM2INT(count);
|
77
|
+
}
|
78
|
+
|
79
|
+
inline void Thread_fiber_reset_ref_count(VALUE self) {
|
80
|
+
rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(0));
|
81
|
+
}
|
82
|
+
|
83
|
+
static VALUE SYM_scheduled_fibers;
|
84
|
+
static VALUE SYM_pending_watchers;
|
85
|
+
|
86
|
+
static VALUE Thread_fiber_scheduling_stats(VALUE self) {
|
87
|
+
VALUE stats = rb_hash_new();
|
88
|
+
VALUE queue = rb_ivar_get(self, ID_run_queue);
|
89
|
+
VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
|
90
|
+
|
91
|
+
long scheduled_count = RARRAY_LEN(queue);
|
92
|
+
rb_hash_aset(stats, SYM_scheduled_fibers, INT2NUM(scheduled_count));
|
93
|
+
|
94
|
+
long pending_count = Gyro_Selector_pending_count(selector);
|
95
|
+
rb_hash_aset(stats, SYM_pending_watchers, INT2NUM(pending_count));
|
96
|
+
|
97
|
+
return stats;
|
98
|
+
}
|
99
|
+
|
100
|
+
inline VALUE Thread_schedule_fiber(VALUE self, VALUE fiber) {
|
101
|
+
VALUE queue = rb_ivar_get(self, ID_run_queue);
|
102
|
+
rb_ary_push(queue, fiber);
|
103
|
+
return self;
|
104
|
+
}
|
105
|
+
|
106
|
+
VALUE Thread_switch_fiber(VALUE self) {
|
107
|
+
VALUE queue = rb_ivar_get(self, ID_run_queue);
|
108
|
+
VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
|
109
|
+
long scheduled_count;
|
110
|
+
|
111
|
+
while (1) {
|
112
|
+
scheduled_count = RARRAY_LEN(queue);
|
113
|
+
// if (break_flag != 0) {
|
114
|
+
// return Qnil;
|
115
|
+
// }
|
116
|
+
if ((scheduled_count > 0) || (Thread_fiber_ref_count(self) == 0)) {
|
117
|
+
break;
|
118
|
+
}
|
119
|
+
|
120
|
+
Gyro_Selector_run(selector);
|
121
|
+
}
|
122
|
+
|
123
|
+
VALUE next_fiber;
|
124
|
+
// while (1) {
|
125
|
+
if (scheduled_count == 0) {
|
126
|
+
return Qnil;
|
127
|
+
}
|
128
|
+
next_fiber = rb_ary_shift(queue);
|
129
|
+
// break;
|
130
|
+
// if (rb_fiber_alive_p(next_fiber) == Qtrue) {
|
131
|
+
// break;
|
132
|
+
// }
|
133
|
+
// }
|
134
|
+
|
135
|
+
// run next fiber
|
136
|
+
VALUE value = rb_ivar_get(next_fiber, ID_scheduled_value);
|
137
|
+
rb_ivar_set(next_fiber, ID_scheduled, Qnil);
|
138
|
+
RB_GC_GUARD(next_fiber);
|
139
|
+
RB_GC_GUARD(value);
|
140
|
+
return rb_funcall(next_fiber, ID_transfer, 1, value);
|
141
|
+
}
|
142
|
+
|
143
|
+
VALUE Thread_reset_fiber_scheduling(VALUE self) {
|
144
|
+
VALUE queue = rb_ivar_get(self, ID_run_queue);
|
145
|
+
rb_ary_clear(queue);
|
146
|
+
Thread_fiber_reset_ref_count(self);
|
147
|
+
return self;
|
148
|
+
}
|
149
|
+
|
150
|
+
VALUE Thread_post_fork(VALUE self) {
|
151
|
+
ev_loop_fork(EV_DEFAULT);
|
152
|
+
Thread_setup_fiber_scheduling(self);
|
153
|
+
return self;
|
154
|
+
}
|
155
|
+
|
156
|
+
inline VALUE Fiber_await() {
|
157
|
+
VALUE thread = rb_thread_current();
|
158
|
+
Thread_ref(thread);
|
159
|
+
VALUE ret = Thread_switch_fiber(thread);
|
160
|
+
Thread_unref(thread);
|
161
|
+
RB_GC_GUARD(ret);
|
162
|
+
return ret;
|
163
|
+
}
|
164
|
+
|
165
|
+
inline VALUE Thread_current_event_selector() {
|
166
|
+
return rb_ivar_get(rb_thread_current(), ID_ivar_event_selector);
|
167
|
+
}
|
168
|
+
|
169
|
+
void Init_Thread() {
|
170
|
+
cQueue = rb_const_get(rb_cObject, rb_intern("Queue"));
|
171
|
+
|
172
|
+
rb_define_singleton_method(rb_cThread, "event_selector=", Thread_event_selector_set_proc, 1);
|
173
|
+
rb_define_singleton_method(rb_cThread, "create_event_selector", Thread_create_event_selector, 1);
|
174
|
+
|
175
|
+
rb_define_method(rb_cThread, "fiber_ref", Thread_ref, 0);
|
176
|
+
rb_define_method(rb_cThread, "fiber_unref", Thread_unref, 0);
|
177
|
+
|
178
|
+
rb_define_method(rb_cThread, "setup_fiber_scheduling", Thread_setup_fiber_scheduling, 0);
|
179
|
+
rb_define_method(rb_cThread, "stop_event_selector", Thread_stop_event_selector, 0);
|
180
|
+
rb_define_method(rb_cThread, "reset_fiber_scheduling", Thread_reset_fiber_scheduling, 0);
|
181
|
+
rb_define_method(rb_cThread, "fiber_scheduling_stats", Thread_fiber_scheduling_stats, 0);
|
182
|
+
|
183
|
+
rb_define_method(rb_cThread, "schedule_fiber", Thread_schedule_fiber, 1);
|
184
|
+
rb_define_method(rb_cThread, "switch_fiber", Thread_switch_fiber, 0);
|
185
|
+
|
186
|
+
|
187
|
+
ID_create_event_selector = rb_intern("create_event_selector");
|
188
|
+
ID_ivar_event_selector = rb_intern("@event_selector");
|
189
|
+
ID_ivar_event_selector_proc = rb_intern("@event_selector_proc");
|
190
|
+
ID_ivar_main_fiber = rb_intern("@main_fiber");
|
191
|
+
ID_fiber_ref_count = rb_intern("fiber_ref_count");
|
192
|
+
ID_run_queue = rb_intern("run_queue");
|
193
|
+
ID_scheduled = rb_intern("scheduled");
|
194
|
+
ID_empty = rb_intern("empty?");
|
195
|
+
ID_pop = rb_intern("pop");
|
196
|
+
ID_push = rb_intern("push");
|
197
|
+
ID_stop = rb_intern("stop");
|
198
|
+
|
199
|
+
SYM_scheduled_fibers = ID2SYM(rb_intern("scheduled_fibers"));
|
200
|
+
SYM_pending_watchers = ID2SYM(rb_intern("pending_watchers"));
|
201
|
+
rb_global_variable(&SYM_scheduled_fibers);
|
202
|
+
rb_global_variable(&SYM_pending_watchers);
|
203
|
+
}
|