polyphony 0.40 → 0.43.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +11 -2
  3. data/.gitignore +2 -2
  4. data/.rubocop.yml +30 -0
  5. data/CHANGELOG.md +29 -2
  6. data/Gemfile.lock +13 -10
  7. data/README.md +0 -1
  8. data/Rakefile +3 -3
  9. data/TODO.md +27 -97
  10. data/docs/_config.yml +56 -7
  11. data/docs/_sass/custom/custom.scss +6 -26
  12. data/docs/_sass/overrides.scss +0 -46
  13. data/docs/{user-guide → _user-guide}/all-about-timers.md +0 -0
  14. data/docs/_user-guide/index.md +9 -0
  15. data/docs/{user-guide → _user-guide}/web-server.md +0 -0
  16. data/docs/api-reference/fiber.md +2 -2
  17. data/docs/api-reference/index.md +9 -0
  18. data/docs/api-reference/polyphony-process.md +1 -1
  19. data/docs/api-reference/thread.md +1 -1
  20. data/docs/faq.md +21 -11
  21. data/docs/favicon.ico +0 -0
  22. data/docs/getting-started/index.md +10 -0
  23. data/docs/getting-started/installing.md +2 -6
  24. data/docs/getting-started/overview.md +486 -0
  25. data/docs/getting-started/tutorial.md +27 -19
  26. data/docs/index.md +6 -2
  27. data/docs/main-concepts/concurrency.md +0 -5
  28. data/docs/main-concepts/design-principles.md +69 -21
  29. data/docs/main-concepts/extending.md +1 -1
  30. data/docs/main-concepts/index.md +9 -0
  31. data/docs/polyphony-logo.png +0 -0
  32. data/examples/adapters/redis_blpop.rb +12 -0
  33. data/examples/core/01-spinning-up-fibers.rb +1 -0
  34. data/examples/core/03-interrupting.rb +4 -1
  35. data/examples/core/04-handling-signals.rb +19 -0
  36. data/examples/core/xx-agent.rb +102 -0
  37. data/examples/core/xx-sleeping.rb +14 -6
  38. data/examples/io/xx-irb.rb +1 -1
  39. data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +7 -6
  40. data/examples/performance/thread-vs-fiber/polyphony_server.rb +13 -36
  41. data/examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb +58 -0
  42. data/examples/performance/xx-array.rb +11 -0
  43. data/examples/performance/xx-fiber-switch.rb +9 -0
  44. data/examples/performance/xx-snooze.rb +15 -0
  45. data/ext/{gyro → polyphony}/extconf.rb +2 -2
  46. data/ext/{gyro → polyphony}/fiber.c +15 -22
  47. data/ext/{gyro → polyphony}/libev.c +0 -0
  48. data/ext/{gyro → polyphony}/libev.h +0 -0
  49. data/ext/polyphony/libev_agent.c +725 -0
  50. data/ext/polyphony/libev_queue.c +217 -0
  51. data/ext/{gyro/gyro.c → polyphony/polyphony.c} +12 -37
  52. data/ext/polyphony/polyphony.h +90 -0
  53. data/ext/polyphony/polyphony_ext.c +21 -0
  54. data/ext/{gyro → polyphony}/thread.c +34 -151
  55. data/ext/{gyro → polyphony}/tracing.c +1 -1
  56. data/lib/polyphony.rb +19 -12
  57. data/lib/polyphony/adapters/irb.rb +1 -1
  58. data/lib/polyphony/adapters/postgres.rb +6 -5
  59. data/lib/polyphony/adapters/process.rb +5 -5
  60. data/lib/polyphony/adapters/redis.rb +3 -2
  61. data/lib/polyphony/adapters/trace.rb +28 -28
  62. data/lib/polyphony/core/channel.rb +3 -3
  63. data/lib/polyphony/core/exceptions.rb +1 -1
  64. data/lib/polyphony/core/global_api.rb +13 -11
  65. data/lib/polyphony/core/resource_pool.rb +3 -3
  66. data/lib/polyphony/core/sync.rb +2 -2
  67. data/lib/polyphony/core/thread_pool.rb +6 -6
  68. data/lib/polyphony/core/throttler.rb +13 -6
  69. data/lib/polyphony/event.rb +27 -0
  70. data/lib/polyphony/extensions/core.rb +22 -14
  71. data/lib/polyphony/extensions/fiber.rb +4 -4
  72. data/lib/polyphony/extensions/io.rb +59 -25
  73. data/lib/polyphony/extensions/openssl.rb +36 -16
  74. data/lib/polyphony/extensions/socket.rb +28 -10
  75. data/lib/polyphony/extensions/thread.rb +16 -9
  76. data/lib/polyphony/net.rb +9 -9
  77. data/lib/polyphony/version.rb +1 -1
  78. data/polyphony.gemspec +3 -3
  79. data/test/helper.rb +12 -1
  80. data/test/test_agent.rb +130 -0
  81. data/test/{test_async.rb → test_event.rb} +13 -7
  82. data/test/test_ext.rb +25 -4
  83. data/test/test_fiber.rb +19 -10
  84. data/test/test_global_api.rb +6 -6
  85. data/test/test_io.rb +46 -24
  86. data/test/test_queue.rb +74 -0
  87. data/test/test_signal.rb +3 -40
  88. data/test/test_socket.rb +34 -0
  89. data/test/test_thread.rb +37 -16
  90. data/test/test_trace.rb +6 -5
  91. metadata +39 -41
  92. data/docs/_includes/nav.html +0 -51
  93. data/docs/_includes/prevnext.html +0 -17
  94. data/docs/_layouts/default.html +0 -106
  95. data/docs/api-reference.md +0 -11
  96. data/docs/api-reference/gyro-async.md +0 -57
  97. data/docs/api-reference/gyro-child.md +0 -29
  98. data/docs/api-reference/gyro-queue.md +0 -44
  99. data/docs/api-reference/gyro-timer.md +0 -51
  100. data/docs/api-reference/gyro.md +0 -25
  101. data/docs/getting-started.md +0 -10
  102. data/docs/main-concepts.md +0 -10
  103. data/docs/user-guide.md +0 -10
  104. data/examples/core/forever_sleep.rb +0 -19
  105. data/ext/gyro/async.c +0 -132
  106. data/ext/gyro/child.c +0 -108
  107. data/ext/gyro/gyro.h +0 -158
  108. data/ext/gyro/gyro_ext.c +0 -33
  109. data/ext/gyro/io.c +0 -457
  110. data/ext/gyro/queue.c +0 -146
  111. data/ext/gyro/selector.c +0 -205
  112. data/ext/gyro/signal.c +0 -99
  113. data/ext/gyro/socket.c +0 -213
  114. data/ext/gyro/timer.c +0 -115
  115. data/test/test_timer.rb +0 -56
