async 1.32.1 → 2.0.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/lib/async/barrier.md +36 -0
 - data/lib/async/barrier.rb +14 -6
 - data/lib/async/clock.rb +11 -0
 - data/lib/async/condition.md +31 -0
 - data/lib/async/condition.rb +27 -16
 - data/lib/async/node.rb +27 -12
 - data/lib/async/notification.rb +4 -4
 - data/lib/async/queue.rb +8 -21
 - data/lib/async/reactor.rb +11 -320
 - data/lib/async/scheduler.rb +235 -48
 - data/lib/async/semaphore.md +41 -0
 - data/lib/async/semaphore.rb +8 -24
 - data/lib/async/task.rb +68 -114
 - data/lib/async/version.rb +1 -1
 - data/lib/async/wrapper.rb +19 -179
 - data/lib/async.rb +0 -5
 - data/lib/kernel/async.rb +26 -2
 - data/lib/kernel/sync.rb +14 -4
 - metadata +10 -10
 - data/lib/async/debug/monitor.rb +0 -47
 - data/lib/async/debug/selector.rb +0 -82
 - data/lib/async/logger.rb +0 -28
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 6e5f7f4cbc1cfc595409b58cfc0b74e2a2767837fc40bae5e1a1b60e7dcd3384
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 4eeb27d8248bc7993cf7758e41c8ffee3a54141d7c521e2a2805bbc8e8be3edd
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: d0b59a751dd4ea8cd7f2a83ad76fbf4dcff30ca11629d2e7f6ba18e017cf5de06880c1a6b19a3297967793e80394e10f8873ed24aa278d2019b11eb90a002394
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 1c23c709f983bc14ba1477b41b3ca7533275eb3464928c7d4d564e897fc2fb893617cde7bb6d1e90d050db9bbc1d1d2ed71c87da02e61cd559f0afef363fc567
         
     | 
| 
         @@ -0,0 +1,36 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            A synchronization primitive, which allows one task to wait for a number of other tasks to complete. It can be used in conjunction with {Semaphore}.
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            ## Example
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            ~~~ ruby
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'async'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'async/barrier'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            Sync do
         
     | 
| 
      
 10 
     | 
    
         
            +
            	barrier = Async::Barrier.new
         
     | 
| 
      
 11 
     | 
    
         
            +
            	
         
     | 
| 
      
 12 
     | 
    
         
            +
            	# Generate an array of 10 numbers:
         
     | 
| 
      
 13 
     | 
    
         
            +
            	numbers = 10.times.map{rand(10)}
         
     | 
| 
      
 14 
     | 
    
         
            +
            	sorted = []
         
     | 
| 
      
 15 
     | 
    
         
            +
            	
         
     | 
| 
      
 16 
     | 
    
         
            +
            	# Sleep sort the numbers:
         
     | 
| 
      
 17 
     | 
    
         
            +
            	numbers.each do |number|
         
     | 
| 
      
 18 
     | 
    
         
            +
            		barrier.async do |task|
         
     | 
| 
      
 19 
     | 
    
         
            +
            			task.sleep(number)
         
     | 
| 
      
 20 
     | 
    
         
            +
            			sorted << number
         
     | 
| 
      
 21 
     | 
    
         
            +
            		end
         
     | 
| 
      
 22 
     | 
    
         
            +
            	end
         
     | 
| 
      
 23 
     | 
    
         
            +
            	
         
     | 
| 
      
 24 
     | 
    
         
            +
            	# Wait for all the numbers to be sorted:
         
     | 
| 
      
 25 
     | 
    
         
            +
            	barrier.wait
         
     | 
| 
      
 26 
     | 
    
         
            +
            	
         
     | 
| 
      
 27 
     | 
    
         
            +
            	Console.logger.info("Sorted", sorted)
         
     | 
| 
      
 28 
     | 
    
         
            +
            end
         
     | 
| 
      
 29 
     | 
    
         
            +
            ~~~
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            ### Output
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
            ~~~
         
     | 
| 
      
 34 
     | 
    
         
            +
            0.0s     info: Sorted [ec=0x104] [pid=50291]
         
     | 
| 
      
 35 
     | 
    
         
            +
            						 | [0, 0, 0, 0, 1, 2, 2, 3, 6, 6]
         
     | 
| 
      
 36 
     | 
    
         
            +
            ~~~
         
     | 
    
        data/lib/async/barrier.rb
    CHANGED
    
    | 
         @@ -23,8 +23,12 @@ 
     | 
|
| 
       23 
23 
     | 
    
         
             
            require_relative 'task'
         
     | 
| 
       24 
24 
     | 
    
         | 
| 
       25 
25 
     | 
    
         
             
            module Async
         
     | 
| 
       26 
     | 
    
         
            -
            	# A  
     | 
| 
      
 26 
     | 
    
         
            +
            	# A synchronization primitive, which allows one task to wait for a number of other tasks to complete. It can be used in conjunction with {Semaphore}.
         
     | 
