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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a2fa4fa731ff52272d3aed456f7a26751e76c63b4335366919bffaf089bf96dd
4
- data.tar.gz: 1afe67258c5c73d9cc1082ca238eb358dac0f5b7a975f90a77b4f6de6a23b2a4
3
+ metadata.gz: 52f8ebf1104d921c9e3b0afa0b4605ee8f912eabe8b6264898f23905d2cb6c6f
4
+ data.tar.gz: 38f0f7cd62997ba5681185c3c4859f57d86de875d8292faf67fffa53c7160181
5
5
  SHA512:
6
- metadata.gz: 175edf315d759f85d2c0d934be36b9fcacd68342206d984ad64f800120a8b65668e9ea81595f47cbbb439402c256b47fde78f0cdad4b42e0c3b1d6ee321135b9
7
- data.tar.gz: 01cfe1d8b51d60a736adb80062eb22e7983a1879a5491cb7a2e47ec4ad5734e0c8bd8664653870a4393276b42fa912953721658ecff634521a672419c8d3cab6
6
+ metadata.gz: 2429259a2e79757ec879c4c00db8fd8b87302b9e0a61c6ae2ddd5fdb6e1a3a06ac63d551ed33a4c77480e156eb1247a0fab4a263179a60fd2e9a2d3173831a58
7
+ data.tar.gz: 04f58dafb5faf1e21b08fd85d508ceb6e9869b0a69d63c133661a834f169eb750b599639ffdbff474abf7f92bc6bfee3a43b9442c2885a6dd88328657b0e1d36
@@ -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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.45.2)
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.0.5)
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.0.5)
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
- 0.45.2
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).
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+ require 'io/console'
6
+
7
+ c = STDIN.raw(min: 1, tim: 0, &:getbyte)
8
+ p result: c
9
+ exit
10
+
11
+ puts '?' * 40
12
+ c = STDIN.getbyte
13
+ puts '*' * 40
14
+ p c
@@ -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
@@ -13,7 +13,7 @@ def handle_client(socket)
13
13
  parser.on_message_complete = proc do |env|
14
14
  reqs << Object.new # parser
15
15
  end
16
- socket.read_loop |data|
16
+ socket.read_loop do |data|
17
17
  parser << data
18
18
  while (req = reqs.shift)
19
19
  handle_request(socket, req)
@@ -76,10 +76,10 @@ module Polyphony
76
76
  end
77
77
 
78
78
  def install_terminating_signal_handlers
79
- trap('SIGTERM', SystemExit)
79
+ trap('SIGTERM') { raise SystemExit }
80
80
  orig_trap('SIGINT') do
81
81
  orig_trap('SIGINT') { exit! }
82
- Thread.current.break_out_of_ev_loop(Thread.main.main_fiber, Interrupt.new)
82
+ Fiber.schedule_priority_oob_fiber { raise Interrupt }
83
83
  end
84
84
  end
85
85
 
@@ -24,9 +24,6 @@ module Polyphony
24
24
  def kill_and_await(sig, pid)
25
25
  ::Process.kill(sig, pid)
26
26
  Thread.current.backend.waitpid(pid)
27
- rescue SystemCallError
28
- # ignore
29
- puts 'SystemCallError in kill_and_await'
30
27
  end
31
28
  end
32
29
  end
@@ -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 spin a fiber that will run the signal handler code, then
157
- # call break_out_of_ev_loop, which will put the fiber at the front of the
158
- # run queue, then wake up the backend.
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
- Thread.current.break_out_of_ev_loop(Thread.main.main_fiber, exception)
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
- # def getbyte
94
- # end
93
+ alias_method :orig_getbyte, :getbyte
94
+ def getbyte
95
+ char = getc
96
+ char ? char.getbyte(0) : nil
97
+ end
95
98
 
96
- # def getc
97
- # end
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)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.45.2'
4
+ VERSION = '0.45.4'
5
5
  end
@@ -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.0.5'
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'
@@ -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
@@ -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
- spin do
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.2
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-08-03 00:00:00.000000000 Z
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.0.5
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.0.5
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