@@ -0,0 +1,217 @@
1
+ #include "polyphony.h"
2
+
3
+ struct async_watcher {
4
+ ev_async async;
5
+ struct ev_loop *ev_loop;
6
+ VALUE fiber;
7
+ };
8
+
9
+ struct async_queue {
10
+ struct async_watcher **queue;
11
+ unsigned int len;
12
+ unsigned int count;
13
+ unsigned int push_idx;
14
+ unsigned int pop_idx;
15
+ };
16
+
17
+ void async_queue_init(struct async_queue *queue) {
18
+ queue->len = 4;
19
+ queue->count = 0;
20
+ queue->queue = malloc(sizeof(struct async_watcher *) * queue->len);
21
+ queue->push_idx = 0;
22
+ queue->pop_idx = 0;
23
+ }
24
+
25
+ void async_queue_free(struct async_queue *queue) {
26
+ free(queue->queue);
27
+ }
28
+
29
+ void async_queue_push(struct async_queue *queue, struct async_watcher *watcher) {
30
+ if (queue->push_idx == queue->len) {
31
+ queue->len = queue->len * 2;
32
+ queue->queue = realloc(queue->queue, sizeof(struct async_watcher *) * queue->len);
33
+ }
34
+ if (queue->count == 0) {
35
+ queue->push_idx = 0;
36
+ queue->pop_idx = 0;
37
+ }
38
+ queue->count++;
39
+ queue->queue[queue->push_idx++] = watcher;
40
+ }
41
+
42
+ struct async_watcher *async_queue_pop(struct async_queue *queue) {
43
+ if (queue->count == 0) return 0;
44
+
45
+ queue->count--;
46
+
47
+ return queue->queue[queue->pop_idx++];
48
+ }
49
+
50
+ void async_queue_remove_at_idx(struct async_queue *queue, unsigned int remove_idx) {
51
+ queue->count--;
52
+ queue->push_idx--;
53
+ if (remove_idx < queue->push_idx)
54
+ memmove(
55
+ queue->queue + remove_idx,
56
+ queue->queue + remove_idx + 1,
57
+ (queue->push_idx - remove_idx) * sizeof(struct async_watcher *)
58
+ );
59
+ }
60
+
61
+ void async_queue_remove_by_fiber(struct async_queue *queue, VALUE fiber) {
62
+ if (queue->count == 0) return;
63
+
64
+ for (unsigned idx = queue->pop_idx; idx < queue->push_idx; idx++) {
65
+ if (queue->queue[idx]->fiber == fiber) {
66
+ async_queue_remove_at_idx(queue, idx);
67
+ return;
68
+ }
69
+ }
70
+ }
71
+
72
+ typedef struct queue {
73
+ VALUE items;
74
+ struct async_queue shift_queue;
75
+ } LibevQueue_t;
76
+
77
+
78
+ VALUE cLibevQueue = Qnil;
79
+
80
+ static void LibevQueue_mark(void *ptr) {
81
+ LibevQueue_t *queue = ptr;
82
+ rb_gc_mark(queue->items);
83
+ }
84
+
85
+ static void LibevQueue_free(void *ptr) {
86
+ LibevQueue_t *queue = ptr;
87
+ async_queue_free(&queue->shift_queue);
88
+ xfree(ptr);
89
+ }
90
+
91
+ static size_t LibevQueue_size(const void *ptr) {
92
+ return sizeof(LibevQueue_t);
93
+ }
94
+
95
+ static const rb_data_type_t LibevQueue_type = {
96
+ "Queue",
97
+ {LibevQueue_mark, LibevQueue_free, LibevQueue_size,},
98
+ 0, 0, 0
99
+ };
100
+
101
+ static VALUE LibevQueue_allocate(VALUE klass) {
102
+ LibevQueue_t *queue;
103
+
104
+ queue = ALLOC(LibevQueue_t);
105
+ return TypedData_Wrap_Struct(klass, &LibevQueue_type, queue);
106
+ }
107
+
108
+ #define GetQueue(obj, queue) \
109
+ TypedData_Get_Struct((obj), LibevQueue_t, &LibevQueue_type, (queue))
110
+
111
+ static VALUE LibevQueue_initialize(VALUE self) {
112
+ LibevQueue_t *queue;
113
+ GetQueue(self, queue);
114
+
115
+ queue->items = rb_ary_new();
116
+ async_queue_init(&queue->shift_queue);
117
+
118
+ return self;
119
+ }
120
+
121
+ VALUE LibevQueue_push(VALUE self, VALUE value) {
122
+ LibevQueue_t *queue;
123
+ GetQueue(self, queue);
124
+ if (queue->shift_queue.count > 0) {
125
+ struct async_watcher *watcher = async_queue_pop(&queue->shift_queue);
126
+ if (watcher) {
127
+ ev_async_send(watcher->ev_loop, &watcher->async);
128
+ }
129
+ }
130
+ rb_ary_push(queue->items, value);
131
+ return self;
132
+ }
133
+
134
+ struct ev_loop *LibevAgent_ev_loop(VALUE self);
135
+
136
+ void async_queue_callback(struct ev_loop *ev_loop, struct ev_async *ev_async, int revents) {
137
+ struct async_watcher *watcher = (struct async_watcher *)ev_async;
138
+ Fiber_make_runnable(watcher->fiber, Qnil);
139
+ }
140
+
141
+ VALUE libev_agent_await(VALUE self);
142
+
143
+ VALUE LibevQueue_shift(VALUE self) {
144
+ LibevQueue_t *queue;
145
+ GetQueue(self, queue);
146
+
147
+ if (RARRAY_LEN(queue->items) == 0) {
148
+ struct async_watcher watcher;
149
+ VALUE agent = rb_ivar_get(rb_thread_current(), ID_ivar_agent);
150
+ VALUE switchpoint_result = Qnil;
151
+
152
+ watcher.ev_loop = LibevAgent_ev_loop(agent);
153
+ watcher.fiber = rb_fiber_current();
154
+ async_queue_push(&queue->shift_queue, &watcher);
155
+ ev_async_init(&watcher.async, async_queue_callback);
156
+ ev_async_start(watcher.ev_loop, &watcher.async);
157
+
158
+ switchpoint_result = libev_agent_await(agent);
159
+ ev_async_stop(watcher.ev_loop, &watcher.async);
160
+
161
+ if (RTEST(rb_obj_is_kind_of(switchpoint_result, rb_eException))) {
162
+ async_queue_remove_by_fiber(&queue->shift_queue, watcher.fiber);
163
+ return rb_funcall(rb_mKernel, ID_raise, 1, switchpoint_result);
164
+ }
165
+ RB_GC_GUARD(watcher.fiber);
166
+ RB_GC_GUARD(agent);
167
+ RB_GC_GUARD(switchpoint_result);
168
+ }
169
+
170
+ return rb_ary_shift(queue->items);
171
+ }
172
+
173
+ VALUE LibevQueue_shift_each(VALUE self) {
174
+ LibevQueue_t *queue;
175
+ VALUE old_queue;
176
+ GetQueue(self, queue);
177
+ old_queue = queue->items;
178
+ queue->items = rb_ary_new();
179
+
180
+ if (rb_block_given_p()) {
181
+ long len = RARRAY_LEN(old_queue);
182
+ long i;
183
+ for (i = 0; i < len; i++) {
184
+ rb_yield(RARRAY_AREF(old_queue, i));
185
+ }
186
+ RB_GC_GUARD(old_queue);
187
+ return self;
188
+ }
189
+ else {
190
+ RB_GC_GUARD(old_queue);
191
+ return old_queue;
192
+ }
193
+ }
194
+
195
+ VALUE LibevQueue_empty_p(VALUE self) {
196
+ LibevQueue_t *queue;
197
+ GetQueue(self, queue);
198
+
199
+ return (RARRAY_LEN(queue->items) == 0) ? Qtrue : Qfalse;
200
+ }
201
+
202
+ void Init_LibevQueue() {
203
+ cLibevQueue = rb_define_class_under(mPolyphony, "LibevQueue", rb_cData);
204
+ rb_define_alloc_func(cLibevQueue, LibevQueue_allocate);
205
+
206
+ rb_define_method(cLibevQueue, "initialize", LibevQueue_initialize, 0);
207
+ rb_define_method(cLibevQueue, "push", LibevQueue_push, 1);
208
+ rb_define_method(cLibevQueue, "<<", LibevQueue_push, 1);
209
+
210
+ rb_define_method(cLibevQueue, "pop", LibevQueue_shift, 0);
211
+ rb_define_method(cLibevQueue, "shift", LibevQueue_shift, 0);
212
+
213
+ rb_define_method(cLibevQueue, "shift_each", LibevQueue_shift_each, 0);
214
+ rb_define_method(cLibevQueue, "empty?", LibevQueue_empty_p, 0);
215
+ }
216
+
217
+
@@ -1,17 +1,14 @@
1
- #include "gyro.h"
1
+ #include "polyphony.h"
2
2
 