| 
      
 27 
     | 
    
         
            +
            	# @public Since `stable-v1`.
         
     | 
| 
       27 
28 
     | 
    
         
             
            	class Barrier
         
     | 
| 
      
 29 
     | 
    
         
            +
            		# Initialize the barrier.
         
     | 
| 
      
 30 
     | 
    
         
            +
            		# @parameter parent [Task | Semaphore | Nil] The parent for holding any children tasks.
         
     | 
| 
      
 31 
     | 
    
         
            +
            		# @public Since `stable-v1`.
         
     | 
| 
       28 
32 
     | 
    
         
             
            		def initialize(parent: nil)
         
     | 
| 
       29 
33 
     | 
    
         
             
            			@tasks = []
         
     | 
| 
       30 
34 
     | 
    
         | 
| 
         @@ -34,10 +38,13 @@ module Async 
     | 
|
| 
       34 
38 
     | 
    
         
             
            		# All tasks which have been invoked into the barrier.
         
     | 
| 
       35 
39 
     | 
    
         
             
            		attr :tasks
         
     | 
| 
       36 
40 
     | 
    
         | 
| 
      
 41 
     | 
    
         
            +
            		# The number of tasks currently held by the barrier.
         
     | 
| 
       37 
42 
     | 
    
         
             
            		def size
         
     | 
| 
       38 
43 
     | 
    
         
             
            			@tasks.size
         
     | 
| 
       39 
44 
     | 
    
         
             
            		end
         
     | 
| 
       40 
45 
     | 
    
         | 
| 
      
 46 
     | 
    
         
            +
            		# Execute a child task and add it to the barrier.
         
     | 
| 
      
 47 
     | 
    
         
            +
            		# @asynchronous Executes the given block concurrently.
         
     | 
| 
       41 
48 
     | 
    
         
             
            		def async(*arguments, parent: (@parent or Task.current), **options, &block)
         
     | 
| 
       42 
49 
     | 
    
         
             
            			task = parent.async(*arguments, **options, &block)
         
     | 
| 
       43 
50 
     | 
    
         | 
| 
         @@ -46,6 +53,8 @@ module Async 
     | 
|
| 
       46 
53 
     | 
    
         
             
            			return task
         
     | 
| 
       47 
54 
     | 
    
         
             
            		end
         
     | 
| 
       48 
55 
     | 
    
         | 
| 
      
 56 
     | 
    
         
            +
            		# Whether there are any tasks being held by the barrier.
         
     | 
| 
      
 57 
     | 
    
         
            +
            		# @returns [Boolean]
         
     | 
| 
       49 
58 
     | 
    
         
             
            		def empty?
         
     | 
| 
       50 
59 
     | 
    
         
             
            			@tasks.empty?
         
     | 
| 
       51 
60 
     | 
    
         
             
            		end
         
     | 
| 
         @@ -60,15 +69,14 @@ module Async 
     | 
|
| 
       60 
69 
     | 
    
         
             
            				begin
         
     | 
| 
       61 
70 
     | 
    
         
             
            					task.wait
         
     | 
| 
       62 
71 
     | 
    
         
             
            				ensure
         
     | 
| 
       63 
     | 
    
         
            -
            					#  
     | 
| 
       64 
     | 
    
         
            -
            					 
     | 
| 
       65 
     | 
    
         
            -
            						# Remove the task from the waiting list if it's finished:
         
     | 
| 
       66 
     | 
    
         
            -
            						@tasks.shift if @tasks.first == task
         
     | 
| 
       67 
     | 
    
         
            -
            					end
         
     | 
| 
      
 72 
     | 
    
         
            +
            					# Remove the task from the waiting list if it's finished:
         
     | 
| 
      
 73 
     | 
    
         
            +
            					@tasks.shift if @tasks.first == task
         
     | 
| 
       68 
74 
     | 
    
         
             
            				end
         
     | 
| 
       69 
75 
     | 
    
         
             
            			end
         
     | 
| 
       70 
76 
     | 
    
         
             
            		end
         
     | 
| 
       71 
77 
     | 
    
         | 
| 
      
 78 
     | 
    
         
            +
            		# Stop all tasks held by the barrier.
         
     | 
| 
      
 79 
     | 
    
         
            +
            		# @asynchronous May wait for tasks to finish executing.
         
     | 
| 
       72 
80 
     | 
    
         
             
            		def stop
         
     | 
| 
       73 
81 
     | 
    
         
             
            			# We have to be careful to avoid enumerating tasks while adding/removing to it:
         
     | 
| 
       74 
82 
     | 
    
         
             
            			tasks = @tasks.dup
         
     | 
    
        data/lib/async/clock.rb
    CHANGED
    
    | 
         @@ -21,6 +21,8 @@ 
     | 
|
| 
       21 
21 
     | 
    
         
             
            # THE SOFTWARE.
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
            module Async
         
     | 
| 
      
 24 
     | 
    
         
            +
            	# A convenient wrapper around the internal monotonic clock.
         
     | 
