polyphony 0.45.2 → 0.45.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/Gemfile.lock +3 -3
- data/TODO.md +9 -3
- data/examples/io/raw.rb +14 -0
- data/examples/io/reline.rb +18 -0
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +1 -1
- data/lib/polyphony.rb +2 -2
- data/lib/polyphony/adapters/process.rb +0 -3
- data/lib/polyphony/extensions/core.rb +5 -18
- data/lib/polyphony/extensions/fiber.rb +20 -6
- data/lib/polyphony/extensions/io.rb +15 -4
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +1 -1
- data/test/test_io.rb +42 -0
- data/test/test_signal.rb +11 -8
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 52f8ebf1104d921c9e3b0afa0b4605ee8f912eabe8b6264898f23905d2cb6c6f
|
4
|
+
data.tar.gz: 38f0f7cd62997ba5681185c3c4859f57d86de875d8292faf67fffa53c7160181
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2429259a2e79757ec879c4c00db8fd8b87302b9e0a61c6ae2ddd5fdb6e1a3a06ac63d551ed33a4c77480e156eb1247a0fab4a263179a60fd2e9a2d3173831a58
|
7
|
+
data.tar.gz: 04f58dafb5faf1e21b08fd85d508ceb6e9869b0a69d63c133661a834f169eb750b599639ffdbff474abf7f92bc6bfee3a43b9442c2885a6dd88328657b0e1d36
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
## 0.45.4
|
2
|
+
|
3
|
+
* Improve signal trapping mechanism
|
4
|
+
|
5
|
+
## 0.45.3
|
6
|
+
|
7
|
+
* Don't swallow error in `Process#kill_and_await`
|
8
|
+
* Add `Fiber#mailbox` attribute reader
|
9
|
+
* Fix bug in `Fiber.await`
|
10
|
+
* Implement `IO#getc`, `IO#getbyte`
|
11
|
+
|
1
12
|
## 0.45.2
|
2
13
|
|
3
14
|
* Rewrite `Fiber#<<`, `Fiber#await`, `Fiber#receive` in C
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
polyphony (0.45.
|
4
|
+
polyphony (0.45.4)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
@@ -87,7 +87,7 @@ GEM
|
|
87
87
|
rack (2.2.3)
|
88
88
|
rainbow (3.0.0)
|
89
89
|
rake (12.3.3)
|
90
|
-
rake-compiler (1.
|
90
|
+
rake-compiler (1.1.1)
|
91
91
|
rake
|
92
92
|
rb-fsevent (0.10.3)
|
93
93
|
rb-inotify (0.10.1)
|
@@ -141,7 +141,7 @@ DEPENDENCIES
|
|
141
141
|
polyphony!
|
142
142
|
pry (= 0.13.1)
|
143
143
|
rack (>= 2.0.8, < 2.3.0)
|
144
|
-
rake-compiler (= 1.
|
144
|
+
rake-compiler (= 1.1.1)
|
145
145
|
redis (= 4.1.0)
|
146
146
|
rubocop (= 0.85.1)
|
147
147
|
sequel (= 5.34.0)
|
data/TODO.md
CHANGED
@@ -1,8 +1,14 @@
|
|
1
|
-
|
1
|
+
(
|
2
|
+
io_uring: some work has been done on an io_uring based scheduler here:
|
3
|
+
https://github.com/dsh0416/evt
|
4
|
+
|
5
|
+
This can serve as a starting point for doing stuff with io_uring
|
6
|
+
)
|
2
7
|
|
8
|
+
0.45.4
|
9
|
+
|
10
|
+
- Adapter for io/console (what does `IO#raw` do?)
|
3
11
|
- Adapter for Pry and IRB (Which fixes #5 and #6)
|
4
|
-
- Redesign signal handling - the current mechanism is problematic in that it
|
5
|
-
does not address signals that do not kill, for instance HUP or USR1.
|
6
12
|
- Improve `#supervise`. It does not work as advertised, and seems to exhibit an
|
7
13
|
inconsistent behaviour (see supervisor example).
|
8
14
|
- Fix backtrace for `Timeout.timeout` API (see timeout example).
|
data/examples/io/raw.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
require 'polyphony/adapters/readline'
|
6
|
+
require 'pry'
|
7
|
+
|
8
|
+
$counter = 0
|
9
|
+
timer = spin do
|
10
|
+
throttled_loop(5) do
|
11
|
+
$counter += 1
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
at_exit { timer.stop }
|
16
|
+
|
17
|
+
puts 'try typing $counter to see the counter incremented in the background'
|
18
|
+
binding.pry
|
data/lib/polyphony.rb
CHANGED
@@ -76,10 +76,10 @@ module Polyphony
|
|
76
76
|
end
|
77
77
|
|
78
78
|
def install_terminating_signal_handlers
|
79
|
-
trap('SIGTERM'
|
79
|
+
trap('SIGTERM') { raise SystemExit }
|
80
80
|
orig_trap('SIGINT') do
|
81
81
|
orig_trap('SIGINT') { exit! }
|
82
|
-
|
82
|
+
Fiber.schedule_priority_oob_fiber { raise Interrupt }
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
@@ -149,32 +149,19 @@ module ::Kernel
|
|
149
149
|
return orig_trap(sig, command) if command.is_a? String
|
150
150
|
|
151
151
|
block = command if !block && command.respond_to?(:call)
|
152
|
-
exception = signal_exception(block, command)
|
153
152
|
|
154
153
|
# The signal trap can be invoked at any time, including while the system
|
155
154
|
# backend is blocking while polling for events. In order to deal with this
|
156
|
-
# correctly, we
|
157
|
-
#
|
158
|
-
#
|
159
|
-
#
|
160
|
-
# If the command argument is an exception class however, it will be raised
|
161
|
-
# directly in the context of the main fiber.
|
155
|
+
# correctly, we run the signal handler code in an out-of-band, priority
|
156
|
+
# scheduled fiber, that will pass any uncaught exception (including
|
157
|
+
# SystemExit and Interrupt) to the main thread's main fiber. See also
|
158
|
+
# `Fiber#schedule_priority_oob_fiber`.
|
162
159
|
orig_trap(sig) do
|
163
|
-
|
160
|
+
Fiber.schedule_priority_oob_fiber(&block)
|
164
161
|
end
|
165
162
|
end
|
166
163
|
end
|
167
164
|
|
168
|
-
def signal_exception(block, command)
|
169
|
-
if block
|
170
|
-
Polyphony::Interjection.new(block)
|
171
|
-
elsif command.is_a?(Class)
|
172
|
-
command.new
|
173
|
-
else
|
174
|
-
raise ArgumentError, 'Must supply block or exception or callable object'
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
165
|
# Override Timeout to use cancel scope
|
179
166
|
module ::Timeout
|
180
167
|
def self.timeout(sec, klass = nil, message = nil, &block)
|
@@ -103,7 +103,7 @@ module Polyphony
|
|
103
103
|
suspend
|
104
104
|
fibers.map(&:result)
|
105
105
|
ensure
|
106
|
-
await_select_cleanup(state)
|
106
|
+
await_select_cleanup(state) if state
|
107
107
|
end
|
108
108
|
alias_method :join, :await
|
109
109
|
|
@@ -165,6 +165,20 @@ module Polyphony
|
|
165
165
|
state[:selected] = true
|
166
166
|
end
|
167
167
|
end
|
168
|
+
|
169
|
+
# Creates and schedules with priority an out-of-band fiber that runs the
|
170
|
+
# supplied block. If any uncaught exception is raised while the fiber is
|
171
|
+
# running, it will bubble up to the main thread's main fiber, which will
|
172
|
+
# also be scheduled with priority. This method is mainly used trapping
|
173
|
+
# signals (see also the patched `Kernel#trap`)
|
174
|
+
def schedule_priority_oob_fiber(&block)
|
175
|
+
f = Fiber.new do
|
176
|
+
block.call
|
177
|
+
rescue Exception => e
|
178
|
+
Thread.current.break_out_of_ev_loop(Thread.main.main_fiber, e)
|
179
|
+
end
|
180
|
+
Thread.current.break_out_of_ev_loop(f, nil)
|
181
|
+
end
|
168
182
|
end
|
169
183
|
|
170
184
|
# Methods for controlling child fibers
|
@@ -173,9 +187,9 @@ module Polyphony
|
|
173
187
|
(@children ||= {}).keys
|
174
188
|
end
|
175
189
|
|
176
|
-
def spin(tag = nil, orig_caller = Kernel.caller, &block)
|
190
|
+
def spin(tag = nil, orig_caller = Kernel.caller, do_schedule: true, &block)
|
177
191
|
f = Fiber.new { |v| f.run(v) }
|
178
|
-
f.prepare(tag, block, orig_caller, self)
|
192
|
+
f.prepare(tag, block, orig_caller, self, do_schedule: do_schedule)
|
179
193
|
(@children ||= {})[f] = true
|
180
194
|
f
|
181
195
|
end
|
@@ -213,14 +227,14 @@ module Polyphony
|
|
213
227
|
|
214
228
|
# Fiber life cycle methods
|
215
229
|
module FiberLifeCycle
|
216
|
-
def prepare(tag, block, caller, parent)
|
230
|
+
def prepare(tag, block, caller, parent, do_schedule: true)
|
217
231
|
@thread = Thread.current
|
218
232
|
@tag = tag
|
219
233
|
@parent = parent
|
220
234
|
@caller = caller
|
221
235
|
@block = block
|
222
236
|
__fiber_trace__(:fiber_create, self)
|
223
|
-
schedule
|
237
|
+
schedule if do_schedule
|
224
238
|
end
|
225
239
|
|
226
240
|
def run(first_value)
|
@@ -314,7 +328,7 @@ class ::Fiber
|
|
314
328
|
extend Polyphony::FiberControlClassMethods
|
315
329
|
|
316
330
|
attr_accessor :tag, :thread, :parent
|
317
|
-
attr_reader :result
|
331
|
+
attr_reader :result, :mailbox
|
318
332
|
|
319
333
|
def running?
|
320
334
|
@running
|
@@ -90,11 +90,22 @@ class ::IO
|
|
90
90
|
# def each_codepoint
|
91
91
|
# end
|
92
92
|
|
93
|
-
|
94
|
-
|
93
|
+
alias_method :orig_getbyte, :getbyte
|
94
|
+
def getbyte
|
95
|
+
char = getc
|
96
|
+
char ? char.getbyte(0) : nil
|
97
|
+
end
|
95
98
|
|
96
|
-
|
97
|
-
|
99
|
+
alias_method :orig_getc, :getc
|
100
|
+
def getc
|
101
|
+
return @read_buffer.slice!(0) if @read_buffer && !@read_buffer.empty?
|
102
|
+
|
103
|
+
@read_buffer ||= +''
|
104
|
+
Thread.current.backend.read(self, @read_buffer, 8192, false)
|
105
|
+
return @read_buffer.slice!(0) if !@read_buffer.empty?
|
106
|
+
|
107
|
+
nil
|
108
|
+
end
|
98
109
|
|
99
110
|
alias_method :orig_read, :read
|
100
111
|
def read(len = nil)
|
data/lib/polyphony/version.rb
CHANGED
data/polyphony.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.require_paths = ["lib"]
|
22
22
|
s.required_ruby_version = '>= 2.6'
|
23
23
|
|
24
|
-
s.add_development_dependency 'rake-compiler', '1.
|
24
|
+
s.add_development_dependency 'rake-compiler', '1.1.1'
|
25
25
|
s.add_development_dependency 'minitest', '5.13.0'
|
26
26
|
s.add_development_dependency 'minitest-reporters', '1.4.2'
|
27
27
|
s.add_development_dependency 'simplecov', '0.17.1'
|
data/test/test_io.rb
CHANGED
@@ -92,6 +92,48 @@ class IOTest < MiniTest::Test
|
|
92
92
|
assert_raises(EOFError) { i.readpartial(1) }
|
93
93
|
end
|
94
94
|
|
95
|
+
def test_getc
|
96
|
+
i, o = IO.pipe
|
97
|
+
|
98
|
+
buf = []
|
99
|
+
f = spin do
|
100
|
+
while (c = i.getc)
|
101
|
+
buf << c
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
snooze
|
106
|
+
assert_equal [], buf
|
107
|
+
|
108
|
+
o << 'f'
|
109
|
+
snooze
|
110
|
+
o << 'g'
|
111
|
+
o.close
|
112
|
+
f.await
|
113
|
+
assert_equal ['f', 'g'], buf
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_getbyte
|
117
|
+
i, o = IO.pipe
|
118
|
+
|
119
|
+
buf = []
|
120
|
+
f = spin do
|
121
|
+
while (b = i.getbyte)
|
122
|
+
buf << b
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
snooze
|
127
|
+
assert_equal [], buf
|
128
|
+
|
129
|
+
o << 'f'
|
130
|
+
snooze
|
131
|
+
o << 'g'
|
132
|
+
o.close
|
133
|
+
f.await
|
134
|
+
assert_equal [102, 103], buf
|
135
|
+
end
|
136
|
+
|
95
137
|
# see https://github.com/digital-fabric/polyphony/issues/30
|
96
138
|
def test_reopened_tempfile
|
97
139
|
file = Tempfile.new
|
data/test/test_signal.rb
CHANGED
@@ -3,18 +3,21 @@
|
|
3
3
|
require_relative 'helper'
|
4
4
|
|
5
5
|
class SignalTrapTest < Minitest::Test
|
6
|
+
def test_int_signal
|
7
|
+
Thread.new { sleep 0.001; Process.kill('INT', Process.pid) }
|
8
|
+
assert_raises(Interrupt) { sleep 5 }
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_term_signal
|
12
|
+
Thread.new { sleep 0.001; Process.kill('TERM', Process.pid) }
|
13
|
+
assert_raises(SystemExit) { sleep 5 }
|
14
|
+
end
|
15
|
+
|
6
16
|
def test_signal_exception_handling
|
7
17
|
i, o = IO.pipe
|
8
18
|
pid = Polyphony.fork do
|
9
19
|
i.close
|
10
|
-
|
11
|
-
spin do
|
12
|
-
sleep 5
|
13
|
-
rescue ::Interrupt => e
|
14
|
-
# the signal should be raised only in the main fiber
|
15
|
-
o.puts "1-interrupt"
|
16
|
-
end.await
|
17
|
-
end.await
|
20
|
+
sleep 5
|
18
21
|
rescue ::Interrupt => e
|
19
22
|
o.puts "3-interrupt"
|
20
23
|
ensure
|
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.45.
|
4
|
+
version: 0.45.4
|
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-
|
11
|
+
date: 2020-09-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.
|
19
|
+
version: 1.1.1
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 1.
|
26
|
+
version: 1.1.1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: minitest
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -377,6 +377,8 @@ files:
|
|
377
377
|
- examples/io/open.rb
|
378
378
|
- examples/io/pry.rb
|
379
379
|
- examples/io/rack_server.rb
|
380
|
+
- examples/io/raw.rb
|
381
|
+
- examples/io/reline.rb
|
380
382
|
- examples/io/system.rb
|
381
383
|
- examples/io/tcpserver.rb
|
382
384
|
- examples/io/tcpsocket.rb
|