3
- VALUE mGyro;
4
- int __gyro_current_generation__ = 0;
3
+ VALUE mPolyphony;
5
4
 
5
+ ID ID_await_no_raise;
6
6
  ID ID_call;
7
7
  ID ID_caller;
8
8
  ID ID_clear;
9
9
  ID ID_each;
10
- ID ID_empty;
11
10
  ID ID_inspect;
12
11
  ID ID_new;
13
- ID ID_pop;
14
- ID ID_push;
15
12
  ID ID_raise;
16
13
  ID ID_ivar_running;
17
14
  ID ID_ivar_thread;
@@ -25,7 +22,7 @@ ID ID_R;
25
22
  ID ID_W;
26
23
  ID ID_RW;
27
24
 
28
- VALUE Gyro_snooze(VALUE self) {
25
+ VALUE Polyphony_snooze(VALUE self) {
29
26
  VALUE ret;
30
27
  VALUE fiber = rb_fiber_current();
31
28
 
@@ -36,15 +33,7 @@ VALUE Gyro_snooze(VALUE self) {
36
33
  return ret;
37
34
  }
38
35
 
39
- static VALUE Gyro_ref(VALUE self) {
40
- return Thread_ref(rb_thread_current());
41
- }
42
-
43
- static VALUE Gyro_unref(VALUE self) {
44
- return Thread_unref(rb_thread_current());
45
- }
46
-
47
- static VALUE Gyro_suspend(VALUE self) {
36
+ static VALUE Polyphony_suspend(VALUE self) {
48
37
  VALUE ret = Thread_switch_fiber(rb_thread_current());
49
38
 
50
39
  TEST_RESUME_EXCEPTION(ret);
@@ -52,38 +41,28 @@ static VALUE Gyro_suspend(VALUE self) {
52
41
  return ret;
53
42
  }
54
43
 
55
- VALUE Gyro_trace(VALUE self, VALUE enabled) {
44
+ VALUE Polyphony_trace(VALUE self, VALUE enabled) {
56
45
  __tracing_enabled__ = RTEST(enabled) ? 1 : 0;
57
46
  return Qnil;
58
47
  }
59
48
 
60
- VALUE Gyro_incr_generation(VALUE self) {
61
- __gyro_current_generation__++;
62
- return Qnil;
63
- }
49
+ void Init_Polyphony() {
50
+ mPolyphony = rb_define_module("Polyphony");
64
51
 
65
- void Init_Gyro() {
66
- mGyro = rb_define_module("Gyro");
52
+ rb_define_singleton_method(mPolyphony, "trace", Polyphony_trace, 1);
67
53
 
68
- rb_define_singleton_method(mGyro, "incr_generation", Gyro_incr_generation, 0);
69
- rb_define_singleton_method(mGyro, "ref", Gyro_ref, 0);
70
- rb_define_singleton_method(mGyro, "trace", Gyro_trace, 1);
71
- rb_define_singleton_method(mGyro, "unref", Gyro_unref, 0);
72
-
73
- rb_define_global_function("snooze", Gyro_snooze, 0);
74
- rb_define_global_function("suspend", Gyro_suspend, 0);
54
+ rb_define_global_function("snooze", Polyphony_snooze, 0);
55
+ rb_define_global_function("suspend", Polyphony_suspend, 0);
75
56
 
57
+ ID_await_no_raise = rb_intern("await_no_raise");
76
58
  ID_call = rb_intern("call");
77
59
  ID_caller = rb_intern("caller");
78
60
  ID_clear = rb_intern("clear");
79
61
  ID_each = rb_intern("each");
80
- ID_empty = rb_intern("empty?");
81
62
  ID_inspect = rb_intern("inspect");
82
63
  ID_ivar_running = rb_intern("@running");
83
64
  ID_ivar_thread = rb_intern("@thread");
84
65
  ID_new = rb_intern("new");
85
- ID_pop = rb_intern("pop");
86
- ID_push = rb_intern("push");
87
66
  ID_raise = rb_intern("raise");
88
67
  ID_runnable = rb_intern("runnable");
89
68
  ID_runnable_value = rb_intern("runnable_value");
@@ -91,8 +70,4 @@ void Init_Gyro() {
91
70
  ID_size = rb_intern("size");
92
71
  ID_switch_fiber = rb_intern("switch_fiber");
93
72
  ID_transfer = rb_intern("transfer");
94
-
95
- ID_R = rb_intern("r");
96
- ID_RW = rb_intern("rw");
97
- ID_W = rb_intern("w");
98
73
  }
@@ -0,0 +1,90 @@
1
+ #ifndef RUBY_EV_H
2
+ #define RUBY_EV_H
3
+
4
+ #include "ruby.h"
5
+ #include "ruby/io.h"
6
+ #include "libev.h"
7
+
8
+ // debugging
9
+ #define OBJ_ID(obj) (NUM2LONG(rb_funcall(obj, rb_intern("object_id"), 0)))
10
+ #define INSPECT(obj) { VALUE s = rb_funcall(obj, rb_intern("inspect"), 0); printf("%s\n", StringValueCStr(s));}
11
+ #define FIBER_TRACE(...) if (__tracing_enabled__) { \
12
+ rb_funcall(rb_cObject, ID_fiber_trace, __VA_ARGS__); \
13
+ }
14
+
15
+ #define TEST_EXCEPTION(ret) (RTEST(rb_obj_is_kind_of(ret, rb_eException)))
16
+
17
+ #define TEST_RESUME_EXCEPTION(ret) if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) { \
18
+ return rb_funcall(rb_mKernel, ID_raise, 1, ret); \
19
+ }
20
+
21
+ extern VALUE mPolyphony;
22
+ extern VALUE cLibevQueue;
23
+ extern VALUE cEvent;
24
+
25
+ extern ID ID_await_no_raise;
26
+ extern ID ID_call;
27
+ extern ID ID_caller;
28
+ extern ID ID_clear;
29
+ extern ID ID_each;
30
+ extern ID ID_fiber_trace;
31
+ extern ID ID_inspect;
32
+ extern ID ID_ivar_agent;
33
+ extern ID ID_ivar_running;
34
+ extern ID ID_ivar_thread;
35
+ extern ID ID_new;
36
+ extern ID ID_raise;
37
+ extern ID ID_runnable;
38
+ extern ID ID_runnable_value;
39
+ extern ID ID_signal;
40
+ extern ID ID_size;
41
+ extern ID ID_switch_fiber;
42
+ extern ID ID_transfer;
43
+
44
+ extern VALUE SYM_fiber_create;
45
+ extern VALUE SYM_fiber_ev_loop_enter;
46
+ extern VALUE SYM_fiber_ev_loop_leave;
47
+ extern VALUE SYM_fiber_run;
48
+ extern VALUE SYM_fiber_schedule;
49
+ extern VALUE SYM_fiber_switchpoint;
50
+ extern VALUE SYM_fiber_terminate;
51
+
52
+ extern int __tracing_enabled__;
53
+
54
+ enum {
55
+ FIBER_STATE_NOT_SCHEDULED = 0,
56
+ FIBER_STATE_WAITING = 1,
57
+ FIBER_STATE_SCHEDULED = 2
58
+ };
59
+
60
+ // watcher flags
61
+ enum {
62
+ // a watcher's active field will be set to this after fork
63
+ GYRO_WATCHER_POST_FORK = 0xFF
64
+ };
65
+
66
+ VALUE Fiber_auto_watcher(VALUE self);
67
+ void Fiber_make_runnable(VALUE fiber, VALUE value);
68
+
69
+ VALUE LibevAgent_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE queue);
70
+ VALUE LibevAgent_break(VALUE self);
71
+ VALUE LibevAgent_pending_count(VALUE self);
72
+ VALUE LibevAgent_wait_io(VALUE self, VALUE io, VALUE write);
73
+
74
+ VALUE LibevAgent_ref(VALUE self);
75
+ VALUE LibevAgent_unref(VALUE self);
76
+ int LibevAgent_ref_count(VALUE self);
77
+ void LibevAgent_reset_ref_count(VALUE self);
78
+
79
+ VALUE Polyphony_snooze(VALUE self);
80
+
81
+ VALUE Polyphony_Queue_push(VALUE self, VALUE value);
82
+
83
+ VALUE Thread_schedule_fiber(VALUE thread, VALUE fiber, VALUE value);
84
+ VALUE Thread_switch_fiber(VALUE thread);
85
+
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
+ #endif /* RUBY_EV_H */
@@ -0,0 +1,21 @@
1
+ #include "polyphony.h"
2
+
3
+ void Init_Fiber();
4
+ void Init_Polyphony();
5
+ void Init_LibevAgent();
6
+ void Init_LibevQueue();
7
+ void Init_Thread();
8
+ void Init_Tracing();
9
+
10
+ void Init_polyphony_ext() {
11
+ ev_set_allocator(xrealloc);
12
+
13
+ Init_Polyphony();
14
+ Init_LibevAgent();
15
+ Init_LibevQueue();
16
+
17
+ Init_Fiber();
18
+ Init_Thread();
19
+
20
+ Init_Tracing();
21
+ }
@@ -1,115 +1,48 @@
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
- }
1
+ #include "polyphony.h"
2
+
3
+ ID ID_deactivate_all_watchers_post_fork;
4
+ ID ID_ivar_agent;
5
+ ID ID_ivar_join_wait_queue;
6
+ ID ID_ivar_main_fiber;
7
+ ID ID_ivar_result;
8
+ ID ID_ivar_terminated;
9
+ ID ID_run_queue;
10
+ ID ID_runnable_next;
11
+ ID ID_stop;
41
12
 
42
13
  static VALUE Thread_setup_fiber_scheduling(VALUE self) {
43
14
  VALUE queue;
44
- VALUE selector;
45
15
 
46
16
  rb_ivar_set(self, ID_ivar_main_fiber, rb_fiber_current());
47
- rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(0));
48
17
  queue = rb_ary_new();
49
18
  rb_ivar_set(self, ID_run_queue, queue);
50
- selector = rb_funcall(rb_cThread, ID_create_event_selector, 1, self);
51
- rb_ivar_set(self, ID_ivar_event_selector, selector);
52
-
53
- return self;
54
- }
55
-
56
- static VALUE Thread_stop_event_selector(VALUE self) {
57
- VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
58
- if (selector != Qnil) {
59
- rb_funcall(selector, ID_stop, 0);
60
- }
61
- // Nullify the selector in order to prevent running the
62
- // selector after the thread is done running.
63
- rb_ivar_set(self, ID_ivar_event_selector, Qnil);
64
-
65
- return self;
66
- }
67
-
68
- static VALUE Thread_deactivate_all_watchers_post_fork(VALUE self) {
69
- VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
70
- if (selector != Qnil) {
71
- rb_funcall(selector, ID_deactivate_all_watchers_post_fork, 0);
72
- }
73
-
74
- return self;
75
- }
76
19
 
77
- VALUE Thread_ref(VALUE self) {
78
- VALUE count = rb_ivar_get(self, ID_fiber_ref_count);
79
- int new_count = NUM2INT(count) + 1;
80
- rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(new_count));
81
- return self;
82
- }
83
-
84
- VALUE Thread_unref(VALUE self) {
85
- VALUE count = rb_ivar_get(self, ID_fiber_ref_count);
86
- int new_count = NUM2INT(count) - 1;
87
- rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(new_count));
88
20
  return self;
89
21
  }