| 
      
 25 
     | 
    
         
            +
            	# @public Since `stable-v1`.
         
     | 
| 
       24 
26 
     | 
    
         
             
            	class Clock
         
     | 
| 
       25 
27 
     | 
    
         
             
            		# Get the current elapsed monotonic time.
         
     | 
| 
       26 
28 
     | 
    
         
             
            		def self.now
         
     | 
| 
         @@ -28,6 +30,8 @@ module Async 
     | 
|
| 
       28 
30 
     | 
    
         
             
            		end
         
     | 
| 
       29 
31 
     | 
    
         | 
| 
       30 
32 
     | 
    
         
             
            		# Measure the execution of a block of code.
         
     | 
| 
      
 33 
     | 
    
         
            +
            		# @yields {...} The block to execute.
         
     | 
| 
      
 34 
     | 
    
         
            +
            		# @returns [Numeric] The total execution time.
         
     | 
| 
       31 
35 
     | 
    
         
             
            		def self.measure
         
     | 
| 
       32 
36 
     | 
    
         
             
            			start_time = self.now
         
     | 
| 
       33 
37 
     | 
    
         | 
| 
         @@ -36,19 +40,25 @@ module Async 
     | 
|
| 
       36 
40 
     | 
    
         
             
            			return self.now - start_time
         
     | 
| 
       37 
41 
     | 
    
         
             
            		end
         
     | 
| 
       38 
42 
     | 
    
         | 
| 
      
 43 
     | 
    
         
            +
            		# Start measuring elapsed time from now.
         
     | 
| 
      
 44 
     | 
    
         
            +
            		# @returns [Clock]
         
     | 
| 
       39 
45 
     | 
    
         
             
            		def self.start
         
     | 
| 
       40 
46 
     | 
    
         
             
            			self.new.tap(&:start!)
         
     | 
| 
       41 
47 
     | 
    
         
             
            		end
         
     | 
| 
       42 
48 
     | 
    
         | 
| 
      
 49 
     | 
    
         
            +
            		# Create a new clock with the initial total time.
         
     | 
| 
      
 50 
     | 
    
         
            +
            		# @parameter total [Numeric] The initial clock duration.
         
     | 
| 
       43 
51 
     | 
    
         
             
            		def initialize(total = 0)
         
     | 
| 
       44 
52 
     | 
    
         
             
            			@total = total
         
     | 
| 
       45 
53 
     | 
    
         
             
            			@started = nil
         
     | 
| 
       46 
54 
     | 
    
         
             
            		end
         
     | 
| 
       47 
55 
     | 
    
         | 
| 
      
 56 
     | 
    
         
            +
            		# Start measuring a duration.
         
     | 
| 
       48 
57 
     | 
    
         
             
            		def start!
         
     | 
| 
       49 
58 
     | 
    
         
             
            			@started ||= Clock.now
         
     | 
| 
       50 
59 
     | 
    
         
             
            		end
         
     | 
| 
       51 
60 
     | 
    
         | 
| 
      
 61 
     | 
    
         
            +
            		# Stop measuring a duration and append the duration to the current total.
         
     | 
| 
       52 
62 
     | 
    
         
             
            		def stop!
         
     | 
| 
       53 
63 
     | 
    
         
             
            			if @started
         
     | 
| 
       54 
64 
     | 
    
         
             
            				@total += (Clock.now - @started)
         
     | 
| 
         @@ -58,6 +68,7 @@ module Async 
     | 
|
| 
       58 
68 
     | 
    
         
             
            			return @total
         
     | 
| 
       59 
69 
     | 
    
         
             
            		end
         
     | 
| 
       60 
70 
     | 
    
         | 
| 
      
 71 
     | 
    
         
            +
            		# The total elapsed time including any current duration.
         
     | 
| 
       61 
72 
     | 
    
         
             
            		def total
         
     | 
| 
       62 
73 
     | 
    
         
             
            			total = @total
         
     | 
| 
       63 
74 
     | 
    
         | 
| 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            A synchronization primitive, which allows fibers to wait until a particular condition is (edge) triggered. Zero or more fibers can wait on a condition. When the condition is signalled, the fibers will be resumed in order.
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            ## Example
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            ~~~ ruby
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'async'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            Sync do
         
     | 
| 
      
 9 
     | 
    
         
            +
            	condition = Async::Condition.new
         
     | 
| 
      
 10 
     | 
    
         
            +
            	
         
     | 
| 
      
 11 
     | 
    
         
            +
            	Async do
         
     | 
| 
      
 12 
     | 
    
         
            +
            		Console.logger.info "Waiting for condition..."
         
     | 
| 
      
 13 
     | 
    
         
            +
            		value = condition.wait
         
     | 
| 
      
 14 
     | 
    
         
            +
            		Console.logger.info "Condition was signalled: #{value}"
         
     | 
| 
      
 15 
     | 
    
         
            +
            	end
         
     | 
