polyphony 0.40 → 0.41

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) 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 +6 -2
  6. data/Gemfile.lock +9 -6
  7. data/Rakefile +2 -2
  8. data/TODO.md +18 -97
  9. data/docs/_includes/head.html +40 -0
  10. data/docs/_includes/nav.html +5 -5
  11. data/docs/api-reference/fiber.md +2 -2
  12. data/docs/main-concepts/design-principles.md +67 -9
  13. data/docs/main-concepts/extending.md +1 -1
  14. data/examples/core/xx-agent.rb +102 -0
  15. data/examples/core/xx-sleeping.rb +14 -6
  16. data/examples/io/xx-irb.rb +1 -1
  17. data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +7 -6
  18. data/examples/performance/thread-vs-fiber/polyphony_server.rb +14 -25
  19. data/ext/{gyro → polyphony}/extconf.rb +2 -2
  20. data/ext/{gyro → polyphony}/fiber.c +15 -19
  21. data/ext/{gyro → polyphony}/libev.c +0 -0
  22. data/ext/{gyro → polyphony}/libev.h +0 -0
  23. data/ext/polyphony/libev_agent.c +503 -0
  24. data/ext/polyphony/libev_queue.c +214 -0
  25. data/ext/{gyro/gyro.c → polyphony/polyphony.c} +16 -25
  26. data/ext/polyphony/polyphony.h +90 -0
  27. data/ext/polyphony/polyphony_ext.c +23 -0
  28. data/ext/{gyro → polyphony}/socket.c +14 -14
  29. data/ext/{gyro → polyphony}/thread.c +32 -115
  30. data/ext/{gyro → polyphony}/tracing.c +1 -1
  31. data/lib/polyphony.rb +16 -12
  32. data/lib/polyphony/adapters/irb.rb +1 -1
  33. data/lib/polyphony/adapters/postgres.rb +6 -5
  34. data/lib/polyphony/adapters/process.rb +5 -5
  35. data/lib/polyphony/adapters/trace.rb +28 -28
  36. data/lib/polyphony/core/channel.rb +3 -3
  37. data/lib/polyphony/core/exceptions.rb +1 -1
  38. data/lib/polyphony/core/global_api.rb +11 -9
  39. data/lib/polyphony/core/resource_pool.rb +3 -3
  40. data/lib/polyphony/core/sync.rb +2 -2
  41. data/lib/polyphony/core/thread_pool.rb +6 -6
  42. data/lib/polyphony/core/throttler.rb +13 -6
  43. data/lib/polyphony/event.rb +27 -0
  44. data/lib/polyphony/extensions/core.rb +20 -11
  45. data/lib/polyphony/extensions/fiber.rb +4 -4
  46. data/lib/polyphony/extensions/io.rb +56 -26
  47. data/lib/polyphony/extensions/openssl.rb +4 -8
  48. data/lib/polyphony/extensions/socket.rb +27 -9
  49. data/lib/polyphony/extensions/thread.rb +16 -9
  50. data/lib/polyphony/net.rb +9 -9
  51. data/lib/polyphony/version.rb +1 -1
  52. data/polyphony.gemspec +2 -2
  53. data/test/helper.rb +12 -1
  54. data/test/test_agent.rb +77 -0
  55. data/test/{test_async.rb → test_event.rb} +13 -7
  56. data/test/test_ext.rb +25 -4
  57. data/test/test_fiber.rb +19 -10
  58. data/test/test_global_api.rb +4 -4
  59. data/test/test_io.rb +46 -24
  60. data/test/test_queue.rb +74 -0
  61. data/test/test_signal.rb +3 -40
  62. data/test/test_socket.rb +33 -0
  63. data/test/test_thread.rb +37 -16
  64. data/test/test_trace.rb +6 -5
  65. metadata +24 -24
  66. data/ext/gyro/async.c +0 -132
  67. data/ext/gyro/child.c +0 -108
  68. data/ext/gyro/gyro.h +0 -158
  69. data/ext/gyro/gyro_ext.c +0 -33
  70. data/ext/gyro/io.c +0 -457
  71. data/ext/gyro/queue.c +0 -146
  72. data/ext/gyro/selector.c +0 -205
  73. data/ext/gyro/signal.c +0 -99
  74. data/ext/gyro/timer.c +0 -115
  75. data/test/test_timer.rb +0 -56