90
22
 
91
23
  int Thread_fiber_ref_count(VALUE self) {
92
- VALUE count = rb_ivar_get(self, ID_fiber_ref_count);
93
- return NUM2INT(count);
24
+ VALUE agent = rb_ivar_get(self, ID_ivar_agent);
25
+ return NUM2INT(LibevAgent_ref_count(agent));
94
26
  }
95
27
 
96
- void Thread_fiber_reset_ref_count(VALUE self) {
97
- rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(0));
28
+ inline void Thread_fiber_reset_ref_count(VALUE self) {
29
+ VALUE agent = rb_ivar_get(self, ID_ivar_agent);
30
+ LibevAgent_reset_ref_count(agent);
98
31
  }
99
32
 
100
33
  static VALUE SYM_scheduled_fibers;
101
34
  static VALUE SYM_pending_watchers;
102
35
 
103
36
  static VALUE Thread_fiber_scheduling_stats(VALUE self) {
37
+ VALUE agent = rb_ivar_get(self,ID_ivar_agent);
104
38
  VALUE stats = rb_hash_new();
105
39
  VALUE queue = rb_ivar_get(self, ID_run_queue);
106
- VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
107
40
  long pending_count;
108
41
 
109
42
  long scheduled_count = RARRAY_LEN(queue);
110
43
  rb_hash_aset(stats, SYM_scheduled_fibers, INT2NUM(scheduled_count));
111
44
 
112
- pending_count = Gyro_Selector_pending_count(selector);
45
+ pending_count = LibevAgent_pending_count(agent);
113
46
  rb_hash_aset(stats, SYM_pending_watchers, INT2NUM(pending_count));
114
47
 
115
48
  return stats;
@@ -137,10 +70,8 @@ VALUE Thread_schedule_fiber(VALUE self, VALUE fiber, VALUE value) {
137
70
  // event selector. Otherwise it's gonna be stuck waiting for an event to
138
71
  // happen, not knowing that it there's already a fiber ready to run in its
139
72
  // run queue.
140
- VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
141
- if (selector != Qnil) {
142
- Gyro_Selector_break_out_of_ev_loop(selector);
143
- }
73
+ VALUE agent = rb_ivar_get(self,ID_ivar_agent);
74
+ LibevAgent_break(agent);
144
75
  }
145
76
  return self;
146
77
  }
