polyphony 0.43.3 → 0.43.9

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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +1 -1
  3. data/CHANGELOG.md +44 -0
  4. data/Gemfile.lock +1 -1
  5. data/README.md +21 -4
  6. data/TODO.md +1 -2
  7. data/bin/stress.rb +28 -0
  8. data/docs/_includes/head.html +40 -0
  9. data/docs/_includes/title.html +1 -0
  10. data/docs/_user-guide/web-server.md +11 -11
  11. data/docs/getting-started/overview.md +4 -4
  12. data/docs/index.md +4 -3
  13. data/docs/main-concepts/design-principles.md +23 -34
  14. data/docs/main-concepts/fiber-scheduling.md +1 -1
  15. data/docs/polyphony-logo.png +0 -0
  16. data/examples/core/xx-channels.rb +4 -2
  17. data/examples/core/xx-using-a-mutex.rb +2 -1
  18. data/examples/io/xx-happy-eyeballs.rb +21 -22
  19. data/examples/io/xx-zip.rb +19 -0
  20. data/examples/performance/fiber_transfer.rb +47 -0
  21. data/examples/performance/mem-usage.rb +34 -28
  22. data/examples/performance/messaging.rb +29 -0
  23. data/examples/performance/multi_snooze.rb +11 -9
  24. data/examples/xx-spin.rb +32 -0
  25. data/ext/polyphony/event.c +86 -0
  26. data/ext/polyphony/fiber.c +0 -5
  27. data/ext/polyphony/libev_agent.c +181 -24
  28. data/ext/polyphony/polyphony.c +0 -2
  29. data/ext/polyphony/polyphony.h +14 -7
  30. data/ext/polyphony/polyphony_ext.c +4 -2
  31. data/ext/polyphony/queue.c +187 -0
  32. data/ext/polyphony/ring_buffer.c +96 -0
  33. data/ext/polyphony/ring_buffer.h +28 -0
  34. data/ext/polyphony/thread.c +18 -12
  35. data/lib/polyphony.rb +5 -14
  36. data/lib/polyphony/core/channel.rb +3 -34
  37. data/lib/polyphony/core/global_api.rb +1 -1
  38. data/lib/polyphony/core/resource_pool.rb +13 -75
  39. data/lib/polyphony/core/sync.rb +12 -9
  40. data/lib/polyphony/core/thread_pool.rb +1 -1
  41. data/lib/polyphony/extensions/core.rb +34 -0
  42. data/lib/polyphony/extensions/fiber.rb +9 -2
  43. data/lib/polyphony/extensions/io.rb +17 -16
  44. data/lib/polyphony/extensions/openssl.rb +8 -0
  45. data/lib/polyphony/extensions/socket.rb +12 -0
  46. data/lib/polyphony/version.rb +1 -1
  47. data/test/helper.rb +1 -1
  48. data/test/q.rb +24 -0
  49. data/test/test_agent.rb +1 -1
  50. data/test/test_event.rb +12 -0
  51. data/test/test_global_api.rb +2 -2
  52. data/test/test_io.rb +24 -2
  53. data/test/test_queue.rb +59 -1
  54. data/test/test_resource_pool.rb +0 -43
  55. data/test/test_trace.rb +18 -17
  56. metadata +15 -5
  57. data/ext/polyphony/libev_queue.c +0 -217
  58. data/lib/polyphony/event.rb +0 -27
@@ -34,7 +34,8 @@ class TraceTest < MiniTest::Test
34
34
 
35
35
  def test_2_fiber_trace
36
36
  records = []
37
- t = Polyphony::Trace.new(:fiber_all) { |r| records << r if r[:event] =~ /^fiber_/ }
37
+ thread = Thread.current
38
+ t = Polyphony::Trace.new(:fiber_all) { |r| records << r if Thread.current == thread && r[:event] =~ /^fiber_/ }
38
39
  t.enable
39
40
  Polyphony.trace(true)
40
41
 
@@ -42,23 +43,23 @@ class TraceTest < MiniTest::Test
42
43
  suspend
43
44
  sleep 0
44
45
 
45
- events = records.map { |r| [r[:fiber], r[:event]] }
46
+ events = records.map { |r| [r[:fiber] == f ? :f : :current, r[:event]] }
46
47
  assert_equal [
47
- [f, :fiber_create],
48
- [f, :fiber_schedule],
49
- [Fiber.current, :fiber_switchpoint],
50
- [f, :fiber_run],
51
- [f, :fiber_switchpoint],
52
- [f, :fiber_ev_loop_enter],
53
- [f, :fiber_schedule],
54
- [f, :fiber_ev_loop_leave],
55
- [f, :fiber_run],
56
- [f, :fiber_terminate],
57
- [Fiber.current, :fiber_switchpoint],
58
- [Fiber.current, :fiber_ev_loop_enter],
59
- [Fiber.current, :fiber_schedule],
60
- [Fiber.current, :fiber_ev_loop_leave],
61
- [Fiber.current, :fiber_run]
48
+ [:f, :fiber_create],
49
+ [:f, :fiber_schedule],
50
+ [:current, :fiber_switchpoint],
51
+ [:f, :fiber_run],
52
+ [:f, :fiber_switchpoint],
53
+ [:f, :fiber_ev_loop_enter],
54
+ [:f, :fiber_schedule],
55
+ [:f, :fiber_ev_loop_leave],
56
+ [:f, :fiber_run],
57
+ [:f, :fiber_terminate],
58
+ [:current, :fiber_switchpoint],
59
+ [:current, :fiber_ev_loop_enter],
60
+ [:current, :fiber_schedule],
61
+ [:current, :fiber_ev_loop_leave],
62
+ [:current, :fiber_run]
62
63
  ], events
