polyphony 0.43.8 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +1 -1
- data/README.md +20 -5
- data/TODO.md +1 -1
- data/bin/stress.rb +28 -0
- data/examples/core/xx-channels.rb +4 -2
- data/examples/core/xx-using-a-mutex.rb +2 -1
- data/ext/polyphony/event.c +86 -0
- data/ext/polyphony/fiber.c +0 -5
- data/ext/polyphony/polyphony_ext.c +2 -0
- data/ext/polyphony/queue.c +21 -2
- data/ext/polyphony/thread.c +2 -4
- data/lib/polyphony.rb +0 -1
- data/lib/polyphony/core/channel.rb +3 -34
- data/lib/polyphony/core/resource_pool.rb +13 -75
- data/lib/polyphony/core/sync.rb +12 -9
- data/lib/polyphony/version.rb +1 -1
- data/test/test_event.rb +1 -0
- data/test/test_queue.rb +20 -0
- data/test/test_resource_pool.rb +0 -43
- metadata +4 -3
- data/lib/polyphony/event.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 14930ef46f39537ad6f2233b23691a05d910ecf6c22cd8429a8a82dcf4f2af51
|
4
|
+
data.tar.gz: a2c53e7082c35025cce3024113162ed5e67032eed82d49c363516441c3293898
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac9d80b5a0fad4b4d164bed60c42d386fc49e978b381a2a9fd6174bf616cb5a97cb4232c317c62ac0439f534d753e5c9a1e9cbb98be41145a9d288d6d719adcc
|
7
|
+
data.tar.gz: 95a8d13b133a0256ffb71df70e4348845dbcbe0c848a94feb0ceaf205e274f918d84529ef7d0773884e51f2e504625a96a4fdf548b17f03fa408c39f763609b6
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
## 0.43.9 2020-07-22
|
2
|
+
|
3
|
+
* Rewrite `Channel` using `Queue`
|
4
|
+
* Rewrite `Mutex` using `Queue`
|
5
|
+
* Reimplement `Event` in C to prevent cross-thread race condition
|
6
|
+
* Reimplement `ResourcePool` using `Queue`
|
7
|
+
* Implement `Queue#size`
|
8
|
+
|
1
9
|
## 0.43.8 2020-07-21
|
2
10
|
|
3
11
|
* Rename `LibevQueue` to `Queue`
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,10 +1,25 @@
|
|
1
|
-
<
|
1
|
+
<h1 align="center">
|
2
|
+
<a href="https://digital-fabric.github.io/polyphony/">
|
3
|
+
<img src="docs/polyphony-logo.png" alt="Polyphony">
|
4
|
+
</a>
|
5
|
+
<br>
|
6
|
+
Polyphony
|
7
|
+
<br>
|
8
|
+
</h1>
|
2
9
|
|
3
|
-
|
10
|
+
<h4 align="center">Fine-Grained Concurrency for Ruby</h4>
|
4
11
|
|
5
|
-
|
6
|
-
|
7
|
-
|
12
|
+
<p align="center">
|
13
|
+
<a href="http://rubygems.org/gems/polyphony">
|
14
|
+
<img src="https://badge.fury.io/rb/polyphony.svg" alt="Ruby gem">
|
15
|
+
</a>
|
16
|
+
<a href="https://github.com/digital-fabric/polyphony/actions?query=workflow%3ATests">
|
17
|
+
<img src="https://github.com/digital-fabric/polyphony/workflows/Tests/badge.svg" alt="Tests">
|
18
|
+
</a>
|
19
|
+
<a href="https://github.com/digital-fabric/polyphony/blob/master/LICENSE">
|
20
|
+
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License">
|
21
|
+
</a>
|
22
|
+
</p>
|
8
23
|
|
9
24
|
[DOCS](https://digital-fabric.github.io/polyphony/) |
|
10
25
|
[EXAMPLES](examples)
|
data/TODO.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
- Implement `LibevAgent#connect` API
|
2
|
-
|
2
|
+
|
3
3
|
-- Add `Fiber#schedule_with_priority` method, aliased by `Fiber#wakeup`
|
4
4
|
- Implement agent interface is virtual function table
|
5
5
|
- Implement proxy agent for plugging in a user-provided agent class
|
data/bin/stress.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
`rake recompile`
|
5
|
+
|
6
|
+
count = ARGV[0] ? ARGV[0].to_i : 100
|
7
|
+
|
8
|
+
TEST_CMD = 'ruby test/run.rb'
|
9
|
+
|
10
|
+
def run_test(count)
|
11
|
+
puts "#{count}: running tests..."
|
12
|
+
system(TEST_CMD)
|
13
|
+
return if $?.exitstatus == 0
|
14
|
+
|
15
|
+
puts "Failure after #{count} tests"
|
16
|
+
exit!
|
17
|
+
end
|
18
|
+
|
19
|
+
trap('INT') { exit! }
|
20
|
+
t0 = Time.now
|
21
|
+
count.times { |i| run_test(i + 1) }
|
22
|
+
elapsed = Time.now - t0
|
23
|
+
puts format(
|
24
|
+
"Successfully ran %d tests in %f seconds (%f per test)",
|
25
|
+
count,
|
26
|
+
elapsed,
|
27
|
+
elapsed / count
|
28
|
+
)
|
@@ -2,10 +2,12 @@
|
|
2
2
|
|
3
3
|
require 'bundler/setup'
|
4
4
|
require 'polyphony'
|
5
|
+
require 'polyphony/core/channel'
|
5
6
|
|
6
7
|
def echo(cin, cout)
|
7
8
|
puts 'start echoer'
|
8
9
|
while (msg = cin.receive)
|
10
|
+
puts "echoer received #{msg}"
|
9
11
|
cout << "you said: #{msg}"
|
10
12
|
end
|
11
13
|
ensure
|
@@ -20,7 +22,7 @@ spin do
|
|
20
22
|
puts 'start receiver'
|
21
23
|
while (msg = chan2.receive)
|
22
24
|
puts msg
|
23
|
-
$main.
|
25
|
+
$main.schedule if msg =~ /world/
|
24
26
|
end
|
25
27
|
ensure
|
26
28
|
puts 'receiver stopped'
|
@@ -42,4 +44,4 @@ $main = spin do
|
|
42
44
|
puts "done #{Time.now - t0}"
|
43
45
|
end
|
44
46
|
|
45
|
-
|
47
|
+
$main.await
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'bundler/setup'
|
4
4
|
require 'polyphony'
|
5
|
+
require 'polyphony/core/sync'
|
5
6
|
|
6
7
|
def loop_it(number, lock)
|
7
8
|
loop do
|
@@ -13,7 +14,7 @@ def loop_it(number, lock)
|
|
13
14
|
end
|
14
15
|
end
|
15
16
|
|
16
|
-
lock = Polyphony::
|
17
|
+
lock = Polyphony::Mutex.new
|
17
18
|
spin { loop_it(1, lock) }
|
18
19
|
spin { loop_it(2, lock) }
|
19
20
|
spin { loop_it(3, lock) }
|
@@ -0,0 +1,86 @@
|
|
1
|
+
#include "polyphony.h"
|
2
|
+
#include "ring_buffer.h"
|
3
|
+
|
4
|
+
typedef struct event {
|
5
|
+
VALUE waiting_fiber;
|
6
|
+
} Event_t;
|
7
|
+
|
8
|
+
VALUE cEvent = Qnil;
|
9
|
+
|
10
|
+
static void Event_mark(void *ptr) {
|
11
|
+
Event_t *event = ptr;
|
12
|
+
rb_gc_mark(event->waiting_fiber);
|
13
|
+
}
|
14
|
+
|
15
|
+
static void Event_free(void *ptr) {
|
16
|
+
xfree(ptr);
|
17
|
+
}
|
18
|
+
|
19
|
+
static size_t Event_size(const void *ptr) {
|
20
|
+
return sizeof(Event_t);
|
21
|
+
}
|
22
|
+
|
23
|
+
static const rb_data_type_t Event_type = {
|
24
|
+
"Event",
|
25
|
+
{Event_mark, Event_free, Event_size,},
|
26
|
+
0, 0, 0
|
27
|
+
};
|
28
|
+
|
29
|
+
static VALUE Event_allocate(VALUE klass) {
|
30
|
+
Event_t *event;
|
31
|
+
|
32
|
+
event = ALLOC(Event_t);
|
33
|
+
return TypedData_Wrap_Struct(klass, &Event_type, event);
|
34
|
+
}
|
35
|
+
|
36
|
+
#define GetEvent(obj, event) \
|
37
|
+
TypedData_Get_Struct((obj), Event_t, &Event_type, (event))
|
38
|
+
|
39
|
+
static VALUE Event_initialize(VALUE self) {
|
40
|
+
Event_t *event;
|
41
|
+
GetEvent(self, event);
|
42
|
+
|
43
|
+
event->waiting_fiber = Qnil;
|
44
|
+
|
45
|
+
return self;
|
46
|
+
}
|
47
|
+
|
48
|
+
VALUE Event_signal(int argc, VALUE *argv, VALUE self) {
|
49
|
+
VALUE value = argc > 0 ? argv[0] : Qnil;
|
50
|
+
Event_t *event;
|
51
|
+
GetEvent(self, event);
|
52
|
+
|
53
|
+
if (event->waiting_fiber != Qnil) {
|
54
|
+
Fiber_make_runnable(event->waiting_fiber, value);
|
55
|
+
event->waiting_fiber = Qnil;
|
56
|
+
}
|
57
|
+
return self;
|
58
|
+
}
|
59
|
+
|
60
|
+
VALUE Event_await(VALUE self) {
|
61
|
+
Event_t *event;
|
62
|
+
GetEvent(self, event);
|
63
|
+
|
64
|
+
if (event->waiting_fiber != Qnil)
|
65
|
+
rb_raise(rb_eRuntimeError, "Event is already awaited by another fiber");
|
66
|
+
|
67
|
+
VALUE agent = rb_ivar_get(rb_thread_current(), ID_ivar_agent);
|
68
|
+
event->waiting_fiber = rb_fiber_current();
|
69
|
+
VALUE switchpoint_result = LibevAgent_wait_event(agent, Qnil);
|
70
|
+
event->waiting_fiber = Qnil;
|
71
|
+
|
72
|
+
TEST_RESUME_EXCEPTION(switchpoint_result);
|
73
|
+
RB_GC_GUARD(agent);
|
74
|
+
RB_GC_GUARD(switchpoint_result);
|
75
|
+
|
76
|
+
return switchpoint_result;
|
77
|
+
}
|
78
|
+
|
79
|
+
void Init_Event() {
|
80
|
+
cEvent = rb_define_class_under(mPolyphony, "Event", rb_cData);
|
81
|
+
rb_define_alloc_func(cEvent, Event_allocate);
|
82
|
+
|
83
|
+
rb_define_method(cEvent, "initialize", Event_initialize, 0);
|
84
|
+
rb_define_method(cEvent, "await", Event_await, 0);
|
85
|
+
rb_define_method(cEvent, "signal", Event_signal, -1);
|
86
|
+
}
|
data/ext/polyphony/fiber.c
CHANGED
@@ -9,8 +9,6 @@ ID ID_trace_runnable;
|
|
9
9
|
ID ID_trace_terminate;
|
10
10
|
ID ID_trace_wait;
|
11
11
|
|
12
|
-
VALUE cEvent = Qnil;
|
13
|
-
|
14
12
|
VALUE SYM_dead;
|
15
13
|
VALUE SYM_running;
|
16
14
|
VALUE SYM_runnable;
|
@@ -35,9 +33,6 @@ static VALUE Fiber_safe_transfer(int argc, VALUE *argv, VALUE self) {
|
|
35
33
|
|
36
34
|
inline VALUE Fiber_auto_watcher(VALUE self) {
|
37
35
|
VALUE watcher;
|
38
|
-
if (cEvent == Qnil) {
|
39
|
-
cEvent = rb_const_get(mPolyphony, rb_intern("Event"));
|
40
|
-
}
|
41
36
|
|
42
37
|
watcher = rb_ivar_get(self, ID_ivar_auto_watcher);
|
43
38
|
if (watcher == Qnil) {
|
@@ -4,6 +4,7 @@ void Init_Fiber();
|
|
4
4
|
void Init_Polyphony();
|
5
5
|
void Init_LibevAgent();
|
6
6
|
void Init_Queue();
|
7
|
+
void Init_Event();
|
7
8
|
void Init_Thread();
|
8
9
|
void Init_Tracing();
|
9
10
|
|
@@ -13,6 +14,7 @@ void Init_polyphony_ext() {
|
|
13
14
|
Init_Polyphony();
|
14
15
|
Init_LibevAgent();
|
15
16
|
Init_Queue();
|
17
|
+
Init_Event();
|
16
18
|
|
17
19
|
Init_Fiber();
|
18
20
|
Init_Thread();
|
data/ext/polyphony/queue.c
CHANGED
@@ -139,6 +139,18 @@ VALUE Queue_shift_all(VALUE self) {
|
|
139
139
|
return ring_buffer_shift_all(&queue->values);
|
140
140
|
}
|
141
141
|
|
142
|
+
VALUE Queue_flush_waiters(VALUE self, VALUE value) {
|
143
|
+
Queue_t *queue;
|
144
|
+
GetQueue(self, queue);
|
145
|
+
|
146
|
+
while(1) {
|
147
|
+
VALUE fiber = ring_buffer_shift(&queue->shift_queue);
|
148
|
+
if (fiber == Qnil) return self;
|
149
|
+
|
150
|
+
Fiber_make_runnable(fiber, value);
|
151
|
+
}
|
152
|
+
}
|
153
|
+
|
142
154
|
VALUE Queue_empty_p(VALUE self) {
|
143
155
|
Queue_t *queue;
|
144
156
|
GetQueue(self, queue);
|
@@ -146,6 +158,13 @@ VALUE Queue_empty_p(VALUE self) {
|
|
146
158
|
return (queue->values.count == 0) ? Qtrue : Qfalse;
|
147
159
|
}
|
148
160
|
|
161
|
+
VALUE Queue_size_m(VALUE self) {
|
162
|
+
Queue_t *queue;
|
163
|
+
GetQueue(self, queue);
|
164
|
+
|
165
|
+
return INT2NUM(queue->values.count);
|
166
|
+
}
|
167
|
+
|
149
168
|
void Init_Queue() {
|
150
169
|
cQueue = rb_define_class_under(mPolyphony, "Queue", rb_cData);
|
151
170
|
rb_define_alloc_func(cQueue, Queue_allocate);
|
@@ -162,7 +181,7 @@ void Init_Queue() {
|
|
162
181
|
|
163
182
|
rb_define_method(cQueue, "shift_each", Queue_shift_each, 0);
|
164
183
|
rb_define_method(cQueue, "shift_all", Queue_shift_all, 0);
|
184
|
+
rb_define_method(cQueue, "flush_waiters", Queue_flush_waiters, 1);
|
165
185
|
rb_define_method(cQueue, "empty?", Queue_empty_p, 0);
|
186
|
+
rb_define_method(cQueue, "size", Queue_size_m, 0);
|
166
187
|
}
|
167
|
-
|
168
|
-
|
data/ext/polyphony/thread.c
CHANGED
@@ -53,11 +53,9 @@ VALUE Thread_schedule_fiber(VALUE self, VALUE fiber, VALUE value) {
|
|
53
53
|
if (rb_fiber_alive_p(fiber) != Qtrue) return self;
|
54
54
|
|
55
55
|
FIBER_TRACE(3, SYM_fiber_schedule, fiber, value);
|
56
|
-
// if fiber is already scheduled, just set the scheduled value, then return
|
57
56
|
rb_ivar_set(fiber, ID_runnable_value, value);
|
58
|
-
if
|
59
|
-
|
60
|
-
}
|
57
|
+
// if fiber is already scheduled, just set the scheduled value, then return
|
58
|
+
if (rb_ivar_get(fiber, ID_runnable) != Qnil) return self;
|
61
59
|
|
62
60
|
queue = rb_ivar_get(self, ID_run_queue);
|
63
61
|
Queue_push(queue, fiber);
|
data/lib/polyphony.rb
CHANGED
@@ -23,7 +23,6 @@ require_relative './polyphony/core/global_api'
|
|
23
23
|
require_relative './polyphony/core/resource_pool'
|
24
24
|
require_relative './polyphony/net'
|
25
25
|
require_relative './polyphony/adapters/process'
|
26
|
-
require_relative './polyphony/event'
|
27
26
|
|
28
27
|
# Main Polyphony API
|
29
28
|
module Polyphony
|
@@ -5,42 +5,11 @@ require_relative './exceptions'
|
|
5
5
|
module Polyphony
|
6
6
|
# Implements a unidirectional communication channel along the lines of Go
|
7
7
|
# (buffered) channels.
|
8
|
-
class Channel
|
9
|
-
|
10
|
-
@payload_queue = []
|
11
|
-
@waiting_queue = []
|
12
|
-
end
|
8
|
+
class Channel < Polyphony::Queue
|
9
|
+
alias_method :receive, :shift
|
13
10
|
|
14
11
|
def close
|
15
|
-
|
16
|
-
@waiting_queue.slice(0..-1).each { |f| f.schedule(stop) }
|
17
|
-
end
|
18
|
-
|
19
|
-
def <<(value)
|
20
|
-
if @waiting_queue.empty?
|
21
|
-
@payload_queue << value
|
22
|
-
else
|
23
|
-
@waiting_queue.shift&.schedule(value)
|
24
|
-
end
|
25
|
-
snooze
|
26
|
-
end
|
27
|
-
|
28
|
-
def receive
|
29
|
-
Thread.current.agent.ref
|
30
|
-
if @payload_queue.empty?
|
31
|
-
@waiting_queue << Fiber.current
|
32
|
-
suspend
|
33
|
-
else
|
34
|
-
receive_from_queue
|
35
|
-
end
|
36
|
-
ensure
|
37
|
-
Thread.current.agent.unref
|
38
|
-
end
|
39
|
-
|
40
|
-
def receive_from_queue
|
41
|
-
payload = @payload_queue.shift
|
42
|
-
snooze
|
43
|
-
payload
|
12
|
+
flush_waiters(Polyphony::MoveOn.new)
|
44
13
|
end
|
45
14
|
end
|
46
15
|
end
|
@@ -10,13 +10,10 @@ module Polyphony
|
|
10
10
|
# @param &block [Proc] allocator block
|
11
11
|
def initialize(opts, &block)
|
12
12
|
@allocator = block
|
13
|
-
|
14
|
-
@stock = []
|
15
|
-
@queue = []
|
16
|
-
@acquired_resources = {}
|
17
|
-
|
18
13
|
@limit = opts[:limit] || 4
|
19
14
|
@size = 0
|
15
|
+
@stock = Polyphony::Queue.new
|
16
|
+
@acquired_resources = {}
|
20
17
|
end
|
21
18
|
|
22
19
|
def available
|
@@ -25,58 +22,17 @@ module Polyphony
|
|
25
22
|
|
26
23
|
def acquire
|
27
24
|
fiber = Fiber.current
|
28
|
-
if @acquired_resources[fiber]
|
29
|
-
yield @acquired_resources[fiber]
|
30
|
-
else
|
31
|
-
begin
|
32
|
-
Thread.current.agent.ref
|
33
|
-
resource = wait_for_resource
|
34
|
-
return unless resource
|
35
|
-
|
36
|
-
@acquired_resources[fiber] = resource
|
37
|
-
yield resource
|
38
|
-
ensure
|
39
|
-
@acquired_resources.delete fiber
|
40
|
-
Thread.current.agent.unref
|
41
|
-
release(resource) if resource
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def wait_for_resource
|
47
|
-
fiber = Fiber.current
|
48
|
-
@queue << fiber
|
49
|
-
ready_resource = from_stock
|
50
|
-
return ready_resource if ready_resource
|
25
|
+
return @acquired_resources[fiber] if @acquired_resources[fiber]
|
51
26
|
|
52
|
-
|
27
|
+
add_to_stock if @size < @limit && @stock.empty?
|
28
|
+
resource = @stock.shift
|
29
|
+
@acquired_resources[fiber] = resource
|
30
|
+
yield resource
|
53
31
|
ensure
|
54
|
-
@
|
55
|
-
|
56
|
-
|
57
|
-
def release(resource)
|
58
|
-
if resource.__discarded__
|
59
|
-
@size -= 1
|
60
|
-
elsif resource
|
61
|
-
return_to_stock(resource)
|
62
|
-
dequeue
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def dequeue
|
67
|
-
return if @queue.empty? || @stock.empty?
|
68
|
-
|
69
|
-
@queue.shift.schedule(@stock.shift)
|
32
|
+
@acquired_resources.delete(fiber)
|
33
|
+
@stock.push resource if resource
|
70
34
|
end
|
71
|
-
|
72
|
-
def return_to_stock(resource)
|
73
|
-
@stock << resource
|
74
|
-
end
|
75
|
-
|
76
|
-
def from_stock
|
77
|
-
@stock.shift || (@size < @limit && allocate)
|
78
|
-
end
|
79
|
-
|
35
|
+
|
80
36
|
def method_missing(sym, *args, &block)
|
81
37
|
acquire { |r| r.send(sym, *args, &block) }
|
82
38
|
end
|
@@ -85,33 +41,15 @@ module Polyphony
|
|
85
41
|
true
|
86
42
|
end
|
87
43
|
|
88
|
-
# Extension to allow discarding of resources
|
89
|
-
module ResourceExtensions
|
90
|
-
def __discarded__
|
91
|
-
@__discarded__
|
92
|
-
end
|
93
|
-
|
94
|
-
def __discard__
|
95
|
-
@__discarded__ = true
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
44
|
# Allocates a resource
|
100
45
|
# @return [any] allocated resource
|
101
|
-
def
|
102
|
-
@size += 1
|
103
|
-
@allocator.().tap { |r| r.extend ResourceExtensions }
|
104
|
-
end
|
105
|
-
|
106
|
-
def <<(resource)
|
46
|
+
def add_to_stock
|
107
47
|
@size += 1
|
108
|
-
|
109
|
-
@stock << resource
|
110
|
-
dequeue
|
48
|
+
@stock << @allocator.call
|
111
49
|
end
|
112
50
|
|
113
51
|
def preheat!
|
114
|
-
|
52
|
+
add_to_stock while @size < @limit
|
115
53
|
end
|
116
54
|
end
|
117
55
|
end
|
data/lib/polyphony/core/sync.rb
CHANGED
@@ -4,18 +4,21 @@ module Polyphony
|
|
4
4
|
# Implements mutex lock for synchronizing access to a shared resource
|
5
5
|
class Mutex
|
6
6
|
def initialize
|
7
|
-
@
|
7
|
+
@store = Queue.new
|
8
|
+
@store << :token
|
8
9
|
end
|
9
10
|
|
10
11
|
def synchronize
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
12
|
+
return yield if @holding_fiber == Fiber.current
|
13
|
+
|
14
|
+
begin
|
15
|
+
token = @store.shift
|
16
|
+
@holding_fiber = Fiber.current
|
17
|
+
yield
|
18
|
+
ensure
|
19
|
+
@holding_fiber = nil
|
20
|
+
@store << token
|
21
|
+
end
|
19
22
|
end
|
20
23
|
end
|
21
24
|
end
|
data/lib/polyphony/version.rb
CHANGED
data/test/test_event.rb
CHANGED
data/test/test_queue.rb
CHANGED
@@ -109,4 +109,24 @@ class QueueTest < MiniTest::Test
|
|
109
109
|
@queue << :foo
|
110
110
|
assert_nil f1.await
|
111
111
|
end
|
112
|
+
|
113
|
+
def test_queue_size
|
114
|
+
assert_equal 0, @queue.size
|
115
|
+
|
116
|
+
@queue.push 1
|
117
|
+
|
118
|
+
assert_equal 1, @queue.size
|
119
|
+
|
120
|
+
@queue.push 2
|
121
|
+
|
122
|
+
assert_equal 2, @queue.size
|
123
|
+
|
124
|
+
@queue.shift
|
125
|
+
|
126
|
+
assert_equal 1, @queue.size
|
127
|
+
|
128
|
+
@queue.shift
|
129
|
+
|
130
|
+
assert_equal 0, @queue.size
|
131
|
+
end
|
112
132
|
end
|
data/test/test_resource_pool.rb
CHANGED
@@ -37,49 +37,6 @@ class ResourcePoolTest < MiniTest::Test
|
|
37
37
|
assert_equal 2, pool.size
|
38
38
|
end
|
39
39
|
|
40
|
-
def test_discard
|
41
|
-
resources = [+'a', +'b']
|
42
|
-
pool = Polyphony::ResourcePool.new(limit: 2) { resources.shift }
|
43
|
-
|
44
|
-
results = []
|
45
|
-
4.times {
|
46
|
-
spin {
|
47
|
-
snooze
|
48
|
-
pool.acquire { |resource|
|
49
|
-
results << resource
|
50
|
-
resource.__discard__ if resource == 'b'
|
51
|
-
snooze
|
52
|
-
}
|
53
|
-
}
|
54
|
-
}
|
55
|
-
6.times { snooze }
|
56
|
-
|
57
|
-
assert_equal ['a', 'b', 'a', 'a'], results
|
58
|
-
assert_equal 1, pool.size
|
59
|
-
end
|
60
|
-
|
61
|
-
def test_add
|
62
|
-
resources = [+'a', +'b']
|
63
|
-
pool = Polyphony::ResourcePool.new(limit: 2) { resources.shift }
|
64
|
-
|
65
|
-
pool << +'c'
|
66
|
-
|
67
|
-
results = []
|
68
|
-
4.times {
|
69
|
-
spin {
|
70
|
-
snooze
|
71
|
-
pool.acquire { |resource|
|
72
|
-
results << resource
|
73
|
-
resource.__discard__ if resource == 'b'
|
74
|
-
snooze
|
75
|
-
}
|
76
|
-
}
|
77
|
-
}
|
78
|
-
6.times { snooze }
|
79
|
-
|
80
|
-
assert_equal ['c', 'a', 'c', 'a'], results
|
81
|
-
end
|
82
|
-
|
83
40
|
def test_single_resource_limit
|
84
41
|
resources = [+'a', +'b']
|
85
42
|
pool = Polyphony::ResourcePool.new(limit: 1) { resources.shift }
|
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.
|
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-
|
11
|
+
date: 2020-07-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|
@@ -241,6 +241,7 @@ files:
|
|
241
241
|
- Rakefile
|
242
242
|
- TODO.md
|
243
243
|
- bin/polyphony-debug
|
244
|
+
- bin/stress.rb
|
244
245
|
- docs/_config.yml
|
245
246
|
- docs/_includes/head.html
|
246
247
|
- docs/_includes/title.html
|
@@ -388,6 +389,7 @@ files:
|
|
388
389
|
- ext/libev/ev_win32.c
|
389
390
|
- ext/libev/ev_wrap.h
|
390
391
|
- ext/libev/test_libev_win32.c
|
392
|
+
- ext/polyphony/event.c
|
391
393
|
- ext/polyphony/extconf.rb
|
392
394
|
- ext/polyphony/fiber.c
|
393
395
|
- ext/polyphony/libev.c
|
@@ -415,7 +417,6 @@ files:
|
|
415
417
|
- lib/polyphony/core/sync.rb
|
416
418
|
- lib/polyphony/core/thread_pool.rb
|
417
419
|
- lib/polyphony/core/throttler.rb
|
418
|
-
- lib/polyphony/event.rb
|
419
420
|
- lib/polyphony/extensions/core.rb
|
420
421
|
- lib/polyphony/extensions/fiber.rb
|
421
422
|
- lib/polyphony/extensions/io.rb
|
data/lib/polyphony/event.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Polyphony
|
4
|
-
# Event watcher for thread-safe synchronisation
|
5
|
-
class Event
|
6
|
-
def await
|
7
|
-
@fiber = Fiber.current
|
8
|
-
Thread.current.agent.wait_event(true)
|
9
|
-
end
|
10
|
-
|
11
|
-
def signal(value = nil)
|
12
|
-
@fiber&.schedule(value)
|
13
|
-
ensure
|
14
|
-
@fiber = nil
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|