polyphony 0.43.8 → 0.43.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|