@@ -168,13 +99,11 @@ VALUE Thread_schedule_fiber_with_priority(VALUE self, VALUE fiber, VALUE value)
168
99
  if (rb_thread_current() != self) {
169
100
  // if the fiber scheduling is done across threads, we need to make sure the
170
101
  // target thread is woken up in case it is in the middle of running its
171
- // event selector. Otherwise it's gonna be stuck waiting for an event to
102
+ // event loop. Otherwise it's gonna be stuck waiting for an event to
172
103
  // happen, not knowing that it there's already a fiber ready to run in its
173
104
  // run queue.
174
- VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
175
- if (selector != Qnil) {
176
- Gyro_Selector_break_out_of_ev_loop(selector);
177
- }
105
+ VALUE agent = rb_ivar_get(self, ID_ivar_agent);
106
+ LibevAgent_break(agent);
178
107
  }
179
108
  return self;
180
109
  }
@@ -182,9 +111,9 @@ VALUE Thread_schedule_fiber_with_priority(VALUE self, VALUE fiber, VALUE value)
182
111
  VALUE Thread_switch_fiber(VALUE self) {
183
112
  VALUE current_fiber = rb_fiber_current();
184
113
  VALUE queue = rb_ivar_get(self, ID_run_queue);
185
- VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
186
114
  VALUE next_fiber;
187
115
  VALUE value;
116
+ VALUE agent = rb_ivar_get(self, ID_ivar_agent);
188
117
  int ref_count;
189
118
 
190
119
  if (__tracing_enabled__) {
@@ -193,31 +122,23 @@ VALUE Thread_switch_fiber(VALUE self) {
193
122
  }
194
123
  }
195
124
 
196
-
125
+ ref_count = LibevAgent_ref_count(agent);
197
126
  while (1) {
198
127
  next_fiber = rb_ary_shift(queue);
199
- // if (break_flag != 0) {
200
- // return Qnil;
201
- // }
202
- ref_count = Thread_fiber_ref_count(self);
203
128
  if (next_fiber != Qnil) {
204
129
  if (ref_count > 0) {
205
130
  // this mechanism prevents event starvation in case the run queue never
206
131
  // empties
207
- Gyro_Selector_run_no_wait(selector, current_fiber, RARRAY_LEN(queue));
132
+ LibevAgent_poll(agent, Qtrue, current_fiber, queue);
208
133
  }
209
134
  break;
210
135
  }
211
- if (ref_count == 0) {
212
- break;
213
- }
136
+ if (ref_count == 0) break;
214
137
 
215
- Gyro_Selector_run(selector, current_fiber);
138
+ LibevAgent_poll(agent, Qnil, current_fiber, queue);
216
139
  }
217
140
 
218
- if (next_fiber == Qnil) {
219
- return Qnil;
220
- }
141
+ if (next_fiber == Qnil) return Qnil;
221
142
 
222
143
  // run next fiber
223
144
  value = rb_ivar_get(next_fiber, ID_runnable_value);
@@ -226,7 +147,8 @@ VALUE Thread_switch_fiber(VALUE self) {
226
147
  rb_ivar_set(next_fiber, ID_runnable, Qnil);
227
148
  RB_GC_GUARD(next_fiber);
228
149
  RB_GC_GUARD(value);
229
- return rb_funcall(next_fiber, ID_transfer, 1, value);
150
+ return (next_fiber == current_fiber) ?
151
+ value : rb_funcall(next_fiber, ID_transfer, 1, value);
230
152
  }
231
153
 
232
154
  VALUE Thread_reset_fiber_scheduling(VALUE self) {
@@ -236,34 +158,13 @@ VALUE Thread_reset_fiber_scheduling(VALUE self) {
236
158
  return self;
237
159
  }
238
160
 
239
- VALUE Thread_post_fork(VALUE self) {
240
- VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
241
- Gyro_Selector_post_fork(selector);
242
-
243
- return self;
244
- }
245
-
246
- VALUE Gyro_switchpoint() {
247
- VALUE ret;
248
- VALUE thread = rb_thread_current();
249
- Thread_ref(thread);
250
- ret = Thread_switch_fiber(thread);
251
- Thread_unref(thread);
252
- RB_GC_GUARD(ret);
253
- return ret;
254
- }
255
-
256
- VALUE Thread_current_event_selector() {
257
- return rb_ivar_get(rb_thread_current(), ID_ivar_event_selector);
258
- }
259
-
260
161
  VALUE Thread_fiber_break_out_of_ev_loop(VALUE self, VALUE fiber, VALUE resume_obj) {
261
- VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
162
+ VALUE agent = rb_ivar_get(self, ID_ivar_agent);
262
163
  if (fiber != Qnil) {
263
164
  Thread_schedule_fiber_with_priority(self, fiber, resume_obj);
264
165
  }
265
166
 
266
- if (Gyro_Selector_break_out_of_ev_loop(selector) == Qnil) {
167
+ if (LibevAgent_break(agent) == Qnil) {
267
168
  // we're not inside the ev_loop, so we just do a switchpoint
268
169
  Thread_switch_fiber(self);
269
170
  }
@@ -272,19 +173,7 @@ VALUE Thread_fiber_break_out_of_ev_loop(VALUE self, VALUE fiber, VALUE resume_ob
272
173
  }
273
174
 
274
175
  void Init_Thread() {
275
- cQueue = rb_const_get(rb_cObject, rb_intern("Queue"));
276
-
277
- rb_define_singleton_method(rb_cThread, "event_selector=", Thread_event_selector_set_proc, 1);
278
- rb_define_singleton_method(rb_cThread, "create_event_selector", Thread_create_event_selector, 1);
279
-
280
- rb_define_method(rb_cThread, "fiber_ref", Thread_ref, 0);
281
- rb_define_method(rb_cThread, "fiber_unref", Thread_unref, 0);
282
-
283
- rb_define_method(rb_cThread, "post_fork", Thread_post_fork, 0);
284
-
285
176
  rb_define_method(rb_cThread, "setup_fiber_scheduling", Thread_setup_fiber_scheduling, 0);
286
- rb_define_method(rb_cThread, "stop_event_selector", Thread_stop_event_selector, 0);
287
- rb_define_method(rb_cThread, "deactivate_all_watchers_post_fork", Thread_deactivate_all_watchers_post_fork, 0);
288
177
  rb_define_method(rb_cThread, "reset_fiber_scheduling", Thread_reset_fiber_scheduling, 0);
289
178
  rb_define_method(rb_cThread, "fiber_scheduling_stats", Thread_fiber_scheduling_stats, 0);
290
179
  rb_define_method(rb_cThread, "break_out_of_ev_loop", Thread_fiber_break_out_of_ev_loop, 2);
@@ -294,18 +183,12 @@ void Init_Thread() {
294
183
  Thread_schedule_fiber_with_priority, 2);
295
184
  rb_define_method(rb_cThread, "switch_fiber", Thread_switch_fiber, 0);
296
185
 
297
- ID_create_event_selector = rb_intern("create_event_selector");
298
186
  ID_deactivate_all_watchers_post_fork = rb_intern("deactivate_all_watchers_post_fork");
299
- ID_empty = rb_intern("empty?");
300
- ID_fiber_ref_count = rb_intern("fiber_ref_count");
301
- ID_ivar_event_selector = rb_intern("@event_selector");
302
- ID_ivar_event_selector_proc = rb_intern("@event_selector_proc");
187
+ ID_ivar_agent = rb_intern("@agent");
303
188
  ID_ivar_join_wait_queue = rb_intern("@join_wait_queue");
304
189
  ID_ivar_main_fiber = rb_intern("@main_fiber");
305
190
  ID_ivar_result = rb_intern("@result");
306
191
  ID_ivar_terminated = rb_intern("@terminated");
307
- ID_pop = rb_intern("pop");
308
- ID_push = rb_intern("push");
309
192
  ID_run_queue = rb_intern("run_queue");
310
193
  ID_runnable_next = rb_intern("runnable_next");
311
194
  ID_stop = rb_intern("stop");