63
64
  ensure
64
65
  t&.disable
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: polyphony
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.43.3
4
+ version: 0.43.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-08 00:00:00.000000000 Z
11
+ date: 2020-07-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -241,7 +241,10 @@ files:
241
241
  - Rakefile
242
242
  - TODO.md
243
243
  - bin/polyphony-debug
244
+ - bin/stress.rb
244
245
  - docs/_config.yml
246
+ - docs/_includes/head.html
247
+ - docs/_includes/title.html
245
248
  - docs/_sass/custom/custom.scss
246
249
  - docs/_sass/overrides.scss
247
250
  - docs/_user-guide/all-about-timers.md
@@ -351,8 +354,11 @@ files:
351
354
  - examples/io/xx-system.rb
352
355
  - examples/io/xx-tcpserver.rb
353
356
  - examples/io/xx-tcpsocket.rb
357
+ - examples/io/xx-zip.rb
358
+ - examples/performance/fiber_transfer.rb
354
359
  - examples/performance/fs_read.rb
355
360
  - examples/performance/mem-usage.rb
361
+ - examples/performance/messaging.rb
356
362
  - examples/performance/multi_snooze.rb
357
363
  - examples/performance/snooze.rb
358
364
  - examples/performance/snooze_raw.rb
@@ -366,6 +372,7 @@ files:
366
372
  - examples/performance/xx-array.rb
367
373
  - examples/performance/xx-fiber-switch.rb
368
374
  - examples/performance/xx-snooze.rb
375
+ - examples/xx-spin.rb
369
376
  - ext/libev/Changes
370
377
  - ext/libev/LICENSE
371
378
  - ext/libev/README
@@ -382,15 +389,18 @@ files:
382
389
  - ext/libev/ev_win32.c
383
390
  - ext/libev/ev_wrap.h
384
391
  - ext/libev/test_libev_win32.c
392
+ - ext/polyphony/event.c
385
393
  - ext/polyphony/extconf.rb
386
394
  - ext/polyphony/fiber.c
387
395
  - ext/polyphony/libev.c
388
396
  - ext/polyphony/libev.h
389
397
  - ext/polyphony/libev_agent.c
390
- - ext/polyphony/libev_queue.c
391
398
  - ext/polyphony/polyphony.c
392
399
  - ext/polyphony/polyphony.h
393
400
  - ext/polyphony/polyphony_ext.c
401
+ - ext/polyphony/queue.c
402
+ - ext/polyphony/ring_buffer.c
403
+ - ext/polyphony/ring_buffer.h
394
404
  - ext/polyphony/thread.c
395
405
  - ext/polyphony/tracing.c
396
406
  - lib/polyphony.rb
@@ -407,7 +417,6 @@ files:
407
417
  - lib/polyphony/core/sync.rb
408
418
  - lib/polyphony/core/thread_pool.rb
409
419
  - lib/polyphony/core/throttler.rb
410
- - lib/polyphony/event.rb
411
420
  - lib/polyphony/extensions/core.rb
412
421
  - lib/polyphony/extensions/fiber.rb
413
422
  - lib/polyphony/extensions/io.rb
@@ -420,6 +429,7 @@ files:
420
429
  - test/coverage.rb
421
430
  - test/eg.rb
422
431
  - test/helper.rb
432
+ - test/q.rb
423
433
  - test/run.rb
424
434
  - test/stress.rb
425
435
  - test/test_agent.rb
@@ -466,7 +476,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
466
476
  - !ruby/object:Gem::Version
467
477
  version: '0'
468
478
  requirements: []
469
- rubygems_version: 3.0.6
479
+ rubygems_version: 3.1.2
470
480
  signing_key:
471
481
  specification_version: 4
472
482
  summary: Fine grained concurrency for Ruby
@@ -1,217 +0,0 @@
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,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Polyphony
4
- # Event watcher for thread-safe synchronisation
5
- class Event
6
- def initialize
7
- @i, @o = IO.pipe
8
- end
9
-
10
- def await
11
- Thread.current.agent.read(@i, +'', 8192, false)
12
- raise @value if @value.is_a?(Exception)
13
-
14
- @value
15
- end
16
-
17
- def await_no_raise
18
- Thread.current.agent.read(@i, +'', 8192, false)
19
- @value
20
- end
21
-
22
- def signal(value = nil)
23
- @value = value
24
- Thread.current.agent.write(@o, '1')
25
- end
26
- end
27
- end