| 
      
 16 
     | 
    
         
            +
            	
         
     | 
| 
      
 17 
     | 
    
         
            +
            	Async do |task|
         
     | 
| 
      
 18 
     | 
    
         
            +
            		task.sleep(1)
         
     | 
| 
      
 19 
     | 
    
         
            +
            		Console.logger.info "Signalling condition..."
         
     | 
| 
      
 20 
     | 
    
         
            +
            		condition.signal("Hello World")
         
     | 
| 
      
 21 
     | 
    
         
            +
            	end
         
     | 
| 
      
 22 
     | 
    
         
            +
            end
         
     | 
| 
      
 23 
     | 
    
         
            +
            ~~~
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            ### Output
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            ~~~
         
     | 
| 
      
 28 
     | 
    
         
            +
            0.0s     info: Waiting for condition... [ec=0x3c] [pid=47943]
         
     | 
| 
      
 29 
     | 
    
         
            +
            1.0s     info: Signalling condition... [ec=0x64] [pid=47943]
         
     | 
| 
      
 30 
     | 
    
         
            +
            1.0s     info: Condition was signalled: Hello World [ec=0x3c] [pid=47943]
         
     | 
| 
      
 31 
     | 
    
         
            +
            ~~~
         
     | 
    
        data/lib/async/condition.rb
    CHANGED
    
    | 
         @@ -24,43 +24,54 @@ require 'fiber' 
     | 
|
| 
       24 
24 
     | 
    
         
             
            require_relative 'node'
         
     | 
| 
       25 
25 
     | 
    
         | 
| 
       26 
26 
     | 
    
         
             
            module Async
         
     | 
| 
       27 
     | 
    
         
            -
            	# A synchronization  
     | 
| 
      
 27 
     | 
    
         
            +
            	# A synchronization primitive, which allows fibers to wait until a particular condition is (edge) triggered.
         
     | 
| 
      
 28 
     | 
    
         
            +
            	# @public Since `stable-v1`.
         
     | 
| 
       28 
29 
     | 
    
         
             
            	class Condition
         
     | 
| 
       29 
30 
     | 
    
         
             
            		def initialize
         
     | 
| 
       30 
31 
     | 
    
         
             
            			@waiting = []
         
     | 
| 
       31 
32 
     | 
    
         
             
            		end
         
     | 
| 
       32 
33 
     | 
    
         | 
| 
      
 34 
     | 
    
         
            +
            		Queue = Struct.new(:fiber) do
         
     | 
| 
      
 35 
     | 
    
         
            +
            			def transfer(*arguments)
         
     | 
| 
      
 36 
     | 
    
         
            +
            				fiber&.transfer(*arguments)
         
     | 
| 
      
 37 
     | 
    
         
            +
            			end
         
     | 
| 
      
 38 
     | 
    
         
            +
            			
         
     | 
| 
      
 39 
     | 
    
         
            +
            			def alive?
         
     | 
| 
      
 40 
     | 
    
         
            +
            				fiber&.alive?
         
     | 
| 
      
 41 
     | 
    
         
            +
            			end
         
     | 
| 
      
 42 
     | 
    
         
            +
            			
         
     | 
| 
      
 43 
     | 
    
         
            +
            			def nullify
         
     | 
| 
      
 44 
     | 
    
         
            +
            				self.fiber = nil
         
     | 
| 
      
 45 
     | 
    
         
            +
            			end
         
     | 
| 
      
 46 
     | 
    
         
            +
            		end
         
     | 
| 
      
 47 
     | 
    
         
            +
            		
         
     | 
| 
      
 48 
     | 
    
         
            +
            		private_constant :Queue
         
     | 
| 
      
 49 
     | 
    
         
            +
            		
         
     | 
| 
       33 
50 
     | 
    
         
             
            		# Queue up the current fiber and wait on yielding the task.
         
     | 
| 
       34 
     | 
    
         
            -
            		# @ 
     | 
| 
      
 51 
     | 
    
         
            +
            		# @returns [Object]
         
     | 
| 
       35 
52 
     | 
    
         
             
            		def wait
         
     | 
| 
       36 
     | 
    
         
            -
            			 
     | 
| 
       37 
     | 
    
         
            -
            			@waiting <<  
     | 
| 
       38 
     | 
    
         
            -
            			
         
     | 
| 
       39 
     | 
    
         
            -
            			Task.yield
         
     | 
| 
      
 53 
     | 
    
         
            +
            			queue = Queue.new(Fiber.current)
         
     | 
| 
      
 54 
     | 
    
         
            +
            			@waiting << queue
         
     | 
| 
       40 
55 
     | 
    
         | 
| 
       41 
     | 
    
         
            -
            			 
     | 
| 
       42 
     | 
    
         
            -
            		 
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
       44 
     | 
    
         
            -
            			@waiting.delete(fiber)
         
     | 
| 
       45 
     | 
    
         
            -
            			raise
         
     | 
