async 1.28.5 → 1.29.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/async/debug/monitor.rb +8 -10
- data/lib/async/debug/selector.rb +8 -15
- data/lib/async/node.rb +25 -20
- data/lib/async/reactor.rb +10 -15
- data/lib/async/scheduler.rb +5 -7
- data/lib/async/task.rb +9 -11
- data/lib/async/version.rb +1 -1
- data/lib/kernel/sync.rb +4 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 421b9e871d367ee3c769c4f7a9f3e51125d5e11c45d37f9d8c562a33ecce70ed
|
4
|
+
data.tar.gz: 868be7ef14d83fb04620c862d69b38e03f0b5ba036cd2d65e6caf0f45c58a689
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 47620eaf32dc53e1978f3c07ef66823c6aa4b3e85ec23ac3a207d1cdb39a06c790428a9b67dc3b955b74edf723faa567b2f8a077893ecf0c3d1383c5c62997e0
|
7
|
+
data.tar.gz: 74e3b0e17cc0d8f63bdc2c7e4aa40033062a07d2a5a1866f3ca3ac072376264463f8b11203485a07bbed11c475cbad6a2ac81f9297e900a732263f8b7b0b401b
|
data/lib/async/debug/monitor.rb
CHANGED
@@ -20,25 +20,23 @@
|
|
20
20
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
21
|
# THE SOFTWARE.
|
22
22
|
|
23
|
+
require 'delegate'
|
24
|
+
|
23
25
|
module Async
|
24
26
|
module Debug
|
25
|
-
class Monitor
|
27
|
+
class Monitor < Delegator
|
26
28
|
def initialize(monitor, selector)
|
27
29
|
@monitor = monitor
|
28
30
|
@selector = selector
|
29
31
|
end
|
30
32
|
|
31
|
-
def
|
32
|
-
@
|
33
|
-
@monitor.close
|
33
|
+
def __getobj__
|
34
|
+
@monitor
|
34
35
|
end
|
35
36
|
|
36
|
-
def
|
37
|
-
@
|
38
|
-
|
39
|
-
|
40
|
-
def respond_to?(*arguments)
|
41
|
-
@monitor.respond_to?(*arguments)
|
37
|
+
def close
|
38
|
+
@selector.deregister(self)
|
39
|
+
@monitor.close
|
42
40
|
end
|
43
41
|
|
44
42
|
def inspect
|
data/lib/async/debug/selector.rb
CHANGED
@@ -24,6 +24,7 @@ require_relative 'monitor'
|
|
24
24
|
require_relative '../logger'
|
25
25
|
|
26
26
|
require 'nio'
|
27
|
+
require 'set'
|
27
28
|
|
28
29
|
module Async
|
29
30
|
module Debug
|
@@ -36,7 +37,7 @@ module Async
|
|
36
37
|
class Selector
|
37
38
|
def initialize(selector = NIO::Selector.new)
|
38
39
|
@selector = selector
|
39
|
-
@monitors =
|
40
|
+
@monitors = Set.new
|
40
41
|
end
|
41
42
|
|
42
43
|
def register(object, interests)
|
@@ -46,26 +47,18 @@ module Async
|
|
46
47
|
raise RuntimeError, "Could not convert #{io} into IO!"
|
47
48
|
end
|
48
49
|
|
49
|
-
if monitor = @monitors[io.fileno]
|
50
|
-
raise RuntimeError, "Trying to register monitor for #{object.inspect} but it was already registered: #{monitor.inspect}!"
|
51
|
-
end
|
52
|
-
|
53
50
|
monitor = Monitor.new(@selector.register(object, interests), self)
|
54
51
|
|
55
|
-
@monitors
|
52
|
+
@monitors.add(monitor)
|
56
53
|
|
57
54
|
return monitor
|
58
55
|
end
|
59
56
|
|
60
|
-
def deregister(
|
61
|
-
Async.logger.debug(self) {"Deregistering #{
|
62
|
-
|
63
|
-
unless io = ::IO.try_convert(object)
|
64
|
-
raise RuntimeError, "Could not convert #{io} into IO!"
|
65
|
-
end
|
57
|
+
def deregister(monitor)
|
58
|
+
Async.logger.debug(self) {"Deregistering #{monitor.inspect}."}
|
66
59
|
|
67
|
-
unless @monitors.delete(
|
68
|
-
raise RuntimeError, "Trying to remove monitor for #{
|
60
|
+
unless @monitors.delete?(monitor)
|
61
|
+
raise RuntimeError, "Trying to remove monitor for #{monitor.inspect} but it was not registered!"
|
69
62
|
end
|
70
63
|
end
|
71
64
|
|
@@ -75,7 +68,7 @@ module Async
|
|
75
68
|
|
76
69
|
def close
|
77
70
|
if @monitors.any?
|
78
|
-
raise LeakError, @monitors
|
71
|
+
raise LeakError, @monitors
|
79
72
|
end
|
80
73
|
ensure
|
81
74
|
@selector.close
|
data/lib/async/node.rb
CHANGED
@@ -24,6 +24,7 @@ module Async
|
|
24
24
|
# A double linked list.
|
25
25
|
class List
|
26
26
|
def initialize
|
27
|
+
# The list behaves like a list node, so @tail points to the next item (the first one) and head points to the previous item (the last one). This may be slightly confusing but it makes the interface more natural.
|
27
28
|
@head = nil
|
28
29
|
@tail = nil
|
29
30
|
@size = 0
|
@@ -36,21 +37,21 @@ module Async
|
|
36
37
|
|
37
38
|
# Inserts an item at the end of the list.
|
38
39
|
def insert(item)
|
39
|
-
unless @
|
40
|
-
@head = item
|
40
|
+
unless @tail
|
41
41
|
@tail = item
|
42
|
+
@head = item
|
42
43
|
|
43
44
|
# Consistency:
|
44
45
|
item.head = nil
|
45
46
|
item.tail = nil
|
46
47
|
else
|
47
|
-
@
|
48
|
-
item.head = @
|
48
|
+
@head.tail = item
|
49
|
+
item.head = @head
|
49
50
|
|
50
51
|
# Consistency:
|
51
52
|
item.tail = nil
|
52
53
|
|
53
|
-
@
|
54
|
+
@head = item
|
54
55
|
end
|
55
56
|
|
56
57
|
@size += 1
|
@@ -59,14 +60,14 @@ module Async
|
|
59
60
|
end
|
60
61
|
|
61
62
|
def delete(item)
|
62
|
-
if @
|
63
|
-
@
|
63
|
+
if @tail.equal?(item)
|
64
|
+
@tail = @tail.tail
|
64
65
|
else
|
65
66
|
item.head.tail = item.tail
|
66
67
|
end
|
67
68
|
|
68
|
-
if @
|
69
|
-
@
|
69
|
+
if @head.equal?(item)
|
70
|
+
@head = @head.head
|
70
71
|
else
|
71
72
|
item.tail.head = item.head
|
72
73
|
end
|
@@ -79,15 +80,17 @@ module Async
|
|
79
80
|
return self
|
80
81
|
end
|
81
82
|
|
82
|
-
def each
|
83
|
+
def each(&block)
|
83
84
|
return to_enum unless block_given?
|
84
85
|
|
85
|
-
|
86
|
-
while
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
86
|
+
current = self
|
87
|
+
while node = current.tail
|
88
|
+
yield node
|
89
|
+
|
90
|
+
# If the node has deleted itself or any subsequent node, it will no longer be the next node, so don't use it for continued traversal:
|
91
|
+
if current.tail.equal?(node)
|
92
|
+
current = node
|
93
|
+
end
|
91
94
|
end
|
92
95
|
end
|
93
96
|
|
@@ -100,19 +103,19 @@ module Async
|
|
100
103
|
end
|
101
104
|
|
102
105
|
def first
|
103
|
-
@
|
106
|
+
@tail
|
104
107
|
end
|
105
108
|
|
106
109
|
def last
|
107
|
-
@
|
110
|
+
@head
|
108
111
|
end
|
109
112
|
|
110
113
|
def empty?
|
111
|
-
@
|
114
|
+
@tail.nil?
|
112
115
|
end
|
113
116
|
|
114
117
|
def nil?
|
115
|
-
@
|
118
|
+
@tail.nil?
|
116
119
|
end
|
117
120
|
end
|
118
121
|
|
@@ -276,6 +279,8 @@ module Async
|
|
276
279
|
if child.finished?
|
277
280
|
delete_child(child)
|
278
281
|
else
|
282
|
+
# In theory we don't need to do this... because we are throwing away the list. However, if you don't correctly update the list when moving the child to the parent, it foobars the enumeration, and subsequent nodes will be skipped, or in the worst case you might start enumerating the parents nodes.
|
283
|
+
delete_child(child)
|
279
284
|
parent.add_child(child)
|
280
285
|
end
|
281
286
|
end
|
data/lib/async/reactor.rb
CHANGED
@@ -47,9 +47,7 @@ module Async
|
|
47
47
|
# running.
|
48
48
|
def self.run(*arguments, **options, &block)
|
49
49
|
if current = Task.current?
|
50
|
-
|
51
|
-
|
52
|
-
return reactor.async(*arguments, **options, &block)
|
50
|
+
return current.async(*arguments, **options, &block)
|
53
51
|
else
|
54
52
|
reactor = self.new
|
55
53
|
|
@@ -96,6 +94,7 @@ module Async
|
|
96
94
|
end
|
97
95
|
|
98
96
|
attr :scheduler
|
97
|
+
attr :logger
|
99
98
|
|
100
99
|
# @reentrant Not thread safe.
|
101
100
|
def block(blocker, timeout)
|
@@ -111,7 +110,7 @@ module Async
|
|
111
110
|
|
112
111
|
begin
|
113
112
|
@blocked += 1
|
114
|
-
|
113
|
+
Task.yield
|
115
114
|
ensure
|
116
115
|
@blocked -= 1
|
117
116
|
end
|
@@ -135,10 +134,6 @@ module Async
|
|
135
134
|
end
|
136
135
|
end
|
137
136
|
|
138
|
-
def logger
|
139
|
-
@logger || Console.logger
|
140
|
-
end
|
141
|
-
|
142
137
|
def to_s
|
143
138
|
"\#<#{self.description} #{@children&.size || 0} children (#{stopped? ? 'stopped' : 'running'})>"
|
144
139
|
end
|
@@ -167,7 +162,7 @@ module Async
|
|
167
162
|
# - Avoid scheduler overhead if no blocking operation is performed.
|
168
163
|
task.run(*arguments)
|
169
164
|
|
170
|
-
# logger.debug "Initial execution of task #{fiber} complete (#{result} -> #{fiber.alive?})..."
|
165
|
+
# Console.logger.debug "Initial execution of task #{fiber} complete (#{result} -> #{fiber.alive?})..."
|
171
166
|
return task
|
172
167
|
end
|
173
168
|
|
@@ -198,7 +193,7 @@ module Async
|
|
198
193
|
def yield(fiber = Fiber.current)
|
199
194
|
@ready << fiber
|
200
195
|
|
201
|
-
|
196
|
+
Task.yield
|
202
197
|
end
|
203
198
|
|
204
199
|
def finished?
|
@@ -210,7 +205,7 @@ module Async
|
|
210
205
|
# @param timeout [Float | nil] the maximum timeout, or if nil, indefinite.
|
211
206
|
# @return [Boolean] whether there is more work to do.
|
212
207
|
def run_once(timeout = nil)
|
213
|
-
# logger.debug(self) {"@ready = #{@ready} @running = #{@running}"}
|
208
|
+
# Console.logger.debug(self) {"@ready = #{@ready} @running = #{@running}"}
|
214
209
|
|
215
210
|
if @ready.any?
|
216
211
|
# running used to correctly answer on `finished?`, and to reuse Array object.
|
@@ -223,7 +218,7 @@ module Async
|
|
223
218
|
@running.clear
|
224
219
|
end
|
225
220
|
|
226
|
-
|
221
|
+
if @unblocked.any?
|
227
222
|
unblocked = Array.new
|
228
223
|
|
229
224
|
@guard.synchronize do
|
@@ -258,7 +253,7 @@ module Async
|
|
258
253
|
interval = timeout
|
259
254
|
end
|
260
255
|
|
261
|
-
# logger.info(self) {"Selecting with #{@children&.size} children with interval = #{interval ? interval.round(2) : 'infinite'}..."}
|
256
|
+
# Console.logger.info(self) {"Selecting with #{@children&.size} children with interval = #{interval ? interval.round(2) : 'infinite'}..."}
|
262
257
|
if monitors = @selector.select(interval)
|
263
258
|
monitors.each do |monitor|
|
264
259
|
monitor.value.resume
|
@@ -295,7 +290,7 @@ module Async
|
|
295
290
|
return initial_task
|
296
291
|
ensure
|
297
292
|
@scheduler&.clear!
|
298
|
-
logger.debug(self) {"Exiting run-loop because #{$! ? $! : 'finished'}."}
|
293
|
+
Console.logger.debug(self) {"Exiting run-loop because #{$! ? $! : 'finished'}."}
|
299
294
|
end
|
300
295
|
|
301
296
|
def stop(later = true)
|
@@ -347,7 +342,7 @@ module Async
|
|
347
342
|
timer = @timers.after(timeout) do
|
348
343
|
if fiber.alive?
|
349
344
|
error = exception.new("execution expired")
|
350
|
-
fiber.resume
|
345
|
+
fiber.resume(error)
|
351
346
|
end
|
352
347
|
end
|
353
348
|
|
data/lib/async/scheduler.rb
CHANGED
@@ -34,24 +34,20 @@ module Async
|
|
34
34
|
|
35
35
|
def initialize(reactor)
|
36
36
|
@reactor = reactor
|
37
|
-
@wrappers = nil
|
38
37
|
end
|
39
38
|
|
39
|
+
attr :wrappers
|
40
|
+
|
40
41
|
def set!
|
41
|
-
@wrappers = {}
|
42
42
|
Fiber.set_scheduler(self)
|
43
43
|
end
|
44
44
|
|
45
45
|
def clear!
|
46
|
-
# Because these instances are created with `autoclose: false`, this does not close the underlying file descriptor:
|
47
|
-
# @ios&.each_value(&:close)
|
48
|
-
|
49
|
-
@wrappers = nil
|
50
46
|
Fiber.set_scheduler(nil)
|
51
47
|
end
|
52
48
|
|
53
49
|
private def from_io(io)
|
54
|
-
|
50
|
+
Wrapper.new(io, @reactor)
|
55
51
|
end
|
56
52
|
|
57
53
|
def io_wait(io, events, timeout = nil)
|
@@ -72,6 +68,8 @@ module Async
|
|
72
68
|
end
|
73
69
|
|
74
70
|
return false
|
71
|
+
rescue TimeoutError
|
72
|
+
return nil
|
75
73
|
ensure
|
76
74
|
wrapper.reactor = nil
|
77
75
|
end
|
data/lib/async/task.rb
CHANGED
@@ -72,20 +72,22 @@ module Async
|
|
72
72
|
# Create a new task.
|
73
73
|
# @param reactor [Async::Reactor] the reactor this task will run within.
|
74
74
|
# @param parent [Async::Task] the parent task.
|
75
|
-
def initialize(reactor, parent = Task.current?, logger: nil, **options, &block)
|
75
|
+
def initialize(reactor, parent = Task.current?, logger: nil, finished: nil, **options, &block)
|
76
76
|
super(parent || reactor, **options)
|
77
77
|
|
78
78
|
@reactor = reactor
|
79
79
|
|
80
80
|
@status = :initialized
|
81
81
|
@result = nil
|
82
|
-
@finished =
|
82
|
+
@finished = finished
|
83
83
|
|
84
|
-
@logger = logger
|
84
|
+
@logger = logger || @parent.logger
|
85
85
|
|
86
86
|
@fiber = make_fiber(&block)
|
87
87
|
end
|
88
88
|
|
89
|
+
attr :logger
|
90
|
+
|
89
91
|
if Fiber.current.respond_to?(:backtrace)
|
90
92
|
def backtrace(*arguments)
|
91
93
|
@fiber&.backtrace(*arguments)
|
@@ -96,10 +98,6 @@ module Async
|
|
96
98
|
"\#<#{self.description} (#{@status})>"
|
97
99
|
end
|
98
100
|
|
99
|
-
def logger
|
100
|
-
@logger || Console.logger
|
101
|
-
end
|
102
|
-
|
103
101
|
# @attr ios [Reactor] The reactor the task was created within.
|
104
102
|
attr :reactor
|
105
103
|
|
@@ -242,9 +240,9 @@ module Async
|
|
242
240
|
raise
|
243
241
|
elsif @finished.nil?
|
244
242
|
# If no one has called wait, we log this as an error:
|
245
|
-
logger.error(self) {$!}
|
243
|
+
Console.logger.error(self) {$!}
|
246
244
|
else
|
247
|
-
logger.debug(self) {$!}
|
245
|
+
Console.logger.debug(self) {$!}
|
248
246
|
end
|
249
247
|
end
|
250
248
|
|
@@ -264,7 +262,7 @@ module Async
|
|
264
262
|
begin
|
265
263
|
@result = yield(self, *arguments)
|
266
264
|
@status = :complete
|
267
|
-
# logger.debug(self) {"Task was completed with #{@children.size} children!"}
|
265
|
+
# Console.logger.debug(self) {"Task was completed with #{@children.size} children!"}
|
268
266
|
rescue Stop
|
269
267
|
stop!
|
270
268
|
rescue StandardError => error
|
@@ -272,7 +270,7 @@ module Async
|
|
272
270
|
rescue Exception => exception
|
273
271
|
fail!(exception, true)
|
274
272
|
ensure
|
275
|
-
# logger.debug(self) {"Task ensure $!=#{$!} with #{@children.size} children!"}
|
273
|
+
# Console.logger.debug(self) {"Task ensure $!=#{$!} with #{@children.size} children!"}
|
276
274
|
finish!
|
277
275
|
end
|
278
276
|
end
|
data/lib/async/version.rb
CHANGED
data/lib/kernel/sync.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: async
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.29.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-04-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: console
|