polyphony 0.49.0 → 0.51.0
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 +31 -0
- data/Gemfile.lock +3 -1
- data/TODO.md +6 -2
- data/examples/core/nested.rb +21 -0
- data/examples/core/suspend.rb +13 -0
- data/examples/core/terminate_main_fiber.rb +12 -0
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +2 -4
- data/ext/polyphony/backend_common.h +29 -2
- data/ext/polyphony/backend_io_uring.c +111 -32
- data/ext/polyphony/backend_libev.c +79 -46
- data/ext/polyphony/fiber.c +2 -1
- data/ext/polyphony/polyphony.h +1 -0
- data/ext/polyphony/runqueue.c +6 -0
- data/ext/polyphony/runqueue_ring_buffer.c +9 -0
- data/ext/polyphony/runqueue_ring_buffer.h +1 -0
- data/ext/polyphony/thread.c +14 -0
- data/lib/polyphony.rb +1 -1
- data/lib/polyphony/adapters/process.rb +2 -0
- data/lib/polyphony/core/exceptions.rb +1 -0
- data/lib/polyphony/core/global_api.rb +1 -1
- data/lib/polyphony/core/timer.rb +63 -20
- data/lib/polyphony/extensions/core.rb +4 -4
- data/lib/polyphony/extensions/fiber.rb +11 -8
- data/lib/polyphony/extensions/io.rb +4 -0
- data/lib/polyphony/extensions/socket.rb +12 -0
- data/lib/polyphony/extensions/thread.rb +1 -2
- data/lib/polyphony/net.rb +3 -6
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +1 -0
- data/test/helper.rb +1 -2
- data/test/test_backend.rb +25 -0
- data/test/test_fiber.rb +31 -0
- data/test/test_io.rb +53 -1
- data/test/test_signal.rb +1 -2
- data/test/test_socket.rb +34 -0
- data/test/test_timer.rb +46 -11
- metadata +19 -2
data/test/test_fiber.rb
CHANGED
@@ -349,6 +349,22 @@ class FiberTest < MiniTest::Test
|
|
349
349
|
assert_equal [:foo, :terminate], buffer
|
350
350
|
end
|
351
351
|
|
352
|
+
CMD_TERMINATE_MAIN_FIBER = <<~BASH
|
353
|
+
ruby -rbundler/setup -rpolyphony -e"spin { sleep 0.1; Thread.current.main_fiber.terminate }; begin; sleep; rescue Polyphony::Terminate; STDOUT << 'terminated'; end" 2>&1
|
354
|
+
BASH
|
355
|
+
|
356
|
+
CMD_TERMINATE_CHILD_FIBER = <<~BASH
|
357
|
+
ruby -rbundler/setup -rpolyphony -e"f = spin { sleep }; spin { sleep 0.1; f.terminate }; f.await" 2>&1
|
358
|
+
BASH
|
359
|
+
|
360
|
+
def test_terminate_main_fiber
|
361
|
+
output = `#{CMD_TERMINATE_CHILD_FIBER}`
|
362
|
+
assert_equal '', output
|
363
|
+
|
364
|
+
output = `#{CMD_TERMINATE_MAIN_FIBER}`
|
365
|
+
assert_equal 'terminated', output
|
366
|
+
end
|
367
|
+
|
352
368
|
def test_interrupt_timer
|
353
369
|
result = []
|
354
370
|
f = Fiber.current.spin do
|
@@ -1038,6 +1054,21 @@ class RestartTest < MiniTest::Test
|
|
1038
1054
|
end
|
1039
1055
|
end
|
1040
1056
|
|
1057
|
+
class ChildrenTerminationTest < MiniTest::Test
|
1058
|
+
def test_shutdown_all_children
|
1059
|
+
f = spin do
|
1060
|
+
1000.times { spin { suspend } }
|
1061
|
+
suspend
|
1062
|
+
end
|
1063
|
+
|
1064
|
+
snooze
|
1065
|
+
assert_equal 1000, f.children.size
|
1066
|
+
|
1067
|
+
f.shutdown_all_children
|
1068
|
+
assert_equal 0, f.children.size
|
1069
|
+
end
|
1070
|
+
end
|
1071
|
+
|
1041
1072
|
class GracefulTerminationTest < MiniTest::Test
|
1042
1073
|
def test_graceful_termination
|
1043
1074
|
buffer = []
|
data/test/test_io.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'helper'
|
4
|
+
require 'msgpack'
|
4
5
|
|
5
6
|
class IOTest < MiniTest::Test
|
6
7
|
def setup
|
@@ -110,7 +111,7 @@ class IOTest < MiniTest::Test
|
|
110
111
|
assert_equal [], buf
|
111
112
|
|
112
113
|
o << "ulous\n"
|
113
|
-
|
114
|
+
sleep 0.01
|
114
115
|
assert_equal ["fabulous\n"], buf
|
115
116
|
|
116
117
|
o.close
|
@@ -173,6 +174,57 @@ class IOTest < MiniTest::Test
|
|
173
174
|
|
174
175
|
assert_equal 'hello: world', buf
|
175
176
|
end
|
177
|
+
|
178
|
+
def test_feed_loop_with_block
|
179
|
+
i, o = IO.pipe
|
180
|
+
unpacker = MessagePack::Unpacker.new
|
181
|
+
buffer = []
|
182
|
+
reader = spin do
|
183
|
+
i.feed_loop(unpacker, :feed_each) { |msg| buffer << msg }
|
184
|
+
end
|
185
|
+
o << 'foo'.to_msgpack
|
186
|
+
sleep 0.01
|
187
|
+
assert_equal ['foo'], buffer
|
188
|
+
|
189
|
+
o << 'bar'.to_msgpack
|
190
|
+
sleep 0.01
|
191
|
+
assert_equal ['foo', 'bar'], buffer
|
192
|
+
|
193
|
+
o << 'baz'.to_msgpack
|
194
|
+
sleep 0.01
|
195
|
+
assert_equal ['foo', 'bar', 'baz'], buffer
|
196
|
+
end
|
197
|
+
|
198
|
+
class Receiver
|
199
|
+
attr_reader :buffer
|
200
|
+
|
201
|
+
def initialize
|
202
|
+
@buffer = []
|
203
|
+
end
|
204
|
+
|
205
|
+
def recv(obj)
|
206
|
+
@buffer << obj
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def test_feed_loop_without_block
|
211
|
+
i, o = IO.pipe
|
212
|
+
receiver = Receiver.new
|
213
|
+
reader = spin do
|
214
|
+
i.feed_loop(receiver, :recv)
|
215
|
+
end
|
216
|
+
o << 'foo'
|
217
|
+
sleep 0.01
|
218
|
+
assert_equal ['foo'], receiver.buffer
|
219
|
+
|
220
|
+
o << 'bar'
|
221
|
+
sleep 0.01
|
222
|
+
assert_equal ['foo', 'bar'], receiver.buffer
|
223
|
+
|
224
|
+
o << 'baz'
|
225
|
+
sleep 0.01
|
226
|
+
assert_equal ['foo', 'bar', 'baz'], receiver.buffer
|
227
|
+
end
|
176
228
|
end
|
177
229
|
|
178
230
|
class IOClassMethodsTest < MiniTest::Test
|
data/test/test_signal.rb
CHANGED
data/test/test_socket.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative 'helper'
|
4
4
|
require 'fileutils'
|
5
|
+
require 'msgpack'
|
5
6
|
|
6
7
|
class SocketTest < MiniTest::Test
|
7
8
|
def setup
|
@@ -33,6 +34,39 @@ class SocketTest < MiniTest::Test
|
|
33
34
|
server&.close
|
34
35
|
end
|
35
36
|
|
37
|
+
def test_feed_loop
|
38
|
+
port = rand(1234..5678)
|
39
|
+
server = TCPServer.new('127.0.0.1', port)
|
40
|
+
|
41
|
+
server_fiber = spin do
|
42
|
+
reader = MessagePack::Unpacker.new
|
43
|
+
while (socket = server.accept)
|
44
|
+
spin do
|
45
|
+
socket.feed_loop(reader, :feed_each) do |msg|
|
46
|
+
msg = { 'result' => msg['x'] + msg['y'] }
|
47
|
+
socket << msg.to_msgpack
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
snooze
|
54
|
+
client = TCPSocket.new('127.0.0.1', port)
|
55
|
+
reader = MessagePack::Unpacker.new
|
56
|
+
client << { 'x' => 13, 'y' => 14 }.to_msgpack
|
57
|
+
result = nil
|
58
|
+
client.feed_loop(reader, :feed_each) do |msg|
|
59
|
+
result = msg
|
60
|
+
break
|
61
|
+
end
|
62
|
+
assert_equal({ 'result' => 27}, result)
|
63
|
+
client.close
|
64
|
+
ensure
|
65
|
+
server_fiber&.stop
|
66
|
+
server_fiber&.await
|
67
|
+
server&.close
|
68
|
+
end
|
69
|
+
|
36
70
|
def test_unix_socket
|
37
71
|
path = '/tmp/test_unix_socket'
|
38
72
|
FileUtils.rm(path) rescue nil
|
data/test/test_timer.rb
CHANGED
@@ -11,7 +11,7 @@ class TimerMoveOnAfterTest < MiniTest::Test
|
|
11
11
|
@timer.stop
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
14
|
+
def test_timer_move_on_after
|
15
15
|
t0 = Time.now
|
16
16
|
v = @timer.move_on_after(0.1) do
|
17
17
|
sleep 1
|
@@ -23,7 +23,7 @@ class TimerMoveOnAfterTest < MiniTest::Test
|
|
23
23
|
assert_nil v
|
24
24
|
end
|
25
25
|
|
26
|
-
def
|
26
|
+
def test_timer_move_on_after_with_value
|
27
27
|
t0 = Time.now
|
28
28
|
v = @timer.move_on_after(0.01, with_value: :bar) do
|
29
29
|
sleep 1
|
@@ -31,13 +31,15 @@ class TimerMoveOnAfterTest < MiniTest::Test
|
|
31
31
|
end
|
32
32
|
t1 = Time.now
|
33
33
|
|
34
|
-
assert_in_range 0.01..0.
|
34
|
+
assert_in_range 0.01..0.025, t1 - t0
|
35
35
|
assert_equal :bar, v
|
36
36
|
end
|
37
37
|
|
38
|
-
def
|
38
|
+
def test_timer_move_on_after_with_reset
|
39
39
|
t0 = Time.now
|
40
40
|
v = @timer.move_on_after(0.01, with_value: :moved_on) do
|
41
|
+
sleep 0.007
|
42
|
+
@timer.reset
|
41
43
|
sleep 0.007
|
42
44
|
@timer.reset
|
43
45
|
sleep 0.007
|
@@ -46,11 +48,11 @@ class TimerMoveOnAfterTest < MiniTest::Test
|
|
46
48
|
t1 = Time.now
|
47
49
|
|
48
50
|
assert_nil v
|
49
|
-
assert_in_range 0.
|
51
|
+
assert_in_range 0.015..0.03, t1 - t0
|
50
52
|
end
|
51
53
|
end
|
52
54
|
|
53
|
-
class
|
55
|
+
class TimerCancelAfterTest < MiniTest::Test
|
54
56
|
def setup
|
55
57
|
@timer = Polyphony::Timer.new(resolution: 0.01)
|
56
58
|
end
|
@@ -59,7 +61,7 @@ class CancelAfterTest < MiniTest::Test
|
|
59
61
|
@timer.stop
|
60
62
|
end
|
61
63
|
|
62
|
-
def
|
64
|
+
def test_timer_cancel_after
|
63
65
|
t0 = Time.now
|
64
66
|
|
65
67
|
assert_raises Polyphony::Cancel do
|
@@ -69,10 +71,10 @@ class CancelAfterTest < MiniTest::Test
|
|
69
71
|
end
|
70
72
|
end
|
71
73
|
t1 = Time.now
|
72
|
-
assert_in_range 0.01..0.
|
74
|
+
assert_in_range 0.01..0.03, t1 - t0
|
73
75
|
end
|
74
76
|
|
75
|
-
def
|
77
|
+
def test_timer_cancel_after_with_reset
|
76
78
|
t0 = Time.now
|
77
79
|
@timer.cancel_after(0.01) do
|
78
80
|
sleep 0.007
|
@@ -80,13 +82,13 @@ class CancelAfterTest < MiniTest::Test
|
|
80
82
|
sleep 0.007
|
81
83
|
end
|
82
84
|
t1 = Time.now
|
83
|
-
assert_in_range 0.
|
85
|
+
assert_in_range 0.013..0.024, t1 - t0
|
84
86
|
end
|
85
87
|
|
86
88
|
class CustomException < Exception
|
87
89
|
end
|
88
90
|
|
89
|
-
def
|
91
|
+
def test_timer_cancel_after_with_custom_exception
|
90
92
|
assert_raises CustomException do
|
91
93
|
@timer.cancel_after(0.01, with_exception: CustomException) do
|
92
94
|
sleep 1
|
@@ -120,3 +122,36 @@ class CancelAfterTest < MiniTest::Test
|
|
120
122
|
end
|
121
123
|
end
|
122
124
|
end
|
125
|
+
|
126
|
+
class TimerMiscTest < MiniTest::Test
|
127
|
+
def setup
|
128
|
+
@timer = Polyphony::Timer.new(resolution: 0.001)
|
129
|
+
sleep 0
|
130
|
+
end
|
131
|
+
|
132
|
+
def teardown
|
133
|
+
@timer.stop
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_timer_after
|
137
|
+
buffer = []
|
138
|
+
f = @timer.after(0.01) { buffer << 2 }
|
139
|
+
assert_kind_of Fiber, f
|
140
|
+
snooze
|
141
|
+
assert_equal [], buffer
|
142
|
+
sleep 0.1
|
143
|
+
p :post_sleep
|
144
|
+
assert_equal [2], buffer
|
145
|
+
end
|
146
|
+
|
147
|
+
def test_timer_every
|
148
|
+
buffer = []
|
149
|
+
t0 = Time.now
|
150
|
+
f = spin do
|
151
|
+
@timer.every(0.01) { buffer << 1 }
|
152
|
+
end
|
153
|
+
sleep 0.05
|
154
|
+
f.stop
|
155
|
+
assert_in_range 4..6, buffer.size
|
156
|
+
end
|
157
|
+
end
|
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.
|
4
|
+
version: 0.51.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-02-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - '='
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: 0.13.1
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: msgpack
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 1.4.2
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 1.4.2
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
112
|
name: pg
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -353,6 +367,7 @@ files:
|
|
353
367
|
- examples/core/forking.rb
|
354
368
|
- examples/core/handling-signals.rb
|
355
369
|
- examples/core/interrupt.rb
|
370
|
+
- examples/core/nested.rb
|
356
371
|
- examples/core/pingpong.rb
|
357
372
|
- examples/core/recurrent-timer.rb
|
358
373
|
- examples/core/resource_delegate.rb
|
@@ -360,6 +375,8 @@ files:
|
|
360
375
|
- examples/core/spin_error_backtrace.rb
|
361
376
|
- examples/core/supervise-process.rb
|
362
377
|
- examples/core/supervisor.rb
|
378
|
+
- examples/core/suspend.rb
|
379
|
+
- examples/core/terminate_main_fiber.rb
|
363
380
|
- examples/core/thread-sleep.rb
|
364
381
|
- examples/core/thread_pool.rb
|
365
382
|
- examples/core/throttling.rb
|