| 
      
 56 
     | 
    
         
            +
            			Fiber.scheduler.transfer
         
     | 
| 
      
 57 
     | 
    
         
            +
            		ensure
         
     | 
| 
      
 58 
     | 
    
         
            +
            			queue.nullify
         
     | 
| 
       46 
59 
     | 
    
         
             
            		end
         
     | 
| 
       47 
60 
     | 
    
         | 
| 
       48 
61 
     | 
    
         
             
            		# Is any fiber waiting on this notification?
         
     | 
| 
       49 
     | 
    
         
            -
            		# @ 
     | 
| 
      
 62 
     | 
    
         
            +
            		# @returns [Boolean]
         
     | 
| 
       50 
63 
     | 
    
         
             
            		def empty?
         
     | 
| 
       51 
64 
     | 
    
         
             
            			@waiting.empty?
         
     | 
| 
       52 
65 
     | 
    
         
             
            		end
         
     | 
| 
       53 
66 
     | 
    
         | 
| 
       54 
67 
     | 
    
         
             
            		# Signal to a given task that it should resume operations.
         
     | 
| 
       55 
     | 
    
         
            -
            		# @ 
     | 
| 
       56 
     | 
    
         
            -
            		# @see Task.yield which is responsible for handling value.
         
     | 
| 
       57 
     | 
    
         
            -
            		# @return [void]
         
     | 
| 
      
 68 
     | 
    
         
            +
            		# @parameter value [Object | Nil] The value to return to the waiting fibers.
         
     | 
| 
       58 
69 
     | 
    
         
             
            		def signal(value = nil)
         
     | 
| 
       59 
70 
     | 
    
         
             
            			waiting = @waiting
         
     | 
| 
       60 
71 
     | 
    
         
             
            			@waiting = []
         
     | 
| 
       61 
72 
     | 
    
         | 
| 
       62 
73 
     | 
    
         
             
            			waiting.each do |fiber|
         
     | 
| 
       63 
     | 
    
         
            -
            				 
     | 
| 
      
 74 
     | 
    
         
            +
            				Fiber.scheduler.resume(fiber, value) if fiber.alive?
         
     | 
| 
       64 
75 
     | 
    
         
             
            			end
         
     | 
| 
       65 
76 
     | 
    
         | 
| 
       66 
77 
     | 
    
         
             
            			return nil
         
     | 
    
        data/lib/async/node.rb
    CHANGED
    
    | 
         @@ -21,7 +21,7 @@ 
     | 
|
| 
       21 
21 
     | 
    
         
             
            # THE SOFTWARE.
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
            module Async
         
     | 
| 
       24 
     | 
    
         
            -
            	# A double linked list.
         
     | 
| 
      
 24 
     | 
    
         
            +
            	# A double linked list used for managing tasks.
         
     | 
| 
       25 
25 
     | 
    
         
             
            	class List
         
     | 
| 
       26 
26 
     | 
    
         
             
            		def initialize
         
     | 
| 
       27 
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.
         
     | 
| 
         @@ -121,6 +121,7 @@ module Async 
     | 
|
| 
       121 
121 
     | 
    
         | 
| 
       122 
122 
     | 
    
         
             
            	private_constant :List
         
     | 
| 
       123 
123 
     | 
    
         | 
| 
      
 124 
     | 
    
         
            +
            	# A list of children tasks.
         
     | 
| 
       124 
125 
     | 
    
         
             
            	class Children < List
         
     | 
| 
       125 
126 
     | 
    
         
             
            		def initialize
         
     | 
| 
       126 
127 
     | 
    
         
             
            			super
         
     | 
| 
         @@ -154,10 +155,10 @@ module Async 
     | 
|
| 
       154 
155 
     | 
    
         
             
            		end
         
     | 
| 
       155 
156 
     | 
    
         
             
            	end
         
     | 
| 
       156 
157 
     | 
    
         | 
| 
       157 
     | 
    
         
            -
            	#  
     | 
| 
      
 158 
     | 
    
         
            +
            	# A node in a tree, used for implementing the task hierarchy.
         
     | 
| 
       158 
159 
     | 
    
         
             
            	class Node
         
     | 
| 
       159 
160 
     | 
    
         
             
            		# Create a new node in the tree.
         
     | 
| 
       160 
     | 
    
         
            -
            		# @ 
     | 
| 
      
 161 
     | 
    
         
            +
            		# @parameter parent [Node | Nil] This node will attach to the given parent.
         
     | 
| 
       161 
162 
     | 
    
         
             
            		def initialize(parent = nil, annotation: nil, transient: false)
         
     | 
| 
       162 
163 
     | 
    
         
             
            			@parent = nil
         
     | 
| 
       163 
164 
     | 
    
         
             
            			@children = nil
         
     | 
| 
         @@ -175,15 +176,21 @@ module Async 
     | 
|
| 
       175 
176 
     | 
    
         
             
            			end
         
     | 
| 
       176 
177 
     | 
    
         
             
            		end
         
     | 