@@ -1,146 +0,0 @@
1
- #include "gyro.h"
2
-
3
- typedef struct queue {
4
- VALUE items;
5
- VALUE shift_waiters;
6
- } Gyro_Queue_t;
7
-
8
- VALUE cGyro_Queue = Qnil;
9
-
10
- static void Gyro_Queue_mark(void *ptr) {
11
- Gyro_Queue_t *queue = ptr;
12
- if (queue->items != Qnil) {
13
- rb_gc_mark(queue->items);
14
- }
15
- if (queue->shift_waiters != Qnil) {
16
- rb_gc_mark(queue->shift_waiters);
17
- }
18
- }
19
-
20
- static size_t Gyro_Queue_size(const void *ptr) {
21
- return sizeof(Gyro_Queue_t);
22
- }
23
-
24
- static const rb_data_type_t Gyro_Queue_type = {
25
- "Gyro_Queue",
26
- {Gyro_Queue_mark, RUBY_DEFAULT_FREE, Gyro_Queue_size,},
27
- 0, 0, 0
28
- };
29
-
30
- static VALUE Gyro_Queue_allocate(VALUE klass) {
31
- Gyro_Queue_t *queue;
32
- // return Data_Make_Struct(klass, Gyro_Queue_t, Gyro_Queue_mark, free, queue);
33
-
34
- queue = ALLOC(Gyro_Queue_t);
35
- // struct Gyro_Queue *queue = ALLOC(struct Gyro_Queue);
36
- return TypedData_Wrap_Struct(klass, &Gyro_Queue_type, queue);
37
- }
38
-
39
- #define GetGyro_Queue(obj, queue) \
40
- TypedData_Get_Struct((obj), Gyro_Queue_t, &Gyro_Queue_type, (queue))
41
-
42
- static VALUE Gyro_Queue_initialize(VALUE self) {
43
- Gyro_Queue_t *queue;
44
- GetGyro_Queue(self, queue);
45
-
46
- queue->items = rb_ary_new();
47
- queue->shift_waiters = rb_ary_new();
48
-
49
- return self;
50
- }
51
-
52
- VALUE Gyro_Queue_push(VALUE self, VALUE value) {
53
- Gyro_Queue_t *queue;
54
- GetGyro_Queue(self, queue);
55
-
56
- if (RARRAY_LEN(queue->shift_waiters) > 0) {
57
- VALUE async = rb_ary_shift(queue->shift_waiters);
58
- rb_funcall(async, ID_signal, 1, Qnil);
59
- }
60
-
61
- rb_ary_push(queue->items, value);
62
- return self;
63
- }
64
-
65
- VALUE Gyro_Queue_shift(VALUE self) {
66
- Gyro_Queue_t *queue;
67
- GetGyro_Queue(self, queue);
68
-
69
- if (RARRAY_LEN(queue->items) == 0) {
70
- VALUE ret;
71
- VALUE async = Fiber_auto_async(rb_fiber_current());
72
- rb_ary_push(queue->shift_waiters, async);
73
- ret = Gyro_Async_await_no_raise(async);
74
- if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) {
75
- rb_ary_delete(queue->shift_waiters, async);
76
- return rb_funcall(rb_mKernel, ID_raise, 1, ret);
77
- }
78
- RB_GC_GUARD(ret);
79
- }
80
-
81
- return rb_ary_shift(queue->items);
82
- }
83
-
84
- VALUE Gyro_Queue_shift_no_wait(VALUE self) {
85
- Gyro_Queue_t *queue;
86
- GetGyro_Queue(self, queue);
87
-
88
- return rb_ary_shift(queue->items);
89
- }
90
-
91
- VALUE Gyro_Queue_shift_each(VALUE self) {
92
- Gyro_Queue_t *queue;
93
- VALUE old_queue;
94
- GetGyro_Queue(self, queue);
95
- old_queue = queue->items;
96
- queue->items = rb_ary_new();
97
-
98
- if (rb_block_given_p()) {
99
- long len = RARRAY_LEN(old_queue);
100
- long i;
101
- for (i = 0; i < len; i++) {
102
- rb_yield(RARRAY_AREF(old_queue, i));
103
- }
104
- RB_GC_GUARD(old_queue);
105
- return self;
106
- }
107
- else {
108
- RB_GC_GUARD(old_queue);
109
- return old_queue;
110
- }
111
- }
112
-
113
- VALUE Gyro_Queue_clear(VALUE self) {
114
- Gyro_Queue_t *queue;
115
- GetGyro_Queue(self, queue);
116
-
117
- rb_ary_clear(queue->items);
118
- return self;
119
- }
120
-
121
- VALUE Gyro_Queue_empty_p(VALUE self) {
122
- Gyro_Queue_t *queue;
123
- GetGyro_Queue(self, queue);
124
-
125
- return (RARRAY_LEN(queue->items) == 0) ? Qtrue : Qfalse;
126
- }
127
-
128
- void Init_Gyro_Queue() {
129
- cGyro_Queue = rb_define_class_under(mGyro, "Queue", rb_cData);
130
- rb_define_alloc_func(cGyro_Queue, Gyro_Queue_allocate);
131
-
132
- rb_define_method(cGyro_Queue, "initialize", Gyro_Queue_initialize, 0);
133
- rb_define_method(cGyro_Queue, "push", Gyro_Queue_push, 1);
134
- rb_define_method(cGyro_Queue, "<<", Gyro_Queue_push, 1);
135
-
136
- rb_define_method(cGyro_Queue, "pop", Gyro_Queue_shift, 0);
137
- rb_define_method(cGyro_Queue, "shift", Gyro_Queue_shift, 0);
138
-
139
- rb_define_method(cGyro_Queue, "shift_no_wait", Gyro_Queue_shift_no_wait, 0);
140
-
141
- rb_define_method(cGyro_Queue, "shift_each", Gyro_Queue_shift_each, 0);
142
- rb_define_method(cGyro_Queue, "clear", Gyro_Queue_clear, 0);
143
- rb_define_method(cGyro_Queue, "empty?", Gyro_Queue_empty_p, 0);
144
- }
145
-
146
-
@@ -1,205 +0,0 @@
1
- #include "gyro.h"
2
-
3
- struct Gyro_Selector {
4
- struct ev_loop *ev_loop;
5
- long run_no_wait_count;
6
- int ev_loop_running;
7
- struct ev_async async;
8
- VALUE active_watchers;
9
- };
10
-
11
- VALUE cGyro_Selector = Qnil;
12
-
13
- static void Gyro_Selector_mark(void *ptr) {
14
- struct Gyro_Selector *selector = ptr;
15
- rb_gc_mark(selector->active_watchers);
16
- }
17
-
18
- static void Gyro_Selector_free(void *ptr) {
19
- struct Gyro_Selector *selector = ptr;
20
- ev_async_stop(selector->ev_loop, &selector->async);
21
- if (selector->ev_loop && !ev_is_default_loop(selector->ev_loop)) {
22
- ev_loop_destroy(selector->ev_loop);
23
- }
24
- xfree(selector);
25
- }
26
-
27
- static size_t Gyro_Selector_size(const void *ptr) {
28
- return sizeof(struct Gyro_Selector);
29
- }
30
-
31
- static const rb_data_type_t Gyro_Selector_type = {
32
- "Gyro_Selector",
33
- {Gyro_Selector_mark, Gyro_Selector_free, Gyro_Selector_size,},
34
- 0, 0, 0
35
- };
36
-
37
- static VALUE Gyro_Selector_allocate(VALUE klass) {
38
- struct Gyro_Selector *selector = ALLOC(struct Gyro_Selector);
39
- return TypedData_Wrap_Struct(klass, &Gyro_Selector_type, selector);
40
- }
41
-
42
- #define GetGyro_Selector(obj, selector) \
43
- TypedData_Get_Struct((obj), struct Gyro_Selector, &Gyro_Selector_type, (selector))
44
-
45
- inline struct ev_loop *Gyro_Selector_ev_loop(VALUE self) {
46
- struct Gyro_Selector *selector;
47
- GetGyro_Selector(self, selector);
48
-
49
- return selector->ev_loop;
50
- }
51
-
52
- inline struct ev_loop *Gyro_Selector_current_thread_ev_loop() {
53
- struct Gyro_Selector *selector;
54
- GetGyro_Selector(Thread_current_event_selector(), selector);
55
-
56
- return selector->ev_loop;
57
- }
58
-
59
- inline ev_tstamp Gyro_Selector_now(VALUE self) {
60
- struct Gyro_Selector *selector;
61
- GetGyro_Selector(self, selector);
62
-
63
- return ev_now(selector->ev_loop);
64
- }
65
-
66
- long Gyro_Selector_pending_count(VALUE self) {
67
- struct Gyro_Selector *selector;
68
- GetGyro_Selector(self, selector);
69
-
70
- return ev_pending_count(selector->ev_loop);
71
- }
72
-
73
- void dummy_async_callback(struct ev_loop *ev_loop, struct ev_async *ev_async, int revents) {
74
- // This callback does nothing, the selector's async is used solely for waking
75
- // up the event loop.
76
- }
77
-
78
- inline void Gyro_Selector_run_ev_loop(struct Gyro_Selector *selector, int flags) {
79
- selector->ev_loop_running = 1;
80
- ev_run(selector->ev_loop, flags);
81
- selector->ev_loop_running = 0;
82
- }
83
-
84
- static VALUE Gyro_Selector_initialize(VALUE self, VALUE thread) {
85
- struct Gyro_Selector *selector;
86
- GetGyro_Selector(self, selector);
87
-
88
- int use_default_loop = (rb_thread_current() == rb_thread_main());
89
- selector->ev_loop = use_default_loop ? EV_DEFAULT : ev_loop_new(EVFLAG_NOSIGMASK);
90
- selector->run_no_wait_count = 0;
91
-
92
- selector->active_watchers = rb_hash_new();
93
-
94
- ev_async_init(&selector->async, dummy_async_callback);
95
- ev_async_start(selector->ev_loop, &selector->async);
96
- Gyro_Selector_run_ev_loop(selector, EVRUN_NOWAIT);
97
- return Qnil;
98
- }
99
-
100
- inline void Gyro_Selector_add_active_watcher(VALUE self, VALUE watcher) {
101
- struct Gyro_Selector *selector;
102
- GetGyro_Selector(self, selector);
103
-
104
- rb_hash_aset(selector->active_watchers, watcher, Qtrue);
105
- }
106
-
107
- inline void Gyro_Selector_remove_active_watcher(VALUE self, VALUE watcher) {
108
- struct Gyro_Selector *selector;
109
- GetGyro_Selector(self, selector);
110
-
111
- rb_hash_delete(selector->active_watchers, watcher);
112
- }
113
-
114
- inline VALUE Gyro_Selector_run(VALUE self, VALUE current_fiber) {
115
- struct Gyro_Selector *selector;
116
- GetGyro_Selector(self, selector);
117
- if (selector->ev_loop) {
118
- selector->run_no_wait_count = 0;
119
- FIBER_TRACE(2, SYM_fiber_ev_loop_enter, current_fiber);
120
- Gyro_Selector_run_ev_loop(selector, EVRUN_ONCE);
121
- FIBER_TRACE(2, SYM_fiber_ev_loop_leave, current_fiber);
122
- }
123
- return Qnil;
124
- }
125
-
126
- inline void Gyro_Selector_run_no_wait(VALUE self, VALUE current_fiber, long runnable_count) {
127
- struct Gyro_Selector *selector;
128
- GetGyro_Selector(self, selector);
129
-
130
- selector->run_no_wait_count++;
131
- if (selector->run_no_wait_count < runnable_count || selector->run_no_wait_count < 10) {
132
- return;
133
- }
134
-
135
- selector->run_no_wait_count = 0;
136
- FIBER_TRACE(2, SYM_fiber_ev_loop_enter, current_fiber);
137
- Gyro_Selector_run_ev_loop(selector, EVRUN_NOWAIT);
138
- FIBER_TRACE(2, SYM_fiber_ev_loop_leave, current_fiber);
139
- }
140
-
141
- VALUE Gyro_Selector_stop(VALUE self) {
142
- struct Gyro_Selector *selector;
143
- GetGyro_Selector(self, selector);
144
-
145
- if (selector->ev_loop && !ev_is_default_loop(selector->ev_loop)) {
146
- // ev_loop_destroy(selector->ev_loop);
147
- // selector->ev_loop = 0;
148
- }
149
- return Qnil;
150
- }
151
-
152
- VALUE Gyro_Selector_post_fork(VALUE self) {
153
- struct Gyro_Selector *selector;
154
- GetGyro_Selector(self, selector);
155
-
156
- ev_loop_fork(selector->ev_loop);
157
- return self;
158
- }
159
-
160
- VALUE Gyro_Selector_break_out_of_ev_loop(VALUE self) {
161
- struct Gyro_Selector *selector;
162
- GetGyro_Selector(self, selector);
163
-
164
- if (selector->ev_loop_running) {
165
- // Since the loop will run until at least one event has occurred, we signal
166
- // the selector's associated async watcher, which will cause the ev loop to
167
- // return. In contrast to using `ev_break` to break out of the loop, which
168
- // should be called from the same thread (from within the ev_loop), using an
169
- // `ev_async` allows us to interrupt the event loop across threads.
170
- ev_async_send(selector->ev_loop, &selector->async);
171
- return Qtrue;
172
- }
173
-
174
- return Qnil;
175
- }
176
-
177
- inline static VALUE Gyro_Selector_wait_readable(VALUE self, VALUE io) {
178
- VALUE watcher = IO_read_watcher(io);
179
- return Gyro_IO_await(watcher);
180
- }
181
-
182
- inline static VALUE Gyro_Selector_wait_writable(VALUE self, VALUE io) {
183
- VALUE watcher = IO_write_watcher(io);
184
- return Gyro_IO_await(watcher);
185
- }
186
-
187
- inline static VALUE Gyro_Selector_wait_timeout(VALUE self, VALUE duration) {
188
- VALUE watcher = rb_funcall(cGyro_Timer, ID_new, 2, duration, Qnil);
189
- VALUE ret = Gyro_Timer_await(watcher);
190
- RB_GC_GUARD(watcher);
191
- return ret;
192
- }
193
-
194
- void Init_Gyro_Selector() {
195
- cGyro_Selector = rb_define_class_under(mGyro, "Selector", rb_cData);
196
- rb_define_alloc_func(cGyro_Selector, Gyro_Selector_allocate);
197
-
198
- rb_define_method(cGyro_Selector, "initialize", Gyro_Selector_initialize, 1);
199
- rb_define_method(cGyro_Selector, "run", Gyro_Selector_run, 1);
200
- rb_define_method(cGyro_Selector, "stop", Gyro_Selector_stop, 0);
201
- rb_define_method(cGyro_Selector, "wait_readable", Gyro_Selector_wait_readable, 1);
202
- rb_define_method(cGyro_Selector, "wait_writable", Gyro_Selector_wait_writable, 1);
203
- rb_define_method(cGyro_Selector, "wait_timeout", Gyro_Selector_wait_timeout, 1);
204
- rb_define_method(cGyro_Selector, "break_out_of_ev_loop", Gyro_Selector_break_out_of_ev_loop, 0);
205
- }
@@ -1,99 +0,0 @@
1
- #include "gyro.h"
2
-
3
- struct Gyro_Signal {
4
- GYRO_WATCHER_DECL(ev_signal);
5
- int signum;
6
- };
7
-
8
- static VALUE cGyro_Signal = Qnil;
9
-
10
- static void Gyro_Signal_mark(void *ptr) {
11
- struct Gyro_Signal *signal = ptr;
12
- GYRO_WATCHER_MARK(signal);
13
- }
14
-
15
- static void Gyro_Signal_free(void *ptr) {
16
- struct Gyro_Signal *signal = ptr;
17
- GYRO_WATCHER_FREE(signal);
18
- }
19
-
20
- static size_t Gyro_Signal_size(const void *ptr) {
21
- return sizeof(struct Gyro_Signal);
22
- }
23
-
24
- static const rb_data_type_t Gyro_Signal_type = {
25
- "Gyro_Signal",
26
- {Gyro_Signal_mark, Gyro_Signal_free, Gyro_Signal_size,},
27
- 0, 0, 0
28
- };
29
-
30
- static VALUE Gyro_Signal_allocate(VALUE klass) {
31
- struct Gyro_Signal *signal = ALLOC(struct Gyro_Signal);
32
- return TypedData_Wrap_Struct(klass, &Gyro_Signal_type, signal);
33
- }
34
-
35
- inline void signal_activate(struct Gyro_Signal *signal) {
36
- if (signal->active) return;
37
-
38
- signal->active = 1;
39
- signal->fiber = rb_fiber_current();
40
- signal->selector = Thread_current_event_selector();
41
- signal->ev_loop = Gyro_Selector_ev_loop(signal->selector);
42
- Gyro_Selector_add_active_watcher(signal->selector, signal->self);
43
- ev_signal_start(signal->ev_loop, &signal->ev_signal);
44
- }
45
-
46
- inline void signal_deactivate(struct Gyro_Signal *signal) {
47
- if (!signal->active) return;
48
-
49
- ev_signal_stop(signal->ev_loop, &signal->ev_signal);
50
- Gyro_Selector_remove_active_watcher(signal->selector, signal->self);
51
- signal->active = 0;
52
- signal->ev_loop = 0;
53
- signal->selector = Qnil;
54
- signal->fiber = Qnil;
55
- }
56
-
57
- void Gyro_Signal_callback(struct ev_loop *ev_loop, struct ev_signal *ev_signal, int revents) {
58
- struct Gyro_Signal *signal = (struct Gyro_Signal*)ev_signal;
59
-
60
- Fiber_make_runnable(signal->fiber, INT2NUM(signal->signum));
61
- signal_deactivate(signal);
62
- }
63
-
64
- #define GetGyro_Signal(obj, signal) \
65
- TypedData_Get_Struct((obj), struct Gyro_Signal, &Gyro_Signal_type, (signal))
66
-
67
- static VALUE Gyro_Signal_initialize(VALUE self, VALUE sig) {
68
- struct Gyro_Signal *signal;
69
- VALUE signum = sig;
70
-
71
- GetGyro_Signal(self, signal);
72
- GYRO_WATCHER_INITIALIZE(signal, self);
73
- signal->signum = NUM2INT(signum);
74
- ev_signal_init(&signal->ev_signal, Gyro_Signal_callback, signal->signum);
75
-
76
- return Qnil;
77
- }
78
-
79
- static VALUE Gyro_Signal_await(VALUE self) {
80
- struct Gyro_Signal *signal;
81
- VALUE ret;
82
- GetGyro_Signal(self, signal);
83
-
84
- signal_activate(signal);
85
- ret = Gyro_switchpoint();
86
- signal_deactivate(signal);
87
-
88
- TEST_RESUME_EXCEPTION(ret);
89
- RB_GC_GUARD(ret);
90
- return ret;
91
- }
92
-
93
- void Init_Gyro_Signal() {
94
- cGyro_Signal = rb_define_class_under(mGyro, "Signal", rb_cData);
95
- rb_define_alloc_func(cGyro_Signal, Gyro_Signal_allocate);
96
-
97
- rb_define_method(cGyro_Signal, "initialize", Gyro_Signal_initialize, 1);
98
- rb_define_method(cGyro_Signal, "await", Gyro_Signal_await, 0);
99
- }