| 
       177 
178 
     | 
    
         | 
| 
       178 
     | 
    
         
            -
            		#  
     | 
| 
       179 
     | 
    
         
            -
            		 
     | 
| 
      
 179 
     | 
    
         
            +
            		# @returns [Node] the root node in the hierarchy.
         
     | 
| 
      
 180 
     | 
    
         
            +
            		def root
         
     | 
| 
      
 181 
     | 
    
         
            +
            			@parent&.root || self
         
     | 
| 
      
 182 
     | 
    
         
            +
            		end
         
     | 
| 
      
 183 
     | 
    
         
            +
            		
         
     | 
| 
      
 184 
     | 
    
         
            +
            		# @private
         
     | 
| 
       180 
185 
     | 
    
         
             
            		attr_accessor :head
         
     | 
| 
      
 186 
     | 
    
         
            +
            		
         
     | 
| 
      
 187 
     | 
    
         
            +
            		# @private
         
     | 
| 
       181 
188 
     | 
    
         
             
            		attr_accessor :tail
         
     | 
| 
       182 
189 
     | 
    
         | 
| 
       183 
     | 
    
         
            -
            		# @ 
     | 
| 
      
 190 
     | 
    
         
            +
            		# @attribute [Node] The parent node.
         
     | 
| 
       184 
191 
     | 
    
         
             
            		attr :parent
         
     | 
| 
       185 
192 
     | 
    
         | 
| 
       186 
     | 
    
         
            -
            		# @ 
     | 
| 
      
 193 
     | 
    
         
            +
            		# @attribute children [Children | Nil] Optional list of children.
         
     | 
| 
       187 
194 
     | 
    
         
             
            		attr :children
         
     | 
| 
       188 
195 
     | 
    
         | 
| 
       189 
196 
     | 
    
         
             
            		# A useful identifier for the current node.
         
     | 
| 
         @@ -215,6 +222,8 @@ module Async 
     | 
|
| 
       215 
222 
     | 
    
         | 
| 
       216 
223 
     | 
    
         
             
            			if @annotation
         
     | 
| 
       217 
224 
     | 
    
         
             
            				"#{@object_name} #{@annotation}"
         
     | 
| 
      
 225 
     | 
    
         
            +
            			elsif line = self.backtrace(0, 1)&.first
         
     | 
| 
      
 226 
     | 
    
         
            +
            				"#{@object_name} #{line}"
         
     | 
| 
       218 
227 
     | 
    
         
             
            			else
         
     | 
| 
       219 
228 
     | 
    
         
             
            				@object_name
         
     | 
| 
       220 
229 
     | 
    
         
             
            			end
         
     | 
| 
         @@ -225,12 +234,14 @@ module Async 
     | 
|
| 
       225 
234 
     | 
    
         
             
            		end
         
     | 
| 
       226 
235 
     | 
    
         | 
| 
       227 
236 
     | 
    
         
             
            		def to_s
         
     | 
| 
       228 
     | 
    
         
            -
            			"\#<#{description}>"
         
     | 
| 
      
 237 
     | 
    
         
            +
            			"\#<#{self.description}>"
         
     | 
| 
       229 
238 
     | 
    
         
             
            		end
         
     | 
| 
       230 
239 
     | 
    
         | 
| 
      
 240 
     | 
    
         
            +
            		alias inspect to_s
         
     | 
| 
      
 241 
     | 
    
         
            +
            		
         
     | 
| 
       231 
242 
     | 
    
         
             
            		# Change the parent of this node.
         
     | 
| 
       232 
     | 
    
         
            -
            		# @ 
     | 
| 
       233 
     | 
    
         
            -
            		# @ 
     | 
| 
      
 243 
     | 
    
         
            +
            		# @parameter parent [Node | Nil] the parent to attach to, or nil to detach.
         
     | 
| 
      
 244 
     | 
    
         
            +
            		# @returns [Node] Itself.
         
     | 
| 
       234 
245 
     | 
    
         
             
            		def parent=(parent)
         
     | 
| 
       235 
246 
     | 
    
         
             
            			return if @parent.equal?(parent)
         
     | 
| 
       236 
247 
     | 
    
         | 
| 
         @@ -263,7 +274,7 @@ module Async 
     | 
|
| 
       263 
274 
     | 
    
         | 
| 
       264 
275 
     | 
    
         
             
            		# Whether the node can be consumed safely. By default, checks if the
         
     | 
| 
       265 
276 
     | 
    
         
             
            		# children set is empty.
         
     | 
| 
       266 
     | 
    
         
            -
            		# @ 
     | 
| 
      
 277 
     | 
    
         
            +
            		# @returns [Boolean]
         
     | 
| 
       267 
278 
     | 
    
         
             
            		def finished?
         
     | 
| 
       268 
279 
     | 
    
         
             
            			@children.nil? || @children.finished?
         
     | 
| 
       269 
280 
     | 
    
         
             
            		end
         
     | 
| 
         @@ -293,7 +304,7 @@ module Async 
     | 
|
| 
       293 
304 
     | 
    
         
             
            		end
         
     | 
| 
       294 
305 
     | 
    
         | 
| 
       295 
306 
     | 
    
         
             
            		# Traverse the tree.
         
     | 
| 
       296 
     | 
    
         
            -
            		# @ 
     | 
| 
      
 307 
     | 
    
         
            +
            		# @yields {|node, level| ...} The node and the level relative to the given root.
         
     | 
| 
       297 
308 
     | 
    
         
             
            		def traverse(level = 0, &block)
         
     | 
| 
       298 
309 
     | 
    
         
             
            			yield self, level
         
     | 
| 
       299 
310 
     | 
    
         | 
| 
         @@ -329,6 +340,10 @@ module Async 
     | 
|
| 
       329 
340 
     | 
    
         
             
            			end
         
     | 
| 
       330 
341 
     | 
    
         
             
            		end
         
     | 
| 
       331 
342 
     | 
    
         | 
| 
      
 343 
     | 
    
         
            +
            		def stopped?
         
     | 
| 
      
 344 
     | 
    
         
            +
            			@children.nil?
         
     | 
| 
      
 345 
     | 
    
         
            +
            		end
         
     | 
| 
      
 346 
     | 
    
         
            +
            		
         
     | 
| 
       332 
347 
     | 
    
         
             
            		def print_hierarchy(out = $stdout, backtrace: true)
         
     | 
| 
       333 
348 
     | 
    
         
             
            			self.traverse do |node, level|
         
     | 
| 
       334 
349 
     | 
    
         
             
            				indent = "\t" * level
         
     | 
    
        data/lib/async/notification.rb
    CHANGED
    
    | 
         @@ -24,13 +24,13 @@ require_relative 'condition' 
     | 
|
| 
       24 
24 
     | 
    
         | 
| 
       25 
25 
     | 
    
         
             
            module Async
         
     | 
| 
       26 
26 
     | 
    
         
             
            	# A synchronization primitive, which allows fibers to wait until a notification is received. Does not block the task which signals the notification. Waiting tasks are resumed on next iteration of the reactor.
         
     | 
| 
      
 27 
     | 
    
         
            +
            	# @public Since `stable-v1`.
         
     | 
| 
       27 
28 
     | 
    
         
             
            	class Notification < Condition
         
     | 
| 
       28 
29 
     | 
    
         
             
            		# Signal to a given task that it should resume operations.
         
     | 
| 
       29 
     | 
    
         
            -
            		# @return [void]
         
     | 
| 
       30 
30 
     | 
    
         
             
            		def signal(value = nil, task: Task.current)
         
     | 
| 
       31 
31 
     | 
    
         
             
            			return if @waiting.empty?
         
     | 
| 
       32 
32 
     | 
    
         | 
| 
       33 
     | 
    
         
            -
            			 
     | 
| 
      
 33 
     | 
    
         
            +
            			Fiber.scheduler.push Signal.new(@waiting, value)
         
     | 
| 
       34 
34 
     | 
    
         | 
| 
       35 
35 
     | 
    
         
             
            			@waiting = []
         
     | 
| 
       36 
36 
     | 
    
         | 
| 
         @@ -42,9 +42,9 @@ module Async 
     | 
|
| 
       42 
42 
     | 
    
         
             
            				true
         
     | 
| 
       43 
43 
     | 
    
         
             
            			end
         
     | 
| 
       44 
44 
     | 
    
         | 
| 
       45 
     | 
    
         
            -
            			def  
     | 
| 
      
 45 
     | 
    
         
            +
            			def transfer
         
     | 
| 
       46 
46 
     | 
    
         
             
            				waiting.each do |fiber|
         
     | 
| 
       47 
     | 
    
         
            -
            					fiber. 
     | 
| 
      
 47 
     | 
    
         
            +
            					fiber.transfer(value) if fiber.alive?
         
     | 
| 
       48 
48 
     | 
    
         
             
            				end
         
     | 
| 
       49 
49 
     | 
    
         
             
            			end
         
     | 
| 
       50 
50 
     | 
    
         
             
            		end
         
     | 
    
        data/lib/async/queue.rb
    CHANGED
    
    | 
         @@ -24,6 +24,7 @@ require_relative 'notification' 
     | 
|
| 
       24 
24 
     | 
    
         | 
| 
       25 
25 
     | 
    
         
             
            module Async
         
     | 
| 
       26 
26 
     | 
    
         
             
            	# A queue which allows items to be processed in order.
         
     | 
| 
      
 27 
     | 
    
         
            +
            	# @public Since `stable-v1`.
         
     | 
| 
       27 
28 
     | 
    
         
             
            	class Queue < Notification
         
     | 
| 
       28 
29 
     | 
    
         
             
            		def initialize(parent: nil)
         
     | 
| 
       29 
30 
     | 
    
         
             
            			super()
         
     | 
| 
         @@ -42,16 +43,14 @@ module Async 
     | 
|
| 
       42 
43 
     | 
    
         
             
            			@items.empty?
         
     | 
| 
       43 
44 
     | 
    
         
             
            		end
         
     | 
| 
       44 
45 
     | 
    
         | 
| 
       45 
     | 
    
         
            -
            		def  
     | 
| 
       46 
     | 
    
         
            -
            			@items 
     | 
| 
      
 46 
     | 
    
         
            +
            		def enqueue(item)
         
     | 
| 
      
 47 
     | 
    
         
            +
            			@items.push(item)
         
     | 
| 
       47 
48 
     | 
    
         | 
| 
       48 
49 
     | 
    
         
             
            			self.signal unless self.empty?
         
     | 
| 
       49 
50 
     | 
    
         
             
            		end
         
     | 
| 
       50 
51 
     | 
    
         | 
| 
       51 
     | 
    
         
            -
            		def  
     | 
| 
       52 
     | 
    
         
            -
            			 
     | 
| 
       53 
     | 
    
         
            -
            			
         
     | 
| 
       54 
     | 
    
         
            -
            			self.signal unless self.empty?
         
     | 
| 
      
 52 
     | 
    
         
            +
            		def <<(item)
         
     | 
| 
      
 53 
     | 
    
         
            +
            			enqueue(item)
         
     | 
| 
       55 
54 
     | 
    
         
             
            		end
         
     | 
| 
       56 
55 
     | 
    
         | 
| 
       57 
56 
     | 
    
         
             
            		def dequeue
         
     | 
| 
         @@ -75,6 +74,7 @@ module Async 
     | 
|
| 
       75 
74 
     | 
    
         
             
            		end
         
     | 
| 
       76 
75 
     | 
    
         
             
            	end
         
     | 
| 
       77 
76 
     | 
    
         | 
| 
      
 77 
     | 
    
         
            +
            	# @public Since `stable-v1`.
         
     | 
| 
       78 
78 
     | 
    
         
             
            	class LimitedQueue < Queue
         
     | 
| 
       79 
79 
     | 
    
         
             
            		def initialize(limit = 1, **options)
         
     | 
| 
       80 
80 
     | 
    
         
             
            			super(**options)
         
     | 
| 
         @@ -86,12 +86,12 @@ module Async 
     | 
|
| 
       86 
86 
     | 
    
         | 
| 
       87 
87 
     | 
    
         
             
            		attr :limit
         
     | 
| 
       88 
88 
     | 
    
         | 
| 
       89 
     | 
    
         
            -
            		# @ 
     | 
| 
      
 89 
     | 
    
         
            +
            		# @returns [Boolean] Whether trying to enqueue an item would block.
         
     | 
| 
       90 
90 
     | 
    
         
             
            		def limited?
         
     | 
| 
       91 
91 
     | 
    
         
             
            			@items.size >= @limit
         
     | 
| 
       92 
92 
     | 
    
         
             
            		end
         
     | 
| 
       93 
93 
     | 
    
         | 
| 
       94 
     | 
    
         
            -
            		def  
     | 
| 
      
 94 
     | 
    
         
            +
            		def enqueue item
         
     | 
| 
       95 
95 
     | 
    
         
             
            			while limited?
         
     | 
| 
       96 
96 
     | 
    
         
             
            				@full.wait
         
     | 
| 
       97 
97 
     | 
    
         
             
            			end
         
     | 
| 
         @@ -99,19 +99,6 @@ module Async 
     | 
|
| 
       99 
99 
     | 
    
         
             
            			super
         
     | 
| 
       100 
100 
     | 
    
         
             
            		end
         
     | 
| 
       101 
101 
     | 
    
         | 
| 
       102 
     | 
    
         
            -
            		def enqueue *items
         
     | 
| 
       103 
     | 
    
         
            -
            			while !items.empty?
         
     | 
| 
       104 
     | 
    
         
            -
            				while limited?
         
     | 
| 
       105 
     | 
    
         
            -
            					@full.wait
         
     | 
| 
       106 
     | 
    
         
            -
            				end
         
     | 
| 
       107 
     | 
    
         
            -
            				
         
     | 
| 
       108 
     | 
    
         
            -
            				available = @limit - @items.size
         
     | 
| 
       109 
     | 
    
         
            -
            				@items.concat(items.shift(available))
         
     | 
| 
       110 
     | 
    
         
            -
            				
         
     | 
| 
       111 
     | 
    
         
            -
            				self.signal unless self.empty?
         
     | 
| 
       112 
     | 
    
         
            -
            			end
         
     | 
| 
       113 
     | 
    
         
            -
            		end
         
     | 
| 
       114 
     | 
    
         
            -
            		
         
     | 
| 
       115 
102 
     | 
    
         
             
            		def dequeue
         
     | 
| 
       116 
103 
     | 
    
         
             
            			item = super
         
     | 
| 
       117 
104 
     | 
    
         |